我想编写一个myHid.dll来劫持A程序对系统Hid.dll的函数调用,但是A程序运行后每次都崩溃,用OD跟踪发现是A程序调用myHid中的函数输入的参数没有出栈,导致栈数据错误。也就是A ---》压栈参数--》调用HidD_GetHidGuid(myHid函数)---》压栈参数--》调用jidD_GetHidGuid(对应系统Hid函数地址)--》jidD_GetHidGuid返回参数出栈---》HidD_GetHidGuid函数返回上述过程中缺少一个A压入参数的出栈过程,我加入汇编手动清栈才能正常,但是始终不明白是什么原因导致的,请各位大牛指点,谢谢。   __asm{
        add esp,4    
        ret 4 //返回时清栈参数
    }
函数大致如下:自定义函数的声名和定义:typedef  void (__stdcall*JidD_GetHidGuid)(OUT LPGUID HidGuid);JidD_GetHidGuid          jidD_GetHidGuid  ;
导出函数:
extern "C"  __declspec(dllexport) void HidD_GetHidGuid( OUT LPGUID HidGuid)
{
       jidD_GetHidGuid( HidGuid);   //须要加入如下汇编
   __asm{
        add esp,4    
        ret 4
    }    return ;
}在DllMain函数中载入系统的Hid.dll,并获取到对应的函数地址。
        hinstance = LoadLibrary("c:\\windows\\system32\\hid.dll");
        jidD_GetHidGuid = (JidD_GetHidGuid )GetProcAddress(hinstance, "HidD_GetHidGuid");汇编Hid.dll

解决方案 »

  1.   

    我没有A程序的源码,只有二进制exe文件。我在网上查到如下信息:
    __stdcall调用约定用于调用Win32 API函数。采用__stdcal约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参数的堆栈。是否可以这样理解,A程序调用Hid函数使用的是__stdcall 方式,即由被调用者释放参数栈,而我实现的myHId函数是__cdecl方式(即由调用者释放参数栈),导致参数栈错误,这些栈释放不是编译器自动搞定吗?如果是上述问题如何修改呢?
      

  2.   

    呵呵,自己貌似找到原因了,解决方案如下:把myHid工程改成__stdcall 方式编译,但是这样DLL导出函数名称会变成_HidD_GetHidGuid@4这样的格式,A程序是找不到对应的函数的,所以必须在工程代码中去掉xtern "C" __declspec(dllexport) 直接函数导出方式,使用定义.def文件的方式约定导出函数名。LIBRARY   "Hid"
    EXPORTS 
    HidD_GetAttributes                       @1 
    HidD_GetHidGuid                          @2 VS2008在链接器-》输入-》模块定义文件中增加对应的.def即可。 使用OD跟踪下堆栈参数释放正确:)