反汇编笔记

1.OD中ctrl+f9:运行到返回,就是运行到当前断点所在的函数末尾"retn xxx"处,若xxx=10,那么
10等于10进制的16,就是说这个函数有4个参数,一个参数默认是占4字节,所以就是retn 10。

2.调试程序时,在OD内部小窗口左上角会显示当前断点所在的函数层,是在系统领空还是某个应用程序领空。

3.call前出现lea edx,dword ptr ss:[ebp-x]的分析方法:
当在call处出现类似于下面,在call内部存在对edx的使用时:
call处:
lea edx,dword ptr ss:[ebp-8]   ;将ebp-8堆栈地址赋给edx,注意是堆栈地址,不是堆栈地址上存储的数据。
call 0045255c
call内部:
mov esi,edx
...
push esi
那么在写call调用的时候,怎么办呢?
只需要查看当程序停在call处时,edx寄存器的数值,然后去找到edx数值代表的堆栈地址处存储的数据是什么。
是1,所以我们就可以通过ce查找出当前为0的值,为0可能就是无关数据,选择一个地址,修改为1,然后将该地址
赋给edx。
就是mov edx, xxxxx
call 0045255c

4.call内部出现mov ebx,dword ptr [esp+8],为什么此句不用分析呢,难道不可能是取call通过堆栈传的参数吗?

5.如果call是堆栈传参,那么在call前面就会有push,那么我们在分析call参数时,就要关注call内部从堆栈取数的操作;
反之,如果call是寄存器传参,那么在call前面就没有push,所以在call内部,我们就不必关注从堆栈取数的操作。
如果是堆栈传参,那么在call内部我们就不用再分析从堆栈取数的操作了,就会更加简单;其实不管是堆栈传参还是寄存器传参,
我们都可以不用管内部类似于mov edx,dword ptr ss:[ebp-8]这样的取堆栈操作,因为假如是堆栈传参,那么这样的操作一定是
取参数的,我们已经知道了在调用call前push了,何必还分析呢;假如是寄存器传参,那么对堆栈的操作也不用分析,因为我们
只关心call的参数,既然参数时寄存器,在call前只需mov xxx,yyy,就可以了。

6.OD中没有$函数头标识以及竖线,可以按ctrl+A进行分析,就可以显示了。

7.使用OD直接打开程序与附加已经运行的程序,会有所不同。
在查找花指令时,若使用附加进程,则找不到花指令,使用od直接
打开就可以找到花指令。

8.OD附加进程出现“调试字串:D3DX系统找不到指定的文件”?
去下载DX9.0c,再去下载个StrongOD插件;安装dx9.0,将StrongOD插件解压放到OD工具
PLUGIN目录下,重启软件就可以了。

9.CALL 的参数其实就是在调用 CALL 的时候所需要的运行环境。

10.找无参数call的方法:
比如找加血减血的call,那么先用CE找出血值地址,然后进入OD,将该地址设置硬件中断(hw 416698),在调用加血减血函数时,在其函数内部就会对血值写入新数值,那么在代码访问到416698地址时,就会发生中断。代码短直接看,代码长使用ctrl+f9执行到返回,这样便很容易找到call。

11.要生成一个Release版本的就可以了,你得先设置一下: 在“工程”中选择“设置”打开Project Settings对话框,
先在“设置”下拉列表中选择Win32 Release,然后在右侧设置为“使用MFC作为静态链接库”。点击确定。 
再打开“组建”下的“批组建”,勾掉Win32 Debug,然后再点击“创建”。这时应该能够生成一个Release版本的应用程序。 这个程序就可以直接拷到别人的电脑上运行,不必安装VC

12.堆栈传参call写法。
经过4次的分析,最终找到了调用call,程序老是崩溃的原因:
在程序中查找call的c代码为:
int add(int a, int b)
{
return (a+b);
}

反汇编代码为:
004014E5   .  E8 44020000   CALL
004014EA   .  8B46 64       MOV EAX,DWORD PTR DS:[ESI+0x64]
004014ED   .  8B4E 68       MOV ECX,DWORD PTR DS:[ESI+0x68]
004014F0   .  50            PUSH EAX
004014F1   .  51            PUSH ECX
004014F2   .  E8 D9FFFFFF   CALL test.004014D0
004014F7   .  83C4 08       ADD ESP,0x8
004014FA   .  8BCE          MOV ECX,ESI
004014FC   .  8946 60       MOV DWORD PTR DS:[ESI+0x60],EAX
004014FF   .  6A 00         PUSH 0x0
00401501   .  E8 28020000   CALL
其中下面是add的call
004014F0   .  50            PUSH EAX
004014F1   .  51            PUSH ECX
004014F2   .  E8 D9FFFFFF   CALL test.004014D0
004014F7   .  83C4 08       ADD ESP,0x8
call内部为:
004014D0  /$  8B4424 08     MOV EAX,DWORD PTR SS:[ESP+0x8]
004014D4  |.  8B4C24 04     MOV ECX,DWORD PTR SS:[ESP+0x4]
004014D8  |.  03C1          ADD EAX,ECX
004014DA  \.  C3            RETN

第一次调用call时,在注射器中输入
push 1
push 2
call 004014f2
add esp,0x8
程序老是要崩溃,然后就自己单步查看堆栈情况,因为这个call是通过堆栈传递的2个参数。
当程序单步到004014D0时,堆栈情况:
0532ffa8 004014f7   ;CALL test.004014D0返回地址
0532ffac 04720009   ;注入的线程调用函数返回地址
0532ffb0 00000002   ;push 2
0532ffb4 00000001   ;push 1
0532ffb8 7c80b729   ;为压栈前esp的值,在调用call之后,esp应该回到这个位置。

而在call内部,分别取ESP+0x8,ESP+0x4,这2个参数,此时esp=0532ffa8,那么
[ESP+0x8]=2,[ESP+0x4]=04720009,可以看到参数已经取错了。再次当call执行完毕后,将0532ffa8处的
函数返回地址弹出,函数继续执行下一条指令ADD ESP,0x8,此时esp=0532ffac+8=0532ffb4,可以看到
esp的值并没有回到调用call之前的值,所以造成堆栈不平衡,程序就崩溃了。
解决方法:
类似于这种堆栈传参的call调用,不能调用call所在的地址,因为这样会多在堆栈中压入一个返回地址,
从而造成堆栈不平衡。只能直接调用call内部的第一条指令,就可以了。
           PUSH EAX
           PUSH ECX
004014F2   CALL test.004014D0
           ADD ESP,0x8

不能call 004014F2,只能call 004014D0。

正确的写法是:
push 1
push 2
call 4014D0
add esp,0x8

不管是有参还是无参call,最好都调用call内部的第一条指令地址,这样一定没有错。

13.OD命令:
hw 00416698,在00416698处添加硬件断点
dd 2AE6C68,显示2AE6C68处的内存地址
dd [03109164]+i*4+00000404   // 在od中数值方式显示数组[i]
dc [03109164]+i*4+00000404   // 在od中ASC字符方式显示数组[i]
ctrl+'-':查看上一个过程
ctrl+'+': 查看下一个过程

14.OD跟踪的使用:
右键->HIT跟踪和RUN跟踪,HIT可以查看代码的执行过程,HIT为“击中”的意思,被执行的代码会变色,而RUN可以设置条件,及从上面某一行代码开始执行(ctrl+f11跟踪步入,strl+f12跟踪步过),执行到下面某行代码满足条件,就会断下来,例如可以查找某寄存器的值在哪条代码被修改。
    在已经使用跟踪的情况下,按"-"键可以一条一条查看执行过的代码和数据情况,同时在寄存器,堆栈窗口的数据也会随着代码的返回而更新。

15.mov eax,dword ptr ds:[esp+20]与mov eax,dword ptr ss:[esp+20]的区别:

ds表示从内存地址esp+20处取一个双字数据存入eax,ss表示从堆栈地址esp+20处取一个双字数据存入eax。

 

你可能感兴趣的:(X86指令集,32位,栈,汇编,内存)