Отключенная функция вылетает на принтф

Я сделал DLL-хук в приложении.
Отключил функцию так:

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

Работает нормально. Почему это происходит?

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

1

Решение

Подпись MyUC2Packets вероятно неверно. Поскольку функции используют соглашение о вызовах stdcall, они должны очистить стек перед тем, как вернуться. Если вы вызываете одну из этих функций с неправильным числом параметров, указатель стека будет неверным при возврате.

Причина, по которой этого не происходит, когда операторы print удаляются, заключается в том, что компилятор, вероятно, оптимизирует переадресацию вызова до одного 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;
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]