假设如下代码:
int f1(int x, int y);
int main(void) {
printf("%d", f1(2,3));
char* x = (char*)&f1;
//edit the stuff here?
printf("%d", f1(2,3));
return 0;
}
int f1(int x, int y){
return x*y;
}
现在,尽管事实上这真的很愚蠢而且您永远不会实际上这样做,但您会怎么做呢?如果我想让这个函数将两个数字相加,而不是相减,或者甚至做一些更复杂的事情,我应该采取什么步骤?我如何找出正确的机器代码以获得所需的结果?
最佳答案
虽然这并非不可能,但通常是不切实际的,因为存在重大障碍,包括:
- 包含机器指令的内存通常标记为不可写,因此您必须先更改保护设置才能更改。 (在 Unix 系统上,查看
mprotect
。) - 需要进行的更改取决于架构——每个处理器架构都有自己的指令和这些指令的编码。您必须弄清楚要编写哪些新指令以及如何对它们进行编码。
- 有一种广泛使用的软件可以对指令进行编码,即汇编程序。要即时将指令转换为编码,可以在程序中嵌入汇编器或在另一个进程中调用汇编器。然后就是如何从汇编程序的输出(目标文件)中提取指令的问题。汇编程序也可以以普通方式用于准备给定的指令序列,而不是在正在运行的程序中即时使用。
- 刚被汇编程序编码后的指令通常以中间形式表示,其中对内存中特定位置的引用要么是符号性的,要么是相对于某些引用点的。在将它们放入正在运行的程序之前,必须将这些引用解析为程序中的实际地址。
- 一旦您知道要在函数中替换哪些指令,就会出现这样的问题,即它们可能比要替换的指令大,所以它们不适合。然后您需要一个解决方法,例如为您的指令找到一个替代位置,而不是将您的指令放在函数中,而是放入一条跳转到您的指令的小指令。请注意,您用于指令的内存必须标记为可执行。
- 更改主内存后,指令缓存可能保存指令的旧副本,因此您需要刷新指令缓存。
从减法到加法的简单更改可以通过找到相关的减法指令、更改内存保护、在减法上写入加法指令以及刷新指令缓存来完成。除此之外的任何事情都会更加复杂。
关于C:转换函数指针以编辑可执行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54891800/