此问题已在此处有答案:
How to write self-modifying code in x86 assembly(7个回答)
6年前关闭。
有没有办法把处理器指令放入数组,使其内存段可执行,并作为一个简单的函数运行:
int main()
{
char myarr[13] = {0x90, 0xc3};
(void (*)()) myfunc = (void (*)()) myarr;
myfunc();
return 0;
}
此问题已在此处有答案:
How to write self-modifying code in x86 assembly(7个回答)
6年前关闭。
有没有办法把处理器指令放入数组,使其内存段可执行,并作为一个简单的函数运行:
int main()
{
char myarr[13] = {0x90, 0xc3};
(void (*)()) myfunc = (void (*)()) myarr;
myfunc();
return 0;
}
3条答案
按热度按时间eh57zj3b1#
在Unix上(现在,这意味着“除了Windows和一些你可能从未听说过的嵌入式和大型机之外的所有东西”),你可以通过使用
mmap
分配一整张页面,将代码写入其中,然后使用mprotect
使它们可执行。您可能会看到,此代码与cherrydt's answer中显示的Windows代码非常相似。只有系统调用的名称和参数不同。
在处理这样的代码时,重要的是要知道,许多现代操作系统不允许您拥有一页RAM,同时可写和可执行。如果我在调用
mmap
或mprotect
时写入PROT_READ|PROT_WRITE|PROT_EXEC
,则会失败。这被称为W^X policy;首字母缩略词代表写入异或执行。它是originates with OpenBSD,其想法是使缓冲区溢出漏洞更难将代码写入RAM并执行。(这仍然是可能的,漏洞只需要find a way to make an appropriate call tomprotect
first。)093gszye2#
这取决于平台。
对于Windows,您可以使用以下代码:
这段代码假设一个
myarr
数组,就像你的问题的代码一样,它假设sizeof
将在它上面工作。即,它具有直接定义的大小,并且不仅仅是从别处传递的指针。如果是后者,则必须以另一种方式指定大小。请注意,这里有两种可能的“简化”,以防你想知道,但我建议不要这样做:
1.您可以使用
PAGE_EXECUTE_READWRITE
调用VirtualAlloc
,但这通常是不好的做法,因为它会为不必要的代码执行打开攻击向量。1.你可以直接在
&myarr
上调用VirtualProtect
,但这只会使内存中的一个随机页面可执行,而这个页面恰好包含你的数组可执行,这比#1更糟糕,因为这个页面中可能还有其他数据,现在突然也可执行了。对于Linux,我在Google上找到了this,但我对它了解不多。
qkf9rpyu3#
非常依赖操作系统:不是所有的操作系统都会故意(阅读:没有bug)允许您执行数据段中的代码。DOS会因为它运行在真实的模式下,Linux也可以拥有相应的特权.我不知道Windows。
铸造往往是未定义的,并有自己的警告,所以一些详细的主题在这里。根据C11标准草案N1570,§J.5.7/1:
指向对象或
void
的指针可以转换为指向函数的指针,允许数据作为函数调用(6.5.4)。(格式已添加。)
所以,它非常好,应该像预期的那样工作。当然,你需要遵守ABI的电话会议。