2012-05-30 16 views
0

我在這裏工作的二進制混淆,所以得到了一個充滿操作碼的緩衝區,並且我使用的是linux,因此,所有的函數調用都使用相同的調用者/被調用者的約定並且沒有問題這裏。x86 E8和FF調用,如何找到E8移位地址?基本的x86 ASM調用

我的問題是關於E8操作碼,這個操作碼接近使用相對地址的呼叫。

我的問題是:我知道調用來自地址,我知道我要調用的地址,所以,我怎麼能找到我必須把在E8呼叫轉移地址?這就是:

signed long src = (signed long)buffer + shift; //get the position where E8 instruction is 
signed long dst = (signed long)srand;   //get the destination position where i want to call (yes, srand(long) function in this case.) 

所以在我的緩衝層i有:

buffer[] = "[....]\xE8\xFF\xFA\xFE\x54[.....]"; //example 

,我需要一個有效的指針函數srand更換,我怎樣才能從我的相對地址?

我只是認爲我可以使用FF指令直接調用,但我無法弄清楚如何做到這一點。我不能將地址複製到(比如說)$ eax,因爲我無法在替換中放置更多的操作碼(它將使所有jmp呼叫都變成香蕉),並且我不明白是否有辦法使直接撥打5個字節。

所以如果有人知道如何獲得正確的值來取代E8相對移位地址,或者是否有辦法使某種直接調用保持與E8調用相同的功能屬性並只使用5個字節.. (之前問,我試圖把FF XX XX XX XX作爲XX是真正的地址,它沒有工作,x86不看起來像一個電話,它解釋爲INC(???)以及一些隨機的事情後,我試圖以這種方式取代。

inline void endian_swap(long& x) { 
     x = (x>>24) | 
      ((x<<8) & 0x00FF0000) | 
      ((x>>8) & 0x0000FF00) | 
      (x<<24); 
} 

endian_swap(dst); 
endian_swap(src); 
unsigned int p = dst - src; 
endian_swap(p); 

,並把我發現E8呼叫地址它沒有反正工作

012。

坦克的注意。

+0

「FF」操作碼的解釋取決於modR/M字節的位5,4,3。 000 = INC,001 = DEC,010 = 011 = CALL,100 = 101 = JMP,110 = PUSH,111 =非法。請參閱http://pdos.csail.mit.edu/6.828/2008/readings/i386/appa.htm。 –

+1

你的'endian_swap'函數是錯誤的(應該在無符號類型上工作,在簽名類型上的轉換工作方式不同)。無論如何,我不明白你爲什麼需要它。 – interjay

+0

無論如何,endian交換是什麼? – harold

回答

1

我解決了它這樣做:

long dst = (long)srand; 
long src = ((long)buffer) + shift + 5; //begin of buffer + actual position + this instruction size 
long p = dst - src; 
p = htonl(p); 

比我更換緩衝呼叫,一切正常。坦克都向我表明,我正在做錯誤的轉換,以獲得幫助。

1

near calljxx/near jmp指令的相對地址等於要控制轉移減去立即您calljump指令的下一條指令的地址的目標地址。相對地址是相對於下一條指令的地址,而不是傳送控制的地址。 IOW,如果其地址操作數是相對的,則必須考慮您的指令長度calljump

一般來說,沒有與calljump指令等效的5個字節或更短的指令。

可以模擬jmppush target address + ret,但在32位模式與任意目標地址,即可獲得這些2個指令中的至少1 + 4 + 1 = 6個字節。您可以用相同的方法模擬call,但是您需要添加另一個pushcall指令將返回地址放在堆棧上。所以,對於這6個字節,你再添加5個字節。

還有一個「絕對」版本的「jmp」(以及IIRC「調用」),它將地址操作數當作由目標偏移量和目標段組成的立即數。這樣的指令長度至少爲1 + 4 + 2 = 7個字節(偏移量爲4個字節,段選擇器爲2個字節)。

如果使用的calljmp的變體,其從指定的內存位置開出目標地址(例如call [ebx]),該指令將是至少1 + 1 = 2個字節長(操作碼+ MODR/M字節),但是你必須使用包含目標地址的那個內存位置的地址加載一個寄存器,這會花費你一些其他的1 + 4 = 5個字節,給你至少7個字節。還有一個變種允許你在一個寄存器中指定目標地址(例如jmp ebx),但是由於必須加載寄存器,你至少需要7個字節。

,你可以讓你的call/jump指令更短的唯一方法是在目標地址非常接近該指令的地址(在這種情況下,你可以使用一個rel16形式(用適當的操作數或地址(我不記得哪一個)覆蓋前綴)或者rel8表格(如果可用)或者當目標地址很小時(在這種情況下,push target address可以是較短的push Ib或較短的operand size prefix + push Iw)。