[DLL劫持] 3 DLL劫持之实践 例子

该系列文章是依据本人平时对动态链接库的学习,归纳总结,所做的学习笔记。如有错误或待改善之处,请留下您宝贵的意见或建议。

 

先说说DLL劫持的原理吧,以下这段来自百度百科对DLL劫持原理的说明:


由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行。这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。

利用这种方法取得控制权后,可以对主程序进行补丁。此种方法只对除kernel32.dllntdll.dll等核心系统库以外的DLL有效,如网络应用程序的ws2_32.dll、游戏程序中的d3d8.dll,还有大部分应用程序都调用的lpk.dllsxs.dll,这些DLL都可被劫持。

伪造的dll制作好后,放到程序当前目录下,这样当原程序调用原函数时就调用了伪造的dll的同名函数,进入劫持DLL的代码,处理完毕后,再调用原DLL此函数。

这种补丁技术,对加壳保护的软件很有效,选择挂接的函数最好是在壳中没有被调用的,当挂接函数被执行时,相关的代码已被解压,可以直接补丁了。在有些情况下,必须用计数器统计挂接的函数的调用次数来接近OEP。此方法巧妙地绕过了壳的复杂检测,很适合加壳程序的补丁制作。

一些木马或病毒也会利用DLL劫持技术搞破坏,因此当在应用程序目录下发现系统一些DLL文件存在时,如lpk.dll,应引起注意。


下面就通过一个简单的例子,来实现一下DLL劫持:


1.    生成原始的DLL

创建一个dllTest工程,添加lib.hlib.cpp文件:

Lib.h

#ifndef LIB_H
#define LIB_H

extern "C" int __declspec(dllexport)add(int x, int y);
#endif

Lib.cpp

#include "lib.h"

int add(int x, int y){
	return x + y;
}

编译生成dllTest.dll


2.    编写应用程序(采用动态加载方式)

新建工程dllcall,添加文件dllcall.cpp,修改调用目录,生成,测试,ok

(隐式方式:使用原来的.lib文件,使用之后的dll

Dllcall.cpp

// dllCall.cpp : 以显式方式调用DLL
#include <stdio.h>
#include "windows.h"
typedef int ( * lpAddFun)(int,int);
	
int main(int argc, char* argv[])
{
    HINSTANCE hDll;   //DLL句柄	
	lpAddFun addFun;  //函数指针
    hDll = LoadLibrary("..\\Release\\dllTest.dll");
	if (hDll != NULL)
	{
		addFun = (lpAddFun)GetProcAddress(hDll,"add");	
		if(addFun!=NULL)
		{
		    int result =  addFun(2,3);    
			printf("%d",result);
		}
		FreeLibrary(hDll);
	}	
	system("pause");
	return 0;
}

3.      使用AheadLib反编译DLL

使用工具AheadLib.exe,反编译dllTest.dll,生成dllTest.cpp,新建dll工程,编译该cpp,生成第二个dllTest.dll

DllText.cpp

// 头文件
#include <Windows.h>
// 导出函数
#pragma comment(linker, "/EXPORT:add=_AheadLib_add,@1")
	
// 宏定义
#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
// Hook 命名空间
namespace Hook
{
	HHOOK m_hHook;
	// HOOK 句柄
	// HOOK 函数
	LRESULT CALLBACK HookProc(INT iCode, WPARAM wParam, LPARAM lParam)
	{
		if (iCode > 0)
		{
			;
		}

		return CallNextHookEx(m_hHook, iCode, wParam, lParam);
	}
	// Hook
	inline BOOL WINAPI Hook(INT iHookId = WH_CALLWNDPROC)
	{
		m_hHook = SetWindowsHookEx(iHookId, HookProc, NULL, GetCurrentThreadId());
		return (m_hHook != NULL);
	}
	// Unhook
	inline VOID WINAPI Unhook()
	{
		if (m_hHook)
		{
			UnhookWindowsHookEx(m_hHook);
		}
	}
}
// AheadLib 命名空间
namespace AheadLib
{
	HMODULE m_hModule = NULL;	// 原始模块句柄
	DWORD m_dwReturn[1] = {0};	// 原始函数返回地址
	// 加载原始模块
	inline BOOL WINAPI Load()
	{
		TCHAR tzPath[MAX_PATH];
		TCHAR tzTemp[MAX_PATH * 2];

		lstrcpy(tzPath, TEXT("dllTestOrg"));
		
		///这一句是为了证明我的ws2_32.dll能被执行
		MessageBox(NULL, tzPath, TEXT("DLL Path"), MB_ICONSTOP);
		
		m_hModule = LoadLibrary(tzPath);
		if (m_hModule == NULL)
		{
			wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath);
			MessageBox(NULL, tzTemp, 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];

		if (m_hModule == NULL)
		{
			if (Load() == FALSE)
			{
				ExitProcess(-1);
			}
		}
		fpAddress = GetProcAddress(m_hModule, pszProcName);
		if (fpAddress == NULL)
		{
			if (HIWORD(pszProcName) == 0)
			{
				wsprintf(szProcName, "%d", pszProcName);
				pszProcName = szProcName;
			}

			wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName);
			MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
			ExitProcess(-2);
		}

		return fpAddress;
	}
}
using namespace AheadLib;
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hModule);

		Hook::Hook();
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		Free();		Hook::Unhook();
	}
	return TRUE;
}
// 导出函数
ALCDECL AheadLib_add(void)
{
	GetAddress("add");
	__asm JMP EAX;
}

重新使用之前的应用程序测试

将第二个自己生成的dll替代原来的dll,将原来的dll名改成dllTestOrg.dll,放入相应的目录,测试,OK

5.    Dll劫持成功

 

 附件:

AheadLib.exe的下载地址:http://download.csdn.net/detail/u010311064/7626887

本文的所有代码下载地址:http://download.csdn.net/detail/u010311064/7626907



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值