《加密与解密(第三版)》读书笔记第4章(逆向分析 阅读汇编代码)

来源:互联网 发布:gif图片尺寸修改软件 编辑:程序博客网 时间:2024/05/28 15:45

在进入WinMain之前,编译器会添加启动函数,获取系统版本,初始化全局变量,加载运行库等等的工作,最后在进入WinMain,分析程序的时候可以略过启动代码,重点放在WinMain函数中

函数组成:函数名、入口参数、返回值、函数功能

函数的识别:通过callret识别,将call的下一行代码压入栈中来记录返回到哪里,换句话说将参数和返回地址(下一行)一起传给被调用函数

调用约定(Calling Convention):

子程序在最后用一句 ret nn是个整数=4*参数个数),功能是ret之后再add esp+n

堆栈传参:

堆栈法访问参数:用ebp记录esp,间接访问参数;或者直接用esp访问参数

局部变量:esp移动让出空间,ebp访问;enterleave来管理;sub esp8分配8个字节用于局部变量

DWORD4个字节

寄存器传参:()fastcall)实际上可能通过任何寄存器传参,VC将最左2个小于4字节用ecxedxBC/Delphi将最左3个小于4字节的参数用eaxedxecdWatcom C分别用eaxedxebxecx。(thiscall)用于类的非静态方法,参数用堆栈传,thisecx寄存器传。

名称修饰(Name Mangling/Decoration):为了操作符和函数重载,C++编译器改写入口点的符号名。

return返回值一般放在eax中,如果超出容量,高32位放在edx

参数引用返回:指针的操作。其实就是高级语言中传值和传指针的区别

局部变量和参数区别:用ebp访问:ebp-XXXX调用局部变量;ebp+XXXX调用参数。

分配局部变量:如果不用ebp(编译器优化模式)esp-n == push reg;撤回相反

Push-reg:将reg用作临时变量

全局变量:一般硬编码在.data区块,可读写;如果在只读区,一般是常量。可以用于注册与否的标记

数组:同类型的元素的集合,在内存中按顺序连续存放,可以通过类似于“基址+偏移”访问各元素,基址可以是常量或寄存器,为定值;偏移可以访问相应单元(结构赋值也类似)

虚函数:每个实例其实有一个指向虚函数表(VTBL)的指针,这里说的this指针也就是指向虚函数表的指针,虚函数表的表项是指向虚成员函数的。虚函数表地址跟普通函数一样,是固定的(绝对地址)

比较操作:cmp整数,浮点数fcom/fcomp

If-then-else:汇编之后cmp abjzjnzxxxx

Testtext eaxeax:若eax0,则与运算结果为0ZF1(减法相等),jneZF=1不跳转(不等才跳)

Switch分支:没有优化跟多个if差不多;优化之后有减法还是跟多个if差不多;case是有规律的可能会有跳转表。

跳转指令计算:不用去刻意记,可以推导。可以注意向前向后跳,多数都要查书才记得。

条件设置指令:用于消除转移指令,当标志位为某些数值时,设置寄存器为1setgecmovfcmov

循环:向前条容易是循环。一般用ecx计数,

加减法:没优化add&subLea c, [a+b78h]c=a+b+78

乘法:没优化mul&imul。 Lea ecx, dword ptr [eax+8*eax] (eax*9)Lea指令还可以做2的整数次幂的乘法。

除法:代价高,比乘法多消耗10cpu时间。Dividiv,优化过会转为乘法等,难从反汇编代码中理解

字符串:C风格最末\0pascaldelphi在字符串的头说明字符串的长度

大小写:大写41h~5Ah,小写是61h~7Ah,相差20h。二进制的第五位0代表大写,1代表小写

计算字符串长度:strlen()mov ecx, FFFFFFFF,很可能是在获取字符串长度

指令修改技巧:寄存器清零mov 0xorsub eax eax,多用eax