三。如何劫持DLL
一。 DLL创建
a. __declspec(dllexport) 关键字导出函数
代码如下:
#include "stdafx.h"
#include
#include
#ifdef _MANAGED
#pragma managed(push, off)
#endif
HANDLE g_hModule = NULL; //保存自己的模块句柄
//导出函数
extern "C" __declspec(dllexport) void Test()
{
TCHAR tcModulePath[MAX_PATH] = {0};
//获得自身的完整路径
GetModuleFileName( (HMODULE)g_hModule,tcModulePath,MAX_PATH);
MessageBox(0,tcModulePath,_T("testdll的加载路径"),0);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hModule = hModule; //保存模块加载句柄
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
#include "stdafx.h"
#include
#ifdef _MANAGED
#pragma managed(push, off)
#endif
HANDLE g_hModule = NULL; //保存自己的模块句柄
// DEF文件方式,函数前不需要导出函数关键字 __declspec(dllexport)
void Test()
{
TCHAR tcModulePath[MAX_PATH] = {0};
//获得自身的完整路径
GetModuleFileName( (HMODULE)g_hModule,tcModulePath,MAX_PATH);
MessageBox(0,tcModulePath,_T("testdll的加载路径"),0);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
g_hModule = hModule; //保存模块加载句柄
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
LIBRARY "testdll.lib" ;导出模块名
DESCRIPTION "DEF文件方式"
EXPORTS ;关键字,后面要跟导出函数信息
Test @2 ;导出Test函数,导出序号为2
;Test @3 noname ;导出函数Test,导出序号为3,并不导出函数名
各种情况下的导出效果对比:
当为 "Test @2 ;导出Test函数,导出序号为2" 时:
当为 "Test @3 noname ;导出函数Test,导出序号为3,并且不导出函数名" 时 :
注意看"Ordinal"与"Function"的不同.
二。DLL调用
a. 静态方式调用
例子对应"a. __declspec(dllexport) 关键字导出函数"创建的DLL库
这种方式,需要.lib文件和.DLL文件。
例子中是用"#pragma comment(lib"方式,也可在工程属性中常规和输入中指定.lib及所在目录
#include "stdafx.h"
////////////////////////////////////////////////////////////////////
//静态链接方式:
#pragma comment(lib,"..\\debug\\testdll.lib")
extern "C" void Test();
int _tmain(int argc, _TCHAR* argv[])
{
Test();
return 0;
}
///////////////////////////////////////////////////////////////////////
b. 动态方式调用
这种方式不需要.lib文件,只要知道DLL导出函数的格式就行了。
#include "stdafx.h"
////////////////////////////////////////////////////////////////////
//动态链接方式:
typedef void (* TEST)();
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hDll = LoadLibraryA("testdll.dll");
if(hDll)
{
TEST test = (TEST)GetProcAddress(hDll,"Test");
if(test != NULL)
{
test();
}
FreeLibrary(hDll);
}
return 0;
}
///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
////////////////////////////////////////////////////////////////////
//DLL仅导出函数序号,没有导出函数名称的调用方式:
typedef void (* TEST)();
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwOrdinal = MAKELONG(3,0); //构造函数序号,低字节为序号,高字为0
HMODULE hDll = LoadLibraryA("testdll.dll");
if(hDll)
{
TEST test = (TEST)GetProcAddress(hDll,(LPCSTR)dwOrdinal);
if(test != NULL)
{
test();
}
FreeLibrary(hDll);
}
return 0;
}
///////////////////////////////////////////////////////////////////////
劫持DLL就是第二种方式的实现方式.
可钻的空子,在于动态链接库文件的加载顺序下,只要让自定义的相同名字的DLL抢先被EXE文件找到,就达到目的了。
顺序如下:
windows xp sp2系统以上会默认开启SafeDllSearchMode,在这种模式下DLL文件的搜索顺序如下所示:
(1)可执行程序加载的目录(可理解为程序安装目录比如 E:\XclCode\testdll\testdll\debug)
(2)系统目录(即 %windir%\system32 )
(3)16位系统目录(即 %windir%\system)
(4)Windows目录(即 %windir%)
(5)当前目录(运行的某个文件所在目录,比如C:\Documents and Settings\Administrator\Desktop\test)
(6)PATH环境变量中列出的目录
具体实现步骤如下:
#include "stdafx.h"
#include
#ifdef _MANAGED
#pragma managed(push, off)
#endif
//这个函数指针保存原始dll导出函数的地址
typedef void (* FUNTEST)();
FUNTEST g_funTest = NULL;
///////////////////////////////////////////////////////////////////////
/*
//方法一:
extern "C" __declspec(dllexport) void Test()
{
g_funTest();
}
*/
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/*
//方法二:
//__declspec(naked) :
// 不生成栈平衡效验代码,栈空间开辟代码等调试代码,函数内部内嵌汇编代码直接跳转到原始DLL的导出函数中执行
extern "C" __declspec(naked) __declspec(dllexport) void Test()
{
__asm jmp dword ptr [g_funTest]
}
*/
///////////////////////////////////////////////////////////////////////
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
//进程加载时调用DLLMain
if(ul_reason_for_call ==DLL_PROCESS_ATTACH)
{
//禁用进程内线程创建或退出而调用DllMain入口函数
DisableThreadLibraryCalls(hModule);
//获取原始dll导出的函数地址并保存
char cDllPath[MAX_PATH] = {0};
//GetSystemDirectoryA( (LPSTR)cDllPath,MAX_PATH);
//strcat(cDllPath," 1"); //采用导出函数序号的方式调用
MessageBoxA(0,"劫持成功 by xiongchuanliang! 可以为所欲为了。","劫持库",0);
//被劫持的,实际要调用的DLL
strcpy(cDllPath,"E:\\XclCode\\testdll\\dll\\testdll.dll");
HMODULE hDll = LoadLibraryA(cDllPath);
g_funTest = (FUNTEST)GetProcAddress(hDll,"Test");
}
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
其中关于函数,有两种方法可以参考下。
如何解决DLL劫持问题,官网有完整的说明:
http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx
MAIL: [email protected]
BLOG: http://blog.csdn.net/xcl168