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