使用气体,我怎样才能得到特定标签的偏移量?

Using gas, how can I get the offset to a particular label?

我正在使用 pwnlib 编写一个小的 shellcode 来应对挑战。我的 shellcode 需要修改自身以通过应用程序过滤器。我首先用 nasm 写了它,然后做了类似的事情:

        sub        edx, edx
        mov        dl, 0x82
        add        al, do_mov_rdi_rax
        sub        dword [rax], edx
        mov        dh, 0x82
        add        al, do_syscall - do_mov_rdi_rax
        sub        dword [rax], edx
        shr        edi, 31

    do_mov_rdi_rax:
        ; mov    rsi, rax
        ; (with 0x82 added to first byte to pass validation)
        db         0xca, 0x89, 0xc6
        sub        eax, eax

    do_syscall:
        ; syscall
        ; (with 0x82 added to both bytes to pass validation)
        db         0x91, 0x87

Pwnlib 使用 gas,但是,所以我的汇编代码必须符合它的语法。除了显而易见的(// 而不是 ;.byte 而不是 db),我还遇到了最后一个问题:虽然 nasm 愉快地转换了我的标签到整数(对于 add al, do_mov_rdi_raxadd al, do_syscall - do_mov_rdi_rax),gas 一直告诉我它不能表示寻址类型 BFD_RELOC_8,或类似的东西(我不知何故得到了一个gas 的法语版本,抱歉缺少错误消息)。

如何获取标签的整数地址?我的 shellcode 基于地址 0(并且 gas 被告知 .org 0x0)。

您正在做的事情很不寻常,看起来它需要 OS X 使用的 Mach-O 对象格式不支持的重定位。问题不在于您试图将标签用作整数,而是您试图将标签用作 8 位整数。这在实践中不是很有用,编译器永远不会做的事情。

如果您真的只想将符号地址的低 8 位(或两个符号之间的差异)添加到 RAX 的低 8 位,您将使用标签作为 32 位整数优先。

例如,您可以先将其移动到另一个 32 位寄存器中:

    mov $do_mov_rdi_rax, %ecx
    add %cl, %al
...
    mov $(do_syscall - do_mov_rdi_rax), %ecx
    add %cl, %al

如果您没有可用的寄存器,那么您可以从内存中加载它:

    add indirect_do_mov_rdi_rax, %al
...
    add indirect_difference, %al

indirect_do_mov_rdi_rax:
    .long   do_mov_rdi_rax

indirect_difference:
    .long   do_syscall - do_mov_rdi_rax

如果真的不想使用 8 位算术,而是想使用地址的所有 64 位进行加法运算,那么您可以改用 64 位寄存器 RAX:

    add $do_mov_rdi_rax, %rax
...
    add $(do_syscall - do_mov_rdi_rax), %rax

由于标签不起作用,我仔细研究了 gas 文档,发现也可以创建表达式符号,并且可以使用 . 来获取位置的地址。事实证明,使用 Mach-O 输出格式,gas 将接受此格式:

.set main, .
    sub     edx, edx
    mov     dl, 0x82
    add     al, do_mov_rdi_rax - main
    sub     dword [rax], edx
    mov     dh, 0x82
    add     al, do_syscall - do_mov_rdi_rax
    sub     dword [rax], edx
    shr     edi, 31

.set do_mov_rdi_rax, .
    // mov  rsi, rax
    // (with 0x82 added to first byte to pass validation)
    .byte   0xca, 0x89, 0xc6
    sub     eax, eax

.set do_syscall, .
    // syscall
    // (with 0x82 added to both bytes to pass validation)
    .byte   0x91, 0x87

在第一次添加时,简单地使用 do_mov_rdi_rax 是行不通的,但是使用它与 main 之间的差异就可以完美地工作。 (然而,将 main 替换为文字零不会这样做。)

不过,它还有其他问题:似乎缺乏对 sub dword [rax], edx 的支持。在我的 Mac 上使用 gas 2.25,它得到 assembled 为 sub dword [rax+4], edx,这是非常错误的。 Xcode 附带的 as 版本拒绝 assemble 它,引用绝对 32 位寻址使用; Debian 的 gas 2.24.90 也拒绝 assemble 它,因为不知何故会有太多的内存引用。因为这都是不正确的,我将坚持使用 shellcode 的 nasm-assembled 二进制版本,而不是使用 pwnlib 的 asm 来编译它。