首先,来看看我们在C++程序中常用的几种结构:
1、循环结构A: For-Loop
For-loop几乎是使用频度最高的一个循环了,For-loop循环结构清晰过程明朗,是遍历搜索必备佳品:)
下面是一个典型的For-loop【For-loop的变种也可以如此分析】:
for( int nIdx = 0; nIdx < 1000; ++nIdx) //附注:其实这里nIdx++与++nIdx的效果是一样的,其汇编编译都是一样的,并没有孰快孰慢的问题
{
..............//循环体部分
}
我们来看看它的底层实现【为了方便起见,本着使用工具最少原则,仅用VS2003逆向在Debug状态下分析,Release状态下做了优化不方便理解问题,有兴趣的朋友可以用OD(OllyDbg)或许更为好理解】:
004112CE mov dword ptr [ebp-30h],0 //将nIdx初始化为零
004112D5 jmp 004112E0 //跳转到地址0X004112E0
004112D7 mov eax,dword ptr [ebp-30h] //将nIdx的值放入累加寄存器
004112DA add eax,1 //将累加寄存器里的值+1
004112DD mov dword ptr [ebp-30h],eax //将EAX的值赋回nIdx
004112E0 cmp dword ptr [ebp-30h],3E8h //将nIdx的值与1000比较
004112E7 jge 004112EB //大于或等于1000则跳出循环(循环Break)
............ //循环体部分
004112E9 jmp 004112D7 //调往地址0X004112D7,继续做++nIdx操作。
2.循环结构B: While-loop
while-loop也是在平时使用比较多的一个循环语句,特别在强调循环条件的时候常用到。
int nIdx = 0;
while( nIdx < 1000 )
{
.............//循环体中语句
++nIdx;
}
逆向后:
00411309 mov dword ptr [ebp-3Ch],0//初始化nIdx为0
00411310 cmp dword ptr [ebp-3Ch],3E8h //将nIdx与1000比较
00411317 jge 00411324 //大于或者等于的时候跳往地址0X00411324(亦即循环Break,跳出循环)
..........//循环体中语句
//以下三条指令就是++nIdx,也是nIdx++
00411319 mov eax,dword ptr [ebp-3Ch]
0041131C add eax,1
0041131F mov dword ptr [ebp-3Ch],eax
00411322 jmp 00411310 //跳往比较位置地址
3.循环结构C:Do-while-loop 这个结构我记得好像《Code Complete2》里面是不推荐使用的,可控性不好,容易出错,同时也可以被上面两个循环代替。
int nIdx = 0;
do
{
..........
++nIdx;
}while( nIdx < 1000 )
逆向后【貌似指令数量还要少些哦,速度快些?比For-loop少了两个跳转指令,比while-loop少一个】:
00413009 mov dword ptr [ebp-3Ch],0 初始化nIdx为0
...........//循环语句
// ++nIdx;
00413010 mov eax,dword ptr [ebp-3Ch]
00413013 add eax,1
00413016 mov dword ptr [ebp-3Ch],eax
00413019 cmp dword ptr [ebp-3Ch],3E8h //nIdx与1000比较
00413020 jl 00413010 //若小于则跳往循环语句(这里循环语句为空的,所以就跳向自增了)
4.switch结构
int nCase = 0;
switch( nCase )
{
case 0:
......
break;
case 1:
......
break;
default:
......
break;
}
逆向后:
int nCase = 0;
00413022 mov dword ptr [ebp-48h],0 //nCase赋初值为0;
switch(nCase)
00413029 mov eax,dword ptr [ebp-48h] //将nCase的值放入累加寄存器中
0041302C mov dword ptr [ebp+FFFFFEF0h],eax //将EAX里的值放入switch自己生成的临时变量中去(注意这个变量在switch语句中的值是不会变的!(废话:)))
00413032 cmp dword ptr [ebp+FFFFFEF0h],0 //与0比较
00413039 je 00413046 若等则跳转到case0 对应的语句地址
0041303B cmp dword ptr [ebp+FFFFFEF0h],1 //与1比较
00413042 je 00413076 若等则跳到case1对应的语句的地址
00413044 jmp 004130A4跳往Default情况对应语句的位置
OK,粗略分析了一下基本结构【if-then-else结构忽略,可以参照以上分析进行】,接下来看看一个容易搞错的问题,就是A += B,是否真的总是A = A + B呢?
就先看两种情况吧(其他的情况碰到了自己分析一下,原理一样:))
int nA = 1;
int nB = 2;
nA += nB;
nA = nA + nB;
逆向看看先:
int nA = 1;
00412FAC mov dword ptr [ebp-30h],1
int nB = 2;
00412FB3 mov dword ptr [ebp-3Ch],2
nA += nB;
00412FBA mov eax,dword ptr [ebp-30h]
00412FBD add eax,dword ptr [ebp-3Ch]
00412FC0 mov dword ptr [ebp-30h],eax
nA = nA + nB;
00412FC3 mov eax,dword ptr [ebp-30h]
00412FC6 add eax,dword ptr [ebp-3Ch]
00412FC9 mov dword ptr [ebp-30h],eax
的确一样哦!
但是看看这个呢:
int szNum[5] = { 1, 2, 3, 4, 5 };
00412F4E mov dword ptr [ebp-18h],1
00412F55 mov dword ptr [ebp-14h],2
00412F5C mov dword ptr [ebp-10h],3
00412F63 mov dword ptr [ebp-0Ch],4
00412F6A mov dword ptr [ebp-8],5
int *ptrA = szNum;
00412F71 lea eax,[ebp-18h]
00412F74 mov dword ptr [ebp-24h],eax
*(ptrA++) += 100;
00412F77 mov eax,dword ptr [ebp-24h]
00412F7A mov ecx,dword ptr [eax]
00412F7C add ecx,64h
00412F7F mov edx,dword ptr [ebp-24h]
00412F82 mov dword ptr [edx],ecx
00412F84 mov eax,dword ptr [ebp-24h]
00412F87 add eax,4
00412F8A mov dword ptr [ebp-24h],eax
*(ptrA++) = *(ptrA++) + 100;
00412F8D mov eax,dword ptr [ebp-24h]
00412F90 mov ecx,dword ptr [eax]
00412F92 add ecx,64h
00412F95 mov edx,dword ptr [ebp-24h]
00412F98 mov dword ptr [edx],ecx
00412F9A mov eax,dword ptr [ebp-24h]
00412F9D add eax,4
00412FA0 mov dword ptr [ebp-24h],eax
00412FA3 mov ecx,dword ptr [ebp-24h]
00412FA6 add ecx,4
00412FA9 mov dword ptr [ebp-24h],ecx
过程不用说了吧~,++p,p++的情况一样分析:),下次就到函数里面去看看,再下次就进入C++对象模型了,看看类的具体实现,再再下次......to be continued.