在C中,是否有可能转发可变函数的调用?如,
int my_printf(char *fmt, ...) {
fprintf(stderr, "Calling printf with fmt %s", fmt);
return SOMEHOW_INVOKE_LIBC_PRINTF;
}
在这种情况下,以上述方式转发调用显然不是严格必要的(因为您可以以其他方式记录调用,或使用vfprintf),但我正在处理的代码库要求包装器做一些实际工作,并且没有(也不可能添加)类似于vfprintf的帮助函数。
[更新:根据目前提供的答案,似乎有一些困惑。用另一种方式来表达这个问题:一般来说,你可以在不修改函数定义的情况下包装任意的变进函数吗?
不是直接的,但是变进函数与可变参数样式的替代函数成对出现是很常见的(在标准库中几乎是普遍的情况)。例如printf函数/
v……函数接受一个va_list形参,它的实现通常是通过编译器特定的“宏魔法”来完成的,但是你可以保证调用v…像这样的可变函数的样式函数可以工作:
#include <stdarg.h>
int m_printf(char *fmt, ...)
{
int ret;
/* Declare a va_list type variable */
va_list myargs;
/* Initialise the va_list variable with the ... after fmt */
va_start(myargs, fmt);
/* Forward the '...' to vprintf */
ret = vprintf(fmt, myargs);
/* Clean up the va_list */
va_end(myargs);
return ret;
}
这应该会给你你正在寻找的效果。
如果你正在考虑编写一个可变值库函数,你还应该考虑将一个va_list样式的同伴作为库的一部分。从你的问题中可以看出,它对你的用户是有用的。
最好的办法是
static BOOL(__cdecl *OriginalVarArgsFunction)(BYTE variable1, char* format, ...)(0x12345678); //TODO: change address lolz
BOOL __cdecl HookedVarArgsFunction(BYTE variable1, char* format, ...)
{
BOOL res;
va_list vl;
va_start(vl, format);
// Get variable arguments count from disasm. -2 because of existing 'format', 'variable1'
uint32_t argCount = *((uint8_t*)_ReturnAddress() + 2) / sizeof(void*) - 2;
printf("arg count = %d\n", argCount);
// ((int( __cdecl* )(const char*, ...))&oldCode)(fmt, ...);
__asm
{
mov eax, argCount
test eax, eax
je noLoop
mov edx, vl
loop1 :
push dword ptr[edx + eax * 4 - 4]
sub eax, 1
jnz loop1
noLoop :
push format
push variable1
//lea eax, [oldCode] // oldCode - original function pointer
mov eax, OriginalVarArgsFunction
call eax
mov res, eax
mov eax, argCount
lea eax, [eax * 4 + 8] //+8 because 2 parameters (format and variable1)
add esp, eax
}
return res;
}
C99支持可变参数宏;取决于你的编译器,你可以声明一个宏来做你想做的事情:
#define my_printf(format, ...) \
do { \
fprintf(stderr, "Calling printf with fmt %s\n", format); \
some_other_variadac_function(format, ##__VA_ARGS__); \
} while(0)
不过,一般来说,最好的解决方案是使用您试图包装的函数的va_list形式(如果存在的话)。
不是直接的,但是变进函数与可变参数样式的替代函数成对出现是很常见的(在标准库中几乎是普遍的情况)。例如printf函数/
v……函数接受一个va_list形参,它的实现通常是通过编译器特定的“宏魔法”来完成的,但是你可以保证调用v…像这样的可变函数的样式函数可以工作:
#include <stdarg.h>
int m_printf(char *fmt, ...)
{
int ret;
/* Declare a va_list type variable */
va_list myargs;
/* Initialise the va_list variable with the ... after fmt */
va_start(myargs, fmt);
/* Forward the '...' to vprintf */
ret = vprintf(fmt, myargs);
/* Clean up the va_list */
va_end(myargs);
return ret;
}
这应该会给你你正在寻找的效果。
如果你正在考虑编写一个可变值库函数,你还应该考虑将一个va_list样式的同伴作为库的一部分。从你的问题中可以看出,它对你的用户是有用的。