zhaorong 发表于 2022-10-17 10:56:10

逆向分析篇四:if语句

一、前言

if语句是属于流程控制语句一种,流程控制语句是进行逆向分析和还原高级代码的基础对于想从事
逆向分析工作流程控制语句是很重要的。

二、if语句分析

if语句是分支结构的重要组成部分。if语句的功能是先运算条件进行比较,然后根据比较结果选择对应的语句块来执行
if 语句只能判断两种情况∶"0"为假值,"非0"为真值。如果为真值,则进入语句块内执行语句;如果为假值,则跳过
if语句块,继续运行程序的其他语句。要注意的是,if语句转换的条件跳转指令与if语句的判断结果是相反的。

源代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int index = 0;
    if (index==0)
    {
      printf("index = 0\n");
    }
    system("pause");
    return 0;
}

Debug x86

在IDA中if语句的流程图和执行伪汇编代码。


在dbg x32中if语句的执行伪汇编代码。


if的比较条件为index == 0,如果成立,即为真值,则进入if语句块内执行语句。转换后的汇编代码使用的条件
指令JNE判断结果为不等于0则跳转,因为按照if语句的规定,满足if判定的表达式才能执行if的语句块,而汇编
语言的条件跳转却是满足某条件则跳转。

//将ebp栈底指针入栈,以便程序执行结束可以进行恢复
00C91850push      ebp
//将栈底变成新的栈顶
00C91851mov         ebp,esp
//开辟一块0CCH大小的堆栈空间
00C91853sub         esp,0CCh
//ebx入栈
00C91859push      ebx
//esi(源地址)入栈
00C9185Apush      esi
//edi(目的地址)入栈
00C9185Bpush      edi
//将ebp-0Ch地址处的值放入到edi中
00C9185Clea         edi,
//ecx =3,为循环次数3次
00C9185Fmov         ecx,3
将开辟内存空间全部初始化成0CCCCCCCCh。
00C91864mov         eax,0CCCCCCCCh
//上边代码都是在做前期初始化操作,开辟新的内存空间和堆栈,把之前栈顶与栈底放入新堆栈中,并将内存空间初始化成C
00C91869rep stos    dword ptr es:
00C9186Bmov         ecx,0C9C00Eh
00C91870call      00C9131B
//上边三行代码其实就是int main()
// = 0
00C91875mov         dword ptr ,0
//使用cmp指令,将ebp-8地址处的4字节与0相减,根据结果改变标志位
00C9187Ccmp         dword ptr ,0
//jne为不相则跳转
00C91880jne         00C9188F
//0C97B30h = (index = 0)
00C91882push      0C97B30h
//调用printf函数,把0C97B30h当参数传进去
00C91887call      00C910CD
//进行平栈,堆栈平衡操作
00C9188Cadd         esp,4
//esi = esp
00C9188Fmov         esi,esp
//0C97B40h = pause
00C91891push      0C97B40h
//调用system函数,把pause当参数传进去
00C91896call      dword ptr ds:
//进行平栈,堆栈平衡操作
00C9189Cadd         esp,4
//其实下边三行做的操作是return 0,函数返回
00C9189Fcmp         esi,esp
00C918A1call      00C9123F
00C918A6xor         eax,eax
   
//下边代码是在做恢复操作,把一开始开辟的堆栈和放入到堆栈地址进行恢复操作
00C918A8pop         edi
00C918A9pop         esi
00C918AApop         ebx
00C918ABadd         esp,0CCh
00C918B1cmp         ebp,esp
00C918B3call      00C9123F
00C918B8mov         esp,ebp
00C918BApop         ebp
00C918BBret

Release x32



Release进行判断,if判断条件为true,直接省略掉了index赋值与判断,直接调用if语句里面的打印语句。

//5E2108h = (index = 0)
005E1040push      5E2108h
//调用printf函数,把0C97B30h当参数传进去
005E1045call      005E1010
//0C97B40h = pause
005E104Apush      5E2114h
//调用system函数,把pause当参数传进去
005E104Fcall      dword ptr ds:
//进行平栈,堆栈平衡操作
005E1055add         esp,8
//eax = 0
005E1058xor         eax,eax
//把值返回
005E105Aret

Debug x64



在64位程序中,默认使用的是 fastcall, fastcall用的不是堆栈传参而是使用了寄存器传参。

// = 0
00007FF7DD69187Bmov         dword ptr ,0
//使用cmp指令,将rbp+4地址处的4字节与0相减,根据结果改变标志位
00007FF7DD691882cmp         dword ptr ,0
//jne为不相则跳转
00007FF7DD691886jne         00007FF7DD691894
//将00007FF7DD699C28h地址的值放入到rcx寄存器里
00007FF7DD691888lea         rcx,
//调用printf函数,把rcx当参数传进去
00007FF7DD69188Fcall      00007FF7DD691190
//将00007FF7DD699C38h地址的值放入到rcx寄存器里
00007FF7DD691894lea         rcx,
//调用system函数,把pause当参数传进去
00007FF7DD69189Bcall      qword ptr
//eax = 0
00007FF7DD6918A1xor         eax,eax
//将rbp+00000000000000E8h地址里的值放入到rsp寄存器里
00007FF7DD6918A3lea         rsp,
00007FF7DD6918AApop         rdi
00007FF7DD6918ABpop         rbp
00007FF7DD6918ACret

Release x64



//将00007FF6EE632260h地址里的值放入到rcx寄存器里
00007FF6EE631074lea         rcx,
//调用printf函数,把rcx当参数传进去
00007FF6EE63107Bcall      00007FF6EE631010
//将00007FF6EE63226Ch地址里的值放入到rcx寄存器里
00007FF6EE631080lea         rcx,
//调用system函数,把pause当参数传进去
00007FF6EE631087call      qword ptr
//eax = 0
00007FF6EE63108Dxor         eax,eax
//进行平栈
00007FF6EE63108Fadd         rsp,28h
00007FF6EE631093ret

先执行各类影响标志位的指令
其后是各种条件跳转指令
jxx   XXXX   

如果遇到以上指令序列,可高度怀疑它是一个由if语句组成的单分支结构,根据比较信息与条件跳转指令找到
其跳转相反的逻辑,即可恢复分支结构原型。由于循环结构中也会出现类似的代码,因此在分析过程中还需
要结合上下文分析。
页: [1]
查看完整版本: 逆向分析篇四:if语句