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
6int 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
4int 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
14int 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
14int 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
26int 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
5int 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
7int 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
7int count = 0;
int i = 10;
do {
count += i;
i--;
} while (i > 0);
printf("count : %d ", count);
Day6:if-else语句识别、switch语句识别、循环语句识别