zoukankan      html  css  js  c++  java
  • switch语句的逆向

    在vc6.0编译器中,会自动为switch转换成4种情况的汇编语句。

    case1:

    当c语言源代码为

     1 #include<stdio.h>
     2 void myFunction(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");
     8         break;
     9     case 2:
    10         printf("2");
    11         break;
    12     case 3:
    13         printf("3");
    14         break;
    15     default:
    16         printf("error");
    17     }
    18 }
    19 int main()
    20 {
    21     myFunction(2);
    22     return 0;
    23 }

    运行的结果可以看出,和if&else一样。

    都是cmp&jcc的。

     1 4:        switch(x)
     2 5:        {
     3 0040D7B8   mov         eax,dword ptr [ebp+8]
     4 0040D7BB   mov         dword ptr [ebp-4],eax
     5 0040D7BE   cmp         dword ptr [ebp-4],1
     6 0040D7C2   je          myFunction+32h (0040d7d2)
     7 0040D7C4   cmp         dword ptr [ebp-4],2
     8 0040D7C8   je          myFunction+41h (0040d7e1)
     9 0040D7CA   cmp         dword ptr [ebp-4],3
    10 0040D7CE   je          myFunction+50h (0040d7f0)
    11 0040D7D0   jmp         myFunction+5Fh (0040d7ff)
    12 6:        case 1:
    13 7:            printf("1");
    14 0040D7D2   push        offset string "1" (0042202c)
    15 0040D7D7   call        printf (00401110)
    16 0040D7DC   add         esp,4
    17 8:            break;
    18 0040D7DF   jmp         myFunction+6Ch (0040d80c)
    19 9:        case 2:
    20 10:           printf("2");
    21 0040D7E1   push        offset string "2" (00422028)
    22 0040D7E6   call        printf (00401110)
    23 0040D7EB   add         esp,4
    24 11:           break;
    25 0040D7EE   jmp         myFunction+6Ch (0040d80c)
    26 12:       case 3:
    27 13:           printf("3");
    28 0040D7F0   push        offset string "4" (00422024)
    29 0040D7F5   call        printf (00401110)
    30 0040D7FA   add         esp,4
    31 14:           break;
    32 0040D7FD   jmp         myFunction+6Ch (0040d80c)
    33 15:
    34 16:       default:
    35 17:           printf("error");
    36 0040D7FF   push        offset string "error" (0042201c)
    37 0040D804   call        printf (00401110)
    38 0040D809   add         esp,4

    当case情况小于等于3时,ifelse和switch并没有什么区别。

    case2:

    当case情况大于等于4种时,且4种case是连续的。

     1 #include<stdio.h>
     2 void myFunction(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");
     8         break;
     9     case 2:
    10         printf("2");
    11         break;
    12     case 3:
    13         printf("3");
    14         break;
    15     case 4:
    16         printf("4");
    17         break;
    18     default:
    19         printf("error");
    20     }
    21 }
    22 int main()
    23 {
    24     myFunction(2);
    25     return 0;
    26 }

    明显的区别是

     1 4:        switch(x)
     2 5:        {
     3 0040D7B8   mov         eax,dword ptr [ebp+8]
     4 0040D7BB   mov         dword ptr [ebp-4],eax
     5 0040D7BE   mov         ecx,dword ptr [ebp-4]
     6 0040D7C1   sub         ecx,1
     7 0040D7C4   mov         dword ptr [ebp-4],ecx
     8 0040D7C7   cmp         dword ptr [ebp-4],3
     9 0040D7CB   ja          $L538+0Fh (0040d813)
    10 0040D7CD   mov         edx,dword ptr [ebp-4]
    11 0040D7D0   jmp         dword ptr [edx*4+40D831h]
    12 6:        case 1:
    13 7:            printf("1");
    14 0040D7D7   push        offset string "1" (0042213c)
    15 0040D7DC   call        printf (00401110)
    16 0040D7E1   add         esp,4
    17 8:            break;
    18 0040D7E4   jmp         $L538+1Ch (0040d820)
    19 9:        case 2:
    20 10:           printf("2");
    21 0040D7E6   push        offset string "2" (0042202c)
    22 0040D7EB   call        printf (00401110)
    23 0040D7F0   add         esp,4
    24 11:           break;
    25 0040D7F3   jmp         $L538+1Ch (0040d820)
    26 12:       case 3:
    27 13:           printf("3");
    28 0040D7F5   push        offset string "3" (00422028)
    29 0040D7FA   call        printf (00401110)
    30 0040D7FF   add         esp,4
    31 14:           break;
    32 0040D802   jmp         $L538+1Ch (0040d820)
    33 15:       case 4:
    34 16:           printf("4");
    35 0040D804   push        offset string "4" (00422024)
    36 0040D809   call        printf (00401110)
    37 0040D80E   add         esp,4
    38 17:           break;
    39 0040D811   jmp         $L538+1Ch (0040d820)
    40 18:       default:
    41 19:           printf("error");
    42 0040D813   push        offset string "error" (0042201c)
    43 0040D818   call        printf (00401110)
    44 0040D81D   add         esp,4
    45 20:       }
    46 21:   }

    代码分析:

    将传进来的x放在ecx中

    在这一段中可以明显看到的是多出了一个sub,ecx减去一个1。ecx移动回ebp-4,ebp-4和3比较。

    后面有一个ja,40d813,这里是default去的地方。即x-1和3比较,大于则跳转至default

    ebp-4放入edx中。

    后面还有一句dword ptr [edx*4+40D831h]

    实际上,这里的sub,减去的是这4个case中的最小值。

    dword ptr [edx*4+40D831h]这个就是编译器自动为我们生成的一张表。按下alt+6,将40D831拖到memery窗口中。

    可以看到

    可以看到40d831。

    总的来说edx=x-1。即(x-1)*4+40d831h这个内存单元的内容,就是大表跳转的地方。

    图中我们可以看到4个地址

    40d7d7,是case1的地方。

    40d7e6,是case2的地方。

    40d7f5,是case3的地方。

    40d804,是case4的地方。

    如果中间随便调整顺序呢,结果发现调整顺序对最终结果无影响。(数据就不贴了)

    那假如不是连续的呢。

    原本的代码

     1 #include<stdio.h>
     2 void Function(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");break;
     8     case 2:
     9         printf("2");break;
    10     case 3:
    11         printf("3");break;
    12     case 4:
    13         printf("4");break;
    14     case 5:
    15         printf("5");break;
    16     case 6:
    17         printf("6");break;
    18     case 7:
    19         printf("7");break;
    20     case 8:
    21         printf("8");break;
    22     case 9:
    23         printf("9");break;
    24     default:
    25         printf("error");break;
    26     }
    27 }
    28 
    29 void main()
    30 {
    31     Function(3);
    32 }

    删除后的代码

     1 #include<stdio.h>
     2 void Function(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");break;
     8     case 2:
     9         printf("2");break;
    10 
    11     case 7:
    12         printf("7");break;
    13     case 8:
    14         printf("8");break;
    15     case 9:
    16         printf("9");break;
    17     default:
    18         printf("error");break;
    19     }
    20 }
    21 
    22 void main()
    23 {
    24     Function(3);
    25 }

    反编译得到

     1 4:        switch(x)
     2 5:        {
     3 00401038   mov         eax,dword ptr [ebp+8]
     4 0040103B   mov         dword ptr [ebp-4],eax
     5 0040103E   mov         ecx,dword ptr [ebp-4]
     6 00401041   sub         ecx,1
     7 00401044   mov         dword ptr [ebp-4],ecx
     8 00401047   cmp         dword ptr [ebp-4],8
     9 0040104B   ja          $L540+0Fh (004010a2)
    10 0040104D   mov         edx,dword ptr [ebp-4]
    11 00401050   jmp         dword ptr [edx*4+4010C0h]
    12 6:        case 1:
    13 7:            printf("1");break;
    14 00401057   push        offset string "1" (00422030)
    15 0040105C   call        printf (004011f0)
    16 00401061   add         esp,4
    17 00401064   jmp         $L540+1Ch (004010af)
    18 8:        case 2:
    19 9:            printf("2");break;
    20 00401066   push        offset string "2" (0042202c)
    21 0040106B   call        printf (004011f0)
    22 00401070   add         esp,4
    23 00401073   jmp         $L540+1Ch (004010af)
    24 10:
    25 11:       case 7:
    26 12:           printf("7");break;
    27 00401075   push        offset string "7" (00422028)
    28 0040107A   call        printf (004011f0)
    29 0040107F   add         esp,4
    30 00401082   jmp         $L540+1Ch (004010af)
    31 13:       case 8:
    32 14:           printf("8");break;
    33 00401084   push        offset string "8" (00422024)
    34 00401089   call        printf (004011f0)
    35 0040108E   add         esp,4
    36 00401091   jmp         $L540+1Ch (004010af)
    37 15:       case 9:
    38 16:           printf("9");break;
    39 00401093   push        offset string "9" (00422020)
    40 00401098   call        printf (004011f0)
    41 0040109D   add         esp,4
    42 004010A0   jmp         $L540+1Ch (004010af)
    43 17:       default:
    44 18:           printf("error");break;
    45 004010A2   push        offset string "error" (00422fcc)
    46 004010A7   call        printf (004011f0)
    47 004010AC   add         esp,4
    48 19:       }
    49 20:   }

    删除后我们发现原本的那张表删除的位置上添加了一个地址,而这个地址我们过去查看发现正是default部分的地址。

    这么弄不就浪费了么,于是我们继续删,看看编译器会如何处理。

    当我们删的只有3个的时候,代码为

     1 #include<stdio.h>
     2 void Function(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");break;
     8     case 2:
     9         printf("2");break;
    10 
    11 
    12     case 9:
    13         printf("9");break;
    14     default:
    15         printf("error");break;
    16     }
    17 }
    18 
    19 void main()
    20 {
    21     Function(3);
    22 }

    反编译得到的代码已经变成这样了

     1 4:        switch(x)
     2 5:        {
     3 00401038   mov         eax,dword ptr [ebp+8]
     4 0040103B   mov         dword ptr [ebp-4],eax
     5 0040103E   cmp         dword ptr [ebp-4],1
     6 00401042   je          Function+32h (00401052)
     7 00401044   cmp         dword ptr [ebp-4],2
     8 00401048   je          Function+41h (00401061)
     9 0040104A   cmp         dword ptr [ebp-4],9
    10 0040104E   je          Function+50h (00401070)
    11 00401050   jmp         Function+5Fh (0040107f)
    12 6:        case 1:
    13 7:            printf("1");break;
    14 00401052   push        offset string "7" (00422028)
    15 00401057   call        printf (004011f0)
    16 0040105C   add         esp,4
    17 0040105F   jmp         Function+6Ch (0040108c)
    18 8:        case 2:
    19 9:            printf("2");break;
    20 00401061   push        offset string "2" (00422024)
    21 00401066   call        printf (004011f0)
    22 0040106B   add         esp,4
    23 0040106E   jmp         Function+6Ch (0040108c)
    24 10:
    25 11:
    26 12:       case 9:
    27 13:           printf("9");break;
    28 00401070   push        offset string "9" (00422020)
    29 00401075   call        printf (004011f0)
    30 0040107A   add         esp,4
    31 0040107D   jmp         Function+6Ch (0040108c)
    32 14:       default:
    33 15:           printf("error");break;
    34 0040107F   push        offset string "error" (00422fcc)
    35 00401084   call        printf (004011f0)
    36 00401089   add         esp,4
    37 16:       }
    38 17:   }

    编译器会自动为我们做出最优化的汇编代码。当浪费超过一定的时候,还是回归到cmp&jcc上了。

    那假如我的case都是连续的,只有一个很突兀,结果会如何呢。

    Case3

    此时代码为

     1 #include<stdio.h>
     2 void Function(int x)
     3 {
     4     switch(x)
     5     {
     6     case 1:
     7         printf("1");break;
     8     case 2:
     9         printf("2");break;
    10     case 3:
    11         printf("3");break;
    12     case 4:
    13         printf("4");break;
    14     case 5:
    15         printf("5");break;
    16 
    17     case 233:
    18         printf("233");break;
    19 
    20     case 7:
    21         printf("7");break;
    22     case 8:
    23         printf("8");break;
    24     case 9:
    25         printf("9");break;
    26     default:
    27         printf("error");break;
    28 
    29     }
    30 }
    31 
    32 void main()
    33 {
    34     Function(3);
    35 }

    汇编代码为

     1 4:        switch(x)
     2 5:        {
     3 0040D898   mov         eax,dword ptr [ebp+8]
     4 0040D89B   mov         dword ptr [ebp-4],eax
     5 0040D89E   mov         ecx,dword ptr [ebp-4]
     6 0040D8A1   sub         ecx,1
     7 0040D8A4   mov         dword ptr [ebp-4],ecx
     8 0040D8A7   cmp         dword ptr [ebp-4],0E8h
     9 0040D8AE   ja          $L548+0Fh (0040d950)
    10 0040D8B4   mov         eax,dword ptr [ebp-4]
    11 0040D8B7   xor         edx,edx
    12 0040D8B9   mov         dl,byte ptr  (0040d996)[eax]
    13 0040D8BF   jmp         dword ptr [edx*4+40D96Eh]
    14 6:        case 1:
    15 7:            printf("1");break;
    16 0040D8C6   push        offset string "1" (0042203c)
    17 0040D8CB   call        printf (004011f0)
    18 0040D8D0   add         esp,4
    19 0040D8D3   jmp         $L548+1Ch (0040d95d)
    20 8:        case 2:
    21 9:            printf("2");break;
    22 0040D8D8   push        offset string "2" (00422038)
    23 0040D8DD   call        printf (004011f0)
    24 0040D8E2   add         esp,4
    25 0040D8E5   jmp         $L548+1Ch (0040d95d)
    26 10:       case 3:
    27 11:           printf("3");break;
    28 0040D8E7   push        offset string "3" (00422034)
    29 0040D8EC   call        printf (004011f0)
    30 0040D8F1   add         esp,4
    31 0040D8F4   jmp         $L548+1Ch (0040d95d)
    32 12:       case 4:
    33 13:           printf("4");break;
    34 0040D8F6   push        offset string "4" (00422030)
    35 0040D8FB   call        printf (004011f0)
    36 0040D900   add         esp,4
    37 0040D903   jmp         $L548+1Ch (0040d95d)
    38 14:       case 5:
    39 15:           printf("5");break;
    40 0040D905   push        offset string "5" (0042202c)
    41 0040D90A   call        printf (004011f0)
    42 0040D90F   add         esp,4
    43 0040D912   jmp         $L548+1Ch (0040d95d)
    44 16:
    45 17:       case 233:
    46 18:           printf("233");break;
    47 0040D914   push        offset string "12" (0042201c)
    48 0040D919   call        printf (004011f0)
    49 0040D91E   add         esp,4
    50 0040D921   jmp         $L548+1Ch (0040d95d)
    51 19:
    52 20:       case 7:
    53 21:           printf("7");break;
    54 0040D923   push        offset string "7" (00422028)
    55 0040D928   call        printf (004011f0)
    56 0040D92D   add         esp,4
    57 0040D930   jmp         $L548+1Ch (0040d95d)
    58 22:       case 8:
    59 23:           printf("8");break;
    60 0040D932   push        offset string "10" (00422024)
    61 0040D937   call        printf (004011f0)
    62 0040D93C   add         esp,4
    63 0040D93F   jmp         $L548+1Ch (0040d95d)
    64 24:       case 9:
    65 25:           printf("9");break;
    66 0040D941   push        offset string "11" (00422020)
    67 0040D946   call        printf (004011f0)
    68 0040D94B   add         esp,4
    69 0040D94E   jmp         $L548+1Ch (0040d95d)
    70 26:       default:
    71 27:           printf("error");break;
    72 0040D950   push        offset string "error" (00422fcc)
    73 0040D955   call        printf (004011f0)
    74 0040D95A   add         esp,4
    75 28:
    76 29:       }
    77 30:   }

    可以很明显看到不一样的地方

    有一个ja,跳转至default。然后多了个edx,且将edx归零。而重点在这0040d996mov dl,byte ptr (0040d996)[eax],这句话的意思是将内存单元[eax+40d996]的内容放到dl中。

    我们打开这个地址,发现里面是一个个数字

    这张表就是小表。这里的09似乎是最多的。当[40d996+eax]为09时,edx*4+40D96Eh就是24+40D96eh。即为40d992。

    然后40d992中存放的是40d950。这个地址是default的地址。

    小表是两位数字。那假如突然出来一个超过255的case呢。

    整个全变了。

     1 4:        switch(x)
     2 5:        {
     3 0040D898   mov         eax,dword ptr [ebp+8]
     4 0040D89B   mov         dword ptr [ebp-4],eax
     5 0040D89E   cmp         dword ptr [ebp-4],104h
     6 0040D8A5   jg          Function+4Dh (0040d8cd)
     7 0040D8A7   cmp         dword ptr [ebp-4],104h
     8 0040D8AE   je          $L540+0Fh (0040d920)
     9 0040D8B0   mov         ecx,dword ptr [ebp-4]
    10 0040D8B3   sub         ecx,1
    11 0040D8B6   mov         dword ptr [ebp-4],ecx
    12 0040D8B9   cmp         dword ptr [ebp-4],8
    13 0040D8BD   ja          $L548+0Fh (0040d95c)
    14 0040D8C3   mov         edx,dword ptr [ebp-4]
    15 0040D8C6   jmp         dword ptr [edx*4+40D97Ah]
    16 0040D8CD   jmp         $L548+0Fh (0040d95c)
    17 6:        case 1:
    18 7:            printf("1");break;
    19 0040D8D2   push        offset string "1" (0042203c)
    20 0040D8D7   call        printf (004011f0)
    21 0040D8DC   add         esp,4
    22 0040D8DF   jmp         $L548+1Ch (0040d969)
    23 8:        case 2:
    24 9:            printf("2");break;
    25 0040D8E4   push        offset string "2" (00422038)
    26 0040D8E9   call        printf (004011f0)
    27 0040D8EE   add         esp,4
    28 0040D8F1   jmp         $L548+1Ch (0040d969)
    29 10:       case 3:
    30 11:           printf("3");break;
    31 0040D8F3   push        offset string "3" (00422034)
    32 0040D8F8   call        printf (004011f0)
    33 0040D8FD   add         esp,4
    34 0040D900   jmp         $L548+1Ch (0040d969)
    35 12:       case 4:
    36 13:           printf("4");break;
    37 0040D902   push        offset string "4" (00422030)
    38 0040D907   call        printf (004011f0)
    39 0040D90C   add         esp,4
    40 0040D90F   jmp         $L548+1Ch (0040d969)
    41 14:       case 5:
    42 15:           printf("5");break;
    43 0040D911   push        offset string "5" (0042202c)
    44 0040D916   call        printf (004011f0)
    45 0040D91B   add         esp,4
    46 0040D91E   jmp         $L548+1Ch (0040d969)
    47 16:
    48 17:       case 260:
    49 18:           printf("260");break;
    50 0040D920   push        offset string "260" (0042201c)
    51 0040D925   call        printf (004011f0)
    52 0040D92A   add         esp,4
    53 0040D92D   jmp         $L548+1Ch (0040d969)
    54 19:
    55 20:       case 7:
    56 21:           printf("7");break;
    57 0040D92F   push        offset string "7" (00422028)
    58 0040D934   call        printf (004011f0)
    59 0040D939   add         esp,4
    60 0040D93C   jmp         $L548+1Ch (0040d969)
    61 22:       case 8:
    62 23:           printf("8");break;
    63 0040D93E   push        offset string "10" (00422024)
    64 0040D943   call        printf (004011f0)
    65 0040D948   add         esp,4
    66 0040D94B   jmp         $L548+1Ch (0040d969)
    67 24:       case 9:
    68 25:           printf("9");break;
    69 0040D94D   push        offset string "11" (00422020)
    70 0040D952   call        printf (004011f0)
    71 0040D957   add         esp,4
    72 0040D95A   jmp         $L548+1Ch (0040d969)
    73 26:       default:
    74 27:           printf("error");break;
    75 0040D95C   push        offset string "error" (00422fcc)
    76 0040D961   call        printf (004011f0)
    77 0040D966   add         esp,4
    78 28:
    79 29:       }
    80 30:   }

    首先把参数放到eax,eax和104h对比(104h==260)。大于等于则跳走。小于则继续走大表。

    最后一种

    Case4:

    整个case完全没有规律。那么将按照二叉树来进行查找每个case的地址。然本人目前还没学到。暂时不多叙述了,学到二叉树时再将其补上。

  • 相关阅读:
    iOS--------cocoapods遇到的问题
    NTFS
    交换机配置telnet
    交换机
    华为模拟器配置telnet
    路由器
    OSI模型
    网络拓扑
    为什么CAS加锁是线程安全的?--理解原子操作
    零基础自学编程选哪种语言好?世上最好编程语言推荐
  • 原文地址:https://www.cnblogs.com/zimudao/p/8618150.html
Copyright © 2011-2022 走看看