`

C与汇编

阅读更多

 

转自:http://bbs.pediy.com/showthread.php?t=89379

 

标 题: 【分享】从C语言到汇编,从汇编到C语言
作 者: wzjok
时 间: 2009-05-20,17:03
链 接: http://bbs.pediy.com/showthread.php?t=89379

要从事“逆向工程”工作,或对其感兴趣,请必然要接触到汇编语言。然而我们在对计算机语言的了解大都是从高级语言(如C、VB、Dephi)开始的。那当我们阅读由高级语言翻译成的机器语言时肯定会遇到很多障碍。下面是我在看了相关书籍后,做的一些笔记,希望有点参考价值!

一、循环语句与发汇编后的机器语言
1、for循环
   下面是一段C语言的代码,我们的目的是来看其反汇编的结果:
   int myfunction(int a,int b) 
    { 
         int c = a+b; 
         int i; 
         for(i=0;i<50;i++) 
         { 
             c = c+i; 
         } 
         return c; 
    } 
    前面的反汇编暂时不理它,这里从for的地方开始反汇编,结果如下: 
      for(i=0;i<50;i++) 
      00412BC7  mov        dword ptr [i],0   // i=0; 给循环变量赋初值 
      00412BCE  jmp         myfunction+39h (412BD9h)// 跳到第一次循环处   
  >  00412BD0  mov        eax,dword ptr [i]  
  |   00412BD3  add         eax,1  // i++;修改循环变量
  |   00412BD6  mov        dword ptr [i],eax  
  |   00412BD9  cmp        dword ptr [i],32h //  比较 i 与50的关系, 检查循环条件
  |   00412BDD  jge          myfunction+4Ah (412BEAh)  // 当 i>=50 [即 !(i<50) ] 时则跳出循环
  |   { 
  |      c = c+i; 
  |   00412BDF  mov         eax,dword ptr [c]  // 变量 c
  |   00412BE2  add         eax,dword ptr [i]   // 变量 i
  |   00412BE5  mov         dword ptr [c],eax  // c=c+i;
  |   } 
  <  00412BE8  jmp         myfunction+30h (412BD0h)  // 跳回去修改循环变量
      00412BEA  mov         eax,dword ptr [c]  
     }
      可以看到for循环主要用这么几条指令来实现:mov进行初始化。jmp跳过循环变量改变代码。cmp实现条件判断,jge根据条件跳转。
用jmp回到循环改变代码进行下一次循环。所以for结构有以下的显著特征: 

           mov <循环变量>,<初始值>   ; 给循环变量赋初值 
       jmp B       ;跳到第一次循环处 
    A: (改动循环变量)       ;修改循环变量。 
        … 
    B: cmp <循环变量>,<限制变量>  ;检查循环条件 
       jgp  跳出循环 
       (循环体) 
          …                
        jmp A       ;跳回去修改循环变量 

2、do循环  
  再看一下do循环,因为 do循环没有修改循环变量的部分,所以比for循环要简单一些。 
        do 
           { 
                  c = c+i; 
            00411A55  mov        eax,dword ptr [c]  
            00411A58  add         eax,dword ptr [i]  
            00411A5B  mov         dword ptr [c],eax  
            } while(c< 100); 
            00411A5E  cmp        dword ptr [c],64h   
            00411A62  jl           myfunction+35h (411A55h)  

            return c;

   do循环就是一个简单的条件跳转回去。只有两条指令: 
   cmp <循环变量>,<限制变量> 
    jl <循环开始点> 

3、while循环
        while(c<100){ 
            00411A55  cmp         dword ptr [c],64h 
            00411A59  jge         myfunction+46h (411A66h)  

               c = c+i; 
            00411A5B  mov         eax,dword ptr [c]  
            00411A5E  add         eax,dword ptr [i]  
            00411A61  mov         dword ptr [c],eax  
              } 
            00411A64  jmp         myfunction+35h (411A55h)  
            return c; 
    很明显,我们会发现while要更复杂一点。因为while除了开始的时候判断循环条件之外,后面还必须有一条无条件跳转回到循环开始的地方,共用三条指令实现: 
             A: cmp <循环变量>,<限制变量> 
                 jge  B 
                ( 循环体) 
                … 
           jmp A 
             B: (循环结束了) 

这样,我们对C语言中的循环结构的分析,就基本弄完了!当然,我们用同样的方法也可以分析出C语言在“分支语句”、以及其它的数据结构中的C代码与机器反汇编代码的关系了!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

为了知识的完整性,这里补充一下C语言里的分支语句

二、分支语句

1、if-else 语句
为了观察其汇编语句,下面是一个简单的if判断结构:  
      if(a>0 && a<10) 
         { 
               printf("a>0"); 
         } 
         else if( a>10 && a<100) 
         { 
               printf("a>10 && a<100"); 
         } 
         else  
         { 
               printf("a>10 && a<100"); 
          }
         
    if 判断都是使用cmp再加上条件跳转指令。对于if( A && B)的情况,一般都是使用否决法。如果A不成立,立刻跳下一个分支。依次,如果 B 不成立,同样跳下一分支。 
          cmp 条件 
          jle 下一个分支
  所以开始部分的反汇编为: 
         if(a>0 && a<10) 
         00411A66  cmp       dword ptr [c],0  
         00411A6A  jle         411A81h   ; 跳下一个else if的判断点 
      00411A6C  cmp       dword ptr [c],0Ah  
         00411A70  jge        411A81h   ; 跳下一个else if的判断点 
      { 
            printf("a>0"); 
         00411A72  push      offset string "a>0" (4240DCh)  
         00411A77  call        @ILT+1300(_printf) (411519h)  
         00411A7C  add       esp,4  
         } 

    else if 的和 else 的特点是,开始都有一条无条件跳转到判断结束处,阻止前面的分支执行结束后,直接进入这个分支。这个分支能执行到的唯一途径只是,前面的判断条件不满足。
   else 则在jmp之后直接执行操作。而else if则开始重复if之后的操作,用cmp比较,然后用条件跳转指令时行跳转。
       else if( a>10 && a<100) 
          00411A7F  jmp          411AA9h     ;直接跳到判断块外 
       00411A81  cmp         dword ptr [c],0Ah         ;比较+条件跳转,目标为下一个分支处 
       00411A85  jle          411A9Ch  
          00411A87  cmp         dword ptr [c],64h  
          00411A8B  jge          411A9Ch  
          { 
                printf("a>10 && a<100"); 
          00411A8D  push        offset string "a>10 && a<100" (424288h)  
          00411A92  call          @ILT+1300(_printf) (411519h)  
          00411A97  add         esp,4  
           } 
          else  
          00411A9A  jmp        411AA9h   ;这里是else,所以只有简单的一条跳转。 
       { 
             printf("a>10 && a<100"); 
          00411A9C  push        offset string "a>10 && a<100" (424288h)  
          00411AA1  call          @ILT+1300(_printf) (411519h)  
          00411AA6  add          esp,4  
           } 
          return c;

2、switch-case 语句
   switch 的特点是有多个判断。因为 swtich 显然不用判断大于小于,所以都是je(因此,C语言中switch语句不支持float类型的变量),分别跳到每个case处。最后一个是无条件跳转,直接跳到default处。以下的代码:  
          switch(a) 
           {
            case 0: 
                 printf("a>0"); 
            case 1: 
            { 
                 printf("a>10 && a<100"); 
                 break; 
            } 
           default: 
                  printf("a>10 && a<100"); 
           } 
反汇编的switch(a) 
          00411A66  mov         eax,dword ptr [a]  
          00411A69  mov         dword ptr [ebp-0E8h],eax  
          00411A6F  cmp         dword ptr [ebp-0E8h],0  // case 0:
          00411A76  je            411A83h  
          00411A78  cmp         dword ptr [ebp-0E8h],1  // case 1:
          00411A7F  je            411A90h  
          00411A81  jmp         411A9Fh  // default:
          { 
             … 
   显然是比较a 是否是0、1这两个数字。汇编指令先把a移动到[ebp-0E8h]这个地址,然后再比较,这是调试版本编译的特点。可能是为了防止直接操作堆栈而导致堆栈破坏?最后一条直接跳转到default处。当然,如果没有default,就会跳到swtich{}之外。
   从这里我们可以发现:switch语句里,完成“比较判断”的指令会与“case”指令的两部分,在汇编中,不是按照C语句逐句翻译的,而是分开为两个指令模块来实现的!
       case 0: 
                printf("a>0"); 
          00411A83  push        offset string "a>0"  (4240DCh)  
          00411A88  call          @ILT+1300(_printf) (411519h)  
          00411A8D  add         esp,4  
          case 1: 
          { 
               printf("a>10 && a<100"); 
          00411A90  push        offset string "a>10 && a<100" (424288h)  
          00411A95  call          @ILT+1300(_printf) (411519h)  
          00411A9A  add         esp,4  
              break; 
          00411A9D  jmp         myfunction+8Ch (411AACh)  
          } 
          default: 
               printf("a>10 && a<100"); 
          00411A9F  push        offset string "a>10 && c<100" (424288h)  
          00411AA4  call          @ILT+1300(_printf) (411519h)  
          00411AA9  add         esp,4  
           } 
    至于case 和 default分支中,如果有break,则会增加一个无条件跳转汇编指令。若没有break,则就没有任何循环控制代码。 

   小结:如果在反汇编代码中发现连续多个“比较cmp”和“相等跳转je”就会让人联想到“switch”语句了!

分享到:
评论

相关推荐

    嵌入式软件基础-C语言与汇编的融合(高清中文版)

    《嵌入式软件基础:C语言与汇编的融合(翻译版)》以实践中最常运用的方式讲解汇编语言——实现小型、快速或特殊目的的例程,这些例程由主程序(高级语言编写,如C)调用。通过运用嵌入式软件环境,《嵌入式软件基础:...

    《c语言与汇编语言》资料下载

    C语言编译器会将源代码转换成汇编语言,然后再通过汇编器转换为机器码,这个过程使得C程序能够在多种不同的硬件平台上运行,这也是C语言被广泛用于操作系统、嵌入式系统以及各种软件开发的原因。 汇编语言是与特定...

    Keil中C与汇编混合编程的方法

    "Keil 中 C 与汇编混合编程的方法" Keil 中 C 与汇编混合编程的方法是指在 Keil 环境中将 C 语言和汇编语言结合使用,以实现特定的编程目标。这种混合编程方式可以充分发挥 C 语言的高级编程能力和汇编语言的低级...

    单片机C语言与汇编混编经典实例

    在"单片机C语言与汇编混编经典实例"中,你可能会学到如何定义汇编子程序并在C代码中调用,如何在C语言中使用汇编语句块(__asm__),以及如何在C代码中访问和修改硬件寄存器。这些实例将涵盖各种实际应用,包括...

    单片机编程C语言与汇编比较

    ### 单片机编程C语言与汇编比较 #### 1. C语言和汇编语言在开发单片机时各有哪些优缺点? - **汇编语言**: - **优点**: - **资源占用少**:由于汇编语言直接对应机器码,因此程序执行效率较高,特别适合资源...

    嵌入式软件基础——C语言与汇编的融合(翻译版) 作者 : 陈宗斌

    3. C语言调用汇编代码:讨论C语言的函数调用约定,并展示如何在汇编代码中实现与C函数的接口。 4. 汇编代码调用C函数:说明如何在汇编程序中调用C函数,包括传递参数和返回值的机制。 5. 优化技巧:探讨如何通过...

    c语言与汇编的混用

    当需要进行性能优化或者访问特定硬件功能时,程序员可能会选择将C语言与汇编语言混合使用。以下将详细探讨这个主题。 1. **C语言的优势与局限性** C语言的优点在于其抽象程度适中,它允许程序员高效地编写代码,...

    浅谈单片机中C语言与汇编语言的转换.docx

    在计数和加减运算上,C语言的`++`和`--`操作符在汇编中对应`inc`和`dec`指令。 在实际的单片机设计中,C语言和汇编语言的选择和结合取决于项目需求。C语言简化了程序设计,提高了开发效率,适合于处理复杂逻辑和...

    avr中嵌入汇编 iar中c与汇编混合编程

    ### AVR中嵌入汇编 iar中C与汇编混合编程 #### 概述 本应用笔记阐述了如何在包括C语言和汇编代码的项目中设置并使用IAR C编译器来支持AVR控制器。通过混合使用C语言和汇编语言,设计者可以将强大的C语言指令与接近...

    嵌入式软件基础:C语言与汇编的融合.pdf

    嵌入式软件基础:C语言与汇编的融合.pdf

    单片机C语言和汇编语言混合编程实例详解-杜树春.rar

    1. C语言与汇编语言的基础:首先,读者需要了解两种语言的基本概念和语法,包括C语言的关键字、数据类型、流程控制语句以及汇编语言的指令集、寄存器使用等。 2. 混合编程环境设置:介绍如何配置开发环境,如选择...

    C语言与汇编语言混合编程浅析

    - 在C语言程序中调用汇编程序时,由于汇编子程序与C语言主程序不在同一源文件中,因此汇编子程序被视为C程序的外部函数。 - 使用`extern`关键字声明汇编子程序,例如:`extern int my_asm_function(int param1, ...

    C语言与汇编语言混合编程

    C 语言与汇编语言混合编程 本实验主要介绍了 ARM 嵌入式 C 语言编程的基本方法、嵌入式汇编(Inline Assembly)编程规则和方法,以及汇编语言程序和 C 语言程序之间的相互调用规则和编程方法。 一、ARM 嵌入式 C ...

    CCS集成环境下C与汇编的混合编程实现

    总结来说,CCS集成开发环境下的C与汇编的混合编程实现,要求开发者必须对C语言和汇编语言都有较好的掌握,同时还需要了解目标硬件平台的指令集和特性。通过合理选择编程语言和编写高效的混合代码,可以在DSP开发中...

    嵌式软件基础_C语言与汇编的融合_翻译版

    4. **C语言与汇编的接口**:在嵌入式编程中,开发者常常需要在C程序中插入汇编代码段,以实现特定功能或优化关键部分。这种混合编程要求对两种语言都有深入理解。 5. **调用约定**:当C语言调用汇编函数或反之时,...

    C语言与汇编语言混合编程的实现.pdf

    【C语言与汇编语言混合编程的实现】 在嵌入式系统开发中,尤其是在单片机编程中,C语言和汇编语言的混合编程是一种常见的技术。C语言因其高级抽象和良好的可移植性而受到广泛欢迎,而汇编语言则能提供对底层硬件的...

    嵌入式软件基础c语言与汇编的融合 翻译版

    《嵌入式软件基础:C语言与汇编的融合》是一本专为嵌入式系统开发者设计的基础教程,由国际知名专家编著。本书旨在帮助读者深入理解嵌入式开发的核心概念,通过C语言和汇编语言的结合,提升开发者的编程技能和底层...

    基于C语言与汇编语言的混合编程方法研究.pdf

    为了更好地理解和实践C语言与汇编语言的混合编程方法,研究者们分析了TurboC与汇编语言的混合编程应用方法,并提供了具体的实例,以方便C语言开发人员掌握这种方法。 最后,由于本文档是研究性质的文献,因此研究者...

    C语言与汇编的混合编程

    在本例中,我们关注的是C语言与汇编语言的混合编程,这通常发生在需要高效性能或者直接控制硬件操作的情况下。下面将详细探讨这个主题。 首先,C语言是一种高级编程语言,以其简洁、通用和接近机器代码的特性而闻名...

    嵌入式软件基础C语言与汇编的融合 翻译版

    嵌入式软件基础C语言与汇编的融合,是学习嵌入式的必要之书

Global site tag (gtag.js) - Google Analytics