前言
分析windwos下的木马时经常会碰见dump的恶意代码文件无法直接查看。
一是因为文件数据在内存展开,而区段的属性未修改;
二是因为数据在内存展开后,重定位数据被修改。
因此写个工具进行修复。
说明一下dump内存起始地址为dump恶意代码内存块的起始地址。
一、代码示例
1.文件对齐
//文件对齐
DWORD CFixDumpDlg::GetOffset(DWORD argc)
{
DWORD a = 0;
DWORD b = 0;
a = argc % 0x200;
if (a > 0)
{
b = (argc / 0x200) + 1;
return b;
}
else
{
b = argc / 0x200;
return b;
}
}
2.RVA转换FOA
//RVA转换FOA
DWORD rvaTOfoa(PIMAGE_NT_HEADERS pNT, DWORD rva)
{
//获取区段头
PIMAGE_SECTION_HEADER psection = IMAGE_FIRST_SECTION(pNT);
//循环比较获取所在区段
for (DWORD i = 0; i < pNT->FileHeader.NumberOfSections; i++)
{
if ((rva >= psection[i].VirtualAddress) && (rva <= (psection[i].VirtualAddress + psection[i].SizeOfRawData)))
{
return rva - psection[i].VirtualAddress + psection[i].PointerToRawData;
// 获取到虚拟地址后加上区段在文件内的起始位置就是文件偏移
}
}
}
3.将内存展开数据还原为文件数据
BOOL CFixDumpDlg::FixPeVirtualData(LPVOID data,CString filepath)
{
//声明变量
PIMAGE_DOS_HEADER pdos = NULL;
PIMAGE_NT_HEADERS pnt = NULL;
PIMAGE_FILE_HEADER pfile = NULL;
PIMAGE_OPTIONAL_HEADER poptional = NULL;
DWORD count = 0; //区段数量
DWORD AlignmentSize = 0; //内存对齐后的大小
LPVOID p_address = NULL; //申请的内存地址
DWORD size = 0;
DWORD index = 0;
//初始化
pdos = (PIMAGE_DOS_HEADER)data;
pnt = (PIMAGE_NT_HEADERS)((DWORD)data + pdos->e_lfanew);
pfile = &(pnt->FileHeader);
poptional = &(pnt->OptionalHeader);
//获取区段的数量和大小
count = pfile->NumberOfSections;
//获取区段信息 区段头表在NT头后面
PIMAGE_SECTION_HEADER psection = IMAGE_FIRST_SECTION(pnt);
size = psection[count - 1].SizeOfRawData + psection[count - 1].PointerToRawData;
size = GetOffset(size) * 0x200;
//在内存中申请展开后的大小
p_address = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
Save_address = p_address;
FileSize = size;
if (p_address == NULL) return FALSE;
//修复PE头
memcpy(p_address, data, 0x400);
p_address = (LPVOID)((DWORD)p_address + 0x400);
//展开区段数据
while (count)
{
DWORD rawsize = psection->SizeOfRawData;
DWORD v_address = psection->VirtualAddress;
DWORD rawdata = psection->PointerToRawData;
LPVOID data_addr = (LPVOID)((DWORD)data + v_address);
if (rawsize != 0)
{
rawsize = GetOffset(rawsize) * 0x200;
memcpy(p_address, data_addr, rawsize);
}
p_address = (LPVOID)((DWORD)p_address + rawsize);
psection++;
count--;
index++;
}
return TRUE;
}
4.修复重定位
//修复重定位
void CFixDumpDlg::FixReloc(LPVOID buff)
{
//声明变量
PIMAGE_DOS_HEADER pdos = NULL;
PIMAGE_NT_HEADERS pnt = NULL;
PIMAGE_FILE_HEADER pfile = NULL;
PIMAGE_OPTIONAL_HEADER poptional = NULL;
DWORD old_imagebase;
DWORD new_imagebase;
struct typeoffset
{
WORD offset : 12;
WORD type : 4;
}*pTpOffset;
//初始化
pdos = (PIMAGE_DOS_HEADER)buff;
pnt = (PIMAGE_NT_HEADERS)((DWORD)buff + pdos->e_lfanew);
poptional = &(pnt->OptionalHeader);
//获取重定位表的偏移
DWORD RelRva = poptional->DataDirectory[5].VirtualAddress;
DWORD RelFoa = rvaTOfoa(pnt,RelRva);
PIMAGE_BASE_RELOCATION pRelTable = (PIMAGE_BASE_RELOCATION)((DWORD)buff+RelFoa);
while (pRelTable->SizeOfBlock != 0)
{
pTpOffset = (typeoffset*)(pRelTable + 1);
DWORD RELcount = (pRelTable->SizeOfBlock - 8) / 2;
for (int i = 0; i < RELcount; i++)
{
if (pTpOffset[i].type == 3)
{
RelFoa= rvaTOfoa(pnt, pRelTable->VirtualAddress);
DWORD fix_addr = (DWORD)buff+ RelFoa + pTpOffset[i].offset;
*(DWORD*)fix_addr -= MemoryAddress;
*(DWORD*)fix_addr += poptional->ImageBase;
}
}
pRelTable = (IMAGE_BASE_RELOCATION*)((LPBYTE)pRelTable + pRelTable->SizeOfBlock);
}
}