浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码...

浅析VS2010反汇编

第一篇

1. 如何进行反汇编

在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息。如下图所示。

image

记得中断程序的运行,不然看不到反汇编的指令

image

看一个简单的程序及其生成的汇编指令

复制代码
#include<stdio.h>
#include<windows.h>
const long Lenth=5060000/5;
int main(){
    while(true){
        for(long i=0;i<Lenth;i++){
            ;
        }
        Sleep(10);
    }
}
复制代码
 

汇编窗口

image

 

 

2.  预备知识:

 

函数调用大家都不陌生,调用者向被调用者传递一些参数,然后执行被调用者的代码,最后被调用者向调用者返回结果,还有大家比较熟悉的一句话,就是函数调用是在栈上发生的,那么在计算机内部到底是如何实现的呢?
 
对于程序,编译器会对其分配一段内存,在逻辑上可以分为代码段,数据段,堆,栈
代码段:保存程序文本,指令指针EIP就是指向代码段,可读可执行不可写
数据段:保存初始化的全局变量和静态变量,可读可写不可执行
BSS:未初始化的全局变量和静态变量
堆(Heap):动态分配内存,向地址增大的方向增长,可读可写可执行
栈(Stack):存放局部变量,函数参数,当前状态,函数调用信息等,向地址减小的方向增长,非常非常重要,可读可写可执行
如图所示
 
寄存器
EAX:累加(Accumulator)寄存器,常用于函数返回值
EBX:基址(Base)寄存器,以它为基址访问内存
ECX:计数器(Counter)寄存器,常用作字符串和循环操作中的计数器
EDX:数据(Data)寄存器,常用于乘除法和I/O指针
ESI:源变址寄存器
DSI:目的变址寄存器
ESP:堆栈(Stack)指针寄存器,指向堆栈顶部
EBP:基址指针寄存器,指向当前堆栈底部
EIP:指令寄存器,指向下一条指令的地址

第二篇

 

一、VS反汇编方法

1、调出反汇编窗口。

2、调用寄存器窗口(只有在反汇编下才可见)

如果在调试状态还是没有此菜单项,可试着以下操作:

在VS中点击“工具”->“导入和导出设置”,选择“重置所有设置”,下一步,这时你可以保存当前设置或不保存,我觉得无所谓,下一步,选择“Visual C**开发设置”,“完成”。这样,“调试”->“窗口”->“寄存器”菜单项应该用显示出来了,记得要确保你的程序是在调试的过程中。

3、查看内存

点击“调试”->“窗口”->“内存”->“内存1”...“内存4”(选一个就可以了。)。在内存窗口中的“地址”栏输入地址,按回车即可看到该地地址处的内存信息。

 二、常用汇编指令介绍

1、常用指令

为了照顾到没学过汇编程序的同志们,这里简单介绍一下常见的几种汇编指令。

A、add:加法指令,第一个是目标操作数,第二个是源操作数,格式为:目标操作数 = 目标操作数 + 源操作数;

B、sub:减法指令,格式同 add;

C、call:调用函数,一般函数的参数放在寄存器中;

D、ret:跳转会调用函数的地方。对应于call,返回到对应的call调用的下一条指令,若有返回值,则放入eax中;

E、push:把一个32位的操作数压入堆栈中,这个操作在32位机中会使得esp被减4(字节),esp通常是指向栈顶的(这里要指出的是:学过单片机的同学请注意单片机种的堆栈与Windows下的堆栈是不同的,请参考相应资料),这里顶部是地址小的区域,那么,压入堆栈的数据越多,esp也就越来越小;

F、pop:与push相反,esp每次加4(字节),一个数据出栈。pop的参数一般是一个寄存器,栈顶的数据被弹出到这个寄存器中;

一般不会把sub、add这样的算术指令,以及call、ret这样的跳转指令归入堆栈相关指令中。但是实际上在函数参数传递过程中,sub和add最常用来操作堆栈;call和ret对堆栈也有影响。

 

G、mov:数据传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的一份。

H、xor:异或指令,这本身是一个逻辑运算指令,但在汇编指令中通常会见到它被用来实现清零功能。

              用 xor eax,eax这种操作来实现 mov eax,0,可以使速度更快,占用字节数更少。

I、lea:取得第二个参数地址后放入到前面的寄存器(第一个参数)中。

               然而lea也同样可以实现mov的操作,例如:

                                  lea edi,[ebx-0ch]

方括号表示存储单元,也就是提取方括号中的数据所指向的内容,然而lea提取内容的地址,这样就实现了把(ebx-0ch)放入到了edi中,但是mov指令是不支持第二个操作数是一个寄存器减去一个数值的。

 

J、stos:串行存储指令,它实现把eax中的数据放入到edi所指的地址中,同时edi后移4个字节,这里的stos实际上对应的是stosd,其他的还有stosb,stosw分别对应1,2个字节。

K、jmp:无条件跳转指令,对应于大量的条件跳转指令。

L、jg:条件跳转,大于时成立,进行跳转,通常条件跳转之前会有一条比较指令(用于设置标志位)。

M、jl:小于时跳转。

N、jge:大于等于时跳转。

O、cmp:比较大小指令,结果用来设置标志位。

P ,rep 根据ECX寄存器的值进行重复循环操作

 

 注: 
   

mov ax,[bx]
[ ]表示是间接寻址,bx和[bx]的区别是,前者操作数就是bx中存放的数,后者操作数是以bx中存放的数为地址的单元中的数。比如bx中存放的数是40F6H,40F6H、40F7H两个单元中存放的数是22H、23H,则
mov ax,[bx];2223H传送到ax中
mov ax,bx;40F6H传送到ax中

 

ILT是INCREMENTAL LINK TABLE的缩写,这个@ILT其实就是一个静态函数跳转的表,它记录了一些函数的入口然后跳过去,每个跳转jmp占一个字节,然后就是一个四字节的内存地址,加起为五个字节
比如代码中有多处地方调用boxer函数,别处的调用也通过这个ILT表的入口来间接调用,而不是直接call 该函数的偏移,这样在编译程序时,如果boxer函数更新了,地址变了,只需要修改跳表中的地址就可以,有利于提高链接生成程序的效率。这个是用在程序的调试阶段,当编译release程序时,就不再用这种方法。

 

我试着将HEX数据改成00 00,对应的汇编指令变成了add byte ptr [eax],al ,反过来,如果将一个地方的汇编指令改成add byte ptr [eax],al ,对应的HEX数据就成了00 00,也就是说,他们是一一对应的,编译器认为,00 00 这样两个字节宽度的二进制数对应的汇编指令就是add byte ptr [eax],al ;

 

dword 双字 就是四个字节
ptr pointer缩写 即指针

2  、函数参数传递方式

函数调用规则指的是调用者和被调用函数间传递参数及返回参数的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。

A、_cdecl C调用规则:

(a)参数从右到左进入堆栈;

(b)在函数返回后,调用者要负责清除堆栈,这种调用方式通常会生成较大的可执行程序。

B、_stdcall又称为WINAPI,调用规则如下:

(a)参数从右到左进入堆栈;

(b)被调用的函数在返回前自行清理堆栈,这种方式生成的代码比cdecl小。

C、Pascal调用规则(主要用于Win16函数库中,现在基本不用):

(a)参数从左到右进入堆栈;

(b)被调用的函数在返回前自行清理堆栈。

(c)不支持可变参数的函数调用。

第三篇

 

了解反汇编的一些小知识对于我们在开发软件时进行编程与调试大有好处,下面以简单介绍一下反汇编的一些小东西!如果有些解释有问题的地方,希望大家能够指出。

1、新建简单的VC控制台应用程序(对此熟悉的同学可以略过)

A、打开Microsoft Visual Studio 2010,选择主菜单“File”

B、选择子菜单“New”下面的“Project”,打开“New Project”对话框。

C、左边选择Visual C++下的win32,右边选择Win32 Console Application,然后输入一个工程名,点击“OK”即可,在出现的向导中,一切默认,点击Finish即可。

D、在出现的编辑区域内会出现以你设定的工程名命名的CPP文件。内容如下:

      #include "stdafx.h"

      int _tmain(int argc, _TCHAR* argv[])

      {

            return 0;

      }

2、VS查看汇编代码

A、VC处于调试状态才能看到汇编指令窗口。因此,可以在 return 0 上设置一个断点:把光标移到 return 0 那一行上,然后按下F9键设置一个断点。

B、按下F5键进入调试状态,当程序停在 return 0 这一行上时,打开菜单“Debug”下的“Windows”子菜单,选择“Disassembly”。这样,出现一个反汇编的窗口,显示下面的信息:

--- d:/my documents/visual studio 2008/projects/casmtest/casmtest/casmtest_main.cpp 
// CAsmTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
00411370  push        ebp  
00411371  mov         ebp,esp 
00411373  sub         esp,0C0h 
00411379  push        ebx  
0041137A  push        esi  
0041137B  push        edi  
0041137C  lea         edi,[ebp-0C0h] 
00411382  mov         ecx,30h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi] 
 return 0;
0041138E  xor         eax,eax 
}
00411390  pop         edi  
00411391  pop         esi  
00411392  pop         ebx  
00411393  mov         esp,ebp 
00411395  pop         ebp  
00411396  ret  

上面就是系统生成的main函数原型,确切的说是_tmain()的反汇编的相关信息,相信学过汇编语言的肯定就能够了解它所做的操作了。


 

VC中访问无效变量出错原因

我们看上面主函数反汇编后的其中一段代码如下:

0041137C  lea         edi,[ebp-0C0h] 
00411382  mov         ecx,30h 
00411387  mov         eax,0CCCCCCCCh 
0041138C  rep stos    dword ptr es:[edi]

从代码的表面上看,它是实现把从ebp-0C0h开始的30h个字的空间写入0CCCCCCCCh。其中eax为四位的数据,这样可以计算:

                      0C0h = 30h * 4

也就是把从ebp-0C0h 到ebp之间的空间初始化为0CCCCCCCCh。大家在学习反汇编的过程中会发现,其实编译器会根据情况把相应长度的这样一段作为局部变量的空间,而这里把局部变量区域全都初始化成0CCCCCCCCh也是有其用意的,做VC编程的工作者,特别是初学者可能不会对0CCCCCCCCh这个常量陌生。0cch实际上是int 3指令的机器码,这是一个断点中断指令(在反编译出的信息中大家会看到int 3),因为局部变量不可被执行,或者如果在没有初始化的时候进行了访问,则就会出现访问失败错误。这个在VC编译Debug版本中才能看到提示这个错误,在Release版本中,会以另外一种错误形式体现。下面,我们修改主程序看下new与delete的反汇编的效果(注释直接加到反汇编的代码中了)。

VC生成工程,写入源代码如下:

(1)情况1

// ASM_Test.cpp : Defines the entry point for the console application.                    (  源代码1 )
//
#include "stdafx.h"
#include "stdlib.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int *pTest = new int(3);                //定义一个整型指针,并初始化为 3
    printf( "*pTest = %d/r/n", *pTest );    //调用库函数printf输出数据
    delete []pTest;                            //删除这个指针

    return 0;
}
这里仅仅看下在new与delete进行空间管理时进行反汇编时可能出现的一些情况,我们把上面源代码称为源代码(1),我们按照前面讲解的查看VS下反汇编的方法可以看到对应于上面代码的反汇编代码如下:
--- f:/mysource/asm_test/asm_test/asm_test.cpp ---------------------------------                      ( 反汇编代码 1)
// ASM_Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdlib.h"

int _tmain(int argc, _TCHAR* argv[])
{

;(1)函数预处理部分
004113C0  push        ebp  
004113C1  mov         ebp,esp ;保存堆栈的栈顶位置
004113C3  sub         esp,0E8h ;要置为0CCCCCCCCh 保留变量空间长度
004113C9  push        ebx       ;保存寄存器ebx、esi、edi
004113CA  push        esi  
004113CB  push        edi  
004113CC  lea         edi,[ebp-0E8h]    ;提出要置为0CCCCCCCCh 的空间起始地址
004113D2  mov         ecx,3Ah      ;要置为0CCCCCCCCh 的个数,每个占4个字节
004113D7  mov         eax,0CCCCCCCCh  ;于是3Ah * 4 = 0E8h
004113DC  rep stos    dword ptr es:[edi]  ;进行置为0CCCCCCCCh操作;

 

(2)定义一个int 型指针,分配空间后,并初始化为 3 ,

    int *pTest = new int(3);                //定义一个整型指针,并初始化为 3
004113DE  push        4    ;要分配的空间长度,会根据定义的数据类型而不同
004113E0  call        operator new (411186h)   ;分配空间,并把分配空间的起始地址放入eax中
004113E5  add         esp,4    ;由于new与delete函数本身没有对栈进行弹出操作,所以,要编写者自己处理
004113E8  mov         dword ptr [ebp-0E0h],eax  ;比较分配的空间是否为0,如果为0 
004113EE  cmp         dword ptr [ebp-0E0h],0 
004113F5  je          wmain+51h (411411h) 
004113F7  mov         eax,dword ptr [ebp-0E0h]      ;对于分配的地址分配空间进行赋值为:3
004113FD  mov         dword ptr [eax],3 
00411403  mov         ecx,dword ptr [ebp-0E0h] 
00411409  mov         dword ptr [ebp-0E8h],ecx   ;似乎用[ebp - 0E0h]和[ebp - 0E8h]作为了中间存储单元
0041140F  jmp         wmain+5Bh (41141Bh) 
00411411  mov         dword ptr [ebp-0E8h],0     ;上面分配空间失败是的操作
0041141B  mov         edx,dword ptr [ebp-0E8h] 
00411421  mov         dword ptr [pTest],edx           ;数据最后送入pTest变量中

;调用printf函数进行数据输出
    printf( "*pTest = %d/r/n", *pTest );    //调用库函数printf输出数据
00411424  mov         esi,esp   ;用于调用printf后的Esp检测,不明白编译器为什么这样做
00411426  mov         eax,dword ptr [pTest]   ;提取要打印的数据,先是地址,下面一条是提取具体数据
00411429  mov         ecx,dword ptr [eax] 
0041142B  push        ecx         ;两个参数入栈
0041142C  push        offset string "*pTest = %d/r/n" (41573Ch) 
00411431  call        dword ptr [__imp__printf (4182C4h)]      ;调用函数
00411437  add         esp,8         ;由于库函数无出栈管理操作,同new与delete,所以要加 8,进行堆栈处理
0041143A  cmp         esi,esp        ;对堆栈的栈顶进行测试
0041143C  call        @ILT+325(__RTC_CheckEsp) (41114Ah) 

;进行指针变量的清理工作
    delete []pTest;                            //删除这个指针
00411441  mov         eax,dword ptr [pTest]   ;[pTest] 中放入的是分配的地址,下面几条指令转悠一圈
00411444  mov         dword ptr [ebp-0D4h],eax   ;就是要把要清理的地址送入堆栈,然后调用delete函数
0041144A  mov         ecx,dword ptr [ebp-0D4h] 
00411450  push        ecx  
00411451  call        operator delete (411091h) 
00411456  add         esp,4     ;对堆栈进行处理,同new与printf函数

;函数结束后,进行最终的清理工作
    return 0;
00411459  xor         eax,eax   ;做相应的清理工作,堆栈中保存的变量送回原寄存器
}
0041145B  pop         edi  
0041145C  pop         esi  
0041145D  pop         ebx  
0041145E  add         esp,0E8h       ;进行堆栈的栈顶判断
00411464  cmp         ebp,esp 
00411466  call        @ILT+325(__RTC_CheckEsp) (41114Ah) 
0041146B  mov         esp,ebp 
0041146D  pop         ebp  
0041146E  ret  

--- No source file -------------------------------------------------------------;后面不再是源代码

 

在列出反汇编程序时把反汇编代码的上下的分解注释也列了出来,亲手去查看的朋友可能会发现在这段代码的之外的其他部分会有大量的int 3汇编中的中断指令,这个是与上面的所说的0CCCCCCCCh具有一致性,这些区域是无效区域,但代码访问这些区域时就会出现非法访问提示。当然,你应该可以想到,那个提示是可以被屏蔽掉的,你可以把这部分区域填充上数据或者修改 iint 3 调用的中断程序。

从以上反汇编程序,我们可以发现几点:

A、一些内部的库函数是不会对堆栈进行出栈管理的,所以若要对反汇编程序进行操作时,一点要注意这一点

B、编译器会自动的加上一些对栈顶的检查工作,这个是我们在做VC调试时经常遇到的一个问题,就是堆栈错误

当然以上只是对debug版本下的程序进行反汇编,如果为release 版本,代码就会进行大量的优化,在理解时会有一定的难度,有兴趣朋友可以试着反汇编一下,推荐大家有IDA返回工具,感觉挺好用的。


 

 

 

 

版权声明:本文为原创文章,转载请标明出处。 https://blog.csdn.net/u013467442/article/details/47060261
 

VS 反汇编方法及常用汇编指令介绍

 

 

在调试没有源码的文件时,我们可能要用到反汇编设计。

一、VS反汇编方法

1、调出反汇编窗口。

2、调用寄存器窗口(只有在反汇编下才可见)

如果在调试状态还是没有此菜单项,可试着以下操作:

在VS中点击“工具”->“导入和导出设置”,选择“重置所有设置”,下一步,这时你可以保存当前设置或不保存,我觉得无所谓,下一步,选择“Visual C#开发设置”,“完成”。这样,“调试”->“窗口”->“寄存器”菜单项应该用显示出来了,记得要确保你的程序是在调试的过程中。

3、查看内存

点击“调试”->“窗口”->“内存”->“内存1”...“内存4”(选一个就可以了。)。在内存窗口中的“地址”栏输入地址,按回车即可看到该地地址处的内存信息。

 二、常用汇编指令介绍

1、常用指令

为了照顾到没学过汇编程序的同志们,这里简单介绍一下常见的几种汇编指令。

A、add:加法指令,第一个是目标操作数,第二个是源操作数,格式为:目标操作数 = 目标操作数 + 源操作数;

B、sub:减法指令,格式同 add;

C、call:调用函数,一般函数的参数放在寄存器中;

D、ret:跳转会调用函数的地方。对应于call,返回到对应的call调用的下一条指令,若有返回值,则放入eax中;

E、push:把一个32位的操作数压入堆栈中,这个操作在32位机中会使得esp被减4(字节),esp通常是指向栈顶的(这里要指出的是:学过单片机的同学请注意单片机种的堆栈与Windows下的堆栈是不同的,请参考相应资料),这里顶部是地址小的区域,那么,压入堆栈的数据越多,esp也就越来越小;

F、pop:与push相反,esp每次加4(字节),一个数据出栈。pop的参数一般是一个寄存器,栈顶的数据被弹出到这个寄存器中;

一般不会把sub、add这样的算术指令,以及call、ret这样的跳转指令归入堆栈相关指令中。但是实际上在函数参数传递过程中,sub和add最常用来操作堆栈;call和ret对堆栈也有影响。

 

G、mov:数据传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的一份。

H、xor:异或指令,这本身是一个逻辑运算指令,但在汇编指令中通常会见到它被用来实现清零功能。

              用 xor eax,eax这种操作来实现 mov eax,0,可以使速度更快,占用字节数更少。

I、lea:取得第二个参数地址后放入到前面的寄存器(第一个参数)中。

               然而lea也同样可以实现mov的操作,例如:

                                  lea edi,[ebx-0ch]

方括号表示存储单元,也就是提取方括号中的数据所指向的内容,然而lea提取内容的地址,这样就实现了把(ebx-0ch)放入到了edi中,但是mov指令是不支持第二个操作数是一个寄存器减去一个数值的。

 

J、stos:串行存储指令,它实现把eax中的数据放入到edi所指的地址中,同时edi后移4个字节,这里的stos实际上对应的是stosd,其他的还有stosb,stosw分别对应1,2个字节。

K、jmp:无条件跳转指令,对应于大量的条件跳转指令。

L、jg:条件跳转,大于时成立,进行跳转,通常条件跳转之前会有一条比较指令(用于设置标志位)。

M、jl:小于时跳转。

N、jge:大于等于时跳转。

O、cmp:比较大小指令,结果用来设置标志位。

2  、函数参数传递方式

函数调用规则指的是调用者和被调用函数间传递参数及返回参数的方法,在Windows上,常用的有Pascal方式、WINAPI方式(_stdcall)、C方式(_cdecl)。

A、_cdecl C调用规则:

(a)参数从右到左进入堆栈;

(b)在函数返回后,调用者要负责清除堆栈,这种调用方式通常会生成较大的可执行程序。

B、_stdcall又称为WINAPI,调用规则如下:

(a)参数从右到左进入堆栈;

(b)被调用的函数在返回前自行清理堆栈,这种方式生成的代码比cdecl小。

C、Pascal调用规则(主要用于Win16函数库中,现在基本不用):

(a)参数从左到右进入堆栈;

(b)被调用的函数在返回前自行清理堆栈。

(c)不支持可变参数的函数调用。

 

 

VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码

时间: 2017-02-26 21:27:26      阅读:9414      评论:0      收藏:0      [点我收藏+]

标签:vs2015使用技巧   调试-反汇编   查看c语言代码对应的汇编代码   

镇场文:
       学儒家经世致用,行佛家普度众生,修道家全生保真,悟易理象数通变。以科技光耀善法,成就一良心博客。
______________________________________________________________________________________________________

code:

#include <stdio.h>

void main()
{
    int num1 = 0;
    int num2 = 0;
    int result = 0;

    num1 = 2;
    num2 = 3;
    result = num1 + num2;
    printf("%d", result);

    return 0;
    
}

 

查看反汇编步骤:

    step0 

        在一行上设置断点,鼠标挪到最左边 竖着的条条 处,点击一下即可设置断点

 

技术分享

 

    step1

        按F5或者 调试->开始调试

技术分享

 

    step1 show:

技术分享

 

    step2:

        点击 调试->窗口->反汇编

技术分享

 

    step2 show:

        这个就是C语言对应的汇编语言啦。我的电脑是64位的。

技术分享



转载于:https://www.cnblogs.com/cjm123/p/9391976.html

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值