我想对我的应用程序进行性能分析,具体来说我希望记录程序启动后每个函数调用(忽略DLL中的函数)进入和退出的时间,即我想要一个简单的表格,类似于这样:
THREAD_ID FUNCTION_ADDRESS TIME EVENT_TYPE
5520 0xFF435360 0 ENTERED
5520 0xFF435ED3 25 ENTERED
5520 0xFF433550 40 ENTERED
5520 0xFF433550 50 EXITED
5520 0xFF433550 60 ENTERED
5520 0xFF433550 70 EXITED
5520 0xFF435ED3 82 EXITED
5520 0xFF435360 90 EXITED
对于一个程序,如果忽略编译器优化,它看起来像这样:
void test1(void)
{
int a = 0;
++a;
}
void test(void)
{
test1();
test1();
}
void main(void)
{
test();
}
我找不到现成的解决方案,最接近的是Microsofts VSPerfReport,但它只提供了每个函数花费的时间,没有进入和退出时间。
因此,我开始研究如何用一个简单的函数来挂钩所有我的函数,并生成上述表格所需的缓冲区。为了做到这一点,我想创建一个在main函数开始时调用的函数,可以遍历整个exe并修改CALL指令,使其调用我的挂钩函数。
那些像MinHook等的库对我来说都有点过头了,而且可能行不通,因为它是一个x64应用程序,我不想挂钩DLL函数。
因此,我考虑只修改每个CALL指令中的JMP指令,比如这个程序:
void main(void)
{
...asm prologue
test();
002375C9 call test (235037h)
}
...asm epilogue
这里的调用是针对 JMP 表格的:
@ILT+40(__set_errno):
0023502D jmp _set_errno (243D80h)
@ILT+45(___crtGetEnvironmentStringsA):
00235032 jmp __crtGetEnvironmentStringsA (239B10h)
test:
00235037 jmp test (237170h)
@ILT+55(_wcstoul):
0023503C jmp wcstoul (27C5D0h)
@ILT+60(__vsnprintf_s_l):
我希望遍历此表格并重新路由所有与应用程序的 .exe 中函数相关联的JMP到包含计时代码的钩子函数,然后返回到调用函数。
那么ILT代表什么?我假设是某种查找表,我该如何获得它?
这是否可能?我听说过IAT hooking,但在我看来,它只适用于hooking DLL。在这里,我忽略了退出,尽管使用另一个JMP替换RET指令可能会有所帮助?
感谢任何帮助。