了解简单 C 程序生成的汇编代码

2024-01-07

我试图通过使用 gdb 的反汇编程序检查简单 C 程序的汇编级代码。

以下是C代码:

#include <stdio.h>

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}

void main() {
  function(1,2,3);
}

以下是两者的反汇编代码main and function

gdb) disass main
Dump of assembler code for function main:
0x08048428 <main+0>:    push   %ebp
0x08048429 <main+1>:    mov    %esp,%ebp
0x0804842b <main+3>:    and    $0xfffffff0,%esp
0x0804842e <main+6>:    sub    $0x10,%esp
0x08048431 <main+9>:    movl   $0x3,0x8(%esp)
0x08048439 <main+17>:   movl   $0x2,0x4(%esp)
0x08048441 <main+25>:   movl   $0x1,(%esp)
0x08048448 <main+32>:   call   0x8048404 <function>
0x0804844d <main+37>:   leave  
0x0804844e <main+38>:   ret
End of assembler dump.

(gdb) disass function
Dump of assembler code for function function:
0x08048404 <function+0>:    push   %ebp
0x08048405 <function+1>:    mov    %esp,%ebp
0x08048407 <function+3>:    sub    $0x28,%esp
0x0804840a <function+6>:    mov    %gs:0x14,%eax
0x08048410 <function+12>:   mov    %eax,-0xc(%ebp)
0x08048413 <function+15>:   xor    %eax,%eax
0x08048415 <function+17>:   mov    -0xc(%ebp),%eax
0x08048418 <function+20>:   xor    %gs:0x14,%eax
0x0804841f <function+27>:   je     0x8048426 <function+34>
0x08048421 <function+29>:   call   0x8048340 <__stack_chk_fail@plt>
0x08048426 <function+34>:   leave  
0x08048427 <function+35>:   ret    
End of assembler dump.

我正在寻求以下问题的答案:

  1. 寻址是如何工作的,我的意思是(main+0),(main+1),(main+3)
  2. 主要是为什么使用 $0xfffffff0,%esp
  3. 在函数中,为什么使用 %gs:0x14,%eax , %eax,-0xc(%ebp) 。
  4. 如果有人可以解释一步一步发生的情况,那将不胜感激。

“奇怪”地址的原因例如main+0, main+1, main+3, main+6等等,是因为每条指令占用的字节数是可变的。例如:

main+0: push %ebp

是一个单字节指令,所以下一条指令位于main+1。另一方面,

main+3: and $0xfffffff0,%esp

是一个三字节指令,因此之后的下一条指令位于main+6.

而且,既然你在评论中问为什么movl似乎需要可变数量的字节,对此的解释如下。

指令长度不仅取决于opcode(例如movl)以及寻址模式operands以及(操作码正在操作的东西)。我没有专门检查你的代码,但我怀疑

movl $0x1,(%esp)

指令可能更短,因为不涉及偏移量 - 它只是使用esp作为地址。而类似的东西:

movl $0x2,0x4(%esp)

需要一切movl $0x1,(%esp) does, plus偏移量的额外字节0x4.

事实上,这是一个调试会话,显示了我的意思:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

c:\pax> debug
-a
0B52:0100 mov word ptr [di],7
0B52:0104 mov word ptr [di+2],8
0B52:0109 mov word ptr [di+0],7
0B52:010E
-u100,10d
0B52:0100 C7050700      MOV     WORD PTR [DI],0007
0B52:0104 C745020800    MOV     WORD PTR [DI+02],0008
0B52:0109 C745000700    MOV     WORD PTR [DI+00],0007
-q
c:\pax> _

您可以看到带有偏移量的第二条指令实际上与没有偏移量的第一条指令不同。它多了一个字节(5 个字节而不是 4 个字节,用于保存偏移量)并且实际上具有不同的编码c745代替c705.

您还可以看到,可以用两种不同的方式对第一条和第三条指令进行编码,但它们基本上执行相同的操作。


The and $0xfffffff0,%esp指导是一种强迫的方式esp处于特定的边界上。这用于确保变量的正确对齐。现代处理器上的许多内存访问如果遵循对齐规则(例如 4 字节值必须与 4 字节边界对齐),将会更加高效。如果您不遵守这些规则,一些现代处理器甚至会引发故障。

遵循此说明后,您可以保证esp均小于或等于其先前值and与 16 字节边界对齐。


The gs:前缀只是意味着使用gs段寄存器来访问内存而不是默认的。

指令mov %eax,-0xc(%ebp)意思是获取内容ebp寄存器,减去 12 (0xc),然后输入值eax进入该内存位置。


重新解释一下代码。你的function函数基本上是一大无操作。生成的程序集仅限于堆栈帧设置和拆卸,以及使用上述方法的一些堆栈帧损坏检查%gs:14内存位置。

它从该位置加载值(可能类似于0xdeadbeef)进入堆栈帧,完成其工作,然后检查堆栈以确保它没有被损坏。

在这种情况下,它的工作就没什么了。所以你看到的只是功能管理的东西。

堆栈建立发生在function+0 and function+12。之后的一切都是在中设置返回代码eax并拆除堆栈框架,包括损坏检查。

相似地,main包括堆栈帧设置,推送参数function, 呼叫function,拆除堆栈框架并退出。

注释已插入到以下代码中:

0x08048428 <main+0>:    push   %ebp                 ; save previous value.
0x08048429 <main+1>:    mov    %esp,%ebp            ; create new stack frame.
0x0804842b <main+3>:    and    $0xfffffff0,%esp     ; align to boundary.
0x0804842e <main+6>:    sub    $0x10,%esp           ; make space on stack.

0x08048431 <main+9>:    movl   $0x3,0x8(%esp)       ; push values for function.
0x08048439 <main+17>:   movl   $0x2,0x4(%esp)
0x08048441 <main+25>:   movl   $0x1,(%esp)
0x08048448 <main+32>:   call   0x8048404 <function> ; and call it.

0x0804844d <main+37>:   leave                       ; tear down frame.
0x0804844e <main+38>:   ret                         ; and exit.

0x08048404 <func+0>:    push   %ebp                 ; save previous value.
0x08048405 <func+1>:    mov    %esp,%ebp            ; create new stack frame.
0x08048407 <func+3>:    sub    $0x28,%esp           ; make space on stack.
0x0804840a <func+6>:    mov    %gs:0x14,%eax        ; get sentinel value.
0x08048410 <func+12>:   mov    %eax,-0xc(%ebp)      ; put on stack.

0x08048413 <func+15>:   xor    %eax,%eax            ; set return code 0.

0x08048415 <func+17>:   mov    -0xc(%ebp),%eax      ; get sentinel from stack.
0x08048418 <func+20>:   xor    %gs:0x14,%eax        ; compare with actual.
0x0804841f <func+27>:   je     <func+34>            ; jump if okay.
0x08048421 <func+29>:   call   <_stk_chk_fl>        ; otherwise corrupted stack.
0x08048426 <func+34>:   leave                       ; tear down frame.
0x08048427 <func+35>:   ret                         ; and exit.

我认为原因是%gs:0x14从上面可能很明显,但为了以防万一,我将在这里详细说明。

它使用此值(哨兵)放入当前堆栈帧,以便函数中的某些内容执行一些愚蠢的操作,例如将 1024 字节写入堆栈上创建的 20 字节数组,或者在您的情况下:

char buffer1[5];
strcpy (buffer1, "Hello there, my name is Pax.");

然后哨兵将被覆盖,函数末尾的检查将检测到这一点,调用失败函数让您知道,然后可能中止以避免任何其他问题。

如果它放置0xdeadbeef到堆栈上,这被更改为其他内容,然后是xor with 0xdeadbeef将产生一个非零值,该值在代码中检测到je操作说明。

相关部分解释如下:

          mov    %gs:0x14,%eax     ; get sentinel value.
          mov    %eax,-0xc(%ebp)   ; put on stack.

          ;; Weave your function
          ;;   magic here.

          mov    -0xc(%ebp),%eax   ; get sentinel back from stack.
          xor    %gs:0x14,%eax     ; compare with original value.
          je     stack_ok          ; zero/equal means no corruption.
          call   stack_bad         ; otherwise corrupted stack.
stack_ok: leave                    ; tear down frame.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

了解简单 C 程序生成的汇编代码 的相关文章

随机推荐

  • Komodo编辑自动完成JS对象文字

    问题是 Komodo 智能感知看不到这样定义的对象方法 var App window App method function 输入 应用程序 没有给出任何结果 但是 定义如下所示的对象效果很好 var App method function
  • “SystemInfo.deviceUniqueIdentifier”在 Android 构建中使用什么?

    The 文档 https docs unity3d com ScriptReference SystemInfo deviceUniqueIdentifier html记录 iOS Windows 版本中使用的标识符 但 Android 版
  • 使用 DownloadFileTaskAsync 一次下载所有文件

    给定一个包含 URL 的输入文本文件 我想一次性下载所有相应的文件 我用这个问题的答案使用 WebClient 和 TaskAsync 从异步 CTP 下载 UserState https stackoverflow com questio
  • 如何检查多个单元格的值是否相等?

    假设我有 6 个不同的单元格 并非全部排成一行 我想检查这些单元格中的值是否相等 我怎样才能用一个函数来做到这一点 我希望该函数只是显示 等于 或 不等于 或者可能更改单元格背景颜色 6 个单元的一种选择是 IF AND A1 B2 B2
  • 如何比较用 Java 和 Xamarin C# 编写的 Android 应用程序的性能?无论如何检查定量数据(代码和结果)[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我发现 Xamarin 声称他们在 Android 上的 Mono 实现及其 C 编译的应用程序比 J
  • 如何仅针对特定规则或一组规则运行 eslint - 仅命令行

    我知道你可以在 eslintrc文件 但如果我只想运行怎么办eslint并检查一项特定规则 E g eslint helpme js rule some important rule 我不知道这是否是最好的方法 但我能够让它工作 eslin
  • 如何修改这个缓动函数以减少弹跳?

    我正在尝试修改 Flash CS3 提供的fl motion easing bounce函数使生成的动画弹跳更少 我知道 减少弹跳 有点模糊 但我希望能帮助您理解该功能 Thanks param t Specifies the curren
  • Django 模板中的外键关系

    我知道这个问题已经被问过很多次了 但我仍然无法解决 model py class Awb models Model awb id models CharField primary key True max length 50 awb shi
  • Android 截取 Surface View 的屏幕截图显示黑屏

    我正在尝试通过代码截取我的游戏的屏幕截图并通过意图共享它 我可以做这些事情 但是屏幕截图总是显示为黑色 这是与共享屏幕截图相关的代码 View view MainActivity getView view setDrawingCacheEn
  • iPhone:ubercab 又名 (uber) 地图坐标

    谁能描述如何通过 MKMapView 在屏幕中心的位置获取其地图坐标 查看 Uber 应用程序 免费 它们有一个静态的图钉位于屏幕中间 您拖动地图但图钉仍保留在那里 屏幕中间是他们找到您的位置 非常非常快 向您显示您附近的地址 嘿嘿 我是
  • 临时反应组件中的样式组件

    我在反应中的临时包装器中使用样式组件时遇到两个问题 组件已渲染 但不使用背景颜色 ComponentWithAddedColors 不是有效的打字稿 不知道为什么 有谁可以帮忙解决这个问题吗 interface IProps id stri
  • Numpy 一次将数组与多个标量进行比较

    假设我有一个数组 a np array 1 2 3 我想将它与一些标量进行比较 这工作得很好 就像 a 2 False True False 有没有办法可以同时使用多个标量进行这样的比较 比较两个数组时的默认行为是进行元素比较 但我希望一个
  • Django如何访问抽象Base模型局部变量

    我将这个抽象基本模型定义如下 class ActivityAbstractBaseModel models Model POOR PR FAIR FA MEDIOCRE ME GOOD ENOUGH GE GOOD GO VERY GOOD
  • ODBC 不断提示输入密码

    我有一个在 Access 2003 中构建的应用程序 它使用系统 DSN ODBC 连接到 SQL Server ODBC 使用 SQL 身份验证 当应用程序启动时 系统会提示用户在数据库中进行身份验证 我在同一域中设置了另一台计算机 并安
  • 在 Hive 中获取系统日期 -1

    有什么办法可以得到current date 1在 Hive 中的意思是yesterdays date总是 并且以这种格式 20120805 我可以像这样运行查询来获取数据yesterday s date就像今天一样Aug 6th selec
  • 防止xss攻击的更好方法

    这两种方法中哪一种是更好的防止 xss 攻击的方法 保存在数据库中时的 HTMLEntities 显示 回显时的 HTMLEntities 我发现第一个更好 因为您可能会在显示时忘记添加它 两者中哪一个是更好的防止xss攻击的方法 保存在数
  • 将 Spark 数据加载到 Mongo / Memcached 中以供 Web 服务使用

    我对 Spark 非常陌生 并且有一个特定的工作流程相关问题 虽然它并不是真正与编码相关的问题 但它更像是与 Spark 功能相关的问题 我认为它在这里是合适的 如果您认为这个问题不适合 请随时将我重定向到正确的网站 所以这里是 1 我计划
  • 在没有管理员权限的情况下安装 MSBuild 15(Microsoft 构建工具)?

    有没有办法在没有管理员权限的情况下在我的计算机上本地安装 MSBuild 15 微软安装程序开启https www visualstudio com downloads https www visualstudio com download
  • 我怎样才能获得正确的付款期限?

    我觉得这更像是数学问题 我公司的员工遍布全国各地 公司的某些部门采用 奇数 工资周期 而另一些部门则采用 偶数 工资周期 我将给定支付期的开始日期称为 支付期 我需要做两件事 1 确定给定日期所属的发薪期 Something like th
  • 了解简单 C 程序生成的汇编代码

    我试图通过使用 gdb 的反汇编程序检查简单 C 程序的汇编级代码 以下是C代码 include