反汇编——逆向初步(2)

来源:互联网 发布:中国移动有什么软件 编辑:程序博客网 时间:2024/06/08 18:50
   逆向初步(1)介绍的是if……else语句在反汇编中的事例,现在我们来看看switch……case语句在反汇编长啥样。我们先来看一段简单的使用switch……case语句的程序,其代码如下:
#include
main()
{
       int c = 5;
       switch(c)
       {
       case 0:
              printf("c = 0");
              break;
       case 5:
              printf("c = 5");
              break;
       case 10:
              printf("c = 10");
              break;
       default:break;
       }
}
接下来我们来看它对应的反汇编代码,如下所示:
4:       int c =5;
00401028   mov       dword ptr[ebp-4],5
5:       switch(c)
6:       {
0040102F   mov       eax,dwordptr [ebp-4]
00401032   mov       dword ptr[ebp-8],eax
00401035   cmp       dword ptr[ebp-8],0
00401039   je        main 39h(00401049)
0040103B   cmp       dword ptr[ebp-8],5
0040103F   je        main 48h(00401058)
00401041   cmp       dword ptr[ebp-8],0Ah
00401045   je        main 57h(00401067)
00401047   jmp       main 64h(00401074)
7:       case 0:
8:          printf("c =0");
00401049   push      offset string"c = 0" (0042202c)
0040104E   call      printf(004010b0)
00401053   add       esp,4
9:          break;
00401056   jmp       main 64h(00401074)
10:      case 5:
11:         printf("c =5");
00401058   push      offset string"c = 5" (00422024)
0040105D   call      printf(004010b0)
00401062   add       esp,4
12:         break;
00401065   jmp       main 64h(00401074)
13:      case 10:
14:         printf("c =10");
00401067   push      offset string"c = 10" (0042201c)
0040106C   call      printf(004010b0)
00401071   add       esp,4
15:         break;
16:      default:break;
17:      }
    我们可以看到,第一行代码是将5存入堆栈中,然后再switch语句中,将堆栈中的5取出来,存入eax寄存器中,然后又把eax寄存器中的值存入堆栈中,接下来就是比较了。比较的过程有点类似于if语句,但是if语句去的是区间,而switch语句用的是值,所以比较时用的汇编指令为je。下面我们来具体分析下。
00401035   cmp       dword ptr[ebp-8],0
00401039   je        main 39h(00401049)
   首先,上面这两行代码是判断c的值是否为0,如果是0,则跳转到case  0:处,00401049这个正好是case  0:的地址。接下来的几个比较和跳转指令的意思都类似,不过在最后一个je指令的下面却有一个jmp指令,这是一个无条件跳转指令,它跳转到的位置是00401074,由上面的反汇编代码我们知道,这个地址在switch语句之外,也就是说,如果c的值不和比较的这三个数相等,则不进入case中。
   而在case中,则是对printf函数的调用,然后就是一个jmp指令直接跳出switch语句,这是因为我们在case语句中使用了break的情况。大家可以试想一下,如果我在case中不使用break,那么反汇编代码又会是咋样呢?下面我们就来看看不使用break的case的反汇编长啥样。先看c代码:
#include
main()
{
       int c = 5;
       switch(c)
       {
       case 0:
              printf("c = 0");
       case 5:
              printf("c = 5");
       case 10:
              printf("c = 10");
       default:break;
       }
}
   代码和上面的类似,只是前3个case中少了break,从C的知识我们可以知道,只要进入一个case,那么它下面的case都会被执行,我们可以这样试想,要实现这个功能,那么可能是处理完case中的代码后,没有使用jmp指令,这样程序就不会跳转,就一直往下执行。我们来看看其反汇编代码:
4:       int c =5;
00401028   mov       dword ptr[ebp-4],5
5:       switch(c)
6:       {
0040102F   mov       eax,dwordptr [ebp-4]
00401032   mov       dword ptr[ebp-8],eax
00401035   cmp       dword ptr[ebp-8],0
00401039   je        main 39h(00401049)
0040103B   cmp       dword ptr[ebp-8],5
0040103F   je        main 46h(00401056)
00401041   cmp       dword ptr[ebp-8],0Ah
00401045   je        main 53h(00401063)
00401047   jmp       main 60h(00401070)
7:       case 0:
8:          printf("c =0");
00401049   push      offset string"c = 0" (0042202c)
0040104E   call      printf(004010b0)
00401053   add       esp,4
9:       case 5:
10:         printf("c =5");
00401056   push      offset string"c = 5" (00422024)
0040105B   call      printf(004010b0)
00401060   add       esp,4
11:      case 10:
12:         printf("c =10");
00401063   push      offset string"c = 10" (0042201c)
00401068   call      printf(004010b0)
0040106D   add       esp,4
13:      default:break;
14:      }
    由上面的代码可以看出,我们的猜想是正确的。少了break的case,其后面没有跳转指令,于是程序就继续往下执行了。这也是使用switch语句是需要注意的地方,有的时候我们用到switch语句,可是却发现得出的结果不是我们想要的,这个时候就要检查下看case中有没有漏掉break,如果漏掉了,程序就会继续执行下一个case,就可能得不出我们想要的结果。
   switch语句的反汇编,就介绍这么多了。switch语句很灵活,但是不小心也容易出错,所以大家在使用的时候要小心,特别是新手,经常是漏掉break,然后程序运行不出想要的结果,所以在使用的时候一定要记得把break加上,当然,也不是所有的case都需要加break,要根据情况来定,有的时候几个case要执行同一部分代码,就可以将这部分代码放到最后一个case中,然后前面几个case里不做处理,也不要加break,这样只要命中一个case,最后的那个case都会被执行。
   关于分支语句的反汇编就介绍这么多,希望有兴趣的同学可以看一下,正在学C的同学也可以看看,这样对于理解C语句也有一定的帮助。
0 0
原创粉丝点击