[英]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.