假设我想执行一条任意的mov指令。我可以编写以下函数(使用GCC内联汇编):
void mov_value_to_eax()
{
asm volatile("movl %0, %%eax"::"m"(function_parameter):"%eax");
// will move the value of the variable function_parameter to register eax
}
我可以制作这样的函数,它可以在每个可能的寄存器上工作。 我的意思是 -
void movl_value_to_ebx() { asm volatile("movl %0, %%ebx"::"m"(function_parameter):"%ebx"); }
void movl_value_to_ecx() { asm volatile("movl %0, %%ecx"::"m"(function_parameter):"%ecx"); }
...
以类似的方式,我可以编写将任意地址的存储器移动到特定寄存器中的函数,以及将特定寄存器移动到存储器中任意地址的函数。 (mov eax, [memory_address]
和mov [memory_address]
,eax)
现在,我可以随时执行这些基本指令,因此我可以创建其他指令。例如,要将寄存器移动到另一个寄存器:
function_parameter = 0x028FC;
mov_eax_to_memory(); // parameter is a pointer to some temporary memory address
mov_memory_to_ebx(); // same parameter
所以我可以解析汇编指令并根据它来决定使用哪些函数,如下所示:
if (sourceRegister == ECX) mov_ecx_to_memory();
if (sourceRegister == EAX) mov_eax_to_memory();
...
if (destRegister == EBX) mov_memory_to_ebx();
if (destRegister == EDX) mov_memory_to_edx();
...
如果它可以工作,它允许你执行任意mov指令。
另一种选择是创建一个要调用的函数列表,然后遍历列表并调用每个函数。也许它需要更多技巧来制作这样的等效指令。
所以我的问题是:是否有可能为所有(或某些)可能的操作码制作这样的东西?它可能需要很多函数来编写,但有可能创建一个解析器,它会根据给定的汇编指令以某种方式构建代码,而不是执行它,或者那是不可能的?
编辑:您无法更改内存保护或写入可执行内存位置。
答案 0 :(得分:3)
我真的不清楚你为什么问这个问题。首先,这个功能......
void mov_value_to_eax()
{
asm volatile("movl %0, %%eax"::"m"(function_parameter):"%eax");
// will move the value of the variable function_parameter to register eax
}
...使用GCC内联汇编,但函数本身不是内联的,这意味着将会有序言&包裹它的结尾代码,可能会影响你的预期结果。您可能希望使用GCC内联汇编函数(而不是包含GCC内联汇编的函数),这可能会让您更接近您想要的,但仍然存在问题......
好的,假设您为每个可能的x86操作码编写GCC内联汇编函数(至少是GCC汇编程序知道的操作码)。现在假设您希望以任意顺序调用这些函数来完成您可能希望完成的任何操作(考虑哪些操作码在第3环(或者您编码的任何环)中合法执行)。您的示例显示您使用C语句对逻辑进行编码,以确定是否调用内联汇编函数。猜猜看:那些C语句正在使用处理器寄存器(甚至可能是EAX!)来完成它们的任务。无论你想通过调用这些任意内联汇编函数来做什么,都会被编译器发出的逻辑汇编代码(if (...)
等)所踩踏。反之亦然:你的内联汇编函数任意指令正在踩踏编译器发出的指令期望不被踩踏的寄存器。结果不可能在没有崩溃的情况下运行。
如果你想在汇编代码中编写代码,我建议你只需在汇编代码中编写代码即可。使用GCC汇编程序来组装它。或者,您可以在asm()
语句中编写完整的C可调用汇编函数,并根据需要从C代码中调用它们。但是您编写的C可调用汇编函数需要在您正在使用的调用约定(ABI)的规则内操作:如果汇编函数使用被调用者保存的寄存器,则您的函数需要将原始值保存在该寄存器中(通常在堆栈上),然后在返回调用者之前恢复它。
答案 1 :(得分:1)
...好的,根据您的评论Because if it's working it can be a way to execute code if you can't write it to memory. (the OS may prevent it)
....
当然,您可以执行任意指令(只要它们对于您正在运行的任何响铃都是合法的)。 JIT怎么工作?您只需要调用OS系统调用来设置您的指令所在的内存页面的权限...将它们更改为“可执行文件”,然后调用'em!