2017-05-06 16 views
0

我有一個鉤子函數執行內聯彙編:如何在調用內聯程序集中的函數時保留堆棧?

__declspec(naked) int hookConnect() 
{ 
    __asm 
    { 
     pushad; 
     pushfd; 

     push [esp + 0x2C]; 
     pop sockAddrBackup; 

     push[esp + 0x2C]; 
     push[esp + 0x2C]; 
     call mConnect; 

     popfd; 
     popad; 

     call connectTramp; 

     ret; 
    } 
} 

它保存寄存器和標誌。然後將其中一個參數保存到一個變量中,最後推送2個參數並調用剛剛記錄參數的自定義函數。

之後,它恢復寄存器,標誌。在這個時候,我想打電話給蹦牀:

蹦牀:

5 original bytes 
jmp (original func + 5 bytes) 

,其執行前5個字節,跳轉到原來的FUNC並執行它,然後返回到我的鉤子函數。

在這一點上,我想返回到原來的func的調用者,但由於函數完成時調用leave,它打破了堆棧?

我該如何通過執行來保留堆棧?在呼叫之前保存返回地址?

+2

你的代碼有'call',但你的描述有'jmp'。看起來'jmp'是正確的。另請注意,您必須複製完整的指令,而不是在5個字節後停止。有像MS Detours這樣的圖書館爲您提供所有這些服務。 –

+0

@BenVoigt我打給connectTramp;其中包含原始func的前5個字節,並跳轉到繼續執行原始func,因爲它是一個調用,它會返回。我不喜歡少走彎路:) –

+1

我不知道什麼「功能完成時請假」是指,但我發現你的問題。你的代碼中堆棧佈局被破壞是正確的。 –

回答

2

通過調用蹦牀,您將原始參數上方的另一個堆棧框架放置,這意味着它們不是原始代碼希望找到它們的位置(堆棧中有兩個返回地址,而不是一個)。

必須要麼

  1. 跳轉到蹦牀(鉤子將不能夠有一個尾聲)

  • 在調用蹦牀之前將原始參數複製到堆棧中,並在返回後將其清理乾淨,小心保留返回值。
  • +0

    注意:對原始函數的嵌套調用總是要求您執行堆棧清理,無論是調用約定中的調用者清除,在這種情況下,您負責刪除您創建的副本,或者說被調用者清理其中如果原始功能彈出了您複製的參數,但您必須清理原件。 –

    +0

    謝謝!這確實現在更有意義:)) –

    相關問題