如何在不链接libc.so的情况下访问段寄存器?

2024-03-29

我正在尝试在 Ubuntu 20.10 上使用 NASM 版本 2.15.04 在 64 位程序集中编写一个简单的堆栈金丝雀。执行下面的代码会导致在使用命令进行汇编和链接时出现分段错误nasm -felf64 canary.asm && ld canary.o.

            global  _start

            section .text
_start:     endbr64
            push    rbp                     ; Save base pointer
            mov     rbp, rsp                ; Set the stack pointer
            call    _func                   ; Call _func
            mov     rdi, rax                ; Save return value of _func in RDI
            mov     rax, 0x3c               ; Specify exit syscall 
            syscall                         ; Exit

_func:      endbr64
            push    rbp                     ; Save the base pointer
            mov     rbp, rsp                ; Set the stack pointer
            sub     rsp, 0x8                ; Adjust the stack pointer
            mov     rax,  qword fs:[0x28]   ; Get stack canary
            mov     qword [rbp - 0x8], rax  ; Save stack canary on the stack
            xor     eax, eax                ; Clear RAX
            mov     rax, 0x1                ; Specify write syscall
            mov     rdi, 0x1                ; Specify stdout
            mov     rsi, msg                ; Char* buffer to print
            mov     rdx, 0xd                ; Length of the buffer
            syscall                         ; Write msg
            mov     rax, qword [rbp - 0x8]  ; Retrieve the stack canary
            xor     rax, qword fs:[0x28]    ; Compare to original value    
            je      _return                 ; Jump to _return if canary matched original
            xor     eax, eax                ; Clear RAX
            mov     rax, 0x1                ; Specify write syscall 
            mov     rdi, 0x1                ; Specify stdout
            mov     rsi, stack_fail         ; Char* buffer to print
            mov     rdx, 0x18               ; Length of the buffer 
            syscall                         ; Write stack_fail
            mov     rax, 0x3c               ; Specify exit syscall
            mov     rax, 0x1                ; Specify error code 1    
            syscall                         ; Exit

_return:    xor     eax, eax                ; Set return value to 0
            add     rsp, 0x8                ; Reset stack pointer
            pop     rbp                     ; Get original base pointer
            ret                             ; Return 

            section .data
msg:        db      "Hello, World", 0xa, 0x0
stack_fail  db      "Stack smashing detected", 0xa, 0x0

用GDB调试显示分段错误发生在第16行:mov rax, qword fs:[0x28].

─────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x40101b <_func+4>        push   rbp
     0x40101c <_func+5>        mov    rbp, rsp
     0x40101f <_func+8>        sub    rsp, 0x8
 →   0x401023 <_func+12>       mov    rax, QWORD PTR fs:0x28
     0x40102c <_func+21>       mov    QWORD PTR [rbp-0x8], rax
     0x401030 <_func+25>       xor    eax, eax
     0x401032 <_func+27>       mov    eax, 0x1
     0x401037 <_func+32>       mov    edi, 0x1
     0x40103c <_func+37>       movabs rsi, 0x402000
─────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "a.out", stopped 0x401023 in _func (), reason: SIGSEGV

然而,通过 libc 进行组装和动态链接nasm -felf64 canary.asm && ld canary.o -lc -dynamic-linker /usr/lib64/ld-linux-x86-64.so.2结果执行成功,不再导致分段错误。

使用 Radare2 比较最终的二进制文件表明,两个版本都以相同的方式组装问题指令:

0x00401023 64488b042528. mov rax, qword fs:[0x28]

在这两种情况下,GDB 还显示该指令执行时 FS 寄存器为 0x0000。

因此,无论二进制文件是否与 libc 链接,指令字节和 FS 寄存器都是相同的,并且代码没有使用 libc 中的外部符号。为什么链接 libc 会导致执行成功,而不链接 libc 会导致分段错误?是否有可能和/或如何在不链接 libc 的情况下实现这一点?

注意:此示例中堆栈金丝雀的相关性或需求不是问题的重点。


访问段寄存器没有问题,只需mov eax, fs。但是您想要做的是访问距 FS 段较小偏移的线程本地存储base,libc init 的东西会要求内核进行设置。

最简单的事情是使用正常的 RIP 相对寻址模式访问堆栈金丝雀,而不是相对于 FS 基础,就像 GCC 在针对其他 ISA 时所做的那样。仅当您想让其他漏洞更难到达金丝雀(并且使其地址可单独随机化)时,才需要 TLS。 (或者说,库代码可以访问它,而无需从 GOT 间接加载指针,而不是仅对主可执行文件中的代码有效。)

如果您想复制 GCC 的堆栈金丝雀代码,您当然可以进行与 libc 相同的系统调用来设置线程本地存储并使用它。


有趣的事实:sub rax, qword fs:[0x28]是比 XOR 更有效的检查金丝雀的方法 - 它可以与 JCC 宏融合到单个微指令中。这就是为什么当前的 GCC 改为使用sub. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90568 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90568- 在 GCC10+ 中修复。

我的 GCC 错误报告实际上包含了独立的微基准代码(以证明sub即使使用 FS:寻址模式也可以进行宏熔断)。

如果静态可执行文件中没有 libc,它会设置 FS 段,因此其基地址是缓冲区的地址,因此[fs: 0x28]将工作。这是 TLS 的基本形式。

global _start
_start:

cookie equ 12345
    mov  eax, 158       ; __NR_arch_prctl
    mov  edi, 0x1002    ; ARCH_SET_FS
    lea  rsi, [buf]
    syscall

    mov  qword [fs: 0x28], cookie

...


section .bss
buf:    resb 4096         ; fs.base will point at this buffer

如果内核启用wrfsbase对于用户空间使用,您可以使用wrfsbase rsi而不是进行系统调用。我认为最新的 Linux 内核(5.10)可能已经开始使用wrfsbase本身,但我不知道它是否允许用户空间使用它。

(它可能不会在每次使用时打开/关闭 FSGSBASE,因此内核使用意味着用户空间可以使用它;故障条件在手册中 https://www.felixcloutier.com/x86/wrfsbase:wrgsbase#64-bit-mode-exceptions不要提及特权级别,只提及 CPUID 功能位和 CR4 控制寄存器中的一位。并且仅在 64 位模式下;它会在其他模式下#UD,包括兼容模式。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在不链接libc.so的情况下访问段寄存器? 的相关文章

随机推荐

  • 跳转滚动并重定向到博客上同一博客的另一个页面

    我有一个博客 如果有人点击特定链接我想做 他应该在同一页面上的特定点跳转滚动 然后几秒钟后 他应该自动重定向到同一博客的其他页面 重定向到其他博客 请也给出示例网站地址 我有这个代码 脚本就像 function jumpScroll win
  • Spark Dataframe Write to CSV 在独立集群模式下创建 _temporary 目录文件

    我在跑步spark job在有 2 个工作节点的集群中 我使用下面的代码 spark java 将计算的数据帧作为 csv 保存到工作节点 dataframe write option header false mode SaveMode
  • 如何克隆案例类实例并仅更改 Scala 中的一个字段?

    假设我有一个案例类 代表不同社交网络上的人物角色 该类的实例是完全不可变的 并保存在不可变的集合中 最终由 Akka actor 进行修改 现在 我有一个包含许多字段的案例类 我收到一条消息 说我必须更新其中一个字段 如下所示 case c
  • Python 2.7:从文本中检测表情符号

    我希望能够检测文本中的表情符号并查找它们的名字 我没有使用 unicodedata 模块 我怀疑我不是 了解 UTF 8 约定 我猜想我需要将我的文档加载为 utf 8 然后将 unicode 字符串 分解为 unicode 符号 迭代这些
  • 调用类型参数的方法

    有没有办法做这样的代码 class GenericClass
  • iOS:如何注册推送通知?

    我正在尝试按照 Ray Wenderlich 的指南为我的 iOS 5 应用程序实现推送通知 http www raywenderlich com 3443 apple push notification services tutorial
  • 如何过滤chrome的devtool控制台历史记录

    在 bash 中 我使用历史搜索向前和历史搜索向后功能来允许我输入要运行的命令的几个字符 然后按向上箭头循环浏览历史记录中与这些字符匹配的项目 我想要 chrome devtool 控制台也有同样的东西 我经常使用向上箭头来循环浏览我的历史
  • PHP 相等(== 双等于)和恒等(=== 三等)比较运算符有何不同?

    有什么区别 and 松散究竟如何 比较工作 具体如何严格 比较工作 有哪些有用的例子 之间的区别 and 松散的区别 等于运算符和严格运算符 相同的运算符在中得到了准确的解释manual http php net manual en lan
  • iOS 将大数字转换为较小格式

    如何将所有超过 3 位的数字转换为 4 位或更少的数字 这正是我的意思 10345 10 3k 10012 10k 123546 123 5k 4384324 4 3m 四舍五入并不完全重要 但却是一个额外的优点 我已经研究过 NSNumb
  • 我如何在 Skype 上玩 google?

    此代码用于在 Skype 上向某人发送消息 但我不知道如何设置https play google com store apps details id com skype raider https play google com store
  • 如何从Excel电子表格中读取数据?

    在我正在工作的一个项目中 客户在最后一刻要求我添加从 Excel 电子表格导入数据的功能 他发送给我的示例具有 xlsx 扩展名 因此我假设它们来自 Excel 2010 但如果可能的话 我希望支持所有版本 有没有一种快速 简单的方法可以从
  • Python - 循环多维字典[重复]

    这个问题在这里已经有答案了 如果我解释我认为我在做什么 我希望有人能解释我哪里出错了 我有以下字典 ls The Wolf Gift 13 cover V Books Anne Rice The Wolf Gift 13 cover jpg
  • Linux 上的调试符号是否加载到内存中?

    从可执行文件 或共享库 中剥离调试符号是否会减少内存使用量 我知道它减少了磁盘文件的大小 我感兴趣的是实际使用的 RAM 德雷珀的论文http www akkadia org drepper dsohowto pdf http www ak
  • 每 14 天(每两周)触发一次 UILocalNotification Swift

    这个问题已经在SO上得到了回答 这是参考 iOS 通知触发 每两周和 或每季度 https stackoverflow com questions 41441124 ios notification trigger fortnightly
  • Pandas 的 T 检验

    如果我想计算 Pandas 中两个类别的平均值 我可以这样做 data Category cat2 cat1 cat2 cat1 cat2 cat1 cat2 cat1 cat1 cat1 cat2 values 1 2 3 1 2 3 1
  • 如何覆盖具有多个子项目的 SBT 项目中的子项目中的设置

    我有一个项目 其中子项目作为 git 子模块添加到子目录中 每个独立项目都有自己的build sbt文件 根项目依赖于并聚合这些子项目 如何覆盖设置值 例如organization or version 在那些子项目里面 lazy val
  • mysql使用连接池时为什么需要释放连接?

    我正在尝试实现以下nodejs mysql数据库this https medium com mhagemann create a mysql database middleware with node js 8 and async awai
  • 有没有办法在Python中按第n个分隔符分割字符串?

    例如 如果我有以下字符串 这是一个字符串 我可以将它分割为每个第二个 而不是每个 以便它返回两个值 this is 和 a string 而不是返回四个值吗 这是另一个解决方案 span 2 words this is a string s
  • 使用jquery求div内元素的总和

    我正在对一组用户进行排序 我有 4 个分组 如下所示 显示 2 个 div class groupWrapper div class groupItem div class itemHeader div class first John d
  • 如何在不链接libc.so的情况下访问段寄存器?

    我正在尝试在 Ubuntu 20 10 上使用 NASM 版本 2 15 04 在 64 位程序集中编写一个简单的堆栈金丝雀 执行下面的代码会导致在使用命令进行汇编和链接时出现分段错误nasm felf64 canary asm ld ca