簡體   English   中英

C - 如何在代碼段中創建模式以在內存轉儲中識別它?

[英]C - How to create a pattern in code segment to recognize it in memory dump?

我轉儲我的RAM(它的一部分 - 僅代碼段),以便找到放置C函數的位置。 我沒有map文件,我不知道boot / init例程究竟是做什么的。

我將程序加載到RAM中,然后如果我轉儲RAM,很難找到確切的功能在哪里。 我想在C源代碼中使用不同的模式,以便在內存轉儲中識別它們。

我嘗試使用包含函數名稱的不同第一個變量來啟動每個函數,例如:

char this_function_name[]="main";

但它不起作用,因為此字符串將放在數據段中。

我有簡單的16位RISC CPU和實驗專有編譯器(沒有GCC或任何眾所周知的)。 系統具有16Mb的RAM,與其他應用程序共享(引導加載程序,下載程序)。 幾乎不可能找到一個獨特的N NOP或smth序列。 像0xABCD。 我想在RAM中找到所有函數,所以我需要在RAM-dump中可見的唯一函數標識符。

什么是代碼段的最佳模式?

如果是我,我會使用符號表,例如“nm a.out | grep main”。 獲取您想要的任何功能的真實地址。

如果你真的沒有符號表,那就自己做吧。

struct tab {
    void *addr;
    char name[100];  // For ease of searching, use an array.
} symtab[] = {
    { (void*)main, "main" },
    { (void*)otherfunc, "otherfunc" },
};

搜索名稱,地址將緊接在其之前。 轉到地址。 ;-)

如果您的編譯器具有內聯asm,則可以使用它來創建模式。 編寫一些NOP指令,您可以通過內存轉儲中的操作碼輕松識別這些指令:

MOV r0,r0
MOV r0,r0
MOV r0,r0
MOV r0,r0

數字常量放在代碼段中,在函數說明中編碼。 所以你可以嘗試使用魔術數字,如0xDEADBEEF等。

即這是使用Visual C ++的簡單C函數的反匯編視圖:

void foo(void)
{
00411380  push        ebp  
00411381  mov         ebp,esp 
00411383  sub         esp,0CCh 
00411389  push        ebx  
0041138A  push        esi  
0041138B  push        edi  
0041138C  lea         edi,[ebp-0CCh] 
00411392  mov         ecx,33h 
00411397  mov         eax,0CCCCCCCCh 
0041139C  rep stos    dword ptr es:[edi] 
    unsigned id = 0xDEADBEEF;
0041139E  mov         dword ptr [id],0DEADBEEFh 

您可以看到0xDEADBEEF使其成為函數的源代碼。 請注意,您在可執行文件中實際看到的內容取決於CPU的字節順序(tx.Richard)。

這是一個x86示例。 但RISC CPU(MIPS等)具有將指令移動到寄存器中的指令 - 這些指令也可以具有特殊的可識別值(盡管MIPS只有16位,IIRC)。


Psihodelia - 抓住你的意圖變得越來越難。 它只是您想要找到的單一功能嗎? 那么你不能一個接一個地放置5個NOP並尋找它們嗎? 你控制編譯器/匯編器/鏈接器/加載器嗎? 您可以使用哪些工具?

如你所說,這個:

char this_function_name[]="main";

...最終會將堆棧中的指針設置為包含該字符串的數據段。 但是,這個:

char this_function_name[]= { 'm', 'a', 'i', 'n' };

...可能會將所有這些字節放在您的堆棧中,這樣您就能夠識別代碼中的字符串(我只是在我的平台上嘗試過)。

希望這可以幫助

如何找到一個完全不同的方法來解決你的真正問題,即找到一個特定的代碼塊:使用diff。

使用所包含的函數編譯一次代碼,並將其注釋掉一次。 生成兩者的RAM轉儲。 然后,區分兩個轉儲以查看更改的內容 - 這將是新的代碼塊。 (您可能必須對轉儲進行某種處理以刪除內存地址以獲得干凈的差異,但在任何一種情況下,指令的順序應該相同。)

為什么不讓每個函數轉儲自己的地址。 像這樣的東西:

void* fnaddr( char* fname, void* addr )
{
    printf( "%s\t0x%p\n", fname, addr ) ;
    return addr ;
}


void test( void )
{
    static void* fnaddr_dummy = fnaddr( __FUNCTION__, test ) ;
}

int main (int argc, const char * argv[]) 
{
    static void* fnaddr_dummy = fnaddr( __FUNCTION__, main ) ;
    test() ;
    test() ;
}

通過使fnaddr_dummy為靜態,轉儲每個函數執行一次。 顯然,您需要調整fnaddr()以支持您在系統上的任何輸出或日志記錄方式。 不幸的是,如果系統執行延遲初始化,您將只獲得實際調用的函數的地址(這可能足夠好)。

您可以通過調用相同的虛函數來啟動每個函數,如:

void identifyFunction(unsigned int identifier){}

您的每個函數都會使用不同的參數(1,2,3,...)調用identifyFunction函數。 這不會給你一個神奇的mapfile,但是當你檢查代碼轉儲時,你應該能夠快速找到identifyFunction的位置,因為會有很多跳轉到該地址。 接下來掃描那些跳轉並在跳轉之前檢查以查看傳遞的參數。 然后你可以制作自己的mapfile。 使用一些腳本,這應該是相當自動的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM