【问题标题】:x86 / x64 Using a relative jump to return from a subroutinex86 / x64 使用相对跳转从子程序返回
【发布时间】:2019-08-06 05:01:26
【问题描述】:

我需要编写一些程序集,将其写入另一个进程的地址空间(已经在运行)。

基本上我想要做的是每次调用这个程序集时,它会将堆栈中的值与预定义的值进行比较,然后如果它与预定义的值匹配,我想调用一个指针将很难的函数编码到程序集中,如果没有,我希望程序集基本上什么都不做,所以返回。

到目前为止,我有以下内容(只是为了简单起见,只发布 x86 的 sn-p)

mov eax, [esp+0x04] ; this is the value from the stack
cmp eax, 0x01 ; this is the predefined value I am comparing to

如上所述,如果在这种情况下,eax 中的值与 0x01 匹配,我希望它跳转到一个函数(预定义指针,因此可以硬编码到程序集中),否则我希望子例程返回。问题是我不知道如何在不使用标签的情况下执行此操作,我不相信我将能够使用它,因为这将在另一个进程的上下文中执行,因此地址不会从 0 开始(对于我将要调用的程序集。)

我听说你可以做一个相对跳跃,但我在实现这些方面遇到了麻烦。

有人可以告诉我如何使用相对跳转或其他方法来实现这一点吗?

【问题讨论】:

  • 基本上是Write a jump command to a x86-64 binary file 的副本,它显示了相对跳转的编码方式。您需要知道源目标地址,或者至少是相对位移。仅知道绝对目标是没有用的(或者您必须使用效率较低的跳过 mov eax, imm32/jmp eax
  • 如何确定要跳转的地址?如果你知道地址,你可以将它加载到 eax 并执行“jmp eax”。
  • @prl:似乎效率低下。您将其注入到一个已经运行的进程中,因此在复制它时,您肯定有可用的源地址和目标地址。例如使用db 0x0f, 0x84branch_offset: dd 0 编码一个带有相对位移标签的jz rel32,并在注入时更新位移。 (How does $ work in NASM, exactly? 展示了更多关于手动编码相关分支的信息)。

标签: assembly x86 x86-64


【解决方案1】:

您将其注入到一个已经运行的进程中,因此您在复制它时肯定有可用的源地址和目标地址。

x86 条件分支可用 32 位 rel32 位移,相对于分支指令的 end。即,如果分支条件为真,它们会在通常设置 RIP = 该指令结束后执行RIP += rel32

jz rel32 是对另一个函数进行有条件的尾调用或执行ret 指令的好方法。

有关操作码,请参阅https://www.felixcloutier.com/x86/jccHow does $ work in NASM, exactly? 有一个手动编码 call rel32 的示例,以及生成的机器码。

另请Write a jump command to a x86-64 binary file 获取有关分支编码的另一个问答。

    mov   eax, [esp+0x04]
    cmp   eax, 1

    db 0x0f, 0x84      ; opcode for je rel32
branch_offset: dd 0    ; the rel32 itself

    ; fall-through path
    ret

在你把它组装成机器代码之后,一旦你知道目标进程中的源地址和目标地址,你应该编写代码来修改那个 dword (aka int32_t) 0。 0 只是一个占位符。

je +0 将直接转到下一条指令,无论 ZF 是否设置。)

或者,如果您知道源地址和目标地址,您可以让 YASM 在汇编时为您计算:

    bits 64
    org  0x12345             ; this block of code will start at this address

    cmp  dword [rsp+4], 1
    je   0x123456
    ret

将其组装成一个平面二进制文件给我们:

$ yasm -f bin -l /dev/stdout jz.asm
     1                                 %line 1+1 jz.asm
     2                                 [bits 64]
     3                                 [org 0x12345]
     4                                 
     5 00000000 837C240401              cmp dword [rsp+4], 1
     6 00000005 0F84FD101100            je 0x123456
     7 0000000B C3                      ret
     8                                 
     9 0000000C B854230100              mov eax, $

ORG 指令似乎不适用于 NASM,只能用于 YASM。我不知道为什么。

mov 指令用于查看汇编程序认为其汇编的地址。使用 NASM,我们得到 B8[0C000000] 而不是预期的 54 23 01 00 作为 mov 指令的立即数(它自己的地址)。


如果您提前知道相对位移 / 作为汇编时常数(但不是绝对地址),那也没关系。

在 NASM 语法中,je +0x555555 组装成 0F 84 55 55 55 00

但不是在 YASM 中:在 YASM 中 +0x555555 只是绝对地址 0x555555 作为分支目标。


相关:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-26
    • 2023-03-30
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    相关资源
    最近更新 更多