如何在C语言中拦截静态库调用?
我的问题是: 在xxx.lib中有一个静态库(xxx.lib)和一些调用函数如何在C语言中拦截静态库调用?,c,compilation,linker,C,Compilation,Linker,我的问题是: 在xxx.lib中有一个静态库(xxx.lib)和一些调用函数foo()的C文件。我希望每次调用foo()时都能收到一条通知消息。但我不允许更改任何由他人编写的源代码 我花了几天时间在互联网上搜索,发现了几个类似的问答,但这些建议都不能真正解决我的问题。我列举了其中一些: 使用gcc-wrap: 谢天谢地,我使用的是Microsoft C编译器和链接器,我找不到与-wrap等效的选项 Microsoft绕道: Detours在运行时截取C调用,并将调用重新定向到trampoline
foo()
的C文件。我希望每次调用foo()
时都能收到一条通知消息。但我不允许更改任何由他人编写的源代码
我花了几天时间在互联网上搜索,发现了几个类似的问答,但这些建议都不能真正解决我的问题。我列举了其中一些:
gcc-wrap
:
谢天谢地,我使用的是Microsoft C编译器和链接器,我找不到与-wrap
等效的选项foo()
的开头注入一条jmp指令,将其重定向到我自己的函数。但是,当foo()
为空时,它是不可行的,例如
void foo() ---> will be compiled into 0xC3 (ret)
{ but it'll need at least 8 bytes to inject a jmp
}
LINK : warning LNK4044: unrecognized option '/FUNCTIONPADMIN'; ignored
任何人都可以告诉我如何正确地制作“可热修补”图像?这是解决我问题的可行办法吗我还希望实现它吗?我认为在不更改任何代码的情况下,没有任何方法可以做到这一点。 我能想到的最简单的方法是为
void foo()
函数编写包装器,并用包装器查找/替换它
void myFoo(){
return foo();
}
而不是调用foo()
调用myFoo()
希望这将对您有所帮助。如果您有源代码,您可以在不更改源代码的情况下,通过添加
-finstrument functions
来构建包含您感兴趣的函数的文件。然后,您必须编写uu cyg_profile_func_enter/exit函数来打印跟踪。例如:
#包括
#包括
静态文件*fp_跟踪;
无效的
__属性(构造函数)
跟踪_开始(无效)
{
fp_trace=fopen(“trace.out”,“w”);
}
无效的
__属性(析构函数)
跟踪结束(无效)
{
如果(fp_跟踪!=NULL){
fclose(fp_跟踪);
}
}
无效的
__cyg_profile_func_enter(void*func,void*caller)
{
如果(fp_跟踪!=NULL){
fprintf(fp_跟踪,“e%p%p%lu\n”,func,调用者,时间(NULL));
}
}
无效的
__cyg_profile_func_exit(void*func,void*caller)
{
如果(fp_跟踪!=NULL){
fprintf(fp_跟踪,“x%p%p%lu\n”,func,调用者,时间(NULL));
}
}
如果您有源代码将库重新编译为共享库,那么还有另一种方法。从那里,您可以使用任意数量的调试系统进行自己的.so/.dll运行时插入。(unix上的ltrace,windows上的某物或其他[windows上的某人--请编辑])
如果您没有来源,那么我认为您的选项3应该仍然有效。写病毒的人已经写了很多年了。您可能需要进行一些手动检查(因为x86指令的长度并不完全相同),但诀窍是拉出完整的指令,并将其替换为跳转到安全的地方。执行必须执行的操作,使寄存器恢复到与删除的指令运行时相同的状态,然后跳转到插入的跳转指令之后 VC编译器提供了两个选项&挂钩函数
/Gh
标志导致在每个方法或函数的开头调用\u penter
函数,/Gh
标志导致在每个方法或函数的结尾调用\u pexit
函数
因此,如果我在\u penter
中编写一些代码来找出调用函数的地址,那么我将能够通过比较函数地址有选择地截取任何函数
我做了一个样本:
#include <stdio.h>
void foo()
{
}
void bar()
{
}
void main() {
bar();
foo();
printf ("I'm main()!");
}
void __declspec(naked) _cdecl _penter( void )
{
__asm {
push ebp; // standard prolog
mov ebp, esp;
sub esp, __LOCAL_SIZE
pushad; // save registers
}
unsigned int addr;
// _ReturnAddress always returns the address directly after the call, but that is not the start of the function!
// subtract 5 bytes as instruction for call _penter
// is 5 bytes long on 32-bit machines, e.g. E8 <00 00 00 00>
addr = (unsigned int)_ReturnAddress() - 5;
if (addr == foo) printf ("foo() is called.\n");
if (addr == bar) printf ("bar() is called.\n");
_asm {
popad; // restore regs
mov esp, ebp; // standard epilog
pop ebp;
ret;
}
}
#包括
void foo()
{
}
空条()
{
}
void main(){
bar();
foo();
printf(“我是main()!”;
}
无效uuu declspec(裸体)u cdecl u penter(无效)
{
__asm{
push ebp;//标准prolog
mov-ebp,esp;
子esp,本地大小
pushad;//保存寄存器
}
无符号整数地址;
//\u ReturnAddress总是在调用后直接返回地址,但这不是函数的开始!
//减去5个字节作为调用penter的指令
//在32位机器(例如E8)上为5字节长
地址=(无符号整数)\返回地址()-5;
如果(addr==foo)printf(“调用了foo()。\n”);
如果(addr==bar)printf(“调用了bar()。\n”);
_asm{
popad;//还原注册表
mov esp,ebp;//标准尾声
pop-ebp;
ret;
}
}
使用cl.exe source.c/Gh
构建并运行它:
调用了bar()。
调用foo()。
我是梅因代码>
太完美了
有关如何使用\u penter
和\u pexit
的更多示例,请参见此处和
我已经用这个方法解决了我的问题,我希望它也能帮助你
:)我认为如果没有大量的摆弄,这是不可能的。对象文件并不是专门为实现这一点而设计的。老实说,我会选择选项3。但首先,您必须找到要重定向的函数,因为不会有任何导出,就像您有DLL时一样。所以,是的,这是可以做到的,但是需要做很多工作。一个可能有用的链接:是的,我看到了这篇文章。但这在实际项目中并不实用。我确实希望有一种方法可以在运行时拦截函数调用。想知道迂回是怎么做到的……我对windows没有太多经验。你能检查一下这个吗?感谢@ManthanTilva,本文给出了与上面列出的相同的解决方案。但他们不适合我
#include <stdio.h>
void foo()
{
}
void bar()
{
}
void main() {
bar();
foo();
printf ("I'm main()!");
}
void __declspec(naked) _cdecl _penter( void )
{
__asm {
push ebp; // standard prolog
mov ebp, esp;
sub esp, __LOCAL_SIZE
pushad; // save registers
}
unsigned int addr;
// _ReturnAddress always returns the address directly after the call, but that is not the start of the function!
// subtract 5 bytes as instruction for call _penter
// is 5 bytes long on 32-bit machines, e.g. E8 <00 00 00 00>
addr = (unsigned int)_ReturnAddress() - 5;
if (addr == foo) printf ("foo() is called.\n");
if (addr == bar) printf ("bar() is called.\n");
_asm {
popad; // restore regs
mov esp, ebp; // standard epilog
pop ebp;
ret;
}
}