精华内容
下载资源
问答
  • 反汇编

    2019-04-07 10:47:33
    很多时候,出现段错误,需要反汇编查看,到底是断在哪一行。 这个时候需要反汇编一把,所以熟悉反汇编的还是挺重要的。 disassemble 1.反汇编怎么看 反汇编的指令 参数存的寄存器 2.nm 可以解析符号 3....

    很多时候,出现段错误,需要反汇编查看,到底是断在哪一行。

    这个时候需要反汇编一把,所以熟悉反汇编的还是挺重要的。

    disassemble

    1.反汇编怎么看

    反汇编的指令

    参数存的寄存器

    2.nm 可以解析符号

    3.objdump 也可以解析符号

    展开全文
  • 反汇编初级教程

    千人学习 2018-06-12 20:19:25
    这套课程是反汇编系列课程的基础阶段,后期将陆续推出反汇编进阶及反汇编课程。整套反汇编课程的教学目标是为了让大家能够窥息计算机程序世界的奥妙,为将来成为一名合格的大Hacker打下夯实的基础。 反汇编技术在...
  • ollydbg反汇编软件下载 OD一直是反汇编的首选ollydbg反汇编软件下载 OD一直是反汇编的首选
  • objdump反汇编用法示例

    万次阅读 2016-01-22 18:49:37
    objdump反汇编反汇编与源代码混合显示,C++符号逆向解析。

    objdump反汇编用法示例

    原文:http://blog.csdn.net/zoomdy/article/details/50563680
    mingdu.zheng at gmail dot com

    • -d:将代码段反汇编
    • -S:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出-g,即需要调试信息。
    • -C:将C++符号名逆向解析。
    • -l:反汇编代码中插入源代码的文件名和行号。
    • -j section:仅反汇编指定的section。可以有多个-j参数来选择多个section。

    有代码如下:

    class Main
    {
    	int a;
    public:
    	Main()
    	{
    		a = 0;
    	}
    
    	int getA(void)
    	{
    		return this->a;
    	}
    };
    
    

    $objdump -d a.out # 简单反汇编

    08048456 <_ZN4MainC1Ev>:
     8048456:	55                   	push   %ebp
     8048457:	89 e5                	mov    %esp,%ebp
     8048459:	8b 45 08             	mov    0x8(%ebp),%eax
     804845c:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
     8048462:	5d                   	pop    %ebp
     8048463:	c3                   	ret    
    
    08048464 <_ZN4Main4getAEv>:
     8048464:	55                   	push   %ebp
     8048465:	89 e5                	mov    %esp,%ebp
     8048467:	8b 45 08             	mov    0x8(%ebp),%eax
     804846a:	8b 00                	mov    (%eax),%eax
     804846c:	5d                   	pop    %ebp
     804846d:	c3                   	ret    
    

    $objdump -S a.out # 反汇编代码中混入对应的源代码

    08048456 <_ZN4MainC1Ev>:
    class Main
    {
    	int a;
    public:
    	Main()
     8048456:	55                   	push   %ebp
     8048457:	89 e5                	mov    %esp,%ebp
    	{
    		a = 0;
     8048459:	8b 45 08             	mov    0x8(%ebp),%eax
     804845c:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
    	}
     8048462:	5d                   	pop    %ebp
     8048463:	c3                   	ret    
    
    08048464 <_ZN4Main4getAEv>:
    
    	int getA(void)
     8048464:	55                   	push   %ebp
     8048465:	89 e5                	mov    %esp,%ebp
    	{
    		return this->a;
     8048467:	8b 45 08             	mov    0x8(%ebp),%eax
     804846a:	8b 00                	mov    (%eax),%eax
    	}
     804846c:	5d                   	pop    %ebp
     804846d:	c3                   	ret    
    

    $objdump -C -S a.out # C++符号名逆向解析

    08048456 <Main::Main()>:
    class Main
    {
    	int a;
    public:
    	Main()
     8048456:	55                   	push   %ebp
     8048457:	89 e5                	mov    %esp,%ebp
    	{
    		a = 0;
     8048459:	8b 45 08             	mov    0x8(%ebp),%eax
     804845c:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
    	}
     8048462:	5d                   	pop    %ebp
     8048463:	c3                   	ret    
    
    08048464 <Main::getA()>:
    
    	int getA(void)
     8048464:	55                   	push   %ebp
     8048465:	89 e5                	mov    %esp,%ebp
    	{
    		return this->a;
     8048467:	8b 45 08             	mov    0x8(%ebp),%eax
     804846a:	8b 00                	mov    (%eax),%eax
    	}
     804846c:	5d                   	pop    %ebp
     804846d:	c3                   	ret    
    

    objdump -j .text -l -C -S a.out # 打印源文件名和行号

    08048456 <Main::Main()>:
    _ZN4MainC2Ev():
    ~/objdump/main.h:5
    class Main
    {
    	int a;
    public:
    	Main()
     8048456:	55                   	push   %ebp
     8048457:	89 e5                	mov    %esp,%ebp
    ~/objdump/main.h:7
    	{
    		a = 0;
     8048459:	8b 45 08             	mov    0x8(%ebp),%eax
     804845c:	c7 00 00 00 00 00    	movl   $0x0,(%eax)
    ~/objdump/main.h:8
    	}
     8048462:	5d                   	pop    %ebp
     8048463:	c3                   	ret    
    
    08048464 <Main::getA()>:
    _ZN4Main4getAEv():
    ~/objdump/main.h:10
    
    	int getA(void)
     8048464:	55                   	push   %ebp
     8048465:	89 e5                	mov    %esp,%ebp
    ~/objdump/main.h:12
    	{
    		return this->a;
     8048467:	8b 45 08             	mov    0x8(%ebp),%eax
     804846a:	8b 00                	mov    (%eax),%eax
    ~/objdump/main.h:13
    	}
     804846c:	5d                   	pop    %ebp
     804846d:	c3                   	ret    
    
    展开全文
  • 浅析VS2010反汇编 2015年07月25日 21:53:11 阅读数:4374 第一篇 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息。如下图所示。 记得中断程序的...

    浅析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

    展开全文
  • 单片机反汇编软件汇总

    热门讨论 2012-12-12 14:47:47
    以上软件为网上收集来的反汇编专用软件 PIC16FDisAsm.exe 为pic16fxxx单片机反汇编软件 u51V12.rar为mcs51单片机反汇编软件 EMCdasm.exe为emc单片机反汇编软件 reavr.rar为AVR单片机反汇编软件 STM8反汇编.rar为stm8...
  • 此系列文章都是一些基础的文章,通过几个小例子快速的了解 Win32反汇编与OD的使用,在此作个笔记 如若对您有帮助,记得三连哟 ~ 文章目录 OD介绍 全局变量赋值的反汇编形式(包含) 函数调用的反汇编形式 加法...

    前言

    作者:浪子花梦,一个有趣的程序员 ~
    时间:2020.8.9,一直想学逆向工程,刚好最近时间比较充足,每天除了刷算法题也可以学逆向了 . . .
    此系列文章都是一些基础的文章,通过几个小例子快速的了解 Win32反汇编与OD的使用,在此作个笔记
    如若对您有帮助,记得三连哟 ~

    文章目录


    OD介绍

    在研究反汇编之前,我们先来了解一下以后会一直用的神器:
    Ollydbg

    1. Ollydbg 简介

    Ollydbg 用作动态调试,一般用于逆向一些游戏,而对于软件的逆向一般是使用 IDA,以后我应该会学的,Ollydbg
    集成了许多的脚本与插件,非常牛X 的一个逆向工具 . . .

    界面如下所示:
    在这里插入图片描述
    整个界面被分为五个区域,每一个区域都显示非常重要的数据集,对应如下所示:

    1. 反汇编窗口:显示被调试程序的反汇编代码(地址栏、HEX数据栏、汇编指令栏、注释栏)
    2. 寄存器窗口:显示当前所选线程的CPU寄存器的内容
    3. 信息窗口:显示反汇编窗口中选中的第一个命令的参数及一些跳转的目标地址、字符串等
    4. 数据窗口:显示内存或文件的内容
    5. 堆栈窗口:显示当前线程的堆栈

    我们会在下面的示例中可以观察到上面对应的数据 . . .

    2. 调试方式

    • 用 OD调试器直接打开进程
    • 附加到已经打开的进程(暂时不学习)

    3.定位地址

    Ctrl + G 输入 Win32 API函数名(如:MessageBoxW、printf)

    4. 断点

    • 直接在选中的行上按下 F2
    • bp 指令地址(Win32 API 函数名或者地址)

    5. 调试中经常用到的几个快捷键

    • F2:设置断点
    • F8:单步步过
    • F7:单步步入
    • F9:运行程序
    • Ctrl + F9 执行到返回
    • Alt + F9 执行到用户代码
    • Ctrl + G 查找表达式(定位)
    • Alt + B 查看断点

    对于OD 就介绍到这里,以后遇到再说 . . .

    .


    全局变量赋值的反汇编形式

    首先,我们准备需要逆向的程序,此例子是和全局变量有关的,所以我们准备的代码如下所示:

    // 全局变量反汇编演示
    #include <Windows.h> 
    #include <iostream>
    using namespace std;
    
    int num = 1;
    
    int main() 
    { 
    	MessageBox(nullptr, nullptr, nullptr, MB_OK); 
    
    	num = 0x666666;
    
    	__asm mov num, 0x999999
    	 
    
    	return 0;
    }
    

    其中调用了一个 Win32 的API,消息盒子,并且我们在其中嵌入了一条汇编代码 . . . 下面我们来通过 od对这个程序进行反汇编 . . .

    如下所示,我们将程序直接插进 od中即可:
    在这里插入图片描述

    下面我们来研究上面所写的 cpp 反汇编代码:

    首先我们进行 OD界面,按 Ctrl + G 搜索 MessageBoxW表达式进行定位,如下所示:
    在这里插入图片描述
    红色框的部分就是 MessageBoxW内部的汇编指令,我们按F9 将程序执行到红色断点处,然后按F8 单步执行到如下的指令出,如下所示:
    在这里插入图片描述
    可见消息盒子已经弹出来了,由此发现, MessageBoxW的内部调用了 MessageBoxTimeoutW的方法 . . .

    因为 MessageBoxW 方法是在 main主函数中调用的,所以我们按下快捷键 Alt + F9 一定会返回到 main方法中,效果如下所示:
    在这里插入图片描述
    红色框是 main内部的汇编指令,箭头所指的是上一个方法返回的地方,我们发现返回到了 MessageBoxW 的下一条语句 . . .

    现在我们把 OD 与 VS 相对看一下,如下所示,我后将OD中加入了注释(红色框):
    在这里插入图片描述

    对应的汇编代码中,有压栈平衡的知识,以后的文章中会讲到,这些指令学过 8086的应该都能看懂,所以在此就不多讲了,下面我们看其它的例子吧 . . .

    .
    .


    函数调用的反汇编形式

    上面的例子中,我们已经演示了如何去调用 MessageBoxW这个方法,下面我们自己实现一个函数,按F7单步步入执行,体验一下数据世界的变化吧 . . .

    C/C++ 函数调用翻译成汇编指令相当于 Call 一个 子程序调用 . . .

    首先,我们准备需要逆向的程序,此例子是和函数调用有关的,所以我们准备的代码如下所示(比较简单的函数):

    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
    
    int add(int n1, int n2) {
    	return n1 + n2;
    }
    
    int main() {
    
    	MessageBox(0, nullptr, nullptr, MB_OK);
    
    	int sum = add(0x11, 0x22);
    
    	printf("0x%06x\n", sum);
    
    	return 0;
    }
    

    因为调用函数的地方用的都是常量参数,所以VS会自动优化成 int sum = 0x33; 所以我们需要将VS优化进行设置,方式如下所示:
    在这里插入图片描述
    设置为 已禁用即可 . . .

    按下来,我们就可以使用 OD 来调试这个程序了,我们快速的定位到 main函数中,然后在 MessageBoxW的下面按F2 设置断点,将程序快速的执行到这边,这样我们就可以研究 cpp文件中的代码执行数据的变化,如下所示:
    在这里插入图片描述

    我们在观看反汇编窗口的同时,一定要留意其它窗口中的数据,这样对于我们研究是非常有好处的 . . .

    下面我们按 F7 单步进入 call add 指令中,发现add函数的指令集如下所示:
    在这里插入图片描述
    OD 的功能是非常强大的,它已经把子程序块用 {} 给括起来了,使我们更容易接收 . . .

    在这个子程序块中,访问了两个内存单元:
    dword ptr [ebp + 8]
    dword ptr [ebp + c]

    我们执行完这个子程序块后,eax的值是0x33,单步执行到下面的指令处,将eax给到一个内存单元,我们就可以通过 dd命令查看这个内存单元中的数据,如下所示:
    在这里插入图片描述
    最后,我们在main函数的返回处设置断点,然后快速的执行到这个地方,发现其中 call了 printf函数,所以在控制台中打印出了一个数据,如下所示:
    在这里插入图片描述
    函数调用的简单使用就介绍到这里,下面再介绍一点其它的吧 . . .

    .
    .


    加法计算与内存单元长度的修饰

    我们来研究一下加法计算在汇编中的表示,并且我们来了解内存单元长度的不同,造成结果的不同 . . .

    我们来看一下下面准备的代码,其中包含指针变量,汇编指令,是一个比较杂的程序,也是对我们了解反汇编有一个很大的帮助,如下所示:

    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
     
    int main() {
    
    	int i = 1;
    	int* p = &i;
    
    	i = i + 0x100;
    
    	__asm {
    		mov eax, p
    		add [eax], 0x22222220
    	}
    
    	i = i + 0x200;
    
    	printf("0x%08x\n", i);
    
    
    	return 0;
    }
    

    首先, i = 1,然后 i 加上 0x100,然后通过指针变量间接的又加上了 0x22222220,最后加上了 0x200,所以不出意外的话结果应该是:
    0x22222521

    当我们执行这个程序时,输出如下的结果:
    0x00000321

    这就有疑惑了,这是为什么呢? 下面就让我们通过OD 对这个程序进行反汇编,看看它的底层究竟发生了什么事儿 . . .

    我们直接定位到main的程序中,其中一些汇编指令对应的代码我已经写好注释了,如下所示:
    在这里插入图片描述
    我们来看 mov eax, p 这条指令的下一条指令,如下所示:
    在这里插入图片描述

    我们将 add byte ptr [eax], 20 与 add [eax], 0x22222220 进行对比一下,发现 22222220 变成了 20,这是为什么呢?因为 add byte ptr [eax], 20 前面用 byte ptr 进行了修饰,只取 22222220 的一个字节8位,所以只取了 20,在 cpp 代码中,不指定修饰内存单元长度,则默认为一个字节,下面我们修改代码如下所示:

    #include <Windows.h>
    #include <iostream>
    
    using namespace std;
     
    int main() {
    
    	int i = 1;
    	int* p = &i;
    
    	i = i + 0x100;
    
    	__asm {
    		mov eax, p
    		add dword ptr [eax], 0x22222220
    	}
    
    	i = i + 0x200;
    
    	printf("0x%08x\n", i);
    
    
    	return 0;
    }
    

    在嵌入的汇编代码中, 加入了 dword ptr 长度修饰,这下子就能完全保留后面数的每一位了,OD 中的调试如下所示:
    在这里插入图片描述

    输出的结果为:
    在这里插入图片描述

    各长度的区别:

    1. 字节(1字节):BYTE类型 (unsigned char) 0 ~ 255 表示成十六进制 0 ~ 0xFF
    2. 字(2字节):WORD类型 (unsigned short)0 ~ 65535 表示成十六进制 0 ~ 0xFFFF
    3. 双字 (4字节):DWORD类型 (unsigned int)0 ~ 4294967295 表示成十六进制 0 ~ 0xFFFFFFFF
      .

    展开全文
  • dosbox反汇编和devc++反汇编程序对比

    千次阅读 2019-05-11 18:19:11
    写一个1+1=2的程序,用gcc编译成可执行的e.exe文件,然后用dosbox反汇编和devc++反汇编程序,对比如下: 我们发现:在执行main()函数的时候,cpu先将当前正在运行的指令的基址bp入栈,再将当前正在运行的指令的...
  • 本文将简单介绍如何使用objdump工具进行反汇编。 本文的前提是你的Linux编程环境有gcc工具和objdump工具,没有请自行安装。 先给出一段C代码作为源文件,很简单的功能,就是实现c=a+b的功能,代码如下: #...
  • 反汇编简介

    2020-06-02 11:20:01
    什么是反汇编 在传统软件开发模型中,
  • Java反汇编入门

    2019-02-26 23:44:20
    Java反汇编入门教程 今天刚刚接触到java的反汇编,所以想写一篇文章给大家分享一下。 预备知识 学习反汇编首先应该首先了解JVM的内存模型,这里简单介绍一下。 JVM的内存模型,如下图 其中方法区和堆是线程...
  • 内核反汇编

    千次阅读 2018-01-23 22:47:15
    -S: 将代码段反汇编的同时,将反汇编代码和源代码交替显示,源码编译时需要加-g参数,即需要调试信息 -C: 将C++符号名逆向解析 -l: 反汇编代码中插入源代码的文件名和行号 -j section: 仅反编译所指定的section,...
  • DTB反汇编

    千次阅读 2018-09-05 10:34:37
    在使用设备树时我们将**.dts文件利用dtc...方法一:使用fdtdump工具进行反汇编  使用命令:root#fdtdump **.dtb &gt; temp.dts  反汇编生成的内容保存在temp.dts 方法二:使用dtc编译器进行反汇编  ...
  • 故它的反汇编代码指令都是x86 CPU的,不是真机上的arm指令。 研究模拟器程序的反汇编有两个目的,或叫做好处: 一是为了研究深入到iOS系统的类库,你可以较容易地发现私有API,以及看到系统的实现。 二是,很直接...
  • 汇编与反汇编

    千次阅读 2019-05-17 11:23:00
    学习c语言又发现有许多知识点抓不住重点,就向下学习汇编、学习微机原理,发现汇编与反汇编才是学习计算机科学的必备技能。以后要好好学习汇编,做逆向工程也是不错的。 转载于:...
  • objdump反汇编

    千次阅读 2015-12-11 15:09:49
    objdump反汇编
  • 浅析VS2010反汇编

    万次阅读 2015-07-25 21:53:11
    如何进行反汇编在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息。如下图所示。记得中断程序的运行,不然看不到反汇编的指令看一个简单的程序及其生成的汇编指令#include #include const ...
  • 反汇编工具

    2013-04-11 16:40:43
    最近上网络编程这门课,孙老师给我们介绍了下反汇编相关工具,让我对反汇编有了一个基本的认识,算是增长见识了。大概介绍了三个工具: 1.source insight 此工具为查看源码比较好的工具,让阅读源代码方便了许多。...
  • 反汇编中的数据类型在汇编中,无论是字符串类型,整数类型还是其他类型都只有2个关键单位,地址、长度【注意:LEA为取地址指令】引用和指针的汇编代码:引用并不会影响程序的执行效率,使用引用又比指针多了编译器的...
  • 今天要给大家介绍一款全能型的反汇编引擎Capstone。这一款引擎不仅能够跨平台,还跨多种语言,其中就有我们喜爱的Python。 我们利用Capstone也能轻松写出高大上的反汇编工具啦~~~ Capstone 能轻松反汇编多种平台的...
  • 掌握了基本技巧后,基本上已不难理解所有的反汇编结果。授之以鱼不如授之以渔: 通过观察自己写的代码的反汇编来掌握各种代码的反汇编结果,从而逆向推测系统代码的源码。 调试自己写的代码时,可以不断切换查看...
  • 对抗反汇编

    2018-04-20 13:58:44
    前言恶意代码编写者会使用对抗反汇编技术来延缓或者阻止分析人员分析恶意代码。所以反汇编技术的目的是为了掩盖程序的真实意图。比如jmp short near ptr loc_2+1这个指令看起来没什么,不过结合下文的汇编代码就...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 95,218
精华内容 38,087
关键字:

反汇编