//
//作者: 神杀中龙 microsoftxiao@163.com
//说明: 根据PE文件格式原理书写
//1. 在PE信息浏览器基础上改为增加区段工具 2007-5-12
#include
#include
#include
#include
using namespace std;
#define SAFE_DELETE(p) { if((p)!=NULL) { delete (p); (p) = NULL; }}
bool InsertSection(BYTE *decBuf, struct _stat& st, char** argv); // 插入区块
bool FillZeroArea(FILE* decFile, ULONG VirtualSize, ULONG VirtualAddress); // 填充全0区域
bool HelpInfo(char** argv);
struct _stat ST;
FILE* viewDecFile = NULL;
bool g_bHaveSetVSizeaAddress = false; // 是否设置插入段大小和地址
// Entry
int main(int argc, char** argv)
{
HelpInfo(argv);
srand(time(NULL));
if(argc <2) {
printf("Welcome to use 欢迎使用 ^_^ 神杀中龙 microsoftxiao&#64;163.com\n");
} else {
if(argv[2])
{
printf("Have VSize and VAddress\n");
g_bHaveSetVSizeaAddress &#61; true;
} else {
printf("Not set VSize and VAddress(VSize默认大小4KB(0x1000)\n");
g_bHaveSetVSizeaAddress &#61; false;
}
viewDecFile &#61; fopen(argv[1], "rb");
BYTE *buf &#61; NULL;
::_stat(argv[1], &ST);
buf &#61; new BYTE[ST.st_size];
fread(buf, 1, ST.st_size, viewDecFile);
fclose(viewDecFile);
InsertSection(buf, ST, argv);
SAFE_DELETE(buf);
}
return 0;
}
// 插入区块
bool InsertSection(BYTE *decBuf, struct _stat& st, char** argv)
{
cout<<"计算区块各参数:";
// 插入区块&#xff0c; 先获取OEP
const int offDOSStub &#61; 0x3C;
long off_elfanew &#61; 0; // 根据类型直接读出即可。
char szPEHead[5]; // PE00
WORD Machine &#61; 0; // CPU类型
DWORD AddressOfEntryPoint &#61; 0; // 程序执行入口RVA
DWORD ImageBase &#61; 0; // 程序默认装入基址
WORD SubSystem &#61; 0; // 子系统&#xff0c; 控制台或其他
DWORD SizeOfImage &#61; 0; // 内存中整个PE映像大小
WORD SizeOfOptionalHeader &#61; 0; // 可选映像头大小
DWORD SectionTableHeaderValue &#61; 0; // 块表首值 PE(Base) &#43; 0x12 &#43; SizeOfOptionalHeader
WORD NumberOfSections &#61; 0; // 块(Section)个数
DWORD SectionsLength &#61; 0; // 块长度
memcpy(&off_elfanew, &decBuf[offDOSStub], sizeof(long));
//fwrite(&off_elfanew, 1, sizeof(off_elfanew), test);
memcpy(szPEHead, &decBuf[off_elfanew], sizeof(szPEHead));
//fwrite(szPEHead, 1, sizeof(szPEHead)-1, test);
memcpy(&Machine, &decBuf[off_elfanew &#43; 0x4], sizeof(WORD));
if(Machine &#61;&#61; 0x14C)
printf("CPU Intel i386或以上系列: %X\n", Machine);
memcpy(&AddressOfEntryPoint, &decBuf[off_elfanew &#43; 0x28], sizeof(DWORD));
printf("程序入口点: 0x0%X\n", AddressOfEntryPoint);
memcpy(&ImageBase, &decBuf[off_elfanew &#43; 0x34], sizeof(DWORD));
printf("镜像基址: 0x0%X\n", ImageBase);
memcpy(&SubSystem, &decBuf[off_elfanew &#43; 0x5C], sizeof(WORD));
switch(SubSystem)
{
case 0:
printf("未知子系统\n");
break;
case 1:
printf("不需要子系统: 0x0%X\n", SubSystem);
break;
case 2:
printf("图形接口子系统(GUI): 0x0%X\n", SubSystem);
break;
case 3:
printf("控制台子系统(Console or DOS or CUI): 0x0%X\n", SubSystem);
break;
case 5:
printf("OS/2字符子系统: 0x0%X\n", SubSystem);
break;
case 7:
printf("POSIX字符子系统: 0x0%X\n", SubSystem);
break;
default:
printf("未知子系统\n");
break;
}
memcpy(&SizeOfImage, &decBuf[off_elfanew &#43; 0x50], sizeof(DWORD));
printf("内存镜像大小: 0x%X\n", SizeOfImage);
memcpy(&SizeOfOptionalHeader, &decBuf[off_elfanew &#43; 0x14], sizeof(WORD));
printf("可选映像头大小: %d字节(%X)\n", SizeOfOptionalHeader,SizeOfOptionalHeader);
memcpy(&SectionTableHeaderValue, &decBuf[off_elfanew &#43; 0x18 &#43; SizeOfOptionalHeader], sizeof(DWORD));
printf("块表首值: %X\n", SectionTableHeaderValue);
memcpy(&NumberOfSections, &decBuf[off_elfanew &#43; 0x06], sizeof(WORD));
printf("块(Sections)个数: %X\n", NumberOfSections);
IMAGE_SECTION_HEADER tISH; // 块表结构实例
ZeroMemory(&tISH, sizeof(tISH));
printf("块表项结构大小: %d字节\n", sizeof(tISH));
int t_totalSectionLength &#61; sizeof(tISH) * NumberOfSections;
printf("总块表长度: %d字节(%X)\n", t_totalSectionLength, t_totalSectionLength);
int t_InsertPosition &#61; 0x18 &#43; SizeOfOptionalHeader &#43; t_totalSectionLength;
printf("插块表项偏移位置: 0x0%X\n", t_InsertPosition);
char szNewFileName[260];
sprintf(szNewFileName, "__666%d_.exe",rand()%10000);
FILE* test &#61; fopen(szNewFileName, "wb");
fwrite(decBuf, 1, ST.st_size, test);
// 加区块
if(test) {
strncpy((char*)tISH.Name, ".pediy", sizeof(tISH.Name));
tISH.Misc.VirtualSize &#61; 0x3E000; // 4KB
tISH.SizeOfRawData &#61; 0x3E000;
tISH.VirtualAddress &#61; st.st_size; // 改地址应该为增加的一个空闲区 应该是先加区段&#xff0c;然后再改入口点 此地址作为最后的偏移量
tISH.PointerToRawData &#61; st.st_size; // 行号表中行号的数目
if(g_bHaveSetVSizeaAddress)
{
tISH.Misc.VirtualSize &#61; atoi(argv[2]); // 4KB
tISH.SizeOfRawData &#61; atoi(argv[2]);
}
tISH.PointerToRelocations &#61; 0; // 在OBJ文件中使用&#xff0c; 重定位的偏移
tISH.PointerToLinenumbers &#61; 0; // 行号表的偏移(供调试用)
tISH.NumberOfRelocations &#61; 0; // 在OBJ文件中使用&#xff0c;重定位项目数
tISH.NumberOfLinenumbers &#61; 0;
tISH.Characteristics &#61; 0xE0000020; // 块属性&#xff0c; 表示包含执行代码、可读写并可执行。
fseek(test, 0, SEEK_SET);
fseek(test, off_elfanew &#43; t_InsertPosition, SEEK_SET);
fwrite(&tISH, 1, sizeof(tISH), test); // 写入块结构
fseek(test, off_elfanew &#43; 0x06, SEEK_SET);
NumberOfSections&#43;&#43;;
fwrite(&NumberOfSections, 1, sizeof(NumberOfSections), test); // 修改块数目
SizeOfImage &#43;&#61; tISH.SizeOfRawData; // 对齐后的大小?
fseek(test, off_elfanew &#43; 0x50, SEEK_SET); // 定位
fwrite(&SizeOfImage, 1, sizeof(SizeOfImage), test);
FillZeroArea(test, tISH.Misc.VirtualSize, tISH.VirtualAddress); //在指定地址后写零
}
fclose(test);
remove(argv[1]);
rename(szNewFileName, argv[1]);
return 0;
}
// 填充全零区
bool FillZeroArea(FILE* decFile, ULONG VirtualSize, ULONG VirtualAddress)
{
fseek(decFile, VirtualAddress, SEEK_SET);
BYTE *szBuf &#61; NULL;
szBuf &#61; new BYTE[VirtualSize];
strncpy((char*)szBuf, "Z", VirtualSize);
fwrite(szBuf, 1, VirtualSize, decFile);
BYTE tmp &#61; 0;
fseek(decFile, VirtualAddress, SEEK_SET);
fwrite(&tmp, 1, sizeof(tmp), decFile);
SAFE_DELETE(szBuf);
return 0;
}
bool HelpInfo(char** argv)
{
printf("帮助\n");
printf("%s 目标PE文件(destination) 新加块大小(VirtualSize) 新加块偏移地址(VirtualAddress)\n", argv[0]);
return 0;
}
这里破东西还不让发代码&#xff0c; 总之PE加区段编要注意 内存映像的增加&#xff0c; 区块数的增加。
还有偏移地址等。
strncpy((char*)tISH.Name, ".pediy", sizeof(tISH.Name));
tISH.Misc.VirtualSize &#61; 0x1000; // 4KB
tISH.SizeOfRawData &#61; 0x1000;
tISH.VirtualAddress &#61; SizeOfImage; // 改地址应该为增加的一个空闲区 应该是先加区段&#xff0c;然后再改入口点 此地址作为最后的偏移量
tISH.PointerToRawData &#61; st.st_size; // 行号表中行号的数目
if(g_bHaveSetVSizeaAddress)
{
tISH.Misc.VirtualSize &#61; atoi(argv[2]); // 4KB
tISH.SizeOfRawData &#61; atoi(argv[2]);
}
tISH.PointerToRelocations &#61; 0; // 在OBJ文件中使用&#xff0c; 重定位的偏移
tISH.PointerToLinenumbers &#61; 0; // 行号表的偏移(供调试用)
tISH.NumberOfRelocations &#61; 0; // 在OBJ文件中使用&#xff0c;重定位项目数
tISH.NumberOfLinenumbers &#61; 0;
tISH.Characteristics &#61; 0xE0000020; // 块属性&#xff0c; 表示包含执行代码、可读写并可
加区段工具&#xff0c; 在设置 VirtualAddress 实际上是该区段在内存中的偏移量&#xff0c; 所以&#xff0c; 这个地址只要是内存映像大小即可。
而文件偏移地址 PointerToRawData 则为文件的大小。
这也是为什么有的时候这两个值不一样的原因&#xff0c; 尽管内存映像的各区块大概 和磁盘文件是一一对应的。但是 实际上映射的地址 还是有偏移的。所以 有时当VirtualAddress 和 PointerToRawData相同时则可以执行&#xff0c; 有的时候相同时反而出错&#xff0c; 就是由于 装载地址不一致导致的&#xff0c; 也就是一致的地址&#xff0c;
那个地址值原来可能有数据了&#xff0c; 若再装载就等于要覆盖那个地址的数据。 既然在磁盘上区块是添加在文件尾&#xff0c; 那在内存中当然也就是内存映像尾恩。