首页 > 技术文章 > 逆向-逻辑流控制

wan-xiang 2019-11-05 14:28 原文

逻辑流控制

在我的抽象中执行逻辑有三种-顺序、选择、循环。默认汇编就是从上到下顺序执行,选择用if-else和switch,循环用while、for等。

分支语句

if-else

int main(int argc, char const *argv[])
{
    int a=10;
    if (a>10){
         printf("a>10");
     }else{
         printf("a<=10");
     }
    return 0;

int main(int argc, char const *argv[])
{
    int a=10;
    if (a>10){
        printf("a>10");
    }else if(a<2){
        printf("a<2");
    }else{
        printf("2<=a<=10");
    }
    return 0;
}

从上面两个二分支和三分支可以看出:

  1. 开始标志就是cmp,jcc 这两条标志语句,代表条件判断。
  2. 直接跳转的jmp代表执行的是它上面的分支。
  3. 每个分支内jmp跳的地址是一样的都是else{};这条语句之后的位置。
  4. 巧妙的运用了顺序结构

switch

int main(int argc, char const *argv[])
{
    int a=11;
    switch (a)
    {
    case 10:
        printf("a=10");
        break;
    case 11:
        printf("a=11");
        break;
    case 12:
        printf("a=12");
        break;  
    case 13:
        printf("a=13");c
        break;  
    case 14:
        printf("a=14");
        break;  
    default:
        printf("!!");
    }
    return 0;
}

特征

  1. 当switch分支小的时候(视不同编译器实现,visual studio 为3个(包含)以下)返回百年结构和if-else结构相同,但是当分支测试的常量连续并且有一定数目,就会根据一个表保存要跳转的地址。
  2. 如果不是从0开始编译器会减去测试常量这个连续序列的最小值,直接得到偏移地址,加上基址即可到要跳转的分支。

总结

从分支语句中我们可以总结一些特征,测试条件用cmp、fcmp等指令,下面紧跟着jcc指令。jmp代表这个分支执行完了,一般跳出这个分支检测结构,而上面的cmp;jcc连着用的话一般指紧跟着的分支的否定,一般会跳到最后一个分支。switch在大量、连续的分支测试比if-else性能高。

循环

  for (a=0;a<10;a++){
        sum=sum+a;
    }
 80483ef:       c7 45 f8 00 00 00 00    mov    DWORD PTR [ebp-0x8],0x0
 80483f6:       eb 0a                   jmp    8048402 <main+0x27>
        sum=sum+a;
 80483f8:       8b 45 f8                mov    eax,DWORD PTR [ebp-0x8]
 80483fb:       01 45 fc                add    DWORD PTR [ebp-0x4],eax
    for (a=0;a<10;a++){
 80483fe:       83 45 f8 01             add    DWORD PTR [ebp-0x8],0x1
 8048402:       83 7d f8 09             cmp    DWORD PTR [ebp-0x8],0x9
 8048406:       7e f0                   jle    80483f8 <main+0x1d>

初始化
a=0
mov    DWORD PTR [ebp-0x8],0x0
条件判断,可以看到cmp;jcc;判断
cmp    DWORD PTR [ebp-0x8],0x9
jle    80483f8 <main+0x1d>
控制变量变化
DWORD PTR [ebp-0x8],0x1
从上到下执行,首先初始化变量,接着直接jmp到cmp判断循环变量,向上跳到循环体

break和continue

for (a=0;a<10;a++){
        if (a == 6){
            continue;
        }
        if (a == 7){
            break;
        }
        sum=sum+a;
    }
80483ef:       c7 45 f8 00 00 00 00    mov    DWORD PTR [ebp-0x8],0x0
80483f6:       eb 19                   jmp    8048411 <main+0x36>
80483f8:       83 7d f8 06             cmp    DWORD PTR [ebp-0x8],0x6
80483fc:       74 0e                   je     804840c <main+0x31>
80483fe:       83 7d f8 07             cmp    DWORD PTR [ebp-0x8],0x7
8048402:       74 15                   je     8048419 <main+0x3e>
8048404:       8b 45 f8                mov    eax,DWORD PTR [ebp-0x8]
8048407:       01 45 fc                add    DWORD PTR [ebp-0x4],eax
804840a:       eb 01                   jmp    804840d <main+0x32>
804840c:       90                      nop
804840d:       83 45 f8 01             add    DWORD PTR [ebp-0x8],0x1
8048411:       83 7d f8 09             cmp    DWORD PTR [ebp-0x8],0x9
8048415:       7e e1                   jle    80483f8 <main+0x1d>
8048417:       eb 01                   jmp    804841a <main+0x3f>
8048419:       90                      nop
804841a:       b8 00 00 00 00          mov    eax,0x0
804841f:       c9                      leave
8048420:       c3                      ret

break跳出循环jmp 804840d

continue跳到循环变量控制也就是a++;add DWORD PTR [ebp-0x8],0x1

总结

for循环典型特征jmp指令,循环体,条件控制和判断。jmp跳条件控制和判断,然后回调循环体。

推荐阅读