摘要
最近在使用vs2010編寫shellcode的時候,在將編寫好的shellcode保存為二進制格式的。那么引出一個問題,我剛開始的時候直接: 取地址符 + 函數名 的方式來獲取函數的首地址。當時在使用shellcode的時候,程序一直崩潰,經過分析發現shellcode前面的一些代碼並不是我們所需要的代碼,而是一條jmp指令+一系列的CC指令,再經過對原本編寫shellcode的程序進行逆向,對比分析后得出結論:&取地址符 獲取的函數地址並非真正的起始地址。
分析過程
下面我將會使用一個最簡單的例子來記錄和說明。
環境:win7 64位操作系統 + vs2010.
代碼如下:
void function(){ MessageBox(0, "", "", 0); return ; } int main(){ void *p = (void *)&function; printf("function的Ì?地Ì?址¡¤:êo%x", p); getchar(); return 0; } |
打開od對我們生成的程序, 定位到main函數:
當執行完:lea rax, qword ptr ds:[function]這條匯編指令(相當於執行完:void *p = (void *)&function;)后,此時rax = 0x000000013F7F100A。
接下來我們在定位到rax執向的地址:000000013F7F100A。
可以看出,rax指向的是一條跳轉指令的地址,並非是function函數的真正執行地址。
獲取函數真正地址
那么問題來了,我們要怎么獲取我們需要的函數的真正的地址呢?我們進行進一步的分析。首先明確跳轉指令jmp是由:E9 + 4字節的偏移(相對本條指令結束),那么接下來我們就可以很容易地確定函數的真正執行地址了。其代碼如下:
void *p = (void *)&function; int offset = *(unsigned int *)((char*)p + 1); void *rfadr = (void*)((char*)p + 5 + offset); |
其結果如下:
運行完 lea rax,qword ptr ds:[rcx+rax+5] | ;rax:function 這條指令后,rax = 0x000000013F501020,我們轉移到rax指向的地址:
這次獲取的地址是我們真正想要的函數地址。
總結
經過對這個小例子的分析,我不僅僅知道了所謂的對函數名取地址的操作並非直接獲取函數的真正的起始地址,更是讓我在從發現shellcode執行崩潰,到逆向分析shellcode,再到找出、確認問題產生的原因,最后到給出真正的解決方法,這整個過程中收獲良多。
2018-04-04 21:02:02