IF语句逆向分析
IF语句逆向分析
内存图
代码区 | 存放指令,可读,可执行 |
堆栈 | 存放参数、局部变量、临时数据 |
堆 | 同态申请的,大小是可变的,可读,可写 |
全局变量区 | 存放全局变量,可读,可写 |
常量区 | 存放常量,只读 |
全局变量与局部变量
全局变量
int g_n = 10; //g_n存储到全局变量区
int Function() {
int x = 2;
int y = 3;
return g_n + x + y;
}
全局变量的特点:
-
全局变量在程序编译完成后地址就已经确定下来了,只要程序启动,全局变量就已经存在了,启动后里面是否有值取决于声明时是否给定了初始值,如果没有,默认为
0
-
全局变量的值可以被所有函数所修改,里面存储的是最后一次修改的值
-
全局变量所占用内存会一直存在,直到整个进程结束
-
全局变量的反汇编识别:
MOV Register,byte/word/dword ptr ds:[0x12345678]
通过寄存器的宽度,或者
byte/word/dword
来判断全局变量的宽度全局变量就是所谓的基址
局部变量
int FunctionA() {
int x = 2;
int y = 3;
return g_n + x + y;
}
int FunctionB() {
int x = 3;
int y = 4;
return g_n + x + y;
}
局部变量的特点:
-
局部变量在程序编译完成后并没有分配固定的地址
-
在所属的方法没有被调用时,局部变量并不会分配内存地址,只有当所属的程序被调用了,才会在堆栈中分配内存
-
当局部变量所属的方法执行完毕后,局部变量所占的内存将变成垃圾数据,局部变量消失
-
局部变量只能在方法内部使用,函数
A
无法使用函数B
的局部变量 -
局部变量的反汇编识别:
[ebp-0x4]
[ebp-0x8]
[ebp-0xC]
函数参数分析
int g_r;
void __cdecl Function1(int x,int y, int z) {
g_r = x + y + z;
}
void __stdcall Function2(int x, int y, int z) {
g_r = x + y + z;
}
void __fastcall Function3(int x, int y, int z) {
g_r = x + y + z;
}
一般情况
步骤:
-
观察调用处的代码
push 3 push 2 push 1 call 0040100f
-
找到平衡堆栈的代码继续论证
call 0040100f add esp,0Ch
或者函数内部
ret 4/8/0xC/0x10
-
两者综合,基本确定函数的参数个数
上述一般情况存在问题
-
参数传递未必都是通过堆栈,还可能使用寄存器
如:
push ebx push eax mov ecx,dword ptr ds:[esi] mov edx,dword ptr ds:[edi] push 45 push 33 call 0040100f
-
函数调用处的代码无法查看(进程调用)
00401050 push ebp 00401051 mov ebp,esp 00401053 sub esp,48h 00401056 push ebx 00401057 push esi 00401058 push edi 00401059 push ecx 0040105A lea edi,[ebp-48h] 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
此时的观察步骤:
-
不考虑
ebp
、esp
-
只找给别人赋值的寄存器
eax
、ecx
、edx
、ebx
、esi
、edi
-
找到以后追查其来源,如果该寄存器中的值不是在函数内部赋值的,那么一定时传进来的参数
公式一:
寄存器 + ret = 参数个数
公式二:
寄存器 + [ebp+8] + [ebp+0x] = 参数个数
IF逆向分析
JCC回顾
CMP
指令:比较两个数的大小,相当于减法,但只影响标志寄存器JCC
指令:跳转
IF语句的反汇编判断:
执行各类影响标志寄存器的指令
jxx xxxx
案例一
CPP源码:
#include "stdafx.h"
int max_num;
void Function(int x, int y) {
if (x > y) {
max_num = x;
}
}
int main(int argc, char* argv[]) {
Function(2,3);
return 0;
}
反汇编代码:
00401068 push 3
0040106A push 2
0040106C call @ILT+10(plus) (0040100f)
00401071 add esp,8
0040100F jmp Function (00401020)
00401020 push ebp ;保存栈底
00401021 mov ebp,esp ;提升堆栈
00401023 sub esp,40h
00401026 push ebx ;保存现场
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-40h] ;设置缓冲区
0040102C mov ecx,10h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
00401038 mov eax,dword ptr [ebp+8] ;函数功能
0040103B cmp eax,dword ptr [ebp+0Ch] ;比较参数1与参数2的大小
0040103E jle Function+29h (00401049) ;如果参数1小于等于参数2,则跳转至49
00401040 mov ecx,dword ptr [ebp+8] ;如果跳转则40,43不会执行
00401043 mov dword ptr [max_num (0042c20c)],ecx
00401049 pop edi ;恢复现场
0040104A pop esi
0040104B pop ebx
0040104C mov esp,ebp ;恢复栈顶
0040104E pop ebp ;恢复栈底
0040104F ret ;函数返回
在函数时应从以下几个方面进行分析:
分析参数 | [ebp+8]:x [ebp+0Ch]:y |
分析局部变量 | 无 |
分析全局变量 | mov dword ptr [max_num (0042c20c)],ecx |
功能分析 | mov eax,dword ptr [ebp+8] ;将参数x放入eax中 cmp eax,dword ptr [ebp+0Ch] ;比较eax与参数y的大小 jle Function+29h (00401049) ;如果x<=y那么跳转到00401049 mov ecx,dword ptr [ebp+8] ;否则将x的值存储到全局变量中 mov dword ptr [max_num (0042c20c)],ecx |
返回值分析 | 无 |
练习一
反汇编代码:
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
分析:
分析参数 | [ebp+8]:x [ebp+0Ch]:y |
分析局部变量 | [ebp-4]:a |
分析全局变量 | mov eax,[004225c4]:N |
功能分析 |
00401048 mov eax,[004225c4] ;将全局变量N赋值给eax 0040104D mov dword ptr [ebp-4],eax ;将eax赋值给局部变量a 00401050 mov ecx,dword ptr [ebp+8] ;将x赋值给ecx 00401053 cmp ecx,dword ptr [ebp+0Ch] ;比较x与y的大小 00401056 jg 00401064 ;如果x>y那么跳转到00401064 00401058 mov edx,dword ptr [ebp+0Ch] ;否则将y赋值给edx 0040105B add edx,dword ptr [ebp-4] ;edx+a 0040105E mov dword ptr [004225c4],edx ;将edx赋值给全局变量N |
返回值分析 | 无 |
还原成C函数 |
int N; void Function(int x, int y) { int a = N; if (x <= y) { N = y + a; } } |