SwitchCase语句反汇编分析

SwitchCase语句反汇编分析

在逆向中经常会遇到switch语句,在这里做一个总结,如果有错误,望师傅们可以指正。

switch要求

  1. case后面必须是常量表达式

  2. case后常量表达式的值不能一样

  3. switch后面表达式必须为整数

case中必须是常量,常量的值不能一样,switch表达式的结果必须是整型
当分支条件比较小的时候,switch 和 if else 没有区别

1.添加case后面的值,一个一个增加,观察反汇编代码的变化(何时生成大表).

三个case情况下,生成的汇编码和if else 近似

0040F3E8   mov         eax,dword ptr [ebp+8]
0040F3EB   mov         dword ptr [ebp-4],eax
0040F3EE   cmp         dword ptr [ebp-4],0
0040F3F2   je          Function+32h (0040f402)
0040F3F4   cmp         dword ptr [ebp-4],1
0040F3F8   je          Function+41h (0040f411)
0040F3FA   cmp         dword ptr [ebp-4],2
0040F3FE   je          Function+50h (0040f420)
0040F400   jmp         Function+5Fh (0040f42f)
0040F402   push        offset string "A" (004241a4)
0040F407   call        printf (00401610)
0040F40C   add         esp,4
0040F40F   jmp         Function+6Ch (0040f43c)
0040F411   push        offset string "B" (00424194)
0040F416   call        printf (00401610)
0040F41B   add         esp,4
0040F41E   jmp         Function+6Ch (0040f43c)
0040F420   push        offset string "B" (00424194)
0040F425   call        printf (00401610)
0040F42A   add         esp,4
0040F42D   jmp         Function+6Ch (0040f43c)
0040F42F   push        offset string "Error" (00424214)
0040F434   call        printf (00401610)

四个case的情况下,开始生成大表

    switch(number)
   {    case 0:printf("A");break;    case 1:printf("B");break;    case 2:printf("B");break;    case 3:printf("B");break;    default:printf("Error");break;
   }

其中case从0开始,没有进行sub处理

尝试case从1开始,看是否有sub

    switch(number)
   {    case 1001:printf("A");break;    case 1002:printf("B");break;    case 1003:printf("B");break;    case 1004:printf("B");break;    default:printf("Error");break;
   }

果然出现了sub ecx,1

当case是大数且连续时看sub的情况

    switch(number)
   {    case 1004:printf("A");break;    case 1001:printf("B");break;    case 1002:printf("B");break;    case 1003:printf("B");break;    default:printf("Error");break;
   }


sub ecx,3E9h

其中3E9转换成十进制是1001

由此可以判断,如果case是大数值且连续,编译器会将其处理成0开始的索引,大表中保存各个分支语句函数的地址,配合edx*4+40D841h直接定位到跳转的地方(40D841h是大表的首地址)

当分支语句case多余一定数量时(该数量由编译器界定,不同编译器数量可能不一致,vc6是4)switch 会生成一个大表,大表中保存各个分支语句函数的地址,通过edx*4+40D841h直接定位到跳转的地方(40D841h是大表的首地址)

将case中的常量值的顺序打乱,观察反汇编代码(观察顺序是否会影响生成大表).    

    switch(number)
   {    case 1004:printf("A");break;    case 1002:printf("B");break;    case 1001:printf("C");break;    case 1003:printf("D");break;    default:printf("Error");break;
   }


大表生成顺序,按照case从小到大生成

将case后面的值改成从100开始到109,观察汇编变化(观察值较大时是否生成大表).

switch(number)
{    case 101:printf("A");break;    case 102:printf("B");break;    case 103:printf("C");break;    case 104:printf("D");break;    case 105:printf("E");break;    case 106:printf("F");break;    case 107:printf("I");break;    case 108:printf("J");break;    case 109:printf("K");break;    default:printf("Error");break;
}


值较大时也同样生成大表

将连续的10项中抹去1项或者2项,观察反汇编有无变化(观察大表空缺位置的处理).

    switch(number)
   {    case 101:printf("A");break;    case 103:printf("C");break;    case 104:printf("D");break;    case 105:printf("E");break;    case 107:printf("I");break;    case 108:printf("J");break;    case 109:printf("K");break;    default:printf("Error");break;
   }


被抹去的位置,在大表中会用default的位置填充

在10项中连续抹去,不要抹去最大值和最小值(观察何时生成小表).                

    switch(number)
   {    case 101:printf("A");break;    case 108:printf("J");break;    case 109:printf("K");break;    case 110:printf("K");break;    default:printf("Error");break;
   }

连续删除6项时,出现小表

小表存储时,如果是case中的数值返回大表中对应的分支语句的索引,如果不是返回大表中default的索引

生成的小表最大256个,FF ,如果相差超过一个字节,小表也表示不了

将case后面常量表达式改成毫不连续的值,观察反汇编变化.

    switch(number)
   {    case 101:printf("A");break;    case 999:printf("J");break;    case 9999:printf("K");break;    case 99999:printf("K");break;    default:printf("Error");break;
   }


表达式毫不相干时,是搜索二叉树(没有意义,实战中基本不会遇到)

总结

  1. 分支少于4的时候用switch没有意义,因为编译器会生成类似if..else之类的反汇编

  2. case后面的常量可以是无序的,并不影响大表的生成

  3. 小表与大表在内存中是紧挨着的,小表在大表的下面

switch语句生成四种情况

  1. 分支少,按if else形式生成

  2. 分支间隔特别大,按if else形式生成

  3. 分支连续,生成大表(间隔小时用default生成大表)

  4. 分支间隔大,生成小表

课后练习

1、写一个switch语句,不生产大表也不生产小表,贴出对应的反汇编.
2、写一个switch语句,只生成大表,贴出对应的反汇编.
3、写一个switch语句,生成大表和小表,贴出对应的反汇编.
4、为do..while语句生成的反汇编填写注释.
5、为while语句生成的反汇编填写注释.
6、为for语句生成的反汇编填写注释.
附上练习答案
1.

switch(number)
{    case 1:printf("1");break;    case 2:printf("2");break;    case 3:printf("3");break;    default:printf("Error");break;
}0040F5D8   mov         eax,dword ptr [ebp+8]0040F5DB   mov         dword ptr [ebp-4],eax0040F5DE   cmp         dword ptr [ebp-4],10040F5E2   je          Function+32h (0040f5f2)0040F5E4   cmp         dword ptr [ebp-4],20040F5E8   je          Function+41h (0040f601)0040F5EA   cmp         dword ptr [ebp-4],30040F5EE   je          Function+50h (0040f610)0040F5F0   jmp         Function+5Fh (0040f61f)0040F5F2   push        offset string "1" (00424fbc)0040F5F7   call        printf (00401610)0040F5FC   add         esp,40040F5FF   jmp         Function+6Ch (0040f62c)0040F601   push        offset string "2" (004241a4)0040F606   call        printf (00401610)0040F60B   add         esp,40040F60E   jmp         Function+6Ch (0040f62c)0040F610   push        offset string "3" (00424194)0040F615   call        printf (00401610)0040F61A   add         esp,40040F61D   jmp         Function+6Ch (0040f62c)0040F61F   push        offset string "Error" (00424214)0040F624   call        printf (00401610)

2.

    switch(number)
   {    case 1:printf("1");break;    case 2:printf("2");break;    case 3:printf("3");break;    case 4:printf("4");break;    case 5:printf("5");break;    case 6:printf("6");break;    case 7:printf("7");break;    case 8:printf("8");break;    case 9:printf("9");break;    case 10:printf("10");break;    default:printf("Error");break;
   }0040F5C0   push        ebp0040F5C1   mov         ebp,esp0040F5C3   sub         esp,44h0040F5C6   push        ebx0040F5C7   push        esi0040F5C8   push        edi0040F5C9   lea         edi,[ebp-44h]0040F5CC   mov         ecx,11h0040F5D1   mov         eax,0CCCCCCCCh0040F5D6   rep stos    dword ptr [edi]0040F5D8   mov         eax,dword ptr [ebp+8]0040F5DB   mov         dword ptr [ebp-4],eax0040F5DE   mov         ecx,dword ptr [ebp-4]0040F5E1   sub         ecx,10040F5E4   mov         dword ptr [ebp-4],ecx0040F5E7   cmp         dword ptr [ebp-4],90040F5EB   ja          $L1232+0Fh (0040f697)0040F5F1   mov         edx,dword ptr [ebp-4]0040F5F4   jmp         dword ptr [edx*4+40F6B5h]
$L1214:0040F5FB   push        offset string "1" (00425054)0040F600   call        printf (00401610)0040F605   add         esp,40040F608   jmp         $L1232+1Ch (0040f6a4)
$L1216:0040F60D   push        offset string "2" (00425050)0040F612   call        printf (00401610)0040F617   add         esp,40040F61A   jmp         $L1232+1Ch (0040f6a4)
$L1218:0040F61F   push        offset string "3" (0042504c)0040F624   call        printf (00401610)0040F629   add         esp,40040F62C   jmp         $L1232+1Ch (0040f6a4)
$L1220:0040F62E   push        offset string "4" (00425048)0040F633   call        printf (00401610)0040F638   add         esp,40040F63B   jmp         $L1232+1Ch (0040f6a4)
$L1222:0040F63D   push        offset string "5" (00425044)0040F642   call        printf (00401610)0040F647   add         esp,40040F64A   jmp         $L1232+1Ch (0040f6a4)
$L1224:0040F64C   push        offset string "6" (00425040)0040F651   call        printf (00401610)0040F656   add         esp,40040F659   jmp         $L1232+1Ch (0040f6a4)
$L1226:0040F65B   push        offset string "E" (00424fcc)0040F660   call        printf (00401610)0040F665   add         esp,40040F668   jmp         $L1232+1Ch (0040f6a4)
$L1228:0040F66A   push        offset string "A" (00424fbc)0040F66F   call        printf (00401610)0040F674   add         esp,40040F677   jmp         $L1232+1Ch (0040f6a4)
$L1230:0040F679   push        offset string "9" (004241a4)0040F67E   call        printf (00401610)0040F683   add         esp,40040F686   jmp         $L1232+1Ch (0040f6a4)
$L1232:0040F688   push        offset string "K" (00424194)0040F68D   call        printf (00401610)0040F692   add         esp,40040F695   jmp         $L1232+1Ch (0040f6a4)0040F697   push        offset string "Error" (00424214)0040F69C   call        printf (00401610)

3.

switch(number)
{    case 1:printf("1");break;    case 8:printf("8");break;    case 9:printf("9");break;    case 10:printf("10");break;    default:printf("Error");break;
}040F5C0   push        ebp0040F5C1   mov         ebp,esp0040F5C3   sub         esp,44h0040F5C6   push        ebx0040F5C7   push        esi0040F5C8   push        edi0040F5C9   lea         edi,[ebp-44h]0040F5CC   mov         ecx,11h0040F5D1   mov         eax,0CCCCCCCCh0040F5D6   rep stos    dword ptr [edi]0040F5D8   mov         eax,dword ptr [ebp+8]0040F5DB   mov         dword ptr [ebp-4],eax0040F5DE   mov         ecx,dword ptr [ebp-4]0040F5E1   sub         ecx,10040F5E4   mov         dword ptr [ebp-4],ecx0040F5E7   cmp         dword ptr [ebp-4],90040F5EB   ja          $L1220+0Fh (0040f63b)0040F5ED   mov         eax,dword ptr [ebp-4]0040F5F0   xor         edx,edx0040F5F2   mov         dl,byte ptr  (0040f66d)[eax]0040F5F8   jmp         dword ptr [edx*4+40F659h]
$L1214:0040F5FF   push        offset string "7" (00424fcc)0040F604   call        printf (00401610)0040F609   add         esp,40040F60C   jmp         $L1220+1Ch (0040f648)
$L1216:0040F60E   push        offset string "A" (00424fbc)0040F613   call        printf (00401610)0040F618   add         esp,40040F61B   jmp         $L1220+1Ch (0040f648)
$L1218:0040F61D   push        offset string "9" (004241a4)0040F622   call        printf (00401610)0040F627   add         esp,40040F62A   jmp         $L1220+1Ch (0040f648)
$L1220:0040F62C   push        offset string "K" (00424194)0040F631   call        printf (00401610)0040F636   add         esp,40040F639   jmp         $L1220+1Ch (0040f648)0040F63B   push        offset string "Error" (00424214)0040F640   call        printf (00401610)

4.

void Function()
{    int x = 0;    int y = 3;    do
   {        printf("%dn",x);
       x++;
   }    while(x<y);
}0040F5D8   mov         dword ptr [ebp-4],00040F5DF   mov         dword ptr [ebp-8],30040F5E6   mov         eax,dword ptr [ebp-4]//循环开始//调用printf0040F5E9   push        eax0040F5EA   push        offset string "K" (00424194)0040F5EF   call        printf (00401610)0040F5F4   add         esp,8//x++0040F5F7   mov         ecx,dword ptr [ebp-4]0040F5FA   add         ecx,10040F5FD   mov         dword ptr [ebp-4],ecxwhile(x<y)0040F600   mov         edx,dword ptr [ebp-4]0040F603   cmp         edx,dword ptr [ebp-8]0040F606   jl          Function+26h (0040f5e6)//进行比较如果不满足条件跳转

5.

void Function(int number)
{    int x = 0;    int y = 3;    while(x<y)
   {        printf("%dn",x);
       x++;
   }
}0040F5D8   mov         dword ptr [ebp-4],00040F5DF   mov         dword ptr [ebp-8],3//while(x < y)进行判断0040F5E6   mov         eax,dword ptr [ebp-4]0040F5E9   cmp         eax,dword ptr [ebp-8]0040F5EC   jge         Function+4Ah (0040f60a) //如果x>y就直接跳转到函数结尾//循环体内部,调用printf函数0040F5EE   mov         ecx,dword ptr [ebp-4]0040F5F1   push        ecx0040F5F2   push        offset string "K" (00424194)0040F5F7   call        printf (00401610)0040F5FC   add         esp,8//x++0040F5FF   mov         edx,dword ptr [ebp-4]0040F602   add         edx,10040F605   mov         dword ptr [ebp-4],edx//此处跳到循环开始判断的位置,进行循环0040F608   jmp         Function+26h (0040f5e6)0040F60A   pop         edi0040F60B   pop         esi0040F60C   pop         ebx

6.

void Function(int number)
{    int y = 3;    for(int x=0;x < y;x++)
   {        printf("%dn",x);
   }
}0040F5D8   mov         dword ptr [ebp-4],3//y = 30040F5DF   mov         dword ptr [ebp-8],0//x = 0//for语句开始,跳转到判断位置0040F5E6   jmp         Function+31h (0040f5f1)//x++0040F5E8   mov         eax,dword ptr [ebp-8]0040F5EB   add         eax,10040F5EE   mov         dword ptr [ebp-8],eax//x<y 进行判断,如果不满足条件直接跳到函数尾0040F5F1   mov         ecx,dword ptr [ebp-8]0040F5F4   cmp         ecx,dword ptr [ebp-4]0040F5F7   jge         Function+4Ch (0040f60c)//for循环内部,调用printf0040F5F9   mov         edx,dword ptr [ebp-8]0040F5FC   push        edx0040F5FD   push        offset string "K" (00424194)0040F602   call        printf (00401610)0040F607   add         esp,8//跳转到进行x++0040F60A   jmp         Function+28h (0040f5e8)0040F60C   pop         edi0040F60D   pop         esi0040F60E   pop         ebx

本文作者:星盟安全团队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/126376.html

Tags:
评论  (0)
快来写下你的想法吧!

星盟安全团队

文章数:31 积分: 75

星盟安全团队---"VENI VIDI VICI"(我来,我见,我征服),我们的征途是星辰大海。从事各类安全研究,专注于知识分享。

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号