为了加深对PE文件的理解,以及和进程有关的WIN32 API的应用,就做出了这么一个东西。DUMP的话只需要DUMP出DOS头 + PE头 + 区块即可。
#include "stdafx.h"
typedef struct
{
WORD e_magic;
char Data[23 + sizeof(DWORD) * 3];
LONG e_lfanew;
}Dos,*pDos;
int GetPageSize(void) /* 获取内存页大小 */
{
SYSTEM_INFO SystemInformation;
GetSystemInfo(&SystemInformation);
return SystemInformation.dwPageSize;
}
int main(void)
{
HANDLE Handle;
PROCESSENTRY32W pe;
LPPROCESSENTRY32W ppe;
CHAR szExeFile[MAX_PATH];
CHAR szExePath[MAX_PATH];
MODULEENTRY32W ModuleEntry32W;
HANDLE ProcessHandle;
DWORD old;
HANDLE Process;
HANDLE hFile;
HANDLE hMap;
FILE *File;
CHAR szDumpedFileName[MAX_PATH];
DWORD Oep;
DWORD CodeBaseAddr_;
DWORD DataBaseAddr_;
DWORD pBuf;
PIMAGE_NT_HEADERS32 pNtHeaders32;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_SECTION_HEADER pSecHeader;
PIMAGE_SECTION_HEADER pSec;
pDos MyDosHeader;
char Msg[] = " DumpExeFile Coded by yeeeee ";
unsigned char Buffer[8192] = {0};
unsigned char *pSectionBuffer;
unsigned char *pBuffer;
int Number;
char IsXz[123];
int num;
int Num;
int size;
int i;
Num ^= Num;
Number ^= Number;
/* 获取进程数量 */
SetConsoleTitleW(L"DumpExeFile Coded by yeeeee QQ群:Alg & Sec lab of China 群号:254394017");
Handle = CreateToolhelp32Snapshot(TH32CS_SNAPALL,NULL);
if(Handle == INVALID_HANDLE_VALUE)
{
puts("创建快照失败!");
goto Exit;
}
pe.dwSize = sizeof(PROCESSENTRY32W);
if(!Process32FirstW(Handle,&pe))
{
puts("获取进程列表失败!");
goto Exit;
}
do
Number++;
while(Process32NextW(Handle,&pe));
/* 获取系统全部进程 */
ppe=(LPPROCESSENTRY32W)malloc(Number * sizeof(PROCESSENTRY32W));
if(!ppe)
{
puts("申请内存失败!");
goto Exit;
}
for(i = 0;i < Number;i++)
ppe[i].dwSize = sizeof(PROCESSENTRY32W);
if(!Process32FirstW(Handle,&ppe[0]))
{
puts("获取进程列表失败!");
goto Exit;
}
WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
ppe[0].szExeFile,
sizeof(ppe[0].szExeFile),
szExeFile,
sizeof(szExeFile),
NULL,
FALSE);
printf("1.进程名:%s\n",szExeFile);
for(i = 1;i < Number;i++)
{
if(!Process32NextW(Handle,&ppe[i]))
break;
WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
ppe[i].szExeFile,
sizeof(ppe[i].szExeFile),
szExeFile,
sizeof(szExeFile),
NULL,
FALSE);
printf("%d.进程名:%s\n",i + 1,szExeFile);
}
printf("一共有 %d 个进程\n要Dump的Exe文件进程序号:",Number);
scanf("%d",&num);
ProcessHandle = CreateToolhelp32Snapshot(TH32CS_SNAPALL,ppe[num - 1].th32ProcessID);
if(ProcessHandle == INVALID_HANDLE_VALUE)
{
puts("创建快照失败!");
CloseHandle(Handle);
free(ppe);
goto Exit;
}
ModuleEntry32W.dwSize = sizeof(MODULEENTRY32W);
if(!Module32FirstW(ProcessHandle,&ModuleEntry32W))
{
WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
ppe[num - 1].szExeFile,
sizeof(ppe[num - 1].szExeFile),
szExeFile,
sizeof(szExeFile),
NULL,
FALSE);
printf("%d:%s\n",num,szExeFile);
printf("检索进程信息失败!错误号:%d\n",GetLastError());
goto Clean;
}
WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
ppe[num - 1].szExeFile,
sizeof(ppe[num - 1].szExeFile),
szExeFile,
sizeof(szExeFile),
NULL,
FALSE);
WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
ModuleEntry32W.szExePath,
sizeof(ModuleEntry32W.szExePath),
szExePath,
sizeof(szExePath),
NULL,
FALSE);
printf("%d:%s\n\t- %s\nBase address:%xh\nBase size:%xh\n",
num,
szExeFile,
szExePath,
ModuleEntry32W.modBaseAddr,
ModuleEntry32W.modBaseSize);
Process = OpenProcess(PROCESS_VM_OPERATION|
PROCESS_VM_READ|
PROCESS_VM_WRITE|
PROCESS_TERMINATE,
FALSE,
ModuleEntry32W.th32ProcessID);
if(!Process)
{
printf("打开进程失败!错误号:%d\n",GetLastError());
goto Clean;
}
printf("Exe文件入口点(RVA):");
scanf("%x",&Oep);
printf("代码基址(RVA):");
scanf("%x",&CodeBaseAddr_);
printf("数据基址(RVA):");
scanf("%x",&DataBaseAddr_);
printf("Virtual protect:%d\nLast error:%d\n",
VirtualProtectEx(Process,
ModuleEntry32W.modBaseAddr,
sizeof(Buffer),
PAGE_EXECUTE_READWRITE,
&old),
GetLastError());
ReadProcessMemory(Process,
ModuleEntry32W.modBaseAddr,
Buffer,
sizeof(Buffer),
0),
GetLastError();
strcpy(szDumpedFileName,szExePath);
strcat(szDumpedFileName,".Dumped.exe");
pDosHeader = (PIMAGE_DOS_HEADER)Buffer;
if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
puts("不是有效的PE文件!");
goto Clean;
}
pNtHeaders32 = (PIMAGE_NT_HEADERS32)&Buffer[pDosHeader->e_lfanew];
if(pNtHeaders32->Signature != IMAGE_NT_SIGNATURE)
{
puts("不是PE文件,这像一个DOS文件!");
goto Clean;
}
printf("申请内存大小:%xh\n",
(pNtHeaders32->OptionalHeader.SizeOfImage +
pNtHeaders32->OptionalHeader.SizeOfHeaders +
GetPageSize()) * sizeof(unsigned char));
pBuf = (DWORD)VirtualAlloc(NULL,
(pNtHeaders32->OptionalHeader.SizeOfImage +
pNtHeaders32->OptionalHeader.SizeOfHeaders + GetPageSize()),
MEM_RESERVE|MEM_COMMIT,
PAGE_READWRITE);
if(!pBuf)
{
puts("申请内存失败!");
CloseHandle(Process);
goto Clean;
}
printf("头大小:%xh\n",pNtHeaders32->OptionalHeader.SizeOfHeaders);
puts("Dump文件头......");
/* Dump头 */
memcpy((char*)pBuf,Buffer,pNtHeaders32->OptionalHeader.SizeOfHeaders);
puts("Dump文件头完毕\nDump区块......");
pSecHeader = IMAGE_FIRST_SECTION(pNtHeaders32);
for(i = 0;i < pNtHeaders32->FileHeader.NumberOfSections;i++)
{
printf("区块名 %s\t区块大小:%xh\t区块虚拟地址:%xh\t区块映像地址:%xh\n",
pSecHeader->Name,
pSecHeader->SizeOfRawData,
pSecHeader->VirtualAddress,
pSecHeader->PointerToRawData);
pSectionBuffer = (unsigned char*)malloc(pSecHeader->Misc.VirtualSize * sizeof(unsigned char));
if(!pSectionBuffer)
{
puts("Dump区块失败!无法分配内存!");
VirtualFree((char*)pBuf,0,MEM_RESERVE);
goto Clean;
}
printf("VirtualProtect:%d Last error:%d\n",
VirtualProtectEx(Process,
ModuleEntry32W.modBaseAddr + pSecHeader->VirtualAddress,
pSecHeader->Misc.VirtualSize,
PAGE_EXECUTE_READWRITE,
&old),
GetLastError());
printf("Dumped:%d\n",
ReadProcessMemory(Process,
ModuleEntry32W.modBaseAddr + pSecHeader->VirtualAddress,
pSectionBuffer,
pSecHeader->Misc.VirtualSize,
NULL));
memcpy((char*)pBuf + pSecHeader->PointerToRawData,pSectionBuffer,pSecHeader->Misc.VirtualSize);
free(pSectionBuffer);
pSecHeader++;
}
puts("Dump区块完毕!\n开始保存文件......");
File = fopen(szDumpedFileName,"wb+");
if(!File)
{
puts("保存文件失败!无法创建文件");
VirtualFree((char*)pBuf,0,MEM_RESERVE);
goto Clean;
}
fwrite((char*)pBuf,
pNtHeaders32->OptionalHeader.SizeOfImage +
pNtHeaders32->OptionalHeader.SizeOfHeaders + GetPageSize(),
1,
File);
fseek(File,78,SEEK_SET);/* 移动78个字节,到 'This program cannot be run in dos mode' */
fwrite(Msg,strlen(Msg),1,File);/* 写入信息 */
fclose(File);
puts("文件保存完毕!\n开始修复入口点,代码基址,数据基址");
VirtualFree((char*)pBuf,0,MEM_RESERVE);
/* 修复入口点,代码基址,数据基址 */
hFile = CreateFileA(szDumpedFileName,
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
printf("修复文件失败!打开Dump文件失败.文件名:%s Last error:%d\n",szDumpedFileName,GetLastError());
goto Clean;
}
size = GetFileSize(hFile,0);
hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,size,NULL);
if(hMap == INVALID_HANDLE_VALUE)
{
goto UnView;
UnView:
printf("映射Dump文件到磁盘失败!文件名:%s Last error:%d\n",szExePath,GetLastError());
CloseHandle(hFile);
goto Clean;
}
pBuffer = (unsigned char*)MapViewOfFile(hMap,FILE_MAP_WRITE|FILE_MAP_READ,0,0,size);
if(!pBuffer)
{
CloseHandle(hMap);
goto UnView;
}
pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
pNtHeaders32 = (PIMAGE_NT_HEADERS32)&pBuffer[pDosHeader->e_lfanew];
pNtHeaders32->OptionalHeader.AddressOfEntryPoint = Oep;
pNtHeaders32->OptionalHeader.BaseOfCode = CodeBaseAddr_;
pNtHeaders32->OptionalHeader.BaseOfData = DataBaseAddr_;
printf("修正脱壳镜像中物理地址和物理大小(Y or N):");
scanf("%s",IsXz);
if(!stricmp(IsXz,"Y"))
{
puts("修正物理地址和物理大小......");
/* 修正物理地址和物理大小 */
pSec = IMAGE_FIRST_SECTION(pNtHeaders32);
for(i = 0;i < pNtHeaders32->FileHeader.NumberOfSections;i++)
pSecHeader--;
for(i = 0;i < pNtHeaders32->FileHeader.NumberOfSections;i++)
{
pSec->SizeOfRawData = pSecHeader->Misc.VirtualSize;
pSec->PointerToRawData = pSecHeader->VirtualAddress;
pSec++;
pSecHeader++;
}
puts("修正物理地址和物理大小完毕");
}
MyDosHeader = (pDos)pBuffer;
strcpy(MyDosHeader->Data," QQ群:Alg & Sec lab of China 群号:254394017 ");/* 写入信息 */
UnmapViewOfFile(pBuffer);
CloseHandle(hFile);
CloseHandle(hMap);
puts("Dump完成");
goto Clean;
Clean:
CloseHandle(ProcessHandle);
CloseHandle(Handle);
free(ppe);
goto Exit;
Exit:
system("pause");
return 0;
}
stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: 在此处引用程序需要的其他头文件
#include <stdlib.h>
#include <windows.h>
#include <TlHelp32.h>
程序截图:
DUMP一个文件后,用记事本打开这个文件,会看到这样的东西:
嘿嘿。。。。
参考资料:http://blog.csdn.net/iiprogram/article/details/2298838(我是从这里才知道的 DUMP文件只需要DUMP出DOS头 + PE头 + 区块)就行。