简体   繁体   English

被抛弃的功能在printf上崩溃

[英]Detoured function crashes on printf

I'm made a DLL hook into an application. 我在应用程序中创建了一个DLL钩子。
Detoured a function like so: 绕过这样的功能:

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;

So then I tried to display the values inside the arguments on the detoured function by: 那么我试着通过以下方式在detoured函数的参数内显示值:

 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);
 }

But when ever the function gets called and I display the arguments, the app crashes. 但是当调用函数并显示参数时,应用程序崩溃了。
But if I just leave the function like: 但是,如果我只是留下这样的功能:

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

It runs normally. 它运行正常。 Why is this happening? 为什么会这样?

OLLY coderipper: OLLY 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

The signature of the MyUC2Packets is probably incorrect. MyUC2Packets的签名可能不正确。 Since the functions use stdcall calling convention they are required to clean up the stack before they return. 由于函数使用stdcall调用约定,因此需要在返回之前清理堆栈。 If you call one of these functions with the wrong number of parameters the stack pointer will be incorrect when it returns. 如果使用错误数量的参数调用其中一个函数,则返回时堆栈指针将不正确。

The reason it does not happen when the print statements are removed is because the compiler is likely optimizing the forwarding call down to a single jmp instruction. 删除print语句时不会发生这种情况的原因是编译器可能将转发调用优化为单个jmp指令。 When the print statements are included the detour function actually has work to do and adjusts the stack by an incorrect value before it returns. 当包含print语句时,detour函数实际上有工作要做,并在返回之前用不正确的值调整堆栈。 If MyUC2Packets expects 6 parameters but the function signatures only take 5 parameters this will cause problems any time the detour function can't be optimized down. 如果MyUC2Packets需要6个参数,但功能签名只需要5个参数,这将导致绕行功能无法优化的问题。

The code below demonstrates this by simulating the detour setup in your example. 下面的代码通过模拟示例中的绕行设置来演示这一点。 The function being hooked takes 4 parameters but the detour expects only 3. It simulates calls from a client expecting a function that takes 4 parameters. 被挂钩的函数需要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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM