c - C中的一种自修改程序

标签 c heap-memory machine-code

<分区>

是否可以编写执行以下操作的 C 函数?

  1. 在堆中分配一堆内存
  2. 在里面写机器码
  3. 执行那些机器指令

当然,我必须将堆栈的状态恢复到手动执行这些机器指令之前的状态,但我首先想知道这是否可行。

最佳答案

这当然可能。出于各种原因,在过去的 30 到 40 年里,我们付出了很多努力,试图让它变得尽可能困难,但这是可能的。现在在大多数系统中,都有试图保护数据空间不被执行的硬件和软件机制。

不过,基础知识相当简单:您构造一段代码,然后手动或通过编译器对其进行汇编。然后你需要一段代码空间,所以你将代码插入到你的程序中

unsigned int prgm[] = { 0x0F, 0xAB, 0x9A ... };  // Random numbers, just as an example

因为你想使用你需要分配空间

void * myspace ;
if((myspace= malloc(sizeof(prgm))) != NULL) {
     memcpy(myspace, pgrm, sizeof(pgrm));
} else { // allocation error
}

现在,您需要一种方法让程序计数器 指向也是您的代码块的数据 block 。这是你需要一点技巧的地方。设置程序计数器没什么大不了的;这只是您的底层机器的 JUMP 指令。但是该怎么做呢?

最简单的方法之一是有目的地弄乱堆栈。从概念上讲,堆栈看起来像这样(详细信息取决于您的操作系统和编译器对,以及您的硬件):

    | subroutine return addr |
    | parameters ...         |
    | automatic variables    |

The basic trick here is to sneakily get the address of your code into the return address; when a routine returns, it basically jumps to that return addrfess. If you can fake it out, the PC will be set to where you like.

So, what you need is a routine, let's call it "goThere()"

void goThere(void * addr){
    int a ;     // observe above; this is the first space 
                // on the stack following the parameters
    int * pa;   // so we use it's address

    pa = (&a - (sizeof(int)+(2*sizeof(void*))) ;  // so use the address
                // but back up by the size of an int, the pointer on the
                // stack, and the return address
    // Now 'pa' points to the routine's return add on the stack.
    *pa = addr; // sneak the address of the new code into return addr
    return ;    // and return, tricking it into "returning"
                // to the address of your special code block
}

它会起作用吗?好吧,也许吧,这取决于硬件和操作系统。大多数现代操作系统都会保护堆(通过内存映射或类似方式),防止 PC 进入堆。出于安全目的,这很有用,因为我们不会让您进行这种完全控制。

关于c - C中的一种自修改程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/408592/

相关文章:

c - 错误: control reaches end of non-void function:(

c - C 中的 pthreads - pthread_exit

c - LS |用 C 语言编写的 shell 中的 grep

C Lang - 结构数组和段错误(核心转储)

java - Java内存泄漏是否总是出现在旧代消耗中?

Java 堆转储(hprof 文件)比常驻内存小得多

c - 从 C 生成机器代码

java - 从HDFS传输文件与将文件复制到本地磁盘

c++ - 与调用函数相比,goto 语句是否有效?

php - 机器码和操作码有什么区别?