读书人

OD一段简略的C++代码

发布时间: 2012-12-28 10:29:05 作者: rapoo

OD一段简单的C++代码

开始学习逆向,从熟悉的js、php跳跃到汇编,有点小凌乱OD一段简略的C++代码...

?

先来OD一段简单的C++代码:

?

先来直接在main的入口处下断,然后逐步跟进。

?

00401154? |.? 50?????????????????????? push??? eax
00401155? |.? FF35 0C994000? push??? dword ptr [40990C]
0040115B? |.? FF35 08994000? push??? dword ptr [409908]
00401161? |.? E8 9AFEFFFF?????? call??? 00401000

00401166? |.? 83C4 0C???????????? add???? esp, 0C

?

这是一个典型的函数调用,只不过调的是main罢了。三个参数压栈,然后call,完了消栈,格式很清晰。

main中的汇编代码如下:

?

00401000? /$? 57?????????????????????? push??? edi
00401001? |.? BF 30704000?????? mov???? edi, 00407030??????????????????? ;? ASCII "abc"
00401006? |.? 83C9 FF?????????????? or????? ecx, FFFFFFFF
00401009? |.? 33C0??????????????????? xor???? eax, eax
0040100B? |.? F2:AE?????????????????? repne?? scas byte ptr es:[edi]
0040100D? |.? F7D1????????????? ????? not???? ecx
0040100F? |.? 49??????????????????????? dec???? ecx
00401010? |.? 6A 0A?????????????????? push??? 0A
00401012? |.? 51??????????????????????? push??? ecx
00401013? |.? E8 08000000?????? call??? 00401020??????????????????????????? ;? 该处调用funcA函数
00401018? |.? 83C4 08????????????? add???? esp, 8
0040101B? |.? 5F??????????????????????? pop???? edi
0040101C? \.? C3?????????????????????? retn

?

strlen函数并没有向funcA一样被编译为另外一个call,而是直接编译在了main函数之中。strlen的实现非常之精妙:

这是strlen()在VC优化编译模式下编译后的代码:

00401000? /$? 57?????????????????????? push??? edi????? ;? 因为后面repne的时候要发生更改,所以先暂存edi

00401006? |.? 83C9 FF?????????????? or????? ecx, FFFFFFFF
00401009? |.? 33C0??????????????????? xor???? eax, eax
0040100B? |.? F2:AE?????????????????? repne?? scas byte ptr es:[edi]
0040100D? |.? F7D1????????????? ????? not???? ecx
0040100F? |.? 49??????????????????????? dec???? ecx

?

edi是指向字符串“abc”的指针,repne?? scas byte ptr es:[edi] 指令会扫描字符串“abc”(在内存中为 61 62 63 00),从字母a开始,一直到字符串结束符,一共4个字符。

?

REPNE:用在CMPS、SCAS指令前,每执行一次串操作指令ECX减1,并判断ZF标志是否为1,只要CX=0或ZF=1,则重复执行结束。

SCAS:将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改EDI寄存器的值,使之指向下一个元素。

?

这里需要扫描4次,每次扫描的字符与eax中的低八8位即00相比较,如果相同,则ZF标志位变成1,扫描结束;如果不同,则ecx减1并继续扫描。因此需要事先将eax置0,并且ecx置为-1。扫描完之后的ecx变为FFFFFFFB。取反后变成00000004,这是包含了字符串结束标志的长度,因此还需要减1.

?

随后将10、3入栈,准备调用funcA函数。函数的调用基本上都满足_stdcall约定,即参数从右向左,顺次压栈,函数调用的返回值保存在eax函数中。funcA的汇编码如下:

OD一段简略的C++代码

?

虽然有点长,但是代码还是很好理解的。

开始的两句mov是去栈中取操作数3、10,并且分别存放到eax、ecx中。

随后,sub esp,0xC是将栈顶向上移动,从而开辟出一块空的区域,可以用作预留用。

?

0040102C? |.? 8D3408??????? lea esi,dword ptr ds:[eax+ecx]
0040102F? |.? 0FAFF0??????? imul esi,eax
00401032? |.? 0FAFF1??????? imul esi,ecx

这三句完成了 c = (a + b) * a * b ,运算结果的值保存在esi中。

随后调用的MessageBox的过程暂时忽略。

因为最后需要返回c的值,因此在retn之前,需要执行一句mov eax,esi。

?

这里的call调用都没有被编译成经典的:

PUSH ebp
MOV ebp esp

这个无所谓,值得注意的是需要确保栈的平衡性,即入栈一定要与消栈相对应。

?

?

?

读书人网 >C++

热点推荐