linux 反编译 obj,objdump反汇编

objdump -j .text -Sl stack1 | more

-S 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,

效果比较明显。隐含了-d参数。

-l 用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用

使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求

编译时使用了-g之类的调试编译选项。

-j name 仅仅显示指定section的信息

这是按Section的名称列出的,其中跟动态连接有关的Section也出现在前面名为Dynamic的Segment中,只是在那里是按类型列出的。例如,前面类型为HASH的表项说与此有关的信息在0x8048128处,而这里则说有个名为.hash的Section,其起始地址为0x8048128。还有,前面类型为PLTGOT的表项说与此有关的信息在0x804a2c4处,这里则说有个名为.got的Section,其起始地址为0x804a2c4,不过Section表中提供的信息更加详细一些,有些信息则互相补充。在Section表中,只要类型为PROGBITS,就说明这个Section的内容都来自映像文件,反之类型为NOBITS就说明这个Section的内容并非来自映像文件。

跟区段头表中的信息一对照,就可以知道在第16项.data以前的所有区段都是要装入用户空间的。这里面包括了大家所熟知的.text即“代码段”。此外,.init、.fini两个区段也有着特殊的重要性,因为映像的程序入口就在.init段中,实际上在进入main()之前的代码都在这里。而从main()返回之后的代码,包括对exit()的调用,则在.fini中。还有一个区段.plt也十分重要,plt是“Procedure Linkage Table”的缩写,这就是用来为目标映像跟共享库建立动态连接的。

有些Section名是读者本来就知道的,例如.text、.data、.bss;有些则从它们的名称就可猜测出来,例如.symtab是符号表、.rodata是只读数据、还有.comment和.debug_info等等。还有一些可能就不知道了,这里择其要者先作些简略的介绍:

(1).hash。为便于根据函数/变量名找到有关的符号表项,需要对函数/变量名进行hash计算,并根据计算值建立hash队列。

● .dynsym。需要加以动态连接的符号表,类似于内核模块中的INPORT符号表。这是动态连接符号表的部分,须与.dynstr联用。

● .dynstr。动态连接符号表的字符串部分,与.dynsym联用。

● .rel.dyn。用于动态连接的重定位信息。

● .rel.plt。一个结构数组,其中的每个元素都代表着GOP表中的一个表项GOTn(见下)。

● .init。在进入main()之前执行的代码在这个Section中。

● .plt。“过程连接表(Procedure Linking Table)”,见后。

● .fini。从main()返回之后执行的代码在这个Section中,最后会调用exit()。

● .ctors。表示“Constructor”,是一个函数指针数组,这些函数需要在程序初始化阶段(进入main()之前,在.init中)加以调用。

● .dtors。表示“Distructor”,也是一个函数指针数组,这些函数需要在程序扫尾阶段(从main()返回之后,在.fini中)加以调用。

● .got。“全局位移表(Global Offset Table)”,见后。

● .strtab。与符号表有关的字符串都集中在这个Section中。

gcc -g -o stack1 stack1.c

objdump -dS stack1 (objdump -j .text -Sl stack1 | more 只显示代码段)

Disassembly of section .init:(在进入main()之前执行的代码在这个Section中)

Disassembly of section .plt:(过程连接表(Procedure Linking Table,实现动态链接)

Disassembly of section .text:(代码段)

080482e0 :

80482e0: 31 ed                 xor    ?p,?p

80482e2: 5e                    pop    %esi

80482e3: 89 e1                 mov    %esp,?x

80482e5: 83 e4 f0              and    $0xfffffff0,%esp

80482e8: 50                    push   ?x

80482e9: 54                    push   %esp

80482ea: 52                    push   ?x

80482eb: 68 50 84 04 08        push   $0x8048450

80482f0: 68 f0 83 04 08        push   $0x80483f0

80482f5: 51                    push   ?x

80482f6: 56                    push   %esi

80482f7: 68 c5 83 04 08        push   $0x80483c5

80482fc: e8 c3 ff ff ff        call   80482c4 <>

8048301: f4                    hlt

8048302: 90                    nop

8048303: 90                    nop

8048304: 90                    nop

8048305: 90                    nop

8048306: 90                    nop

8048307: 90                    nop

8048308: 90                    nop

8048309: 90                    nop

804830a: 90                    nop

804830b: 90                    nop

804830c: 90                    nop

804830d: 90                    nop

804830e: 90                    nop

804830f: 90                    nop

08048310 :

8048310: 55                    push   ?p

8048311: 89 e5                 mov    %esp,?p

8048313: 53                    push   ?x

8048314: 83 ec 04              sub    $0x4,%esp

8048317: 80 3d 10 a0 04 08 00  cmpb   $0x0,0x804a010

804831e: 75 3f                 jne    804835f 8048320: a1 14 a0 04 08        mov    0x804a014,?x

8048325: bb 20 9f 04 08        mov    $0x8049f20,?x

804832a: 81 eb 1c 9f 04 08     sub    $0x8049f1c,?x

8048330: c1 fb 02              sar    $0x2,?x

8048333: 83 eb 01              sub    $0x1,?x

8048336: 39 d8                 cmp    ?x,?x

8048338: 73 1e                 jae    8048358 804833a: 8d b6 00 00 00 00     lea    0x0(%esi),%esi

8048340: 83 c0 01              add    $0x1,?x

8048343: a3 14 a0 04 08        mov    ?x,0x804a014

8048348: ff 14 85 1c 9f 04 08  call   *0x8049f1c(,?x,4)

804834f: a1 14 a0 04 08        mov    0x804a014,?x

8048354: 39 d8                 cmp    ?x,?x

8048356: 72 e8                 jb     8048340 8048358: c6 05 10 a0 04 08 01  movb   $0x1,0x804a010

804835f: 83 c4 04              add    $0x4,%esp

8048362: 5b                    pop    ?x

8048363: 5d                    pop    ?p

8048364: c3                    ret

8048365: 8d 74 26 00           lea    0x0(%esi,%eiz,1),%esi

8048369: 8d bc 27 00 00 00 00  lea    0x0(?i,%eiz,1),?i

08048370 :

8048370: 55                    push   ?p

8048371: 89 e5                 mov    %esp,?p

8048373: 83 ec 18              sub    $0x18,%esp

8048376: a1 24 9f 04 08        mov    0x8049f24,?x

804837b: 85 c0                 test   ?x,?x

804837d: 74 12                 je     8048391 804837f: b8 00 00 00 00        mov    $0x0,?x

8048384: 85 c0                 test   ?x,?x

8048386: 74 09                 je     8048391 8048388: c7 04 24 24 9f 04 08  movl   $0x8049f24,(%esp)

804838f: ff d0                 call   *?x

8048391: c9                    leave

8048392: c3                    ret

8048393: 90                    nop

08048394 :

#include#include

int bar(int c,int d)

{

8048394: 55                    push   ?p          //ebp是栈底指针

8048395: 89 e5                 mov    %esp,?p     //esp是栈顶指针

8048397: 83 ec 10              sub    $0x10,%esp

int e=c+d;                               //4个数据寄存器(eax、ebx、ecx和edx)

804839a: 8b 45 0c              mov    0xc(?p),?x

804839d: 8b 55 08              mov    0x8(?p),?x

80483a0: 8d 04 02              lea    (?x,?x,1),?x

80483a3: 89 45 fc              mov    ?x,-0x4(?p)

return e;

80483a6: 8b 45 fc              mov    -0x4(?p),?x

}

80483a9: c9                    leave

80483aa: c3                    ret

080483ab :

int foo(int a,int b)

{

80483ab: 55                    push   ?p

80483ac: 89 e5                 mov    %esp,?p

80483ae: 83 ec 08              sub    $0x8,%esp

return bar(a,b);

80483b1: 8b 45 0c              mov    0xc(?p),?x

80483b4: 89 44 24 04           mov    ?x,0x4(%esp)

80483b8: 8b 45 08              mov    0x8(?p),?x

80483bb: 89 04 24              mov    ?x,(%esp)

80483be: e8 d1 ff ff ff        call   8048394 }

80483c3: c9                    leave

80483c4: c3                    ret

080483c5 :

int main(void)

{

80483c5: 55                    push   ?p

80483c6: 89 e5                 mov    %esp,?p

80483c8: 83 ec 08              sub    $0x8,%esp

foo(2,3);

80483cb: c7 44 24 04 03 00 00  movl   $0x3,0x4(%esp)

80483d2: 00

80483d3: c7 04 24 02 00 00 00  movl   $0x2,(%esp)

80483da: e8 cc ff ff ff        call   80483ab return 0;

80483df: b8 00 00 00 00        mov    $0x0,?x

}

Disassembly of section .fini:(main结束后调用,最后调用exit)

1:“gdb”命令启动GDB

2: file stack1

3:使用“r”命令执行(Run)被调试文件,因为尚未设置任何断点,将直接执行到程序结束

4:使用“b”命令在 main 函数开头设置一个断点(Breakpoint):

5:使用“r”命令执行(Run)被调试程序

6:使用“s”命令(Step)执行下一行代码

代码如下:

#include "stdlib.h"

int sum(int a,int b,int m,int n)

{

return a+b;

}

void main()

{

int result = sum(1,2,3,4);

system("pause");

}

有四个参数的sum函数,接着在main方法中调用sum函数。在debug环境下,单步调试如下:

11:   void main()

12:   {

00401060   push        ebp

;保存ebp,执行这句之前,ESP = 0012FF4C EBP = 0012FF88

;执行后,ESP = 0012FF48(向下增长) EBP = 0012FF88,ESP减小,EBP不变

00401061   mov         ebp,esp

;将esp放入ebp中,此时ebp和esp相同,即执行后ESP = 0012FF48 EBP = 0012FF48

;原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。

;此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),

;从该地址为基准,向上(栈底方向)能获取返回地址、参数值(假如main中有参数,“获取参数值”会比较容易理解,

;不过在看下边的sum函数调用时会有体会的),向下(栈顶方向)能获取函数局部变量值,

;而该地址处又存储着上一层函数调用时的EBP值!

00401063   sub         esp,44h

;把esp往上移动一个范围

;等于在栈中空出一片空间来存局部变量

;执行这句后ESP = 0012FF04 EBP = 0012FF48

00401066   push        ebx

00401067   push        esi

00401068   push        edi

;保存三个寄存器的值

00401069   lea         edi,[ebp-44h]

;把ebp-44h加载到edi中,目的是保存局部变量的区域

0040106C   mov         ecx,11h

00401071   mov         eax,0CCCCCCCCh

00401076   rep stos    dword ptr [edi]

;从ebp-44h开始的区域初始化成全部0CCCCCCCCh,就是int3断点,初始化局部变量空间

;REP           ;CX不等于0 ,则重复执行字符串指令

;格式: STOS OPRD

;功能: 把AL(字节)或AX(字)中的数据存储到DI为目的串地址指针所寻址的存储器单元中去.指针DI将根据DF的值进行自动

;调整. 其中OPRD为目的串符号地址.

;以上的语句就是在栈中开辟一块空间放局部变量

;然后把这块空间都初始化为0CCCCCCCCh,就是int3断点,一个中断指令。

;因为局部变量不可能被执行,执行了就会出错,这时候发生中断提示开发者。

13:       int result = sum(1,2,3,4);

00401078   push        4

0040107A   push        3

0040107C   push        2

0040107E   push        1

;各个参数入栈,注意查看寄存器ESP值的变化

;亦可以看到参数入栈的顺序,从右到左

;变化为:ESP = 0012FEF8-->ESP = 0012FEF4-->ESP = 0012FEF0-->ESP = 0012FEEC-->ESP = 0012FEE8

00401080   call        @ILT+15(boxer) (00401014)

;调用sum函数,可以按F11跟进

;注:f10(step over),单步调试,遇到函数调用,直接执行,不会进入函数内部

;f11(step into),单步调试,遇到函数调用,会进入函数内部

;shift+f11(step out),进入函数内部后,想从函数内部跳出,用此快捷方式

;ctrl+f10(run to cursor),呵呵,看英语注释就应该知道是什么意思了,不再解释

00401084   add         esp,10h

;调用完函数后恢复/释放栈,执行后ESP = 0012FEF8,与sum函数的参数入栈前的数值一致

00401088   mov         dword ptr [ebp-4],eax

;将结果存放在result中,原因详看最后有关ss的注释

14:       system("pause");

0040108B   push        offset string "pause" (00422f6c)

00401090   call        system (0040eed0)

00401095   add   esp ,4

;有关system(“pause”)的处理,此处不讨论

15:   }

00401098   pop         edi

00401099   pop         esi

0040109A   pop         ebx

;恢复原来寄存器的值,怎么“吃”进去,怎么“吐”出来

0040109B   add         esp,44h

;恢复ESP,对应上边的sub esp,44h

0040109E   cmp         ebp,esp

;检查esp是否正常,不正常就进入下边的call里面debug

004010A0   call        __chkesp (004010b0)

;处理可能出现的堆栈异常,如果有的话,就会陷入debug

004010A5   mov         esp,ebp

004010A7   pop         ebp

;恢复原来的esp和ebp,让上一个调用函数正常使用

004010A8   ret

;将返回地址存入eip,转移流程

;如果函数有返回值,返回值将放在eax返回(这就是很多软件给秒杀爆破的原因了,因为eax的返回值是可以改的)

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

;以上即是主函数调用的反汇编过程,下边来看调用sum函数的过程:

;上边有说在00401080   call        @ILT+15(boxer) (00401014)这一句处,用f11单步调试,f11后如下句:

00401014   jmp         sum (00401020)

;即跳转到sum函数的代码段中,再f11如下:

6:    int sum(int a,int b,int m,int n)

7:    {

00401020   push        ebp

00401021   mov         ebp,esp

00401023   sub         esp,40h

00401026   push        ebx

00401027   push        esi

00401028   push        edi

00401029   lea         edi,[ebp-40h]

0040102C   mov         ecx,10h

00401031   mov         eax,0CCCCCCCCh

00401036   rep stos    dword ptr [edi]

;可见,上边几乎与主函数调用相同,每一步不再赘述,可对照上边主函数调用的注释

8:        return a+b;

00401038   mov         eax,dword ptr [ebp+8]

;取第一个参数放在eax

0040103B   add         eax,dword ptr [ebp+0Ch]

;取第二个参数,与eax中的数值相加并存在eax中

9:    }

0040103E   pop         edi

0040103F   pop         esi

00401040   pop         ebx

00401041   mov         esp,ebp

00401043   pop         ebp

00401044   ret

;收尾操作,比前边只是少了检查esp操作罢了

有关ss部分的注释:

;一般而言,ss:[ebp+4]处为返回地址

;ss:[ebp+8]处为第一个参数值(这里是a),ss:[ebp+0Ch]处为第二个参数(这里是b,这里8+4=12=0Ch)

;ss:[ebp-4]处为第一个局部变量(如main中的result),ss:[ebp]处为上一层EBP值

;ebp和函数返回值是32位,所以占4个字节

for example

../prebuilt/-x86/toolchain/arm-eabi-4.4.3/arm-eabi/bin/objdump -j .text -SlD  arch/arm/mach-sc/xxxxxx.o | tee uuu.txt

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言是一种高级编程语言,它经过编译后会生成机器可读的目标代码,通常是二进制文件。因此,C语言的反编译就是将这些二进制文件转换回可读的源代码。 C语言的反编译工具主要通过分析目标代码和逆向工程技术来实现。这些工具可以读取目标文件中的二进制指令,并尝试还原出原始的C语言源代码。 然而,C语言的反编译并不是完全准确和可逆的过程。由于编译器的优化等因素,一些信息在编译后就会丢失,使得反编译后的代码可能存在一些差异和不完全性。此外,由于反编译工具的算法和原始代码的复杂性,反编译结果可能会比较难以理解和修改。 尽管如此,C语言的反编译仍然被广泛用于软件逆向工程、恶意代码分析和漏洞研究等领域。通过反编译,我们可以深入了解程序的执行流程、数据结构和算法逻辑,为后续分析和修改提供了便利。 总结来说,C语言反编译是将编译后的目标代码转换为可读的源代码的过程。虽然反编译结果可能不完全准确,但它在软件逆向工程和漏洞研究等领域具有重要的应用价值。 ### 回答2: C语言中的反编译是指将已编译的对象文件(.obj)转化为可读的源代码的过程。反编译是一种逆向工程的技术,它可以帮助开发者了解和分析已编译的程序,以及进行程序的修改和优化。 要进行C语言的反编译,需要使用专业的反汇编工具。常用的反汇编工具有IDA Pro、OllyDbg等。这些工具可以将机器语言指令逆向还原为汇编语言代码,从而辅助开发者理解源代码的结构和逻辑。 反编译过程中,开发者需要仔细研究汇编代码,通过对指令的分析、跳转和数据交互等操作的观察,来推测原始C语言源代码的结构和功能。这个过程需要一定的经验和技巧,同时也需要对C语言的编译原理和汇编语言有深入的了解。 但需要注意的是,反编译并不意味着完全还原原始的C代码。由于编译过程中存在优化和信息丢失的情况,反编译后的代码可能会有一定的差异,并且可能存在一些不确定性。因此,反编译得到的代码一般需要经过进一步的修复和调试,以便使其在编译时能够正常通过。 总的来说,C语言的反编译是一项复杂而有挑战的工作,它需要一定的专业工具和技术支持,并且对反汇编和C编程有较深的了解。通过反编译,可以帮助开发者了解、分析和修改已编译的程序,提升开发效率和代码质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值