dll重定位内存注入

dll重定位内存注入

PE数据重定位已经是很古老的技术了
但是很多网友想了解相关,但是还是没办法自己实现。
然而有了以下内容:

重定位字面理解就是把一个东西的位置改变了。
关于DLL或者sys等可执行文件,统称PE文件。它的结构始终遵守PE格式。
当把PE文件用相关API(ReadFile)等读入到自己的程序后,它的结构是在系统硬盘的结构。此时就需要进行一个“安装”的过程(拉伸)当然你也可以把这个步骤放到最后。
整理以下步骤即可简单完成此方法:
1.申请文件内存
2.读入DLL数据
3.申请拉伸空间内存
4.拉伸DLL数据(按照内存对齐方式)不懂?没关系,没事再回来看看~~~
5.修复导入表
6.修复需要重定位的数据
完成以上6个步骤其实就可以完成无DLL模块注入至目标进程空间了,是不是很666。

首先获取相关信息:
1.读入DLL数据

INT FILE_ReadFile_(const char* filePath, PBYTE* pBuffer) {
	//打开文件
	FILE* pFile = fopen(filePath, "rb");
	if (!pFile)
	{
		printf("文件打开失败\n");
		return 0;
	}
	//获取文件长度
	fseek(pFile, 0, SEEK_END);
	DWORD size = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);
	//申请存储文件数据缓冲区
	PBYTE pFileBuffer = (PBYTE)malloc(size);
	if (!pFileBuffer)
	{
		printf("分配内存失败!\n");
		fclose(pFile);
		return 0;
	}
	//读取文件数据
	fread(pFileBuffer, size, 1, pFile);
	//判断是否为可执行文件
	if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
	{
		printf("不是标准的可执行文件!!!\n");
		fclose(pFile);
		free(pFileBuffer);
		return 0;
	}
	PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pFileBuffer;
	if (*(PDWORD)(pFileBuffer + (WORD)dos->e_lfanew) != IMAGE_NT_SIGNATURE)
	{
		printf("不是正常的PE文件!!!\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}
	fclose(pFile);
	*pBuffer = pFileBuffer;//最后返回文件buffer指针
	return size;
}

2.拉伸内存

BOOL Load(IN LPVOID 步骤1的指针, IN LPVOID 步骤3的指针){
	PIMAGE_DOS_HEADER        P_D = (PIMAGE_DOS_HEADER)这里是你读取的缓冲区指针;//DOS头
	PIMAGE_NT_HEADERS        P_N = (PIMAGE_NT_HEADERS)((INT64)pFileBuffer + P_D->e_lfanew);//NT头
	PIMAGE_FILE_HEADER		 P_F = (PIMAGE_FILE_HEADER)((PBYTE)P_N + 4);//文件头指针
	PIMAGE_OPTIONAL_HEADER64   P_O = (PIMAGE_OPTIONAL_HEADER64)((PBYTE)P_F + IMAGE_SIZEOF_FILE_HEADER);//可选PE头															 
	PIMAGE_SECTION_HEADER P_S = (PIMAGE_SECTION_HEADER)((INT64)P_O + P_F->SizeOfOptionalHeader);//节区头
	memcpy(步骤3的指针, 步骤1的指针, P_O->SizeOfHeaders/*拷贝整个PE头的大小*/);
	然后拷贝节点
	for (size_t i = 0; i < P_F->NumberOfSections; i++)
	{
		//内存对齐复制节区
		memcpy((LPVOID)((INT64)pImageBuffer + P_S->VirtualAddress), (LPVOID)((INT64)这里是你文件的缓冲区指针+ P_S->PointerToRawData), P_S->SizeOfRawData);
		//循环遍历所有节区 再继续拷贝(拉伸操作)
		P_S = (PIMAGE_SECTION_HEADER)((INT64)P_S + IMAGE_SIZEOF_SECTION_HEADER);
	}
	return true;
}

拉伸完了?Enmmmmm

3.重定位导入表

BOOL RepairImportTable(LPVOID 步骤3的指针) {

	PIMAGE_DOS_HEADER        P_D = (PIMAGE_DOS_HEADER)步骤3的指针;//DOS头
	PIMAGE_NT_HEADERS        P_N = (PIMAGE_NT_HEADERS)((INT64)pImageBuffer + P_D->e_lfanew);//NT头 指针
	PIMAGE_FILE_HEADER		 P_F = (PIMAGE_FILE_HEADER)((PBYTE)P_N + 4);//文件头 指针
	PIMAGE_OPTIONAL_HEADER64   P_O = (PIMAGE_OPTIONAL_HEADER64)((PBYTE)P_F + IMAGE_SIZEOF_FILE_HEADER);//可选头 指针

	//先放几个变量
	HMODULE hModule = NULL;
	PCHAR pDllName = NULL;
	PINT64 pIAT = NULL;
	PIMAGE_THUNK_DATA64 pInt = NULL;
	PIMAGE_IMPORT_BY_NAME funName = NULL;
	INT64 funAddress = 0;
	PIMAGE_DATA_DIRECTORY pDataDirectory = (PIMAGE_DATA_DIRECTORY)P_O->DataDirectory;
	if (pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
	{
		//获取导入表地址
		PIMAGE_IMPORT_DESCRIPTOR pInportAddress = (PIMAGE_IMPORT_DESCRIPTOR)					   ((INT64)P_D + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

		if (!pInportAddress) {
			printf("导入表头地址错误!\n");
			return FALSE;
		}
		printf("导入表头地址:%p\n", pInportAddress);
		//遍历所有的导入表
		while (pInportAddress->OriginalFirstThunk && pInportAddress->FirstThunk)
		{
			//获取模块名称
			pDllName = (PCHAR)((INT64)P_D + pInportAddress->Name);
			hModule = GetModuleHandleA((LPCSTR)pDllName);
			if (!hModule)
			{
				printf("模块句柄获取失败!怎么办?1.加载。2.你猜: %s\n", pDllName);
				return FALSE;
			}
			//判断是否以名字导出的函数 
			pInt = (PIMAGE_THUNK_DATA64)((INT64)P_D + pInportAddress->OriginalFirstThunk);
			//需要修复的表地址
			pIAT = (PINT64)((INT64)P_D + pInportAddress->FirstThunk);
			while (pInt->u1.AddressOfData)
			{
				//获取函数名
				funName = (PIMAGE_IMPORT_BY_NAME)((INT64)P_D + pInt->u1.AddressOfData);
				//修复
				if ((PCHAR)funName->Name < (PCHAR)0x7FFFFFFFFFFF) {
					*pIAT = funAddress = (INT64)GetProcAddress(hModule, (LPCSTR)funName->Name);
				}
				pIAT++;
				pInt++;
				sizeof(PIMAGE_THUNK_DATA64));//反正8个字节,直接++也行
			}
			pInportAddress = (PIMAGE_IMPORT_DESCRIPTOR)((INT64)pInportAddress + sizeof(IMAGE_IMPORT_DESCRIPTOR));

		}
	}
	else
		return FALSE;
	return TRUE;
}

4.我想睡觉~~~
重定位数据
不懂? 简单说就是你把DLL读入到自己程序内了,那DLL的一些数据的地址不就变了,你得给它移动到相应的位置。一句两句也说不清,还是需要自己耐心摸索啊~。。。
贴代码吧!!!

BOOL RepairRelocation table(IN INT64 pImageBase)
{
	//还是先判断下这个文件是否有重定位表吧
	if (!P_O->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
	{
		//printf("文件不存在重定位表 \r\n");
		return FALSE;
	}
	PIMAGE_BASE_RELOCATION pRel = (PIMAGE_BASE_RELOCATION)(pImageBase + P_O->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
	//循环遍历直到结构体VirtualAddress-SizeOfBlock都为NULL
	while (*(PINT64)pRel)
	{
		//需要修复重定位项个数
		DWORD dwRelEntry = (pRel->SizeOfBlock - 8) / 2;
		//指向重定位项
		PWORD pRelData = (PWORD)((PBYTE)pRel + 8);
		for (size_t i = 0; i < dwRelEntry; i++)
		{
			//判断高4位
			//高4位1010
			if ((pRelData[i] & 0xA000) == 0xA000)//if ((pRelData[i] & 0x3000) == 0x3000)
			{
				//低12位 + VirtualAddress=修复数据的RVA
				INT dwData = pRelData[i] & 0xFFF;
				//获取文件中对应数据
				PINT64 pData = (PINT64)((PBYTE)pImageBase + dwData + pRel->VirtualAddress);
				//修复吧
				*pData = (*pData - P_O->ImageBase) + pImageBase;
			}
		}
		//遍历完没有位置,,原谅我打字太累,从不备注的习惯。。。
		pRel = (PIMAGE_BASE_RELOCATION)((PBYTE)pRel + pRel->SizeOfBlock);
	}
	P_O->ImageBase = pImageBase;
	return TRUE;
}

到此呢基本工作也就做完了,在自身程序启动测试,或者在目标进程创建远程线程跑起来就行(dll默认参数不能忘了)
还是给个源码地址 https://wyzf.vip

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Rose

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值