文章作者:crack四K
Poweroff3.0.13功能改进过程
个人觉得Poweroff十分小巧的软件,我下载的是汉化版,未加壳168K,但它功能却非常强大,能定时开关机、关闭显示器、运行程序等等。可以说这是一款十分实用的软件。在使用过程中,发现在选项中的运行程序一项,设计的不是十分合理,其定时运行的程序后,Poweroff本身程序将推动响应,就是说,只有将程序关闭后,Poweroff才能继续运行后面的程序即关机,关显示器等操作,且这个功能只能运行应用程序,虽然可以选择任意文件,但经过测试发现非EXE文件会报错。
经过上面的实验,我对这个软件进行了调试。
打开OD,载入程序,运行。将动作中的选项点到“无”,然后在选项中点运行程序,点右边的程序按钮,选择要打开的程序比如“1.exe”。基于实验中的现像,可以判断这个软件运行外部程序调动的API函数为CreateProcessA,我们就对这个API函数设断,这个函数是在kernel32中。选立即执行选项,点启动,OD成功断下。这时OD当前行在API函数中如下:
kernel32.CreateProcessA
77E41BBC>55PUSHEBP
77E41BBD8BECMOVEBP,ESP
77E41BBF6A00PUSH0
77E41BC1FF752CPUSHDWORDPTRSS:[EBP+2C]
77E41BC4FF7528PUSHDWORDPTRSS:[EBP+28]
77E41BC7FF7524PUSHDWORDPTRSS:[EBP+24]
77E41BCAFF7520PUSHDWORDPTRSS:[EBP+20]
77E41BCDFF751CPUSHDWORDPTRSS:[EBP+1C]
77E41BD0FF7518PUSHDWORDPTRSS:[EBP+18]
77E41BD3FF7514PUSHDWORDPTRSS:[EBP+14]
77E41BD6FF7510PUSHDWORDPTRSS:[EBP+10]
77E41BD9FF750CPUSHDWORDPTRSS:[EBP+C]
77E41BDCFF7508PUSHDWORDPTRSS:[EBP+8]
77E41BDF6A00PUSH0
77E41BE1E84B170100CALLkernel32.CreateProcessInternalA
77E41BE65DPOPEBP
77E41BE7C22800RETN28
77E41BEA>6A00PUSH0
77E41BECFF742408PUSHDWORDPTRSS:[ESP+8]
77E41BF0E883860100CALLkernel32.SleepEx
77E41BF5C20400RETN4
我们要返回到上层,即调用函数的地方,在OD右侧的堆栈中的第一行点右键,选在反汇编窗口中跟随来到★处:
00401059|.83C40CADDESP,0C
0040105C|.8D45E8LEAEAX,DWORDPTRSS:[EBP-18]
0040105F50PUSHEAX
004010608D45A4LEAEAX,DWORDPTRSS:[EBP-5C]
0040106350PUSHEAX
00401064FF75FCPUSHDWORDPTRSS:[EBP-4]
0040106753PUSHEBX
0040106853PUSHEBX
0040106953PUSHEBX
0040106A53PUSHEBX
0040106B53PUSHEBX
0040106C57PUSHEDI
0040106D53PUSHEBX
0040106EFF1564514100CALLDWORDPTRDS:[<&KERNEL32.CreateProcessA>];kernel32.CreateProcessA
★0040107485C0TESTEAX,EAX
00401076750CJNZSHORTcPowerOf.00401084
00401078|.FF7508PUSHDWORDPTRSS:[EBP+8]
0040107B|.56PUSHESI
0040107C|.E84F2E0000CALLcPowerOf.00403ED0
00401081|.59POPECX
00401082|.EB33JMPSHORTcPowerOf.004010B7
00401084|>6840704100PUSHcPowerOf.00417040;ASCII"Waitingforprogramtofinish"
00401089|.E8472C0000CALLcPowerOf.00403CD5
0040108E|.59POPECX
往上看我们就可以看到这个API全部调用的参数的PUSH,这个API共有10个参数,具体用法大家可以到网上搜或者查阅MSDN。从这而也看到
不知道作者是否是有意的,在运行这个函数后没有关闭其内核对象,即调用一个CloseHandle函数,这就是运行外部程序后,Poweroff失去响应的原因所在。找到原因后,我们就要动手进行改造。这里我要把调用外部程序的API改为ShellExecuteA。为了修改成功,我自己随便写了段程序用到ShellExecuteA,调试发现其程序如下:
0040176A|.6A05PUSH5;/IsShown=5
0040176C|.6A00PUSH0;|DefDir=NULL
0040176E|.6A00PUSH0;|Parameters=NULL
00401770|.685E304000PUSHDragDrop.0040305E;|FileName="D:\crack\wya.exe"
00401775|.6817314000PUSHDragDrop.00403117;|Operation="open"
0040177A|.FF7508PUSHDWORDPTRSS:[EBP+8];|hWnd
0040177D|.E810010000CALL;\ShellExecuteA
这里我们就可以发现,要修改成功关键在两点,一个是替换的代码是否比原来的小,比原来的小就方便很多我们可以直接改,如果比原来的大就要动些手脚了,后面我们将发现很不幸是比原来大的,不过刚好我们可以学习一下嘛,总不能都能碰到方便的吧。其次是ShellExecuteA参数中的Operation是一个字符串,这个也是原程序中没有的。下面我就具体介绍解决方法。
首选就是要在原程序中加入"open"这个字符串,因为是4个字节,考虑到字符串最后为一个NULL即空字节,前面相邻的字符串之前至少也有一个NULL,所以我要找到原程序中有6个空字节的地方。在OD的左下方的内存窗口中点右键查找二进制000000000000,为了防止软件可以用到的一些空白的地方,所以要尽量往后找,最好是两个已有字符串的中间地带,我找到的是41C8F3,复制前面一小段数据,或者
后面的也可以。然后关闭OD程序,用16进制编辑软件如winhex等打开poweroff.exe查找刚才复制的数据,找到你需要的空白段,填入open(注意前后必须有一个00),保存文件。再次打开OD,载入程序运行,在内存窗口中来到41C8F3,看到了吧,有“open”了吧,我填的地方首地址是418F4即只空了一个字节。将这个地址记住,后面要用到。
在OD中来到0040105F,这是CreateProcessA第一个函数参数入栈的地方,我们的修改将从这而开始,右键,汇编,依次汇编如下★处
★0040105F.6A05PUSH5
★00401061.6A00PUSH0
★00401063.6A00PUSH0
★00401065.57PUSHEDI
★★00401066.E962390100JMPcPowerOf.004149CD
0040106B.53PUSHEBX;|pProcessSecurity
0040106C.57PUSHEDI;|CommandLine
0040106D.53PUSHEBX;|ModuleFileName
0040106E.FF1564514100CALLDWORDPTRDS:[<&KERNEL32.CreateProcessA>];\CreateProcessA
00401074>85C0TESTEAX,EAX
00401076.750CJNZSHORTcPowerOf.00401084
00401078.FF7508PUSHDWORDPTRSS:[EBP+8]
0040107B.56PUSHESI
0040107C.E84F2E0000CALLcPowerOf.00403ED0
00401081.59POPECX
00401082.EB33JMPSHORTcPowerOf.004010B7
00401084>6840704100PUSHcPowerOf.00417040;ASCII"Waitingforprogramtofinish"
PUSH 5,两个PUSH 0这些就不说了,上面介绍函数时个就说过了,PUSH EDI是参考了CreateProcessA的参数,看到下面还有一个
PUSH EDI了吧,这里放着你在运行外部程序或者文件的路径。大家会认为上面介绍的ShellExecuteA有6个参数,这里压栈了4个怎么就没了呢。这就是我特别要指出的地方。开头就说了,替换的代码比原来的大,所以到这行程序就要停了,再换一行后面就不够用了,所以我们要跳走了看到这个JMP没,★★的地方。这个地址来源我也要介绍一下。一般的程序编译成EXE后,程序中都会有一些空白的地方,无论用哪种语言都一样,只不过有些多有些少一些罢了,这也就是为什么汇编语言写的程序最小的原因。我们在OD中往下翻,快到程序最后的时候有一大片的空白的地方,我们选一个起始地址,我选的是4149CD,所以在上面的代码中我用了JMPcPowerOf.004149CD,然后我们再来到004149CD继续我们的修改如下:
004149C3CCINT3
004149C4$-FF25A4504100JMPDWORDPTRDS:[<&KERNEL32.RtlUnwind>];ntdll.RtlUnwind
004149CA00DB00
004149CB00DB00
004149CC00DB00
★004149CD>68F4C84100PUSHcPowerOf.0041C8F4;|Operation="open"
004149D2.FF7508PUSHDWORDPTRSS:[EBP+8];|hWnd
004149D5.E869F5FE76CALLSHELL32.ShellExecuteA;\ShellExecuteA
004149DA.^E995C6FEFFJMPcPowerOf.00401074
004149DF00DB00
004149E000DB00
看到了吧,这儿就用到了添加的字符串open,还记得地址吗,对写入PUSH0041C8F4,下一个参数就是当然程序的句柄了,这个简单,熟悉软件调试的朋友应该知道,通常在调用API前的句柄放在EBP+8的堆栈中,这个大家最好用之前先验证一下,防止万一嘛,程序出错是小事,系统当掉就是大事了。然后是函数调用了,CALLSHELL32.ShellExecuteA解决。最后大家可别忘了,我们是从上面跳到这块空白地方来开垦的,当然要回去了,我们要把CreateProcessA完全替换掉,跳回来的地方就是它的下面一行即★处
0040106D53PUSHEBX
0040106EFF1564514100CALLDWORDPTRDS:[<&KERNEL32.CreateProcessA>];kernel32.CreateProcessA
★0040107485C0TESTEAX,EAX
00401076750CJNZSHORTcPowerOf.00401084
00401078|.FF7508PUSHDWORDPTRSS:[EBP+8]
0040107B|.56PUSHESI
这样就完全替换掉一部分,绕过一部分原来的代码了。接下来就保存修改了,在OD中点右键,选复制到可执行文件,选全部修改,关掉弹出来一个窗口,点是,就可以保存了。下面运行试试。选择可执行文件,定时运行OK,选择任意有关联的文件,如TXT,DOC,JPG等试试能打开,OK,而Poweroff也不会因为打开程序而停止运行了。成功!
总结:在没有源代码的条件下,通过逆向工程简单地修改软件达到更方便更人性化的使用,是一个往不错的选择。当然,大部分软件都是有版权保护的,一般也都禁止调试和修改,大家还是要把目的端正哦,呵呵,为了学习研究嘛。
原版下载:http://www.onlinedown.net/soft/16579.htm(华军)