IF语句逆向分析

IF语句逆向分析

内存图

代码区 存放指令,可读,可执行
堆栈 存放参数、局部变量、临时数据
同态申请的,大小是可变的,可读,可写
全局变量区 存放全局变量,可读,可写
常量区 存放常量,只读

全局变量与局部变量

全局变量

int g_n = 10; //g_n存储到全局变量区
int Function() {
    int x = 2;
    int y = 3;
    return g_n + x + y;
}

全局变量的特点:

  1. 全局变量在程序编译完成后地址就已经确定下来了,只要程序启动,全局变量就已经存在了,启动后里面是否有值取决于声明时是否给定了初始值,如果没有,默认为0

  2. 全局变量的值可以被所有函数所修改,里面存储的是最后一次修改的值

  3. 全局变量所占用内存会一直存在,直到整个进程结束

  4. 全局变量的反汇编识别:

    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;
}

局部变量的特点:

  1. 局部变量在程序编译完成后并没有分配固定的地址

  2. 在所属的方法没有被调用时,局部变量并不会分配内存地址,只有当所属的程序被调用了,才会在堆栈中分配内存

  3. 当局部变量所属的方法执行完毕后,局部变量所占的内存将变成垃圾数据,局部变量消失

  4. 局部变量只能在方法内部使用,函数A无法使用函数B的局部变量

  5. 局部变量的反汇编识别:

    [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;
}

一般情况

步骤:

  1. 观察调用处的代码

    push	3
    push	2
    push	1
    call	0040100f
    
  2. 找到平衡堆栈的代码继续论证

    call	0040100f
    add		esp,0Ch
    

    或者函数内部

    ret		4/8/0xC/0x10
    
  3. 两者综合,基本确定函数的参数个数

上述一般情况存在问题

  1. 参数传递未必都是通过堆栈,还可能使用寄存器

    如:

    push	ebx
    push	eax
    mov		ecx,dword ptr ds:[esi]
    mov		edx,dword ptr ds:[edi]
    push	45
    push	33
    call	0040100f
    
  2. 函数调用处的代码无法查看(进程调用)

    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				
    

此时的观察步骤:

  1. 不考虑ebpesp

  2. 只找给别人赋值的寄存器eaxecxedxebxesiedi

  3. 找到以后追查其来源,如果该寄存器中的值不是在函数内部赋值的,那么一定时传进来的参数

    公式一:寄存器 + 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;
	}
}
posted @ 2021-08-21 16:38  Ybitsec  阅读(95)  评论(0编辑  收藏  举报