Jessica CHEN Joy and Loneliness CATEGORIES TIMEMACHINE TAGS GEMS

小试detour

[ detour  dll  函数替换  ]
编译detour:

下载Detours Express 2.1并安装后,可以在下面的地址找到:
C:Program FilesMicrosoft ResearchDetours Express 2.1src
不过只是源码,没有现成的lib和dll。需要自己编译。
编译很简单,只要运行cmd,在dos窗口里面运行:
------------
cd "C:Program FilesMicrosoft ResearchDetours Express 2.1"
nmake
------------
不过会报下面的错误:
---------------
detoured.rc(10) : fatal error RC1015: cannot open include file 'winver.h'.
NMAKE : fatal error U1077: “"C:Program FilesMicrosoft Visual Studio 8VCbin
rc.EXE"”: 返回代码“0x1”
Stop.
NMAKE : fatal error U1077: “"C:Program FilesMicrosoft Visual Studio 8VCbin
nmake.exe"”: 返回代码“0x2”
Stop.
---------------
只要在运行nmake前先运行一下面这句就不会报错了。
"C:Program FilesMicrosoft Visual Studio 8VCvcvarsall.bat"
即:
------------
cd "C:Program FilesMicrosoft ResearchDetours Express 2.1"
"C:Program FilesMicrosoft Visual Studio 8VCvcvarsall.bat"
nmake
------------
编译大约需要一到两分钟。

我暂时只用到了samples里面的withdll。
下面是withdll.exe的简单介绍。

withdll可以用来根据函数名称替换一个dll中的函数。
并且可以在新的函数中调用回老的函数。

命令行执行:
withdll /d:你写好的dll名称 要attach到的主程序名称

具体用法请参考下文以及参考资料中的内容。

<code>typedef struct _tagREPFUNC
{
    const char* pcszName;
    void* pfnNewFunc;
    void* pfnOldFunc;
} REPFUNC;

REPFUNC RepFuncList[] = {
    {"要替换的函数的名字", 你定义的新函数名, 用来存放原函数},
    {NULL,NULL,NULL}
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) 
    {
        g_RepFuncList = (REPFUNC*)RepFuncList;

        DetourRestoreAfterWith();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());

        DetourSetIgnoreTooSmall(TRUE);

        for (int i=0; NULL!=RepFuncList[i].pcszName ;i++)
        {
            RepFuncList[i].pfnOldFunc = DetourFindFunction("目标dll名。不用写完整路径。", 
                RepFuncList[i].pcszName);
            if ( NULL==RepFuncList[i].pfnOldFunc )
            {
                continue;
            }
            //下面是用你定义的新的函数替换了老的函数,并在替换后把老的函数的地址改变了。
            //可以用改变后的地址调用老的函数。
            DetourAttach(&RepFuncList[i].pfnOldFunc, RepFuncList[i].pfnNewFunc);
        }
        DetourTransactionCommit();
    }
    return TRUE;
}</code>

要注意函数调用约定新旧要完全一致,就是老的函数如果用的是__stdcall,
新的也一定要用__stdcall。
还要注意的一点是你写的dll要有一个def文件如下:
<code>LIBRARY	"你的library名称"
EXPORTS
   DllMain   @1</code>
注意到上面的@。这里是控制导出的名称按序数排列
(Exporting Functions from a DLL by Ordinal Rather Than by Name)。
必须这样,不然withdll会报下列错误:
withdll.exe: Error: %s does not export function with ordinal #1.

参考资料:
<a href="http://hi.baidu.com/lff0305/blog/item/663e133ba693c8e015cecbb2.html">使用Detour库来实现.DLL中函数替换</a>