绕路函数在打印时崩溃
Detoured function crashes on printf
我做了一个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("%dn", 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
MyUC2Packets
的签名可能有误。由于函数使用标准调用约定,因此需要在返回之前清理堆栈。如果使用错误的形参数调用其中一个函数,则堆栈指针返回时将出现错误。
当print语句被删除时,它没有发生的原因是因为编译器可能会优化转发调用到单个jmp
指令。当包含print语句时,绕道函数实际上有工作要做,并在返回之前根据不正确的值调整堆栈。如果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("%dn", y);
callFinalFunction(x, y, z);
}
int main()
{
// This works
callDetourFunction(0, 1, 2, -1);
// This does not
callDetourFunctionPrint(0, 1, 2, -1);
return 0;
}
相关文章:
- 如何循环打印顶点结构
- 当回溯以零开始时,如何调试崩溃
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么它只打印双链接列表的第一个值,而我的程序却崩溃了
- 如何避免在打印类似于"%q"的字符时在 vsprintf_s() 处崩溃
- GetTempPathA 函数在打印结果后崩溃
- 在C++中实现二叉搜索树,搜索不起作用.尝试打印节点的元素会导致输出崩溃
- C++ 链表打印崩溃
- 试图在C++中打印变量int会导致它崩溃.为什么?
- 打印标头中声明的变量时C++崩溃
- 输出正确,但每次打印输出后程序崩溃
- Tizen IDE中的本机应用程序:签名崩溃并打印奇怪的非ASCII字符
- 打印浮点值时打印 F 崩溃
- 尝试打印变量.程序崩溃
- 在Android NDK中捕获C++信号,并且仍然打印崩溃转储
- 代码崩溃,如果没有打印在循环上,我该如何修复
- 绕路函数在打印时崩溃
- 通过Copy Constructor创建的e2打印崩溃程序
- 程序在打印字符串矢量时崩溃
- 排序算法在试图打印列表信息时崩溃