2011-04-26 90 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,所以它通常無法工作。即使它們意味着不同的東西,它們可能會假定內存中某些特定的函數順序。

我的意見:不要相信這篇文章。