前几天看URLDownloadToFile 时发现最后一个参数是一个类指针(我更喜欢说是委托),它提供C的导出接口,但是 C是无法实现纯虚函数的,这样的话运行会崩溃。然后自己捉摸了下,构造了个虚函数列表,成功调用。写此文章以记录之
#include <stdio.h>
#include <windows.h>
//URLDownloadToFileA原型中最后的一个参数是回调类指针,类似委托机制的delegate
//URLDownloadToFileA(LPUNKNOWN,LPCSTR,LPCSTR,DWORD,LPBINDSTATUSCALLBACK);
//类似 IBindStatusCallback
class CTest
{
//其他成员
int val;
public:
//类似IBindStatusCallback里面 OnProgress
virtual void output() = 0;
};
//这个函数类似URLDownloadToFileA,最后一个是委托,但是不显式声明为类,这样可以以C方式导出
int TestFun(void *pCTest)
{
CTest *pThis = (CTest *)pCTest;
pThis->output();
return 0;
}
//下面这个是在C代码中没有类却要实现这个委托时使用的结构体
typedef struct
{
//虚函数表
void *__vfptr;
//其他成员
int val;
}Test;
typedef void FUN();
//虚函数列表,假设有10个虚函数,这里只用到一个
FUN* VirFunList[10];
//这个是Test的虚函数output
void output(Test *pThis)
{
//在这里可以访问到了私有成员的
printf("OK,val = %d\n",pThis->val);
}
//
//汇编代码对应的二进制实现,作为函数中转,下面给出源汇编
//做个广告,代码由 SCGenerator(ShellCode 辅助工具)生成
// __asm
// {
// push ecx;
// lea eax,output;
// call eax;
// pop ecx;
// ret;
// };
//
char szCode[] = "\x51\x8D\x05\x19\x10\x40\x00\xFF\xD0\x59\xC3";
int main()
{
int *pFun = (int *)&szCode[3];
*pFun = (int)output;//修正函数地址
VirFunList[0] = (FUN *)(void *)szCode;
Test te;
te.val = 10;
te.__vfptr = &VirFunList;
TestFun(&te);
return 0;
}