
全局变量和局部变量
全局变量在exe运行的时候就已经存在 ,其他函数都可以修改
- 生命周期:从程序启动 → 程序结束,一直存在。
- 存储位置:存放在全局数据区,不是栈。
- 默认初始值:如果不赋值,默认等于
0。 - 局部变量
- 只有当函数调用时才会分配空间,且一定要有初值.
- 局部变量的作用范围仅限于当前函数自己,其他函数无法使用
- 当函数执行完毕后,局部变量将变成垃圾数据,可以随时被其他数据所覆盖.
- 局部变量的反汇编识别:
[ebp-0x4]
[ebp-0x8]
[ebp-0xC]
全局变量的反汇编识别:
MOV 寄存器,byte/word/dword ptr ds:[0x12345678]
通过寄存器的宽度,或者byte/word/dword 来判断全局变量的宽度
函数
如果看不到参数的具体情况 需要跟进到函数内部查看
如何判断函数有几个参数,已经分别是什么:
一般情况:
步骤一:观察调用处的代码
push 3
push 2
push 1
call 0040100f
步骤二:找到平衡堆栈的代码继续论证
call 0040100f
add esp,0Ch
或者函数内部
ret 4/8/0xC/0x10
最后,两者一综合,函数的参数个数基本确定.
也就是push和平栈对的上就行
还有一种特殊情况
上面的分析存在的问题:
1、参数传递未必都是通过堆栈,还可能通过使用寄存器.
比如:
push ebx
push eax
mov ecx,dword ptr ds:[esi]
mov edx,dword ptr ds:[edi]
push 45
push 33
call 函数地址
2、函数调用处的代码无法查看.
00401050 push ebp 观察步骤:
00401051 mov ebp,esp
00401053 sub esp,48h 1、不考虑ebp、esp
00401056 push ebx
00401057 push esi 2、只找给别人赋值的寄存器
00401058 push edi eax/ecx/edx/ebx/esi/edi
00401059 push ecx
0040105A lea edi,[ebp-48h] 3、找到以后追查其来源,如果,该寄存器中的值
0040105D mov ecx,12h 不是在函数内存赋值的,那一定是传进来的参数.
00401062 mov eax,0CCCCCCCCh
00401067 rep stos dword ptr [edi]
00401069 pop ecx
0040106A mov dword ptr [ebp-8],edx
0040106D mov dword ptr [ebp-4],ecx
00401070 mov eax,dword ptr [ebp-4]
00401073 add eax,dword ptr [ebp-8]
00401076 add eax,dword ptr [ebp+8]
00401079 mov [g_x (00427958)],eax
0040107E pop edi
0040107F pop esi
00401080 pop ebx
00401081 mov esp,ebp
00401083 pop ebp
00401084 ret 4
找到用寄存器赋值的语句 比如 0040106A mov dword ptr [ebp-8],edx 0040106D mov dword ptr [ebp-4],ecx 这俩句指令 前面虽然有ecx的赋值 最开始也有push ecx ,所以这里的ecx想当于临时使用
ecx edx是参数 看结尾是内平栈 2 + 1 = 3 所以有三个参数
海哥总结的公式:公式一:寄存器 + ret 4 = 参数个数
公式二:寄存器 + [ebp+8] +[ebp+0x] = 参数个数
IF语句逆向分析
汇编中的jcc指令跟我们在编译器中写的刚好相反
Pasted image 20260827085557.png
但实际上是一致的 jle(小于等于则跳不执行) 大于就执行 同代码
还原if和jcc
函数调用处代码:
push 5 分析:
push 4 两个参数
call 0040100f
add esp,8
函数内部代码:
00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,40h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 lea edi,[ebp-40h]
0040103C mov ecx,10h
00401041 mov eax,0CCCCCCCCh
00401046 rep stos dword ptr [edi]
00401048 mov eax,dword ptr [ebp+8]
0040104B cmp eax,dword ptr [ebp+0Ch]
0040104E jle 00401059
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [004225c4],ecx
00401059 pop edi
0040105A pop esi
0040105B pop ebx
0040105C mov esp,ebp
0040105E pop ebp
0040105F ret
函数内部功能分析:
1、分析参数:
ebp+8 ebp+0xc
2、分析局部变量
没有ebp-的变量
3、分析全局变量
004225c4
4、功能分析
00401048 mov eax,dword ptr [ebp+8]
0040104B cmp eax,dword ptr [ebp+0Ch]
比较参数1和参数2的大小 cmp只影响标志位 如果x>y
那么把参数1赋值给ecx 并写道全局变量004225c4
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [004225c4],ecx
5、返回值分析
没有出现eax赋值的情况
而且也可以知道调用约定是cdcel
练习
调用处代码:
push 5
push 4
call 0040100f
add esp,8
函数内部:
00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,44h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 lea edi,[ebp-44h]
0040103C mov ecx,11h
00401041 mov eax,0CCCCCCCCh
00401046 rep stos dword ptr [edi]
00401048 mov eax,[004225c4]
0040104D mov dword ptr [ebp-4],eax
00401050 mov ecx,dword ptr [ebp+8]
00401053 cmp ecx,dword ptr [ebp+0Ch]
00401056 jg 00401064
00401058 mov edx,dword ptr [ebp+0Ch]
0040105B add edx,dword ptr [ebp-4]
0040105E mov dword ptr [004225c4],edx
00401064 pop edi
00401065 pop esi
00401066 pop ebx
00401067 mov esp,ebp
00401069 pop ebp
0040106A ret
函数内部功能分析:
1、分析参数:
ebp+8 ebp+0xc
2、分析局部变量
一个变量
3、分析全局变量
004225c4
4、功能分析
先把全局变量的初始值0 赋值给eax 然后新建一个局部变量eax赋值eax 比较参数1和参数2的大小 如果小于等于则通过edx(参数2) 与局部变量相加 然后把这个值给全局变量
5、返回值分析
eax = 0;
6、代码还原
#include<stdio.h>
#include "stdafx.h"
int a;
void IfFunction(int x,int y)
{
int b = a;
if (x<=y)
{
a = y + b;
}
}
int main(int argc,char* argv[])
{
IfFunction(2, 3);
return 0;
}
反汇编窗口
