编译汇编器操作码

pro*_*ner 0 assembly opcode

我想知道是否可以用等效的操作码替换汇编指令。(即能够编译操作码而不是指令)如果是这样,是否可以在运行时操作这些操作码?干杯

Ped*_*d7g 5

如果可以用等效的操作码替换汇编指令。

是的,您可以编译操作码,生成的机器代码将是相同的。

例如 x86-32 简短的无用汇​​编代码:

uselessFunc:
    xor  eax,eax
    ret
Run Code Online (Sandbox Code Playgroud)

也可以用操作码编写:

uselessFunc:
    db  0x31, 0xC0    ; opcode "xor eax,eax"
    db  0xC3          ; opcode "ret"
Run Code Online (Sandbox Code Playgroud)

两个来源都将产生相同的三个字节的机器代码:31 C0 C3.

是否可以在运行时操作这些操作码

这与来源的形式完全无关。在运行时,您可以操作任何具有写访问权限(理想情况下为读+写访问)的内存。但是在修改操作码之后,如果要运行它们,还需要执行对该内存的访问。

在具有现代操作系统(如 linux)的现代 x86 机器上,这不是默认配置,默认情况下,代码段是只读 + 可执行的,而数据段是读+写,但不可执行,因此如果您尝试修改代码的操作码,你会在写入期间因无效内存访问而崩溃,如果你试图在数据段中执行操作码,你会触发 no-exec 错误。

因此,像 Java VM 和类似的应用程序,它们在运行时生成代码,然后执行它(“JIT”即时编译器.class在运行时将文件中的 java 操作码编译为本机机器代码,以获得更好的性能。重复执行)不仅生成/修改操作码,还管理与其他系统调用的目标内存页,使它们首先可写,然后将它们更改为 no-read+exec 代码内存页。即通常这是可能的,但在许多目标环境中,您必须使用额外的系统服务才能使其正常工作。

请记住,自修改代码在现代被认为是不好的做法,不仅因为它更难调试,而且如果以天真的方式使用,它可能会产生巨大的性能影响(再次例如在 x86 CPU 上只修改很少的操作码执行前的字节将使 CPU 中所有可能的缓存/预取行无效,使其暂停一段时间以重新读取/解码指令)。并且在某些 CPU 上,内存/缓存模型比在 x86 上弱,因此过晚修改操作码可能会被 CPU 忽略,因为它已经对旧内容进行了解码并将执行该内容。

但是只要您知道自己在做什么,就可以生成/修改操作码。它只是不以任何方式取决于源代码的形式,无论您如何生成原始二进制文件,无论您是使用汇编还是 C 语言源代码编写这些操作码,还是将它们直接作为字节值在六进制编辑器中编写。

使用上面的两个示例,在这两种情况下,您都可以执行以下操作:

mov   byte [uselessFunc+1],0xD8 ; modify xor eax,eax to xor eax,ebx
Run Code Online (Sandbox Code Playgroud)

如果你会得到的目标内存区域的写访问,并能持续执行的权利,那么这将转xor eax,eaxxor eax,ebx在两种情况下。