Day6:if-else语句识别、switch语句识别、循环语句识别

if-else语句识别、switch语句识别、循环语句识别

if-else语句识别

  • 第一种,数值比较作为条件(x86debug为例,其余类似,仅是比较方法(如使用sub而不是cmp)和模式特征上的差异)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .text:004702D0                 lea     eax, [ebp+var_C]
    .text:004702D3 push eax
    .text:004702D4 push offset unk_545E50 ; %d
    .text:004702D9 call sub_4681E0 ; scanf
    .text:004702DE add esp, 8
    .text:004702E1 cmp [ebp+var_C], 1
    .text:004702E5 jnz short loc_4702F6 ; if [ebp+var_C]!=1, jump to loc_4702f6
    .text:004702E7 push offset aNEquales1 ; "n equales 1"
    .text:004702EC call sub_468D1B ; printf
    .text:004702F1 add esp, 4
    .text:004702F4 jmp short loc_470303
    .text:004702F6 ; ---------------------------------------------------------------------------
    .text:004702F6
    .text:004702F6 loc_4702F6: ; CODE XREF: main+45↑j
    .text:004702F6 push offset aNDoesNotEqual1 ; "n does not equal 1"
    .text:004702FB call sub_468D1B ; printf
    .text:00470300 add esp, 4

    源码:

    1
    2
    3
    4
    5
    6
    int n;
    scanf("%d", &n);
    if (n == 1)
    printf("n equales 1");
    else
    printf("n does not equal 1");
  • 第二种,变量直接作为条件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .text:00470303                 lea     eax, [ebp+var_18]
    .text:00470306 push eax
    .text:00470307 push offset unk_545E50 ; %d
    .text:0047030C call sub_4681E0 ; scanf
    .text:00470311 add esp, 8
    .text:00470314 cmp [ebp+var_18], 0 ; 和'0'比较
    .text:00470318 jz short loc_470327 ; if [ebp+var_18]==0, jump to loc_470327, 跳过printf
    .text:0047031A push offset aJudgeIsNotZero ; "judge is not zero"
    .text:0047031F call sub_468D1B ; printf
    .text:00470324 add esp, 4

    源码:

    1
    2
    3
    4
    int judge;
    scanf("%d", &judge);
    if (judge)
    printf("judge is not zero");
  • 第三种,返回值(函数式)作为条件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    .text:00470387                 lea     eax, [ebp+var_24]
    .text:0047038A push eax
    .text:0047038B push offset unk_545E50 ; %d
    .text:00470390 call sub_4681E0 ; scanf
    .text:00470395 add esp, 8
    .text:00470398 mov eax, [ebp+var_24]
    .text:0047039B push eax ; 输入的值入栈,即函数传参
    .text:0047039C call sub_46B214 ; 自定义函数
    .text:004703A1 add esp, 4
    .text:004703A4 test eax, eax ; 1 & 1 = 0; 0 & 0 = 1
    .text:004703A6 jz short loc_4703B5
    .text:004703A8 push offset aItS0 ; "it's 0\n"
    .text:004703AD call sub_468D1B
    .text:004703B2 add esp, 4

    ;sub_46b214
    .text:00470110 arg_0 = dword ptr 8
    .text:00470110
    .text:00470110 push ebp
    .text:00470111 mov ebp, esp
    .text:00470113 sub esp, 0C0h
    .text:00470119 push ebx
    .text:0047011A push esi
    .text:0047011B push edi
    .text:0047011C mov edi, ebp
    .text:0047011E xor ecx, ecx
    .text:00470120 mov eax, 0CCCCCCCCh
    .text:00470125 rep stosd
    .text:00470127 mov ecx, offset unk_57500E
    .text:0047012C call sub_46B660
    .text:00470131 nop
    .text:00470132 cmp [ebp+arg_0], 0 ; [ebp+8], eax在栈上的位置
    .text:00470136 jnz short loc_470141 ; eax=0
    .text:00470138 mov eax, 1 ; if [ebp+arg_0]==0, eax=1, return 1(eax)
    .text:0047013D jmp short loc_470143
    .text:0047013F ; ---------------------------------------------------------------------------
    .text:0047013F jmp short loc_470143
    .text:00470141 ; ---------------------------------------------------------------------------
    .text:00470141
    .text:00470141 loc_470141: ; CODE XREF: sub_470110+26↑j
    .text:00470141 xor eax, eax ; eax=0
    .text:00470143
    .text:00470143 loc_470143: ; CODE XREF: sub_470110+2D↑j
    .text:00470143 ; sub_470110+2F↑j
    .text:00470143 pop edi
    .text:00470144 pop esi
    .text:00470145 pop ebx
    .text:00470146 add esp, 0C0h
    .text:0047014C cmp ebp, esp
    .text:0047014E call sub_46A62A
    .text:00470153 mov esp, ebp
    .text:00470155 pop ebp
    .text:00470156 retn

    源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int IfZero(int a) {
    if (a == 0)
    return 1;
    else
    return 0;
    }

    int main(){
    int a;
    scanf("%d", &a);
    if(IfZero(a))
    printf("it's 0\n");
    return 0;
    }

switch语句识别

  • 比较简单的情况下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    .text:00470327                 lea     eax, [ebp+var_24]
    .text:0047032A push eax
    .text:0047032B push offset unk_545E50 ; %d
    .text:00470330 call sub_4681E0 ; scanf
    .text:00470335 add esp, 8
    .text:00470338 mov eax, [ebp+var_24]
    .text:0047033B mov [ebp+var_EC], eax ; [ebp+var_EC]==[ebp+var_24], 用临时变量[ebp+var_EC]来检验case
    .text:00470341 cmp [ebp+var_EC], 1
    .text:00470348 jz short loc_47035E ; case1输出
    .text:0047034A cmp [ebp+var_EC], 5
    .text:00470351 jz short loc_470371 ; case5输出
    .text:00470353 cmp [ebp+var_EC], 0Ah
    .text:0047035A jz short loc_470384 ; case10输出
    .text:0047035C jmp short loc_470395 ; break然后system("pause")
    .text:0047035E ; ---------------------------------------------------------------------------
    .text:0047035E
    .text:0047035E loc_47035E: ; CODE XREF: main+A8↑j
    .text:0047035E mov eax, [ebp+var_24]
    .text:00470361 push eax
    .text:00470362 push offset aNEqualsD ; "n equals %d"
    .text:00470367 call sub_468D1B ; printf
    .text:0047036C add esp, 8
    .text:0047036F jmp short loc_470395
    .text:00470371 ; ---------------------------------------------------------------------------
    .text:00470371
    .text:00470371 loc_470371: ; CODE XREF: main+B1↑j
    .text:00470371 mov eax, [ebp+var_24]
    .text:00470374 push eax
    .text:00470375 push offset aNEqualsD ; "n equals %d"
    .text:0047037A call sub_468D1B ; printf
    .text:0047037F add esp, 8
    .text:00470382 jmp short loc_470395
    .text:00470384 ; ---------------------------------------------------------------------------
    .text:00470384
    .text:00470384 loc_470384: ; CODE XREF: main+BA↑j
    .text:00470384 mov eax, [ebp+var_24]
    .text:00470387 push eax
    .text:00470388 push offset aNEqualsD ; "n equals %d"
    .text:0047038D call sub_468D1B ; printf
    .text:00470392 add esp, 8
    .text:00470395
    .text:00470395 loc_470395: ; CODE XREF: main+BC↑j
    .text:00470395 ; main+CF↑j ...
    .text:00470395 push offset aPause ; "pause"
    .text:0047039A call sub_46AFAD ; system("pause")
    .text:0047039F add esp, 4

    源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int number;
    scanf("%d", &number);
    switch (number) {
    case 1:
    printf("n equals %d", number);
    break;
    case 5:
    printf("n equals %d", number);
    break;
    case 10:
    printf("n equals %d", number);
    break;
    }
    system("pause");
  • 再复杂点,会优化出跳转表,即每个case跳转的地址会被集合成一个数组,像表一样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    .text:004702D3                 push    eax
    .text:004702D4 push offset unk_545E50 ; %d
    .text:004702D9 call sub_4681E0 ; scanf
    .text:004702DE add esp, 8
    .text:004702E1 mov eax, [ebp+var_C]
    .text:004702E4 mov [ebp+var_D4], eax
    .text:004702EA mov ecx, [ebp+var_D4] ; 把输入值传到ecx,下一步减去1,减1的原因见后面的解释
    .text:004702F0 sub ecx, 1 ; switch 67 cases
    .text:004702F3 mov [ebp+var_D4], ecx
    .text:004702F9 cmp [ebp+var_D4], 42h ; 把输入值和42h(66)比较,下一步是大于66就跳出case的判断
    .text:00470300 ja def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:00470306 mov edx, [ebp+var_D4]
    .text:0047030C movzx eax, ds:byte_470418[edx] ; 跳转表索引值表,即预判了输入值的范围并且为每个可能的值建立了索引值表(比如说现在确定了范围是0-66,就枚举了0-66这些数值对应的索引,然后再根据索引找到应改跳转的地址
    .text:00470313 jmp ds:jpt_470313[eax*4] ; switch jump
    .text:0047031A ; ---------------------------------------------------------------------------
    .text:0047031A
    .text:0047031A loc_47031A: ; CODE XREF: sub_4702A0+73↑j
    .text:0047031A ; DATA XREF: .text:jpt_470313↓o
    .text:0047031A mov eax, [ebp+var_C] ; jumptable 00470313 case 1
    .text:0047031D push eax
    .text:0047031E push offset aNEqualsD ; "n equals %d"
    .text:00470323 call sub_468D1B ; printf
    .text:00470328 add esp, 8
    .text:0047032B jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:0047032D ; ---------------------------------------------------------------------------
    .text:0047032D
    .text:0047032D loc_47032D: ; CODE XREF: sub_4702A0+73↑j
    .text:0047032D ; DATA XREF: .text:jpt_470313↓o
    .text:0047032D mov eax, [ebp+var_C] ; jumptable 00470313 case 5
    .text:00470330 push eax
    .text:00470331 push offset aNEqualsD ; "n equals %d"
    .text:00470336 call sub_468D1B ; printf
    .text:0047033B add esp, 8
    .text:0047033E jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:00470340 ; ---------------------------------------------------------------------------
    .text:00470340
    .text:00470340 loc_470340: ; CODE XREF: sub_4702A0+73↑j
    .text:00470340 ; DATA XREF: .text:jpt_470313↓o
    .text:00470340 mov eax, [ebp+var_C] ; jumptable 00470313 case 10
    .text:00470343 push eax
    .text:00470344 push offset aNEqualsD ; "n equals %d"
    .text:00470349 call sub_468D1B ; printf
    .text:0047034E add esp, 8
    .text:00470351 jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:00470353 ; ---------------------------------------------------------------------------
    .text:00470353
    .text:00470353 loc_470353: ; CODE XREF: sub_4702A0+73↑j
    .text:00470353 ; DATA XREF: .text:jpt_470313↓o
    .text:00470353 mov eax, [ebp+var_C] ; jumptable 00470313 case 17
    .text:00470356 push eax
    .text:00470357 push offset aNEqualsD ; "n equals %d"
    .text:0047035C call sub_468D1B ; printf
    .text:00470361 add esp, 8
    .text:00470364 jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:00470366 ; ---------------------------------------------------------------------------
    .text:00470366
    .text:00470366 loc_470366: ; CODE XREF: sub_4702A0+73↑j
    .text:00470366 ; DATA XREF: .text:jpt_470313↓o
    .text:00470366 mov eax, [ebp+var_C] ; jumptable 00470313 case 11
    .text:00470369 push eax
    .text:0047036A push offset aNEqualsD ; "n equals %d"
    .text:0047036F call sub_468D1B ; printf
    .text:00470374 add esp, 8
    .text:00470377 jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:00470379 ; ---------------------------------------------------------------------------
    .text:00470379
    .text:00470379 loc_470379: ; CODE XREF: sub_4702A0+73↑j
    .text:00470379 ; DATA XREF: .text:jpt_470313↓o
    .text:00470379 mov eax, [ebp+var_C] ; jumptable 00470313 case 67
    .text:0047037C push eax
    .text:0047037D push offset aNEqualsD ; "n equals %d"
    .text:00470382 call sub_468D1B ; printf
    .text:00470387 add esp, 8
    .text:0047038A jmp short def_470313 ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:0047038C ; ---------------------------------------------------------------------------
    .text:0047038C
    .text:0047038C loc_47038C: ; CODE XREF: sub_4702A0+73↑j
    .text:0047038C ; DATA XREF: .text:jpt_470313↓o
    .text:0047038C mov eax, [ebp+var_C] ; jumptable 00470313 case 3
    .text:0047038F push eax
    .text:00470390 push offset aNEqualsD ; "n equals %d"
    .text:00470395 call sub_468D1B ; printf
    .text:0047039A add esp, 8
    .text:0047039D
    .text:0047039D def_470313: ; CODE XREF: sub_4702A0+60↑j
    .text:0047039D ; sub_4702A0+73↑j ...
    .text:0047039D push offset aPause ; jumptable 00470313 default case, cases 2,4,6-9,12-16,18-66
    .text:004703A2 call sub_46AFAD ; system
    .text:004703A7 add esp, 4

    源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    int number;
    scanf("%d", &number);
    switch (number) {
    case 1:
    printf("n equals %d", number);
    break;
    case 5:
    printf("n equals %d", number);
    break;
    case 10:
    printf("n equals %d", number);
    break;
    case 17:
    printf("n equals %d", number);
    break;
    case 11:
    printf("n equals %d", number);
    break;
    case 67:
    printf("n equals %d", number);
    break;
    case 3:
    printf("n equals %d", number);
    break;
    }
    system("pause");
  • 对跳转表和索引值表进行进一步解释:

    先看跳转表:

    跳转表

    可以看到跳转表只有简单的8种情况。但是编译器(反编译器?)只能根据case的最大值用笨方法枚举可能的值,这时候,就可以给这些枚举的值分成两种:一种是case里有的,一种是case里没有的。看跳转表的最后一个,叫def而不是loc,这个就是给case里没有的枚举值准备的。因为分为case里有的和没有的,因此,case里有的,会给出具体的索引值;case里没有的,统一导向跳转表的最后一个。再看索引值表:

    索引值表

    可以看到,里面枚举了0到66对应的索引值。看汇编代码,是将输入的值作为索引值表的索引来用的,索引出来的值再作为跳转表的索引。注意看,索引值表的最小值为0,因此,跳转表和数组一样从0开始索引,而0-7对应跳转表的八种情况。通过进一步挖掘信息,还可以知道跳转表是把case按照从小到大的顺序排列的。因此,最开始会对输入值有一个减的操作。至于为什么减1,我们就可以推测最小的case是1了,因为索引从0开始,而最小的case在索引0处。

  • 这样解释下来可能还有点绕,所以我们按照机器的动作走一遍:

    首先,把case按顺序排出跳转表。

    然后,假设我们拿到输入的值。作为机器,我们知道case有:1,3,5,10,17,11,67,所以先给输入的值减1,以便这个值是1的时候我们可以索引到跳转表下标0处。同时,如果这个值大于66,我们还可以直接跳过case检查,直接导出去(刚好和在case最大最小值范围内但不是case的值一样对待)

    再然后,我们枚举0-66的值,并且把这些值和case里有的值一一比较,分出两种值:一种在case里,一种不再case里。

    ok,然后我们建立索引值表,给在case里的枚举值对应的跳转表索引值,比如说枚举值2(输入值是3),刚好case里有3,按顺序排第二,我们就给索引值1(从0开始索引)。回头看截出来的索引值表,在下标2的地方刚好是1(枚举值索引出跳转表索引);给不在case里的值索引到7,对应跳转表最后一位(为没在case里的值专门准备的那一位)。

    最后,我们就准备好我们的解决方案了,对于任意输入的值我们就都有对策了。

  • 请务必真正理解上述内容,因为在逆向工程中,这么绕的操作很常见。在PE文件结构部分,我们或许还有机会再接触到这么绕的操作。(其实只需要写出程序拿到ida里点开跳转表和索引值表(如果有的话)看几眼就明白了,亲身实践总比阅读文字来的有效,因为文字还取决于书写者的表达水平(●’◡’●))

循环语句识别

  • 第一种,for循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    .text:00464096                 mov     [ebp+var_8], 0  ; 一个变量初始化为0
    .text:0046409D mov [ebp+var_14], 1 ; 另一个变量初始化为1
    .text:004640A4 jmp short loc_4640AF
    .text:004640A6 ; ---------------------------------------------------------------------------
    .text:004640A6
    .text:004640A6 loc_4640A6: ; CODE XREF: sub_464070+4E↓j
    .text:004640A6 mov eax, [ebp+var_14]
    .text:004640A9 add eax, 1 ; 用eax过渡,给[ebp+var_14]加1
    .text:004640AC mov [ebp+var_14], eax
    .text:004640AF
    .text:004640AF loc_4640AF: ; CODE XREF: sub_464070+34↑j
    .text:004640AF cmp [ebp+var_14], 0Ah
    .text:004640B3 jg short loc_4640C0 ; [ebp+var_14]大于0Ah时跳转(出循环)
    .text:004640B5 mov eax, [ebp+var_8]
    .text:004640B8 add eax, [ebp+var_14] ; 用eax过渡,把[ebp+var_14]的值加到[ebp+var_8]上
    .text:004640BB mov [ebp+var_8], eax
    .text:004640BE jmp short loc_4640A6 ; 跳回去,形成循环
    .text:004640C0 ; ---------------------------------------------------------------------------
    .text:004640C0
    .text:004640C0 loc_4640C0: ; CODE XREF: sub_464070+43↑j
    .text:004640C0 mov eax, [ebp+var_8]
    .text:004640C3 push eax
    .text:004640C4 push offset aCountD ; "count : %d "
    .text:004640C9 call sub_45DB54 ; printf
    .text:004640CE add esp, 8

    源码

    1
    2
    3
    4
    5
    int count = 0;
    for (int i = 1; i <= 10; i++) {
    count += i;
    }
    printf("count : %d ", count);
  • 第二种,while循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .text:004640D1                 mov     [ebp+var_8], 0  ; 一个变量初始化为0
    .text:004640D8 mov [ebp+var_20], 0Ah ; 另一个变量初始化为10
    .text:004640DF
    .text:004640DF loc_4640DF: ; CODE XREF: sub_464070+87↓j
    .text:004640DF cmp [ebp+var_20], 0
    .text:004640E3 jle short loc_4640F9 ; [ebp+var_20]小于等于0时跳转(出循环)
    .text:004640E5 mov eax, [ebp+var_8]
    .text:004640E8 add eax, [ebp+var_20] ; eax过渡,把[ebp+var_20]值加到[ebp+var_8]上
    .text:004640EB mov [ebp+var_8], eax
    .text:004640EE mov eax, [ebp+var_20]
    .text:004640F1 sub eax, 1 ; eax过渡,给[ebp+var_20]减1
    .text:004640F4 mov [ebp+var_20], eax
    .text:004640F7 jmp short loc_4640DF ; 回跳,形成循环
    .text:004640F9 ; ---------------------------------------------------------------------------
    .text:004640F9
    .text:004640F9 loc_4640F9: ; CODE XREF: sub_464070+73↑j
    .text:004640F9 mov eax, [ebp+var_8]
    .text:004640FC push eax
    .text:004640FD push offset aCountD ; "count : %d "
    .text:00464102 call sub_45DB54 ; printf
    .text:00464107 add esp, 8

    源码

    1
    2
    3
    4
    5
    6
    7
    int count = 0;
    int n = 10;
    while (n > 0) {
    count += n;
    n--;
    }
    printf("count : %d ", count);
  • 第三种,do-while循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .text:0046410A                 mov     [ebp+var_8], 0  ; 一个变量初始化为0
    .text:00464111 mov [ebp+var_2C], 0Ah ; 另一个变量初始化为10
    .text:00464118
    .text:00464118 loc_464118: ; CODE XREF: sub_464070+BE↓j
    .text:00464118 mov eax, [ebp+var_8]
    .text:0046411B add eax, [ebp+var_2C] ; eax过渡,把[ebp+var_2C]值加到[ebp+var_8]上
    .text:0046411E mov [ebp+var_8], eax
    .text:00464121 mov eax, [ebp+var_2C]
    .text:00464124 sub eax, 1 ; eax过渡,给[ebp+var_2C]减1
    .text:00464127 mov [ebp+var_2C], eax
    .text:0046412A cmp [ebp+var_2C], 0
    .text:0046412E jg short loc_464118 ; [ebp+var_2C]大于0时回跳
    .text:00464130 mov eax, [ebp+var_8]
    .text:00464133 push eax
    .text:00464134 push offset aCountD ; "count : %d "
    .text:00464139 call sub_45DB54 ; printf
    .text:0046413E add esp, 8

    源码

    1
    2
    3
    4
    5
    6
    7
    int count = 0;
    int i = 10;
    do {
    count += i;
    i--;
    } while (i > 0);
    printf("count : %d ", count);

Day6:if-else语句识别、switch语句识别、循环语句识别

https://sydzi.github.io/2025/07/15/Day6-switch语句识别/

作者

SydzI

发布于

2025-07-15

更新于

2025-10-03

许可协议

评论