2013-04-23 61 views
1

我做了一個DLL鉤入應用程序。
繞道的功能,像這樣:無盡的函數在printf上崩潰

typedef void (WINAPI *pUCPackets)(int a1, int a2, char* a3, int a4, int a5); 
void WINAPI MyUCPackets(int a1, int a2, char* a3, int a4, int a5); 
pUCPackets MyUC2Packets = (pUCPackets)(0x408050); 

(...) some irrelevant code (...) 

DetourTransactionBegin(); 
DetourUpdateThread(GetCurrentThread()); 
DetourAttach(&(PVOID&)MyUC2Packets, MyUCPackets); 
if(DetourTransactionCommit() == NO_ERROR) 
    cout << "[" << MyUCPackets << "] successfully detoured." << endl; 

於是我試圖通過對繞道功能顯示的參數內的值:

void WINAPI MyUCPackets(int a1, int a2, char* a3, int a4, int a5) 
{ 
    printf("%d ", a5); 
    printf("%d\n", a2); 
    return MyUC2Packets(a1, a2, a3, a4, a5); 
} 

但是,當曾經的函數被調用,我顯示爭論,應用程序崩潰。
但是,如果我剛剛離開的功能,如:

void WINAPI MyUCPackets(int a1, int a2, char* a3, int a4, int a5) 
{ 
    //no prints whatsoever 
    return MyUC2Packets(a1, a2, a3, a4, a5); 
} 

它正常運行。這是爲什麼發生?

奧利coderipper:

Gate_00408050:        ;<= Procedure Start 

     MOV EDX,DWORD PTR SS:[ESP+0xC] 
     PUSH EBP 
     PUSH EDI 
     MOV EDI,ECX 
     XOR EBP,EBP 
     MOV CL,BYTE PTR DS:[EDI+0x21C] 
     TEST EDX,EDX 
     JBE Gate_004080F0 
     MOV EAX,DWORD PTR DS:[EDI+0x218] 
     PUSH EBX 
     PUSH ESI 
     MOV DWORD PTR SS:[ESP+0x1C],EDX 

Gate_00408074: 

     MOV EDX,DWORD PTR SS:[ESP+0x14] 
     DEC EAX 
     TEST EAX,EAX 
     MOV DL,BYTE PTR DS:[EDX] 
     JLE Gate_004080A5 
     LEA ESI,DWORD PTR DS:[EDI+EBP+0xEC7D] 

Gate_00408086: 

     MOV BL,BYTE PTR DS:[ESI+EAX] 
     CMP BL,DL 
     JA Gate_00408091 
     SUB DL,BL 
     JMP Gate_00408097 

Gate_00408091: 

     NOT BL 
     INC BL 
     ADD DL,BL 

Gate_00408097: 

     MOV BL,BYTE PTR DS:[ESI+EAX+0xFFFF8AD0] 
     XOR DL,BL 
     DEC EAX 
     TEST EAX,EAX 
     JG Gate_00408086 

Gate_004080A5: 

     MOV AL,BYTE PTR DS:[EDI+EBP+0xEC7D] 
     CMP AL,DL 
     JA Gate_004080B4 
     SUB DL,AL 
     JMP Gate_004080BA 

Gate_004080B4: 

     NOT AL 
     INC AL 
     ADD DL,AL 

Gate_004080BA: 

     MOV AL,BYTE PTR DS:[EDI+EBP+0x774D] 
     MOV EBX,DWORD PTR SS:[ESP+0x14] 
     XOR AL,DL 
     MOV EDX,DWORD PTR SS:[ESP+0x18] 
     XOR AL,CL 
     MOV BYTE PTR DS:[EDX],AL 
     XOR CL,AL 
     MOV EAX,DWORD PTR DS:[EDI+0x218] 
     ADD EBP,EAX 
     INC EBX 
     INC EDX 
     MOV DWORD PTR SS:[ESP+0x14],EBX 
     MOV DWORD PTR SS:[ESP+0x18],EDX 
     MOV EDX,DWORD PTR SS:[ESP+0x1C] 
     DEC EDX 
     MOV DWORD PTR SS:[ESP+0x1C],EDX 
     JNZ Gate_00408074 
     POP ESI 
     POP EBX 

Gate_004080F0: 

     POP EDI 
     POP EBP 
     RETN 0xC        ;<= Procedure End 
+0

該行似乎是可疑的:cout <<「[」<< MyUCPackets <<「]成功繞道。 << endl; 。這是一個錯誤(對於MyUC2Packets)? – lucasg 2013-04-23 11:51:51

+0

其實一切正常。如果該功能不會打印任何東西。我想那部分是好的。這被顯示,它不會崩潰。只是當它得到實際的功能,然後崩潰。 – zikdaljin 2013-04-23 11:55:19

回答

3

MyUC2Packets的簽名可能不正確。由於函數使用stdcall調用約定,因此它們在返回之前需要清理堆棧。如果你調用其中一個參數數量錯誤的函數,堆棧指針在返回時將不正確。

當打印語句被刪除時,不會發生這種情況的原因是因爲編譯器可能會將轉發調用優化爲單條指令jmp。當包含打印語句時,繞道函數實際上有工作要做,並在返回之前通過不正確的值調整堆棧。如果MyUC2Packets需要6個參數,但功能簽名僅需要5個參數,則每次繞行功能無法優化時都會導致問題。

下面的代碼通過模擬示例中的繞行設置來演示這一點。被掛鉤的函數需要4個參數,但繞行只需要3個。它模擬來自期望使用4個參數的函數的客戶端的調用。

#include <stdio.h> 
#include <ios> 
#pragma inline_depth(0) 

typedef void (WINAPI *Function3)(int, int, int); 
typedef void (WINAPI *Function4)(int, int, int, int); 

void WINAPI FinalFunction(int x, int y, int z, int q); 
void WINAPI DetourFunction(int x, int y, int z); 
void WINAPI DetourFunctionPrint(int x, int y, int z); 

Function3 callFinalFunction = reinterpret_cast<Function3>(FinalFunction); 
Function4 callDetourFunction = reinterpret_cast<Function4>(DetourFunction); 
Function4 callDetourFunctionPrint = reinterpret_cast<Function4>(DetourFunctionPrint); 


void WINAPI FinalFunction(int x, int y, int z, int q) 
{ 
    std::cout << x << " " << y << " " << z << " " << q << std::endl; 
} 

void WINAPI DetourFunction(int x, int y, int z) 
{ 
    callFinalFunction(x, y, z); // Optimzed to a single jmp instruction. 
} 

void WINAPI DetourFunctionPrint(int x, int y, int z) 
{ 
    printf("%d", x); 
    printf("%d\n", y); 
    callFinalFunction(x, y, z); 
} 


int main() 
{ 
    // This works 
    callDetourFunction(0, 1, 2, -1); 

    // This does not 
    callDetourFunctionPrint(0, 1, 2, -1); 

    return 0; 
} 
+0

Aaah。我想我現在明白了。現在我無法考慮如何修復我的代碼。大聲笑 – zikdaljin 2013-04-23 16:29:55

+0

很簡單,只要找出調用約定是什麼以及函數需要什麼參數。由於該函數在返回時記錄堆棧,並在調用返回之後清除堆棧。在調試器(attach)中加載並設置一個斷點可能會更容易。 – 2013-04-23 16:35:30

+0

所以我打開ollydbg並在00408050上添加了一個斷點。我現在想弄清楚它。我不知道如何檢查olly的參數。我更新了我的問題,你能否瞭解發生了什麼?謝謝/ – zikdaljin 2013-04-23 18:59:01