首页
社区
课程
招聘
[求助][求助]如何hOOK不定参数的函数?
发表于: 2009-7-11 20:24 9498

[求助][求助]如何hOOK不定参数的函数?

2009-7-11 20:24
9498
近来在研究 SQLite数据库,找到一个oDBC的开源驱动,想改造它一下,但遇到一个问题没法解决。
在SQLite数据库中有一个类似于 err_Printf(char *,...);

我想在接口不变的情况下,替换这个函数,处理完成后,在传给原来的这个函数。
但怎么调用这个函数呢?

例:

原来的: char * err_Printf(char *,...);
自定义的:char *Myerr_printf(char *,...);

err_printf("the value is %d,%d,%d",i,j,k);

Myerr_printf("the value is %d,%d,%d",i,j,k)
{
     //somecode。。。

return err_printf(这里添写什么呢?);

}

谢谢啦:)

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 0
支持
分享
最新回复 (8)
雪    币: 768
活跃值: (515)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
2
竟然沉了,自己顶起来!!
盼高手释疑!
2009-7-12 17:06
0
雪    币: 367
活跃值: (20)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
pushad

// do your stuff

popad
jmp org_funcentry
2009-7-12 22:23
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
sprintf实现,希望对你有帮助

extern "C" int __cdecl sprintf(char *buffer, const char * format, ...)
{
    int retValue;
    va_list argptr;
         
    va_start( argptr, format );
    retValue = wvsprintf( buffer, format, argptr );
    va_end( argptr );

    return retValue;
}
2009-7-13 08:05
0
雪    币: 768
活跃值: (515)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
5
谢谢楼上两位,问题解决!
以下是转载的网上的一篇文章,有同样问题的兄弟可以参考!!
//============================================

va_start() va_end()函数应用

作者不详摘自网上收集人气6456  
1:当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表
void foo(...);
void foo(parm_list,...);

2:函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈.eg:
#include <iostream>  
void fun(int a, ...)
{
        int *temp = &a;
        temp++;
        for (int i = 0; i < a; ++i)
        {
                cout << *temp << endl;
                temp++;
        }
}

int main()
{
        int a = 1;
        int b = 2;
        int c = 3;
        int d = 4;
        fun(4, a, b, c, d);
        system("pause");
        return 0;
}
Output::
1
2
3
4

3:获取省略号指定的参数
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
        va_list args;
        va_start(args, pszFormat);
        _vsnprintf(pszDest, DestLen, pszFormat, args);
        va_end(args);
}

4.va_start使argp指向第一个可选参数。va_arg返回参数列表中的当前参数并使argp指向参数列表中的下一个参数。va_end把argp指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。

  ).演示如何使用参数个数可变的函数,采用ANSI标准形式
  #include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉
/*函数原型声明,至少需要一个确定的参数,注意括号内的省略号*/
int demo( char, ... );
void main( void )
{
        demo("DEMO", "This", "is", "a", "demo!", "");
}
/*ANSI标准形式的声明方式,括号内的省略号表示可选参数*/
int demo( char msg, ... )
{
        /*定义保存函数参数的结构*/
        va_list argp;
        int argno = 0;  
        char para;
        /*argp指向传入的第一个可选参数,msg是最后一个确定的参数*/
        va_start( argp, msg );
        while (1)
        {
                para = va_arg( argp, char);
                if ( strcmp( para, "") == 0 )
                        break;
                printf("Parameter #%d is: %s\n", argno, para);
                argno++;
        }
        va_end( argp );
        /*将argp置为NULL*/
        return 0;
}

        2)//示例代码:可变参数函数的使用
#include "stdio.h"
#include "stdarg.h"
void simple_va_fun(int start, ...)
        {
                va_list arg_ptr;
                int nArgValue =start;
                int nArgCout=0;     //可变参数的数目
                va_start(arg_ptr,start); //以固定参数的地址为起点确定变参的内存起始地址。
                do
                {
                        ++nArgCout;
                        printf("the %d th arg: %d\n",nArgCout,nArgValue);     //输出各参数的值
                        nArgValue = va_arg(arg_ptr,int);                      //得到下一个可变参数的值
                } while(nArgValue != -1);               
                return;
        }
        int main(int argc, char* argv[])
        {
                simple_va_fun(100,-1);
                simple_va_fun(100,200,-1);
                return 0;
        }

        3)//示例代码:扩展——自己实现简单的可变参数的函数。
                下面是一个简单的printf函数的实现,参考了<The C Programming Language>中的例子
#include "stdio.h"
#include "stdlib.h"
                void myprintf(char* fmt, ...)  //一个简单的类似于printf的实现,//参数必须都是int 类型
        {
                char* pArg=NULL;               //等价于原来的va_list
                char c;

                pArg = (char*) &fmt;       //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值
                pArg += sizeof(fmt);       //等价于原来的va_start         

                do
                {
                        c =*fmt;
                        if (c != '%')
                        {
                                putchar(c);            //照原样输出字符
                        }
                        else
                        {
                                //按格式字符输出数据
                                switch(*++fmt)
                                {
                                case'd':
                                        printf("%d",*((int*)pArg));           
                                        break;
                                case'x':
                                        printf("%#x",*((int*)pArg));
                                        break;
                                default:
                                        break;
                                }
                                pArg += sizeof(int);               //等价于原来的va_arg
                        }
                        ++fmt;
                }while (*fmt != '\0');
                pArg = NULL;                               //等价于va_end
                return;
        }
        int main(int argc, char* argv[])
        {
                int i = 1234;
                int j = 5678;

                myprintf("the first test:i=%d\n",i,j);
                myprintf("the secend test:i=%d; %x;j=%d;\n",i,0xabcd,j);
                system("pause");
                return 0;
        }
2009-7-13 09:03
0
雪    币: 15
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
兄弟,你这个这个问题咋解决的啊?
2020-3-6 10:18
0
雪    币: 15
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
morning pushad // do your stuff popad jmp org_funcentry
大神,能否提供一个简单的demo看一下
2020-3-6 11:48
0
雪    币: 3085
活跃值: (3623)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
不定参数都是外平栈,你只要在函数之内该怎么hook还是怎么hook,没啥影响
2020-3-6 13:41
0
雪    币: 251
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
1. 获取传入参数, 参数都是在esp 上面, 只要取第一个参数的地址, 后面的参数就可以根据如此取到
如 f(p1, p2, p3)

f(p1, ...)
{
     p2 = *(&p1 + 1)
     p3 = *(&p1 + 2)
}

2. 参数个数, 参数个数一般无法明确知道, 有两个办法
  a. 分析参数传入的数据, 来确定有几个 
      如printf("%d-%s", ..)    通过"%d-%s" 知道有 1+2个参数
  b. 使用尽量多的参数, 如20个, 如果实际只有3个, 但是你传递20个参数过去也不会有影响的, 变参属于c方式, 没关系, API方式就不行
2020-3-6 14:19
0
游客
登录 | 注册 方可回帖
返回
//