自修改代码[C++]

5
我正在阅读一篇密码分析专家的文章,涉及到自修改代码,其中有这段代码片段:
void Demo(int (*_printf) (const char *,...))
{ 
      _printf("Hello, OSIX!n"); 
      return; 
} 
int main(int argc, char* argv[]) 
{ 
  char buff[1000]; 
  int (*_printf) (const char *,...); 
  int (*_main) (int, char **); 
  void (*_Demo) (int (*) (const char *,...)); 
  _printf=printf; 
  int func_len = (unsigned int) _main ­- (unsigned int) _Demo; 
  for (int a=0; a<func_len; a++) 
    buff[a] = ((char *) _Demo)[a]; 
  _Demo = (void (*) (int (*) (const char *,...))) &buff[0]; 
  _Demo(_printf); 
  return 0; 
}

这段代码应该在堆栈上执行Demo()。我理解大部分代码,但是他们赋值'func_len'的部分让我困惑。据我所知,他们正在从另一个随机指针地址中减去一个随机指针地址。

有人能解释一下吗?


1
你能链接到这篇文章吗? - BlueRaja - Danny Pflughoeft
3
这段代码存在许多错误。看起来的想法是将 Demo 中的机器码复制到 buff 中,然后从 buff 中执行,但这假定操作码是可重定位的(这是一个危险的假设,可能需要编译器标志来生成位置无关代码)。"fun_len" 应该是指 "_main - _Demo",作为 "Demo" 函数大小的最大值。然而,它在将 "Demo" 分配到地址之前从 "_Demo" 复制,所以根本不行。它还有可能存在对齐问题,因为缓冲区可能与函数不一致。 - Tony Delroy
1
我没有文章的链接,它是我电脑上的PDF文件。我会上传到mediafire:http://www.mediafire.com/?8zslfj6fjsgcsxd - Gogeta70
2
抱歉直言,但是……写那段代码的人真的很蠢。简单明了地说,不要写这样的代码。 - asveikau
2个回答

8
该代码依赖于编译器对函数布局的了解,这可能在其他编译器中不可靠。
一旦更正了缺失的连字符,func_len行通过从_main(它应该包含main()的起始地址)的地址中减去_Demo(它应该包含Demo()的起始地址)的地址来确定函数Demo的长度。假定这是函数Demo的长度,然后将其逐字节复制到缓冲区buff中。将buff的地址强制转换为函数指针,然后调用该函数。但是,由于_Demo_main都没有初始化,因此该代码极其有缺陷。而且,不清楚无符号整数是否足够大以准确地保存指针;类型转换应该从<stdint.h><inttypes.h>进行到uintptr_t
如果修复了错误,如果对代码布局的假设正确,如果代码是位置无关代码,并且如果没有防止执行数据空间的保护,则此代码可以工作。它不可靠、不可移植,不推荐使用。但是,如果它起作用,它确实说明了代码和数据非常相似。
我记得在两个进程之间拉取类似的噱头,将一个程序中的函数复制到共享内存中,然后让另一个程序从共享内存中执行该函数。那是大约25年前的事了,但技术类似且对于尝试的机器“有效”。自那以后我从未需要使用这种技术,谢天谢地!

好的,我明白代码是如何工作的。我不明白的是为什么代码的原作者要将一个未初始化的指针减去另一个未初始化的指针。尽管如此,这段代码的概念让我达到了想要的目的。我现在有一个自己编写的可工作示例。对于那些感兴趣的人,这里是链接:http://friendpaste.com/2B2NA1UyI8TDn0wXXCXEGH - Gogeta70

5

这段代码使用了未初始化的变量_main_Demo,因此它通常无法正常工作。即使它们意味着不同的东西,也可能假定了函数在内存中的某些特定顺序。

我的观点是:不要相信这篇文章。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接