全局变量、局部变量

内存图:

当然以上的是否可读写都是对于正向开发来讲的,逆向可以随意操作

全局变量:

只要是见到用立即数直接寻址的多半都是全局变量

局部变量:

局部变量不仅可以通过 ebp-? 来找,也可以通过栈顶加什么 esp+? 来找,所以看到这个形式不要惊慌,因为编译器的不同/不同的版本,寻找的方式可能会不同

函数参数的分析

分析一个程序,你肯定得去看它有几个参数、分别是什么,如何判断?

一般情况:

  • 步骤一:观察调用处的代码

    1
    2
    3
    4
    push 3
    push 2
    push 1
    call 0040100F
  • 步骤二:找到平衡堆栈的代码继续论证

    1
    2
    call 0040100F
    add esp, 0Ch

    或者函数内部

    1
    ret 4/8/0xC/0x10
  • 最后,两者一综合,函数的参数个数基本确定,但也不能百分之百确定,为什么?

上面的分析存在的问题:

  1. 函数传递参数未必都是通过堆栈,还可能通过寄存器(比如 fastcall)

    1
    2
    3
    4
    5
    6
    7
    push ebx
    push eax
    mov ecx,dword ptr ds:[esi]
    mov edx,dword ptr ds:[edi]
    push 45
    push 33
    call 函数地址

    到底哪几个是参数我们无从得知,更坏的是,这个汇编代码并不是每次逆向时都能看到的,call 上面那些可能会回溯不到,那看不到情况时要怎么分析?见第二点

  2. 函数调用处的代码无法查看

    需要注意的点:

    • 学习 fastcall 的时候学到用来传递参数的寄存器是 edx 和 ecx,但这是理论,实际上那一些寄存器都可能会用到,所以都要关注
    • 参数是把一个值从函数外面传进来给函数里面用,所以当一个寄存器出现在一条汇编语句的左边(被赋值方),那它肯定不是参数,因为它得作为右边那个。当它出现在了右边,而上面又没有别人给它赋值,那么就可以断定它是参数。

IF语句逆向分析

如果看到一个影响标志位的语句后面紧跟着一个 jcc,那么就很有可能是 if 语句。

需要注意的一点是,汇编翻译 C 语言时反着来的,就比如图中的例子,C 语言是 x>y,但是 jle 是小于等于。这是因为在 C 语言中,是符合条件就执行,而在汇编中,是符合条件则跳转(不执行),想要实现原本的继续执行,就要反着来判断。

接下来看一个更复杂的例子熟悉一下步骤:

课后作业

还原成 C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int p;

void func(int x, int y) {
int a;

a = p;
if (x <= y) {
p = a + y;
}
}

int main() {
func(4, 5);
return 0;
}