繁体   English   中英

如果 x86 jmp 跳转到其他两个连续有效地址之间的地址会发生什么?

[英]What happens if x86 jmp jumps to an address between two other consecutive valid ones?

在 x86 程序集的例程中,如果代码包含指向两个有效地址之间的有效地址的跳转,会发生什么情况? 这是一个人工示例:

0x0001: mov ...
0x0005: add ... 
0x0009: jmp 0x0003

此外,我如何在本地机器或在线上进行类似的实验? 我检查了在线 x86 编辑器,如https://defuse.ca/online-x86-assembler.htm#disassembly ,但它不允许我放置像“0x0001”这样的指令地址。

没有“有效”或“无效”地址之类的东西。 每个地址都可以跳转到,如果对应的页面被映射,则执行。

那么当你在指令之间跳转时会发生什么? 好吧,处理器不知道您打算从哪里开始和结束指令。 它只是执行它看到的字节。 此代码将与您期望的不同,因为 CPU 尝试将其他指令的中间部分解析为操作码。

您的具体示例不足以让我说出指令的结果。 也许您可以提供一个完整的示例(包括机器代码),以便我可以给出更好的解释。

CPU 将在目标地址处开始解码指令。

您在反汇编中看到的指令流(当使用像objdump这样的工具时)只是对程序可执行字节的一种解释,假设给定的起点。

碰巧“跳到指令的中间”是一种混淆技术,有时被恶意软件用来隐藏线性扫描反汇编程序(如objdump )的程序语义。 更复杂的反汇编程序将尝试跟随这些“未对齐”的跳转,但这可能是不可能的,这取决于静态/动态确定什么可以/不能确定。

Linn 和 Debray的论文“对可执行代码进行混淆以提高对静态反汇编的抵抗力”更详细地讨论了这一点。

请参阅第 3.2 节“垃圾插入”。 您描述的场景是他们所说的“部分或完全重叠指令”,即对字节流的不同解释可以为重叠地址范围提供不同的汇编指令。

我最近在 codegolf 的“在 x86/x64 机器代码中打高尔夫球的技巧”中添加了一个关于跳过指令的技巧。 您会发现这些是有意应用到先前指令的一部分。 而且不仅仅是为了混淆。 这是该答案的全文:

跳过指令

跳过指令是与一个或多个后续操作码组合的操作码片段。 后续操作码可用于与前置跳过指令不同的入口点。 使用跳过指令代替无条件短跳转可以节省代码空间,速度更快,并设置诸如NC (无进位)之类的附带状态。

我的示例都是针对 16 位实/虚拟 86 模式的,但是这些技术中有很多可以类似地用于 16 位保护模式,或者 32 位或 64 位模式。

引用我的 ACEGALS 指南

11:跳过指令

常量 __TEST_IMM8、__TEST_IMM16 和 __TEST_OFS16_IMM8 被定义为这些指令的相应字节串。 它们可用于跳过适合以下 1、2 或 3 个字节的后续指令。 但是,请注意,它们修改了标志寄存器,包括始终设置 NC。 16 位偏移量加 16 位立即测试指令不包括在这些用途中,因为它可能访问段中偏移量 0FFFFh 处的字。 此外,所提供的 __TEST_OFS16_IMM8 应仅用于 86M,以避免访问超出段限制的数据。 在使用这些常量之一的 db 指令之后,应在括号中列出跳过的指令。

86 模式在 lmacros1.mac 323cc150061e (2021-08-29 21:45:54 +0200) 中定义

%define __TEST_IMM8 0A8h                        ; changes flags, NC
%define __TEST_IMM16 0A9h                       ; changes flags, NC
                                        ; Longer NOPs require two bytes, like a short jump does.
                                        ; However they execute faster than unconditional jumps.
                                        ; This one reads random data in the stack segment.
                                        ;  (Search for better ones.)
%define __TEST_OFS16_IMM8 0F6h,86h              ; changes flags, NC

16 位模式下的0F6h,86h操作码为test byte [bp + disp16], imm8指令。 我相信我实际上并没有在任何地方使用这个。 (实际上,堆栈内存访问实际上可能比无条件短跳转慢。)

0A8htest al, imm8在任何模式下的操作码。 0A9h操作码在 32 位和 64 位模式下更改为test eax, imm32形式的指令。

ldosboot boot32.asm 07f4ba0ef8cd (2021-09-10 22:45:32 +0200) 中的两个用例:

首先,为一个公共函数链接两个不同的入口点,这两个入口点都需要初始化一个字节大小的寄存器。 mov al, X指令各占 2 个字节,因此可以使用__TEST_IMM16跳过一个这样的指令。 (如果有两个以上的入口点,则可以重复此模式。)

error_fsiboot:
        mov al,'I'

        db __TEST_IMM16 ; (skip mov)
read_sector.err:
        mov al, 'R'     ; Disk 'R'ead error

error:

其次,某个入口点需要两个字节的额外拆卸,但可以与后续代码部分的失败案例共享。

                mov bx, [VAR(para_per_sector)]
                sub word [VAR(paras_left)], bx
                jbe @F          ; read enough -->

                loop @BB
                pop bx
                pop cx

                call clust_next
                jnc next_load_cluster
                inc ax
                inc ax
                test al, 8      ; set in 0FFF_FFF8h--0FFF_FFFFh,
                                ;  clear in 0, 1, and 0FFF_FFF7h
                jz fsiboot_error_badchain
                db __TEST_IMM16
@@:
                pop bx
                pop cx
                call check_enough
                jmp near word [VAR(fsiboot_table.success)]

这是inicomp lz4.asm 4d568330924c (2021-09-03 16:59:42 +0200)中的一个用例,我们依赖于test al, X指令清除进位标志:

.success:
        db __TEST_IMM8                  ; (NC)
.error:
        stc
        retn

最后,这里是DOSLFN Version 0.41c (11/2012) 中一个非常相似的跳过指令的用法 他们使用mov cx, imm16而不是test ax, imm16 mov cx, imm16状态标志没有影响,但会破坏cx寄存器。 (操作码0B9h在非 16 位模式下是mov ecx, imm32 ,并写入完整的ecxrcx寄存器。)

;THROW-Geschichten... [english: THROW stories...]
SetErr18:
        mov     al,18
        db      0B9h            ;mov cx,nnnn
SetErr5:
        mov     al,5
        db      0B9h            ;mov cx,nnnn
SetErr3:
        mov     al,3
        db      0B9h            ;mov cx,nnnn
SetErr2:
        mov     al,2
SetError:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM