pe结构里移动导入表问题
本帖最后由 谦虚求学 于 2018-4-17 11:32 编辑各位 朋友 大神门好, 我有一个导入表的问题想请教下 朋友门 ,这几天 看了 小甲鱼老师的 PE结构讲解 非常感兴趣,但是到了导入表这里 出了些 问题 老想不通,在网上查了下资料,导入表的讲解很少,都很保守,最后找了一个滴水的 导入表视频,听得很带劲,再加上小甲鱼老师的PE结构视频 让我更加了解了 PE ,滴水教育视频里 有一个导入表注入的作业题 ,我很想把它做出来 ,可是我失败了 ,因为我做的 扩大一个 节表 ,移动导出表,移动重定位表 都成功,到了 移动导入表的时候就是不成功,程序无法启动。我用的 是C语言写的代码,因为我是新手学PE,所以希望 有好心的大神 或者 朋友 能用C语言写的 导入表注入(移动导入表)源代码 发我个,我想知道 我错在哪里 ,我一定研究了一个月了 {:10_266:} 心好累 ,因为像这种 简单地 移动导入表代码 一定对现在的网络软件不起什么伤害了 ,只能仅供学习 了 ,有的朋友 大神门发下代码 ,WIN32 通讯 线程 进程都没学,高级的也不需要,只要能移动导入表代码成功,发我 ,100鱼币希望大神不要嫌少,跪求。。。。。。。。。 谦虚求学 发表于 2018-6-3 11:23
我是真心的求教 ,我感觉 移动导入表 到新的增加节了,程序不能运行 这和 IAT表有很大关系,看了看...
我什么也不想说
main.c
#pragma warning(disable:4996)
#include "PE_Functions.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define FREE_SPACE 0x2000
// *************************************************************************************
IMAGE_IMPORT_DESCRIPTOR *g_dest_iid = NULL;
IMAGE_THUNK_DATA *g_dest_itd = NULL;
IMAGE_IMPORT_BY_NAME *g_dest_iibn = NULL;
char *g_dest_string = NULL;
// 使用全局变量 g_dest_string
// 返回复制后的字符串的 RVA
static DWORD MoveString(char *base, char *src)
{
DWORD ret = OffsetToRva(base, ((char *)g_dest_string - base));
strcpy(g_dest_string, src);
g_dest_string += strlen(g_dest_string) + 1; // g_dest_string 指向下一个
return ret;
}
// 使用全局变量 g_dest_iibn
static DWORD MoveImportByName(char *base, IMAGE_IMPORT_BY_NAME *src)
{
DWORD ret = OffsetToRva(base, ((char *)g_dest_iibn - base));
g_dest_iibn->Hint = src->Hint;
strcpy(g_dest_iibn->Name, src->Name);
// 要确保 g_dest_iibn 指向下一个,由于结构体对齐,其他环境可能会出问题
g_dest_iibn = (IMAGE_IMPORT_BY_NAME *)((char *)g_dest_iibn + sizeof(IMAGE_IMPORT_BY_NAME) + strlen(g_dest_iibn->Name) - 1);
return ret;
}
// 使用全局变量 g_dest_itd
// 返回复制后的 IMAGE_THUNK_DATA 结构的RVA
static DWORD MoveThunkData(char *base, IMAGE_THUNK_DATA *src)
{
DWORD ret = OffsetToRva(base, ((char *)g_dest_itd - base));
for(int i = 0; src.u1.AddressOfData != 0; ++i)
{
g_dest_itd->u1.AddressOfData = MoveImportByName(base, (IMAGE_IMPORT_BY_NAME *)(RvaToOffset(base, src.u1.AddressOfData) + base));
++g_dest_itd;
}
memset(g_dest_itd, 0, sizeof(IMAGE_THUNK_DATA)); // 最后一个全为0的结构
++g_dest_itd; // 指向下一个
return ret;
}
// 使用全局变量 g_dest_iid
static void MoveImportDescriptor(char *base, IMAGE_IMPORT_DESCRIPTOR *src)
{
for(int i = 0; src.Characteristics != 0; ++i)
{
g_dest_iid->OriginalFirstThunk = MoveThunkData(base, (IMAGE_THUNK_DATA *)(RvaToOffset(base, src.OriginalFirstThunk) + base));
g_dest_iid->TimeDateStamp = src.TimeDateStamp; // 原样复制
g_dest_iid->ForwarderChain = src.ForwarderChain; // 原样复制
g_dest_iid->Name = MoveString(base, RvaToOffset(base, src.Name) + base);
g_dest_iid->FirstThunk = src.FirstThunk; // FirstThunk 不做改变
++g_dest_iid;
}
memset(g_dest_iid, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR)); // 最后一个全为0的结构
++g_dest_iid; // 指向下一个
}
// ----------------------------------------------------------------
void DebugPrintImportByName(char *base, IMAGE_IMPORT_BY_NAME *iibn)
{
printf("\t\tiibn->Hint: %x\n", iibn->Hint);
printf("\t\tiibn->Name: %s\n", iibn->Name);
}
void DebugPrintThunkData(char *base, IMAGE_THUNK_DATA *itd)
{
for(int i = 0; itd.u1.AddressOfData != 0; ++i)
{
printf("\t{\n");
printf("\t\titd.u1.AddressOfData: %x\n", itd.u1.AddressOfData);
DebugPrintImportByName(base, (IMAGE_IMPORT_BY_NAME *)(RvaToOffset(base, itd.u1.AddressOfData) + base));
printf("\t}\n");
}
}
void Debug(char *base)
{
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)base;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)(base + idh->e_lfanew);
DWORD import_rva = inh->OptionalHeader.DataDirectory.VirtualAddress;
IMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)(base + RvaToOffset(base, import_rva));
for(int i = 0; iid.Characteristics != 0; ++i)
{
printf("{\n");
printf("\tiid.OriginalFirstThunk: %x\n", iid.OriginalFirstThunk);
DebugPrintThunkData(base, (IMAGE_THUNK_DATA *)(RvaToOffset(base, iid.OriginalFirstThunk) + base));
printf("}\n");
printf("iid.TimeDateStamp: %x\n", iid.TimeDateStamp);
printf("iid.ForwarderChain: %x\n", iid.ForwarderChain);
printf("iid.Name: %x\t\t\t%s\n", iid.Name, RvaToOffset(base, iid.Name) + base);
printf("{\n");
printf("\tiid.FirstThunk: %x\n", iid.FirstThunk);
DebugPrintThunkData(base, (IMAGE_THUNK_DATA *)(RvaToOffset(base, iid.FirstThunk) + base));
printf("}\n");
printf("------------------------------------------------\n");
}
}
// ----------------------------------------------------------------
// 将导入表移动到 ish 指向的区块
void MoveImportTable(char *base, IMAGE_SECTION_HEADER *ish)
{
// 0x00- 0x1FF 存放 IMAGE_IMPORT_DESCRIPTOR
// 0x200 - 0x3FF 存放 IMAGE_THUNK_DATA
// 0x400 - 0x9FF 存放 IMAGE_IMPORT_BY_NAME
// 0xa00 - 0xaFF 存放 dll字符串(ASCII 字符串)
// 初始化全局变量
char *data = (char *)(base + ish->PointerToRawData);
g_dest_iid = (IMAGE_IMPORT_DESCRIPTOR *)(data + 0x00);
g_dest_itd = (IMAGE_THUNK_DATA *)(data + 0x200);
g_dest_iibn = (IMAGE_IMPORT_BY_NAME *)(data + 0x400);
g_dest_string = (char *)(data + 0xa00);
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)base;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)(base + idh->e_lfanew);
DWORD import_rva = inh->OptionalHeader.DataDirectory.VirtualAddress;
IMAGE_IMPORT_DESCRIPTOR *iid = (IMAGE_IMPORT_DESCRIPTOR *)(base + RvaToOffset(base, import_rva));
MoveImportDescriptor(base, iid);
// 修正数据目录表
inh->OptionalHeader.DataDirectory.VirtualAddress = OffsetToRva(base, ish->PointerToRawData);
}
// *************************************************************************************
int main(void)
{
//char *filename = "NewHello.exe";
//CopyFile("Hello.exe", "NewHello.exe", FALSE);
char *filename = "NewMessageBox.exe";
CopyFile("MessageBox.exe", "NewMessageBox.exe", FALSE);
HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open: %s", filename);
exit(1);
}
DWORD orig_file_size = GetFileSize(hFile, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, orig_file_size + FREE_SPACE, NULL);
LPVOID pMem = MapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ | FILE_MAP_COPY, 0, 0, 0);
MoveImportTable(pMem, (IMAGE_SECTION_HEADER *)(AddSection(pMem, "hello", 0xb00) + (char *)pMem));
UnmapViewOfFile(pMem);
CloseHandle(hMap);
CloseHandle(hFile);
return 0;
}
PE_Functions.c
#pragma warning(disable:4996)
#include "PE_Functions.h"
#include <windows.h>
#include <time.h>
DWORD PE_Align(DWORD tar_num, DWORD align_to)
{
DWORD n = tar_num / align_to;
if(n * align_to < tar_num)
++n;
return n * align_to;
}
DWORD RvaToOffset(LPVOID base, DWORD rva)
{
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)base;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((char *)base + idh->e_lfanew);
IMAGE_SECTION_HEADER *ish = (IMAGE_SECTION_HEADER *)(inh + 1);
for(int i = 0; i < inh->FileHeader.NumberOfSections; ++i)
{
if((ish.VirtualAddress <= rva) && (rva < ish.VirtualAddress + ish.SizeOfRawData))
{
return rva - ish.VirtualAddress + ish.PointerToRawData;
}
}
return -1;
}
DWORD OffsetToRva(LPVOID base, DWORD offset)
{
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)base;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((char *)base + idh->e_lfanew);
IMAGE_SECTION_HEADER *ish = (IMAGE_SECTION_HEADER *)(inh + 1);
for(int i = 0; i < inh->FileHeader.NumberOfSections; ++i)
{
if((ish.PointerToRawData <= offset) && (offset < ish.PointerToRawData + ish.SizeOfRawData))
{
return offset - ish.PointerToRawData + ish.VirtualAddress;
}
}
return -1;
}
// **************************************************************************************
static DWORD GetVirtualAddress(IMAGE_NT_HEADERS32 *inh, IMAGE_SECTION_HEADER *ish)
{
DWORD address = ish.VirtualAddress;
DWORD size = ish.Misc.VirtualSize;
return address + size;
}
static DWORD GetPointerToRawData(IMAGE_NT_HEADERS32 *inh, IMAGE_SECTION_HEADER *ish)
{
DWORD address = ish.PointerToRawData;
DWORD size = ish.SizeOfRawData;
return address + size;
}
// 返回值为 新增区块表的偏移
DWORD AddSection(LPVOID base, const char *section_name, DWORD section_size)
{
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)base;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((char *)base + idh->e_lfanew);
IMAGE_SECTION_HEADER *ish = (IMAGE_SECTION_HEADER *)(inh + 1);
DWORD ret = (DWORD)((char *)&ish - (char *)base);
strncpy(ish.Name, section_name, 8);
ish.Misc.VirtualSize = section_size;
ish.VirtualAddress = PE_Align(GetVirtualAddress(inh, ish), inh->OptionalHeader.SectionAlignment);
ish.SizeOfRawData = PE_Align(section_size, inh->OptionalHeader.FileAlignment);
ish.PointerToRawData = PE_Align(GetPointerToRawData(inh, ish), inh->OptionalHeader.FileAlignment);
ish.PointerToRelocations = 0;
ish.PointerToLinenumbers = 0;
ish.NumberOfRelocations = 0;
ish.NumberOfLinenumbers = 0;
ish.Characteristics = 0xE00000E0; // 可读可写可执行
// 对数据区填0
RtlZeroMemory((char *)base + ish.PointerToRawData, ish.SizeOfRawData);
inh->FileHeader.TimeDateStamp = (DWORD)time(NULL); // 修改时间戳
inh->OptionalHeader.SizeOfImage =
PE_Align(ish.VirtualAddress + ish.Misc.VirtualSize,
inh->OptionalHeader.SectionAlignment); // 调整 SizeOfImage
inh->FileHeader.NumberOfSections += 1; // 区块个数加1
return ret;
}
// **************************************************************************************
PE_Functions.h
#ifndef _PE_FUNCTIONS_H_
#define _PE_FUNCTIONS_H_
#include <windows.h>
DWORD PE_Align(DWORD tar_num, DWORD align_to);
DWORD RvaToOffset(LPVOID base, DWORD rva);
DWORD OffsetToRva(LPVOID base, DWORD offset);
// 返回值为 新增区块表的偏移
DWORD AddSection(LPVOID base, const char *section_name, DWORD section_size);
#endif
{:10_269:} 没有一个人回答吗 {:10_266:}这问题 难吗 本帖最后由 world.com 于 2018-4-17 19:01 编辑
不太清除楼主碰到的问题在什么地方。导入表可以通过数据目录表的第二个元素找到,导入表其实就是一个结构体数组。需要添加一个新区段,将导入表结构体拷贝进去 world.com 发表于 2018-4-17 19:00
不太清除楼主碰到的问题在什么地方。导入表可以通过数据目录表的第二个元素找到,导入表其实就是一个结构体 ...
朋友感谢你的回答 好开心 , 我遇到的问题是 我把导入表移动了数据目录里的导入表RVA和大小 都修改了 ,指向我新移动的导入表的位置 可是不能运行了 ,我找不到我错在那,用LordePE软件注入 程序能运行,所以 我想找个别人用C语言写的简单移动导入表源代码 比较下 看我错在那 ,希望 朋友能帮助下{:10_250:} 是不是你找的空位远了,好像要放在一个区段里? clauslam 发表于 2018-4-18 11:30
是不是你找的空位远了,好像要放在一个区段里?
我是把最后一个 节 扩大 , 然后把旧的导入表移动过去 ,把最后一个节的属性改为 可写 可读 初始化数据,
这是我看LordePE 注入后 节的属性改的 ,因为我扩大一个节的代码是正确的可运行的 没有错误,
兄弟有代码给我发个好闷{:10_250:}
嗯!感觉思路没错,能运行的话可以放OD里面调试一下看看哪里出问题了 world.com 发表于 2018-4-18 15:35
嗯!感觉思路没错,能运行的话可以放OD里面调试一下看看哪里出问题了
我用 OD 不能加载,我就是找不到 问题在那,电脑报的是 “无法启动0xc0000005”问题真烦,希望 来个 代码哎。。。 {:10_266:}有没有大神出来指点指点 啊这100鱼币 甩不出去了 啊 好心人 在哪里啊 {:10_250:} 真的没有人学 PE结构吗 真的有真么难吗 {:10_261:}等待这大神解答。。。。。。 我也是遇到了和楼主同样的问题 349561280 发表于 2018-4-29 18:19
我也是遇到了和楼主同样的问题
你能不能找到大神解释下 到底哪里出问题了 {:10_266:} 我到是很想看看你写的代码错在哪了,发你的代码
人造人 发表于 2018-4-30 00:36
我到是很想看看你写的代码错在哪了,发你的代码
代码量有点大,我试试能不能发上来
void ImportTableInjection()
{
//#pragma comment (lib,"zhuru.dll")
char* lpszFile="C:\\1.exe";
char* pszDllPath="zhuru.dll";
char* pszFunctionName="ExportFunction";
LPVOID pFileBuffer=NULL;
LPVOID pNewFileBuffer=NULL;
PIMAGE_NT_HEADERS pNtHeader=NULL;
PIMAGE_FILE_HEADER pPeHeader=NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader=NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_SECTION_HEADER pSectionHeader=NULL;
BOOL isOk;
int len=ReadFileToBuffer( lpszFile, &pFileBuffer);
if(len)
{
printf("文件读取成功\n",len);
}
else
{
printf("失败");
}
//分配一个新空间在原有文件上增加1000字节
pNewFileBuffer=malloc(len+0x1000);
if(!pNewFileBuffer)
{
printf("分配失败");
free(pFileBuffer);
return;
}
memset(pNewFileBuffer,0,len+0x1000);
memcpy(pNewFileBuffer,pFileBuffer,len);
pNtHeader=(PIMAGE_NT_HEADERS)((DWORD)pNewFileBuffer+PIMAGE_DOS_HEADER(pNewFileBuffer)->e_lfanew);
pPeHeader=(PIMAGE_FILE_HEADER)((DWORD)pNtHeader+4);
pOptionHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pPeHeader+IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPeHeader->SizeOfOptionalHeader);
pDataDirectory=(PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;//数组名就是一个地址 所以不需要在取地址
pImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewFileBuffer+RvaToFoa( pNewFileBuffer,pDataDirectory.VirtualAddress));
//扩大节 增加的首地址
char* pNewMoveAdd= (char*)(pNewFileBuffer)+len;
//修复最后一个节表的元素数据
PIMAGE_SECTION_HEADER pDestSectionHeader=(pSectionHeader+pPeHeader->NumberOfSections)-1;
pDestSectionHeader->SizeOfRawData+=0x1000;
pDestSectionHeader->Misc.VirtualSize=pDestSectionHeader->SizeOfRawData;
//pDestSectionHeader->Characteristics=pSectionHeader->Characteristics;
int i=0;
//移动原来的导入表到新的地址
while(true)
{
if( pImportDescriptor->Characteristics==0)
{
break;//判断结构体20个字节为0则结束(Characteristics为0表示结束)
}
if(pImportDescriptor->Name!=0&&pImportDescriptor->TimeDateStamp==0)
{
memcpy(pNewMoveAdd,pImportDescriptor,0x14);
pImportDescriptor++;
pNewMoveAdd+=0x14;
i++;
}
}
//增加一个新的导入表
memcpy(pNewMoveAdd,(pNewMoveAdd-0x14),0x14);
//辟免导入不需要的表
PIMAGE_THUNK_DATA pImageThunkData=(PIMAGE_THUNK_DATA)(pNewMoveAdd+0x14*2);//pImageThunkData 结构的位置
//导入DLL名
PBYTE pszDllNamePosition=(PBYTE)(pImageThunkData+2);//Dll名字的位置
memcpy(pszDllNamePosition,pszDllPath,strlen(pszDllPath));
//确定PIMAGE_IMPORT_BY_NAME的位置
PIMAGE_IMPORT_BY_NAME pImageImportByName=(PIMAGE_IMPORT_BY_NAME)(pszDllNamePosition+strlen(pszDllPath)+1);
//初始化 PIMAGE_THUNK_DATA里面的元素
pImageThunkData->u1.Ordinal=FoaToRva(pNewFileBuffer,(DWORD)pImageImportByName-(DWORD) pNewFileBuffer )- pOptionHeader->ImageBase;
//初始化IMAGE_IMPORT_BY_NAME
pImageImportByName->Hint=0;
memcpy(pImageImportByName->Name,pszFunctionName,strlen(pszFunctionName));
//初始化OriginalFirstThunk
((PIMAGE_IMPORT_DESCRIPTOR)pNewMoveAdd)->OriginalFirstThunk=FoaToRva(pNewFileBuffer,(DWORD)pImageThunkData-(DWORD) pNewFileBuffer )- pOptionHeader->ImageBase;
//初始化 FirstThunk
((PIMAGE_IMPORT_DESCRIPTOR)pNewMoveAdd)->FirstThunk=FoaToRva(pNewFileBuffer,(DWORD)pImageThunkData-(DWORD) pNewFileBuffer )- pOptionHeader->ImageBase;
// 初始化 Name
((PIMAGE_IMPORT_DESCRIPTOR)pNewMoveAdd)->Name=FoaToRva(pNewFileBuffer,(DWORD)pszDllNamePosition-(DWORD) pNewFileBuffer )-pOptionHeader->ImageBase;
//找到新增加的导入表地址 ,修复导入表的入口
pNewMoveAdd= (char*)(pNewFileBuffer)+len;
pDataDirectory.VirtualAddress=FoaToRva(pNewFileBuffer,(DWORD)pNewMoveAdd-(DWORD) pNewFileBuffer )-pOptionHeader->ImageBase;
pDataDirectory.Size=(i+1)*0x14;
//修复可选头里的 元素
pOptionHeader->SizeOfImage+=0x1000;
isOk= MeMeryToFile(pNewFileBuffer ,len+0x1000,"C:\\11.exe" );
if(isOk)
{
printf("存盘成功");
return ;
}
free(pFileBuffer);
free(pNewFileBuffer);
} 谦虚求学 发表于 2018-4-30 12:49
代码量有点大,我试试能不能发上来
zip压缩,然后网盘共享 int ReadFileToBuffer(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
{
FILE *pFile=NULL;
DWORDFilesize=0;
LPVOID pTempFileBuffer=NULL;
pFile=fopen(lpszFile, "rb");
if(!pFile)
{
printf("无法打开文件");
return NULL;
}
fseek(pFile,0,SEEK_END);
Filesize=ftell(pFile);
fseek(pFile,0,SEEK_SET);
pTempFileBuffer=malloc(Filesize);
if(!pTempFileBuffer)
{
printf("分配失败");
fclose(pFile);
return NULL;
}
size_tn=fread(pTempFileBuffer,Filesize,1,pFile);
if(!n)
{
printf("读取数据失败");
free(pTempFileBuffer);
fclose(pFile);
return NULL;
}
*pFileBuffer= pTempFileBuffer;
pTempFileBuffer =NULL;
fclose(pFile);
return Filesize;
} //存盘
BOOL MeMeryToFile(LPVOID pNewBuffer, SIZE_T Size,OUT LPSTR File)
{
FILE *fp=NULL;
fp=fopen( File,"wb+");
if(fp==NULL)
{
return FALSE;
}
fwrite(pNewBuffer,Size,1,fp);
fclose(fp);
fp=NULL;
return TRUE;
} 这些代码的意思是把文件打开 在文件里扩大文件,在扩大的最后一个节里移动导入表,在创造一个新的导入表结构等等 ,在保存文件 ,此时感觉是不是少了个文件拉伸环节,但是拉伸了还有压缩文件在保存,心理号挠。求人指点