Я сделал 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
Подпись 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;
}
Других решений пока нет …