逆向工程核心原理第十章
函数调用约定
函数调用约定是对函数调用时如何传递参数的一种约定
函数调用前会把各个参数逆序压入栈(因为栈是先进后出),栈是定义在进程中的一段内存空间,向低地址方向扩展,且其大小被记录在PE头中,进程运行时就确定了栈内存大小
函数执行完后,栈中参数如何处理?
不用管,因为只是临时存储在栈中,即使不在使用,清除相应的值也会浪费CPU资源,下一次向栈中存入其他值时会覆盖原来的值,因此函数执行完后不用管栈中参数
函数执行完后,ESP如何变化?
栈内存是固定的,ESP用来指示栈当前的位置,如果ESP指向栈底,则无法继续使用该栈。函数调用后如何处理ESP,这就是函数调用约定要解决的问题。
主要的函数调用约定有以下3种
- cdecl
- stdcall
- fastcall
cdecl
cdecl是C语言函数默认使用的方式,调用者复则处理栈,调用者的代码有以下特征,在调用完函数后,调用者会调整esp指向的位置(比如下面的
ADD ESP, 8
),这种由调用者直接清理其压入栈的参数的方式就是cdecl1
2
3
4
5
6...
push 2
push 1
call 00401000
add esp, 8
...
stdcall
stdcall常用于Win32API,该方式是由被调用者来清理栈,C语言中如果要用该方式,需要在定义时,在函数名前加上"__stdcall"关键字,stdcall被调用这有以下特征,
retn 8
含义retn + pop 8字节,即返回后使ESP增加到指定大小,这就是由被调用者来完成栈的清理工作1
2
3...
pop ebp
retn 8
fastcall
- fastcall与stdcall基本相似,但fastcall通常用寄存器传递部分函数参数(ECX和EDX传递前2个参数)
逆向工程核心原理第十一章
Part10Tus.ReverseMe下载链接1307-lenas-reversing-for-newbies,如果提示缺少MSVBVM50.dll,需要下载VB5依赖,VB5依赖下载链接:http://download.microsoft.com/download/vb50pro/utility/1/win98/EN-US/Msvbvm50.exe
运行查看
软件第一个弹窗提示要去除该弹窗并找到正确的序列号
用OD打开程序exe文件,可以看到是EP具有典型的VB特征
接下来我们还是采用检索字符串的方式定位相关代码,因为第一个目标是去掉第一个弹窗,因此先定位到字符串"Get rid of all ..."所在位置"00402C85"
往下继续调试,可以发现,第一个弹窗是在"00402CFE"调用弹出的,接下来就是去掉这个弹窗了
尝试直接nop掉这句call,运行发现无事发生,没有弹出输入序列号的窗口。原因是输入序列号的窗口是需要我们点击第一个窗口的确定才能弹出来的,我们除了nop掉这句代码,还需要模拟运行这句call命令并且用户点击了确定的状态,这样才能正确去掉弹窗
我们重新运行到"00402CFE"位置,然后F8让程序弹出窗口,并且我们点击"确定",观察寄存器的变化
可以看到变化了寄存器有EAX、ECX、EDX、ESP、EIP、EFLAGS这些寄存器,为了更好判断哪些值至关重要,我们再次重新调试并运行到"00402CFE"位置,F8让程序弹出窗口,这次我们点击"取消",观察寄存器的变化
对比上面两张图,我们可以推断出EAX寄存器的值是弹窗函数的返回值,并且"1"代表用户点击了确定,"2"代表点击了取消
那么去弹窗就可以按这样来实现,修改EAX值为1,修复ESP指向位置(以保证代码不会乱),所以可以这样修改
1
2mov eax, 0x1
add esp, 0x14add esp, 0x14
是怎么得出来的呢?这个思路可以跟上面一样,记录下执行"ç"处的call命令前的ESP值"0019F9E4",在记录下执行完后ESP的值"0019F9F8",两者一减就得出了ESP需要偏移的大小了"0x14"但这里有个问题是"00402CFE"处的call 命令只有5个字节大小,
mov eax, 0x1
(机器码:B801000000,共5个字节)和add esp, 0x14
(机器码:83C414)两句总共需要8个字节的大小,单改"00402CFE"处的代码是不够的,所以这里决定往上一点从"00402CF9"(压入函数参数)处开始修改,这样命令大小就足够了。因为修改位置变了,所以add命令整理栈的也相应地需要改变下,因为程序运行到"00402CF9"处时ESP值为"0019F9EC",因此ESP偏移的大小为0x0019F9F8-0x0019F9EC=0xC,1
2mov eax, 0x1
add esp, 0xc按上述修改后,调试运行,可以发现成功弹出了主窗口,第一步去掉多余弹窗完成
《逆向工程核心原理》书中提到了另一种跟简单粗暴的方式,就是从"00402CFE"位置处往上找,直到函数初始位置,然后直接修改
push ebp
和mov ebp, esp
为retn 4
,也就是让函数直接返回并整理栈,这样相当于调用rtcMessageBox的上层函数直接返回了也就没有调用rtcMessageBox了就不会弹窗了接下来,找出序列号,继续检索字符串,我们双击成功提示信息的字符串"Yep! You succeeded registering! "定位到相应的代码位置
定位到相应代码位置,再往上查看代码,可以看到有"004028C2"地方调用了__vbaStrCmp函数,从名字上来看就是字符串比较函数,而且其中一个参数为"I'mlena151",显然这就是我们要找的注册码
回到软件中输入序列号"I'mlena151"验证下,可以看到成功弹出正确提示,至此分析结束