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”的部分让我感到困惑。据我所知,他们从另一个随机指针地址中减去一个随机指针地址。

有人愿意解释吗?

4

2 回答 2

7

该代码依赖于编译器对函数布局的了解——这对于其他编译器可能不可靠。

func_len行,一旦更正以包含-最初丢失的,Demo通过从地址中减去地址_Demo(应该包含的起始地址Demo())来确定函数的长度_mainmain())。这被认为是函数的长度,Demo然后按字节复制到缓冲区buff中。然后将地址buff强制转换为函数指针,然后调用该函数。然而,由于既没有_Demo也没有_main实际初始化,代码是极端错误的。此外,还不清楚 anunsigned int是否足够大以准确地保存指针。演员应该是uintptr_t<stdint.h><inttypes.h>

如果错误已修复,如果关于代码布局的假设是正确的,如果代码是与位置无关的代码,并且如果没有针对执行数据空间的保护,则此方法有效。它不可靠,不便携,不推荐。但它确实说明,如果它有效,代码和数据非常相似。

我记得在两个进程之间进行了类似的特技,将一个程序中的一个函数复制到共享内存中,然后让另一个程序从共享内存中执行该函数。那是大约 25 年前的事了,但该技术是相似的,并且在它所试用的机器上“有效”。从那以后我就再也不需要使用这种技术了,谢天谢地!

于 2011-04-26T06:33:19.560 回答
5

此代码使用未初始化的变量_main_Demo,因此它通常无法工作。即使它们的含义不同,它们也可能假定内存中函数的某些特定顺序。

我的意见:不要相信这篇文章。

于 2011-04-26T06:24:19.503 回答