WIndwos下API形式封的DLL 调用时 使用LoadLibrary,GetProcAddress,FreeLibrary通过文件路径和文件名以及接口直接调用。
如果需要分析某一个DLL的调用过程和出入口参数,可以通过文件替换的方式,利用新的DLL调用原来的DLL来实现。当然接口名称和参数一定要对。
实例:
某加密狗DLL文件有以下接口,CheckDog,SendData,GetData,导出接口名称通过Dependency Walker或IDA以及其它PE工具分析Export Table就可以了。
接口参数的跟踪与分析,这个通过IDA直接分析出来,入口参数的个数类似于arg_0,这样的形式。
参数类型的分析:通过猜测与IDA以及动态调试的方式,对大部分简单的数据类型很容易分析出来。这个在动态调试时通过压栈的情况可以直接看到。返回值的分析,通过调用过程以后的反汇编大概能猜出来一些。
通过分析本列中的接口参数的原型如下:
long CheckDog(); 返回狗是否存在,1存在,0或者<0错误
long SedData(unsigned char* data); 返回发送是否成功,1成功,0失败,data是要发送的数据地址。
long GetData(unsigned char* data); 返回接收是否成功,1成功,0失败,data是要接收的数据地址。
有了接口参数的原型,可以自己先写一个dll,编译以后替换原来的dll,测试一下能否调用成功。如果没有调用上的接口问题,哪就成功了。
本列中调用时由于__stdcall和__cdecl的不同,作了调整,测试成功以后,就可以在新的dll中调用原来的dll,以达到功能不变,只跟踪日志的目的,当然也可以修改代码的逻辑。
部分源代码如下:
#define USBDLL_API __declspec(dllexport)
HINSTANCE hDllInstUSB = 0 ; //DLL加载以后保存
unsigned char _data[5]; //临时变量,发送数据以后接收用
USBDLL_API int CheckDog(void)
{
int tmpRet =1;
WriteLog("%s:","CheckDog:");
if(!hDllInstUSB)
{
hDllInstUSB = LoadLibrary(("libusb0.dll"));
}
if(hDllInstUSB)
{
typedef DWORD (WINAPIV *MYFUNC)(); //CheckDog的参数原型
MYFUNC check_usb0 = NULL;
check_usb0 = (MYFUNC)GetProcAddress(hDllInstUSB,"CheckDog");
if(check_usb0)
{
tmpRet = check_usb0();
}
}
char buffer [2];
sprintf(buffer,"%d",tmpRet);
WriteLog("->%s\n",buffer);
return tmpRet;
}
USBDLL_API int SendData(unsigned char* data)
{
WriteLog("%s ","SendData:");
int tmpRet=0;
if(!hDllInstUSB)
{
hDllInstUSB = LoadLibrary(("libusb0.dll"));
}
if(hDllInstUSB)
{
typedef DWORD (WINAPIV *MYFUNC)(unsigned char*); //SendData的参数原型
MYFUNC send_data0 = NULL;
send_data0 = (MYFUNC)GetProcAddress(hDllInstUSB,"SendData");
if(send_data0)
{
tmpRet = send_data0(data);
}
}
FILE *fp;
fp=fopen("test.log","a");
for(int i=0;i<5;i++)
{
_data[i]=*data;
if(i>0 && *data==0)
{
break;
}
fprintf(fp,"%02x ", *data++);
}
fclose(fp);
char buffer [2];
sprintf(buffer,"%d",tmpRet);
WriteLog("->%s\n",buffer);
return tmpRet;
}
USBDLL_API int GetData(unsigned char* data)
{
WriteLog("%s ","GetData:");
int tmpRet =0;
//这里可以根据自己的需要做不同的数据返回了
if(tmpRet==0)
{
if(hDllInstUSB)
{
typedef DWORD (WINAPIV *MYFUNC)(unsigned char*); //SendData的参数原型
MYFUNC get_data0 = NULL;
get_data0 = (MYFUNC)GetProcAddress(hDllInstUSB,"GetData");
if(get_data0)
{
tmpRet = get_data0(data);
}
FILE *fp;
fp=fopen("test.log","a");
for(int i=0;i<32;i++)
{
fprintf(fp,"%02x ",*data++);
}
fclose(fp);
}
}
char buffer [2];
sprintf(buffer,"%d",tmpRet);
WriteLog("->%s\n",buffer);
return tmpRet;
}
void WriteLog(char *format,char *data)
{
FILE *fp;
fp=fopen("test.log","a");
fprintf(fp,format,data);
fclose(fp);
}
最终效果:
在调用原dll的程序位置会生成test.log,记录每个接口的调用以及输入输出参数情况。
本例生成的文件如下:
CheckDog:->1
SendData 00 00 01 02 03 04 00 00 ->1
GetData 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ->1
......