吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7|回复: 0
收起左侧

[C&C++ 原创] 让你的第三方DLL"静"起来

[复制链接]
gt2333588 发表于 2024-12-13 09:42
我们在自己开发程序的过程中或多或少都会使用到一些第三方dll.比较常见的诸如验证.皮肤库.插件等等.这些三方库也会都有静态版本.但可能会涉及到更高的价格.用dll的好处也不言而喻.比如可以更好的宣传自己产品.当然弊端也很明显.比如同行业者发现你的产品会觉得你能力不足使用第三方或有好的三方库被他人引用.验证类的就会找针对类的破解方法等等.最近我也是闲来无事看了一个三方的皮肤库国产的.叫炫彩.他们自己是有收费的静态版.其实我对这类的收费并不反感.但要用其他验证就是我不喜欢的了.不便携.so.我就想我是否可以把dll隐藏起来以作为伪静态使用呢.

一.正常的dll引用流程
#include "xxxx.h" //这是第三方库文件
#pragma comment(lib, "xxxx.lib")
build之后就可以带着第三方dll走了.dll也会一直暴露在你的根目录下 当然你可以把它丢system里...这东西要客户的权限很敏感


二.使用loadlibrary
这个大家应该也不陌生.就是手动加载dll.然后用GetProcAddress去找对应的函数去用.这种也是有弊端的.就是dll释放的路径也会被发现.有心者还是可以看到你使用的dll文件.还有就是每一个函数都要找对应的地址也是很累的一件事(这个我目前没想到好的解决方案,有更好的思路欢迎共享)


三.就是今天我想主要说的(注意:本次技术讨论可能涉及到了一些敏感内容.仅做技术讨论.千万不要拿去违法乱纪)
在安全领域一直有文件不落地的技术解决方案.如果我们使用此方案.那岂不是就可以把第三方的dll完美隐藏掉了呢.

实现起来并不困难.无外乎几个步骤
1.将dll完整载入到自己exe的内存空间
2.重定向修复与导入表
3.执行dll的DLLEntry入口(可能会有一些第三方程序的初始化.遵循完整dll功能就执行一次吧)
4.读取新的导出表地址
5.写一个自己的GetProcAddress去call新的找出表地址

话不多说直接上干货.主打一手不藏着掖着

首先就是1.2.3的解决.RDI的代码网上有很多.我忘记了我是哪里找到的 改了改 支持64位就好了
[C] 纯文本查看 复制代码
static LPVOID RDILoadXCDllByRes()
{
	//将DLL字节读入内存缓冲区
	char* dll_bytes = NULL;
	DWORD dll_size = 0;
	dll_bytes = ReleaseFile2(g_hModule, IDR_DATA1, "DATA", &dll_size);
	// 解析dll
	PIMAGE_DOS_HEADER dosheaders = (PIMAGE_DOS_HEADER)dll_bytes;
	PIMAGE_NT_HEADERS ntheaders = (PIMAGE_NT_HEADERS)((DWORD64)dll_bytes + dosheaders->e_lfanew);
	SIZE_T dllImage_size = ntheaders->OptionalHeader.SizeOfImage;   //内存中对齐后的大小

	// 为DLL分配新的内存空间
	LPVOID dllbase = VirtualAlloc(NULL, dllImage_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	/*
	char szAAA[512] = { 0 };
	sprintf(szAAA, "new memory addr:%p\n", dllbase);
	MessageBox(NULL, szAAA, NULL, 0);
	*/
	//计算得到dll基地址的偏移量,也就是实际的 DLL 加载地址减去 DLL 的首选加载地址
	DWORD64 delta_image_base = (DWORD64)dllbase - (DWORD64)ntheaders->OptionalHeader.ImageBase;

	// 将DLL节表头复制到新分配的DLL空间
	memcpy(dllbase, dll_bytes, ntheaders->OptionalHeader.SizeOfHeaders);

	// 将DLL节部分复制到新分配的DLL空间
	PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntheaders);
	for (size_t i = 0; i < ntheaders->FileHeader.NumberOfSections; i++, section++)
	{
		LPVOID section_destination = (LPVOID)((DWORD64)dllbase + (DWORD64)section->VirtualAddress);
		LPVOID section_bytes = (LPVOID)((DWORD64)dll_bytes + (DWORD64)section->PointerToRawData);
		memcpy(section_destination, section_bytes, section->SizeOfRawData);
	}

	//修复重定位
	IMAGE_DATA_DIRECTORY relocations = ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	DWORD64 relocation_table = relocations.VirtualAddress + (DWORD64)dllbase;
	DWORD64 relocations_processed = 0;

	while (relocations_processed < relocations.Size)
	{
		PBASE_RELOCATION_BLOCK relocation_block = (PBASE_RELOCATION_BLOCK)(relocation_table + relocations_processed);
		relocations_processed += sizeof(BASE_RELOCATION_BLOCK);
		DWORD relocations_count = (relocation_block->block_size - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
		PBASE_RELOCATION_ENTRY relocation_entries = (PBASE_RELOCATION_ENTRY)(relocation_table + relocations_processed);

		for (DWORD i = 0; i < relocations_count; i++)
		{
			relocations_processed += sizeof(BASE_RELOCATION_ENTRY);

			if (relocation_entries[i].type == 0)
			{
				continue;
			}

			DWORD64 relocation_rva = relocation_block->page_addr + relocation_entries[i].offset;
			DWORD64 address_2_patch = 0;
			ReadProcessMemory(GetCurrentProcess(), (LPCVOID)((DWORD64)dllbase + relocation_rva), &address_2_patch, sizeof(DWORD64), NULL);
			address_2_patch += delta_image_base;
			memcpy((PVOID)((DWORD64)dllbase + relocation_rva), &address_2_patch, sizeof(DWORD64));
		}
	}

	//解析导入地址表
	IMAGE_DATA_DIRECTORY imports_directory = ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	PIMAGE_IMPORT_DESCRIPTOR import_descriptor = (PIMAGE_IMPORT_DESCRIPTOR)(imports_directory.VirtualAddress + (DWORD64)dllbase);
	LPCSTR libraryname = "";
	HMODULE library = NULL;
	while (import_descriptor->Name != NULL)
	{
		libraryname = (LPCSTR)import_descriptor->Name + (DWORD64)dllbase;
		library = LoadLibraryA(libraryname);
		if (library)
		{
			PIMAGE_THUNK_DATA thunk = NULL;
			thunk = (PIMAGE_THUNK_DATA)((DWORD64)dllbase + import_descriptor->FirstThunk);

			while (thunk->u1.AddressOfData != NULL)
			{
				if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
				{
					LPCSTR functionOrdinal = (LPCSTR)IMAGE_ORDINAL(thunk->u1.Ordinal);
					thunk->u1.Function = (DWORD64)GetProcAddress(library, functionOrdinal);
				}
				else
				{
					PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD64)dllbase + thunk->u1.AddressOfData);
					DWORD64 functionAddress = (DWORD64)GetProcAddress(library, functionName->Name);
					thunk->u1.Function = functionAddress;
				}
				++thunk;
			}
		}
		import_descriptor++;
	}

	//执行
	DLLEntry dllentry = (DLLEntry)((DWORD64)dllbase + ntheaders->OptionalHeader.AddressOfEntryPoint);
	(*dllentry)((HINSTANCE)dllbase, DLL_PROCESS_ATTACH, 0);
	HeapFree(GetProcessHeap(), 0, dll_bytes);

	return dllbase;
}


这段代码就是直接把dll分配到自己的内存空间.并直接运行了.具体的代码分析可以丢给ai.他讲的比我好.哈哈哈哈,我由于比较懒直接用资源文件加载的dll.ReleaseFile2(g_hModule, IDR_DATA1, "DATA", &dll_size);.当然如果你想更完美就把exe先build之后用overlay方式加载dll可以做到几乎啥也看不见

然后解决4.5.获得导出表地址并寻址
[C] 纯文本查看 复制代码
LPVOID MyGetProcAddress(LPVOID Address, char* ApiName)
{
	DWORD64 baseAddress = (DWORD64)Address;
	IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)baseAddress;
	IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(baseAddress + dosHeader->e_lfanew);
	IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)(baseAddress + ntHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);

	DWORD* nameRvas = (DWORD*)(baseAddress + exportDirectory->AddressOfNames);
	DWORD* funcRvas = (DWORD*)(baseAddress + exportDirectory->AddressOfFunctions);
	WORD* ordinals = (WORD*)(baseAddress + exportDirectory->AddressOfNameOrdinals);

	for (DWORD i = 0; i < exportDirectory->NumberOfNames; i++) {
		char* functionName = (char*)(baseAddress + nameRvas[i]);
		if (strcmp(functionName, ApiName) == 0)
		{
			// 获取函数的虚拟地址
			DWORD funcRva = funcRvas[ordinals[i]];
			FARPROC functionAddress = (FARPROC)(baseAddress + funcRva);

			return functionAddress;
		}
	}

	return NULL;
}


好了.现在有了加载代码和寻址代码.我们就可以把他们拼在一起利用起来了
例子:
[C] 纯文本查看 复制代码
typedef BOOL(WINAPI* XInitXCGUI_t)(BOOL bD2D); //先定义一个函数原型

	LPVOID pBaseAddr = RDILoadXCDllByRes();
	if (pBaseAddr == NULL) {
		printf("Failed to load library\n");
		return;
	}

pXInitXCGUI = (XInitXCGUI_t)MyGetProcAddress(pBaseAddr, "XInitXCGUI");

pXInitXCGUI(FALSE);


你的三方dll就此"静"了起来

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-13 09:54

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表