我正在使用Detours 3.0挂钩到从Ida Pro获得的功能。问题是我遇到了一个似乎无法挂钩的函数,这是由于无效的争论或由于它使用了可变的争论列表而引起的。

int (*MakePacketBuffer)(const char * buf, int len, const char * splitstr, ...);
#define MakePacketBufferProto int (*)(const char *, int, const char *, ...)
我想像的是参数,在Ida Pro中实际上是这样显示的:

int sub_66EEF0(int a1, int a2, const char *a3, ...)


如何在Ida中调用该函数:

sub_66EEF0(buf, 2048, "%c%c%c%c%s%c%c", v15, 250, v20, v21, v22, v23, v25);


评论

您必须使用MS Detours吗?知道函数的序言也将有很大帮助(因编译器而异)

你为什么不能钩住这个?如果您知道函数的地址,则可以绕过它并获得控制权。但是,如果没有诸如“撤消”该功能和绕开返回地址之类的技巧,您可能无法随后恢复执行,因为该功能的序言可能不合适(如@Ditmar所暗示)。

您做了什么尝试来钩住它?

您是在尝试将功能钩入,移出还是同时钩挂?

#1 楼

您需要了解编译器如何生成函数。对于使用MSVC编译的32位Windows应用程序,由于所有参数都在堆栈上传递,因此您的工作会变得轻松一些。 Windows:

----------------
 Return Address 
----------------
 Argument #0 
----------------
 Argument #1
----------------
 Argument #2 
----------------
  ....


vararg例程仍然如此。这是一个简单的示例,向您展示如何获取附加值。如果您拦截诸如printf之类的东西,就会遇到的问题是,您必须解析格式字符串才能知道已向您传递了多少个参数。

#include <stdio.h>
#include <windows.h>
#include <intrin.h>

#define print(x) printf("%10s: %x\n", #x, x)

void fn(int a, int b, ...) {
    void ** Stack = (void**) _AddressOfReturnAddress();

    print(Stack);    // Address of SP upon function entry
    print(Stack[0]); // Return address
    print(Stack[1]); // a
    print(Stack[2]); // b
    print(Stack[3]); // vararg 1
};

void main() {
    fn(1,2,3,4,5,6);
}


打印出:

   Stack: 101feac
Stack[0]: ce10a4
Stack[1]: 1
Stack[2]: 2
Stack[3]: 3


#2 楼

不必知道参数的数量。

实际上,参数的数量受常数限制(否则程序将需要无限的内存:)。

因此,您可以使用16个实参声明一个钩子函数,打印这些实参,并使用相同的16个实参调用原始函数。如果代码中断,则将args的数量加倍。

typedef unsigned long DW;
#define DW_MANYARGS  DW arg1,DW arg2,DW arg3,DW arg4,DW arg5,DW arg6,DW arg7,DW arg8
#define MANYARGS     arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8

DW hookFunc(DW_MANYARGS) {
    // we do not expect a quadruple-word result here
    DW res = originalFunc(MANYARGS);
    return res;
}


注意事项:

不要忘记返回原始函数返回的内容。

请记住,有两个隐藏的参数:

0)如果返回值不适合int的大小,则返回值的地址;

1)this指针