我想知道是否有可能用等效的操作码替换汇编程序指令。 (即能够编译操作码而不是指令) 如果是这样,是否可以在运行时操作这些操作码? 干杯
答案 0 :(得分:4)
如果可以用等效的操作码替换汇编指令。
是的,您可以编译操作码,生成的机器代码将完全相同。
例如x86-32短无用的汇编代码:
uselessFunc:
xor eax,eax
ret
也可以用操作码编写:
uselessFunc:
db 0x31, 0xC0 ; opcode "xor eax,eax"
db 0xC3 ; opcode "ret"
两个来源都会生成相同的三个字节的机器代码:31 C0 C3
。
是否可以在运行时操作这些操作码
这与源的形式完全无关。在运行时,您可以操作您具有写访问权限的任何内存(理想情况下是读取/写入访问)。但是在修改操作码之后,如果要运行它们,还需要执行对该内存的访问。
在具有现代操作系统(如linux)的现代x86机器上,这不是默认配置,默认情况下代码段是只读+可执行文件,数据段是读取+写入,但不可执行,因此如果您尝试修改操作码如果您的代码在写入期间无效的内存访问会崩溃,如果您尝试在数据段中执行操作码,则会触发no-exec错误。
Java VM等类似的应用程序,它们在运行时生成代码,然后执行它(“JIT”实时编译器在运行时将.class
文件中的java操作码编译为本机机器代码为了重复执行的部分获得更好的性能)不仅要生成/修改操作码,还要管理目标内存页面以及其他系统调用,使它们首先可写,然后将它们更改为no-read + exec代码内存页面。即通常它是可能的,但在许多目标环境中,您必须使用其他系统服务才能使其正常工作。
请记住,自修改代码在现代时代被认为是不好的做法,不仅因为它更难调试,而且如果以天真的方式使用,它可能会产生巨大的性能影响(例如,再次修改x86 CPU)在执行之前只有几个字节的操作码将使CPU中所有可能的高速缓存/预取行失效,使其在重新读取/解码指令时暂停。在某些CPU上,内存/缓存模型比在x86上弱,因此CPU可能会忽略太晚修改操作码,因为它已经解码了旧内容并将执行该操作。
但只要您知道自己在做什么,就可以生成/修改操作码。它只是不依赖于你的源代码形式,无论你是如何产生原始二进制文件,无论你是用汇编语言或C语言源编写那些操作码,还是直接将它们作为字节值写入hexa编辑器。
通过以上两个例子,在这两种情况下都可以:
mov byte [uselessFunc+1],0xD8 ; modify xor eax,eax to xor eax,ebx
如果您将获得对目标内存区域的写入权限,并且它将保留可执行权限,则在这两种情况下都会将xor eax,eax
变为xor eax,ebx
。