2014-09-01 83 views
0

我嘗試掛鉤某些函數,如果x86上有__stdcall或__cdecl,則無關緊要。ASM - 在「函數調用」期間修改寄存器

我想要做以下的事情:
1.保留堆棧
2.保留德註冊
3.執行我的東西
4.恢復寄存器
5.恢復堆棧

我沒有堆棧問題,但是我的註冊備份存在一些問題:我無法修改其中的一些備份寄存器(我無法使用堆棧,因爲我無法以這種方式備份堆棧)!

我可以將它們備份在堆上(我使用一些.EAX,.EBX等成員的結構),我從ASM訪問該結構,這是問題...我必須修改一些註冊表就可以做到這一點!

但是,這是我的故事。我真正想要了解的是對以下問題的回答:

是否存在關於可以修改的寄存器以及在函數調用期間未修改的寄存器的任何「規則」?

我用調試器檢查了一些函數調用。我在「調用SomeFunction」處添加一個斷點,按F8鍵「跳過函數調用」並檢查修改的寄存器。我可以看到類似這樣的東西: 1.根據調用約定(cdecl vs stdcall)可以修改ESP/EBP 2. EAX,EBX,EDX - 幾乎總是被修改! 3. EBX,EDI,ESI似乎總是保留下來!

因此,我的「僞解決方案」:如果我只保留那些寄存器(EBX,EDI,ESI),那麼可以嗎?我不會搞亂堆棧,所以EBP和ESP不是問題。但我必須修改一些寄存器(EAX,ECX,EDX)。

我對某些編譯器優化有任何問題嗎?是否有可能通過修改那些「無辜」寄存器來搞亂代碼:EAX,ECX,EDX?

謝謝

+0

保留堆棧是什麼意思?你並沒有真正保留它,只是在完成後恢復SP。 – Andrey 2014-09-01 12:39:21

+0

是的,我不修改EBP,我修改但恢復ESP。這個問題比我描述的更復雜。我只需要知道是否可以只保留那些寄存器:EBX,EDI,ESI。 – Ionut 2014-09-01 12:49:20

+0

@lonut你必須保存所有寄存器。但我不明白你的問題,這聽起來很瑣碎。 – Andrey 2014-09-01 12:53:20

回答

0

目前還不清楚爲什麼你需要比來保存這些寄存器標準技術的任何其他。通常的方案是:

; call site: push args into stack, move to registers as required for callee 
      push arg1 
      push arg2 
      mov reg, arg3 
      call subroutine 
      lea esp, sizeof(arg1)+sizeof(arg2)[esp] ; pop arg1 and arg2 
      ... 

    subroutine: 
      push ebp 

      push reg1  ; save the registers that subroutine is documented to preserve 
      ... 
      push regn  ; if you insist, save *all* the registers 
      mov ebp, esp ; now ebp points to stacked args/saved registers no matter what you do next 
      ; note: we have not saved the ESP, but we do know how much we pushed on ESP 
      ... 
      body of subroutine, move ESP up and down 
      ... 
    subroutine_exit: 
      mov esp, ebp ; now points to saved registers 
      pop regn 
      ... 
      pop reg1 
      pop ebp 
      ret 
+0

我假設他正在做一個通用鉤子,不知道參數佔用了多少空間。 – Jester 2014-09-01 13:27:41

+0

我的代碼示例並不在乎他推送了多少個參數,或者他們是否在寄存器中。 – 2014-09-01 13:58:46

+0

但它不是一個鉤子,或者至少我不明白它是如何。 – Jester 2014-09-01 14:00:32

0

是的,調用約定允許你揍EAXECXEDX。儘管如此,我相信微軟的C++ ECX用於this指針。注意這適用於僅遵循約定的功能。如果你試圖鉤住一個內部函數,這個內部函數可能已經被優化爲不使用標準約定,那麼它將不起作用。

你可以在數據部分保存東西,如果適用的話,要特別注意重入性和併發性。

0

是的,我做以下事情:
1.將跳轉到的,而不是前5個功能字節(經典鉤)
2.跳轉到我赤裸的ASM唯一功能
3。在我的函數中,我需要調用一些函數(memcpy - 恢復原始字節,FlushInstruction緩存)並使用一個結構,所以在這裏我需要修改一些寄存器
4.我在堆棧中添加東西,但最後堆棧是與「呼叫」時刻相同
5.使用正確的堆棧跳轉到回調函數(jmp EAX)!我不能回到這裏,因爲在回調函數中,我需要調用原始函數並返回「call function + 5」(在通話時返回EIP放入堆棧)。我必須跳轉正確的堆棧,因爲參數在堆棧中,鉤子是通用的,我不知道有多少個參數!

因此,在回調函數中,我做我的東西,調用原始函數並恢復掛鉤。我需要的是這樣的:我需要恢復寄存器,或者確保我不修改它們,但正如我所說的,我必須這樣做。

在這一刻,我試圖避免使用EBX,EDI和ESI。我希望它能起作用,我不會遇到優化問題。如果它不起作用,我會嘗試在我的結構中備份它們並在回調函數中恢復它們。

謝謝大家!