2011-04-26 87 views
5

我正在读的自修改代码一个密码破译期刊文章和有此代码段:自修改代码[C++]

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; 
} 

此代码理应在堆栈上演示()执行。我了解大部分代码,但他们分配'func_len'的部分让我感到困惑。据我所知,他们从另一个随机指针地址中减去一个随机指针地址。

有人在乎解释吗?

+1

你能链接到文章吗? – 2011-04-26 06:08:11

+3

发布的代码充满了错误。这个想法似乎是将机器代码从Demo复制到buff中,然后从那里执行,但假定操作码是可重定位的(这是一个危险的假设,可能需要一个用于位置独立代码的编译器标志)。 'fun_len'大概意味着'_main - _Demo',作为'Demo'函数大小的最大值。尽管如此,它还是在_Demo之前将它分配给Demo,所以它没有希望。它也有风险对齐问题,因为缓冲区可能不按照功能对齐。 – 2011-04-26 06:13:20

+1

我没有指向文章的链接,它是我电脑上的PDF文件。我将它上传到mediafire:http://www.mediafire.com/?8zslfj6fjsgcsxd – Gogeta70 2011-04-26 06:13:56

回答

7

该代码依赖于来自编译器的函数布局知识 - 这可能对其他编译器不可靠。

func_len线,一旦校正为包括最初缺少-,通过在_main减去_Demo从地址的地址(其被假定为包含的Demo()起始地址)确定功能Demo的长度(它应该包含main()的开始地址)。推测这是函数Demo的长度,然后将其按字节顺序复制到缓冲区buff中。然后将buff的地址强制为一个函数指针,然后调用该函数。但是,因为_Demo_main都没有实际初始化,所以代码在极端的情况下是很麻烦的。另外,还不清楚unsigned int是否足够大以准确地保存指针;演员可能应该从<stdint.h><inttypes.h>uintptr_t

如果错误是固定的,如果关于代码布局的假设是正确的,如果代码是位置无关的代码,并且没有对执行数据空间的保护,这是有效的。这是不可靠的,不可移植的,不推荐。但它确实说明了,如果它有效,代码和数据非常相似。

我记得在两个进程之间拉一个类似的特技,从一个程序拷贝一个函数到共享内存,然后让另一个程序从共享内存中执行那个函数。大约四分之一世纪前,这项技术与其试用过的机器类似并“有效”。我从来不需要使用这种技术,谢天谢地!

+0

没错。我明白代码的工作原理。我不明白的是为什么代码的原始作者是从另一个未初始化的指针中减去一个未初始化的指针。不过,代码的概念让我想到了我想要的地方。我现在有一个我自己写的例子。对于那些有兴趣的,这里是:http://friendpaste.com/2B2NA1UyI8TDn0wXXCXEGH – Gogeta70 2011-04-26 06:53:49

5

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

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