【发布时间】:2011-11-25 13:26:07
【问题描述】:
考虑以下代码,它采用函数 f(),将函数本身整个复制到缓冲区,修改其代码并运行更改后的函数。实际上,返回数字 22 的原始函数被克隆并修改为返回数字 42。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ENOUGH 1000
#define MAGICNUMBER 22
#define OTHERMAGICNUMBER 42
int f(void)
{
return MAGICNUMBER;
}
int main(void)
{
int i,k;
char buffer[ENOUGH];
/* Pointer to original function f */
int (*srcfptr)(void) = f;
/* Pointer to hold the manipulated function */
int (*dstfptr)(void) = (void*)buffer;
char* byte;
memcpy(dstfptr, srcfptr, ENOUGH);
/* Replace magic number inside the function with another */
for (i=0; i < ENOUGH; i++) {
byte = ((char*)dstfptr)+i;
if (*byte == MAGICNUMBER) {
*byte = OTHERMAGICNUMBER;
}
}
k = dstfptr();
/* Prints the other magic number */
printf("Hello %d!\n", k);
return 0;
}
现在的代码依赖于猜测函数是否适合 1000 字节的缓冲区。由于函数 f() 很可能比 1000 字节短很多,因此它也违反了规则,因为它向缓冲区复制了太多内容。
这将我们带到问题:有没有一种方法可以计算出 C 中任何给定函数的大小?一些方法包括查看中间链接器输出,并根据函数中的指令进行猜测,但这还不够。有什么办法可以确定吗?
请注意:它可以在我的系统上编译和工作,但并不完全符合标准,因为函数指针和 void* 之间的转换是不完全允许的:
$ gcc -Wall -ansi -pedantic fptr.c -o fptr
fptr.c: In function 'main':
fptr.c:21: warning: ISO C forbids initialization between function pointer and 'void *'
fptr.c:23: warning: ISO C forbids passing argument 1 of 'memcpy' between function pointer and 'void *'
/usr/include/string.h:44: note: expected 'void * __restrict__' but argument is of type 'int (*)(void)'
fptr.c:23: warning: ISO C forbids passing argument 2 of 'memcpy' between function pointer and 'void *'
/usr/include/string.h:44: note: expected 'const void * __restrict__' but argument is of type 'int (*)(void)'
fptr.c:26: warning: ISO C forbids conversion of function pointer to object pointer type
$ ./fptr
Hello 42!
$
请注意:在某些系统上,从可写内存执行是不可能的,这段代码会崩溃。它已经在 x86_64 架构上运行的 Linux 上使用 gcc 4.4.4 进行了测试。
【问题讨论】:
-
没有任何代码可以尝试这样的事情,甚至可以远程遵守标准。即使函数占用内存中的连续空间也无法保证。当然不能保证字节
MAGICNUMBER不会出现在不代表返回值的函数代码中,而是因为它恰好是某些操作码的一部分。 -
函数的代码不需要连续。也不要求编译器生成与位置无关的代码。 (大多数人不会。)
-
或者操作系统将允许您执行堆栈上的代码。
-
带有Harvard Architecture 的机器不会让您轻松地将函数指针转换为数据指针或以其他方式直接在 C 中读取/修改代码。
-
哈佛建筑相当过时,对语言律师来说是一种好奇心。不过,其他问题都是完全相关的。
标签: c