PE文件笔记-代码解析PE
作为一个java开发人员。再学了一个多月的PE的文件了把PE文件中的一些常识都了解一波;想着继续整理一下PE的知识,但是想着自己的文笔有限,怎么样才能更好的表达自己的想法了。这里就用代码来代替我的想法;我这个exe文件只有导入表;所以这里我就只解析了项目表中导入表.同时我这里使用的是 【吾爱破解论坛学习脱壳实例_VC6.exe】这是站内教学中的一个exe。我这里就直接拿来用了(本来想着上传exe的,但是发现上次失败。。)这里主要是对PE文件中的固定部分进行了解析:[*]dos头部分
[*]NT pe文件
[*]节表头
以及在pe文件中会使用到的PE项目表--导入表;
exe一般来说只有导入表,没有导出表,所以没有解析导出表。
----
然后做一个坑两个多月的菜鸡来说,在看了站内的脱壳课程,了解了一些脱基础壳的知识后。在加上一个月PE的学习,稍稍了解了大佬们的那些脱壳操作为什么要这么做了。
对于一些和我一样刚刚入坑的小伙伴们说一声学PE文件真的很有必要。{:1_927:}#include<Windows.h>
#include<stdio.h>
#define FILE_ANALY_WRAP printf("\n\n");
#define SINGAL_WRAP printf("\n\n");
PIMAGE_SECTION_HEADER nodeArr;
int nodeLength;
int SectionAlignment;
int getFoa(DWORD RVA) {
int FOA = 0;
if (SectionAlignment > RVA) {
return RVA;
}
for (int i = 0;i < nodeLength;i++) {
if (nodeArr.VirtualAddress < RVA &&
(nodeArr.VirtualAddress + nodeArr.Misc.VirtualSize) > RVA) {
FOA = nodeArr.PointerToRawData + (RVA - nodeArr.VirtualAddress);
}
}
return FOA;
}
void AnalyEntryImportFile(int offset, LPVOID pFile) {
printf("IMAGE_DIRECTORY_ENTRY_IMPORT FOA【%X】\n", offset);
int count = 0;
UINT fileStart = (UINT)pFile;
do {
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(fileStart + offset+count*sizeof(_IMAGE_IMPORT_DESCRIPTOR));
if (pImport->OriginalFirstThunk == NULL)
{
printf("import file total 【%d】\n", count);
break;
}
count++;
int nameAddr = getFoa(pImport->Name);
int oft = getFoa(pImport->OriginalFirstThunk);
printf("add dll file name is 【%s】 \t FOA:【%X】\n",(char *)(fileStart +nameAddr),oft);
int flag = 0;
do
{
PIMAGE_THUNK_DATA32 pThunkData = (PIMAGE_THUNK_DATA32)(fileStart + oft + flag * sizeof(_IMAGE_THUNK_DATA32));
if (pThunkData->u1.AddressOfData == 0) {
break;
}
flag++;
/*
* DWORD最高位为0,那么该数值是一个RVA,指向_IMAGE_IMPORT_BY_NAME结构,表明函数是以字符串类型的函数名导入的
* DWORD最高位为1,那么该数值的低31位就是函数的导出函数的序号
*/
int thunkAddressOfData = getFoa(pThunkData->u1.AddressOfData);
if ((pThunkData->u1.AddressOfData & 0x80000000) > 1) {
int addr = pThunkData->u1.AddressOfData & 0x7FFFFFFF;
printf("\t\t import file method NO 【%d】\n", addr,(WORD*)((UINT)pFile + addr));
}
else
{
PIMAGE_IMPORT_BY_NAME pImpotName = (PIMAGE_IMPORT_BY_NAME)((UINT)pFile + thunkAddressOfData);
printf("\t METHOD【%s】 FOA【%X】\n", pImpotName->Name, thunkAddressOfData);
}
} while (true);
SINGAL_WRAP
} while (true);
};
int main() {
printf("hello PE file.....\n");
//读取文件,返回文件句柄
HANDLE hFile = CreateFileA("C:\\Users\\dragon\\Desktop\\吾爱破解论坛学习脱壳实例_VC6.exe"
, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
//根据文件句柄创建映射
HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, 0, 0, 0);
//映射内容
LPVOID pFile = MapViewOfFile(hMap, FILE_SHARE_WRITE, 0, 0, 0);
//创建DOS对应的结构体指针
_IMAGE_DOS_HEADER* dos;
//类型转换,用结构体的方式来读取
//DOS 数据头
dos = (_IMAGE_DOS_HEADER*)pFile;
printf("DOS INFO MESSAGE \n");
printf("dos->e.magic:%X \n", dos->e_magic);
//输出dos->e_magic,以十六进制输出
printf("dos->e.magic:%X \n", dos->e_magic);
//PE文件开头的位置
printf("dos->PE NT header offset :\t%X", dos->e_lfanew);
FILE_ANALY_WRAP
//NT头文件
//_IMAGE_NT_HEADERS
PIMAGE_NT_HEADERS32 NT_PeHeader = (PIMAGE_NT_HEADERS32)((UINT)dos + dos->e_lfanew);
printf("PE NT Signature:%X\n", NT_PeHeader->Signature);
PIMAGE_FILE_HEADER pFileHeader = &NT_PeHeader->FileHeader;
printf("Machine 【CPU类型】%X\n", pFileHeader->Machine);
printf("NumberOfSections 【节表数量】%X\n", pFileHeader->NumberOfSections);
printf("SizeOfOptionalHeader 【扩展PE头大小】%X\n\n", pFileHeader->SizeOfOptionalHeader);
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &NT_PeHeader->OptionalHeader;
printf("NT MAGIC【程序类型 (32位则10B,64位则20B)】 : %X \n", pOptionalHeader->Magic);
printf("program AddressOfEntryPoint :【入口偏移地址】 %X \n", pOptionalHeader->AddressOfEntryPoint);
printf("ImageBase 【基地址】:%X \n", pOptionalHeader->ImageBase);
printf(" 【程序实际入口位置】:%X \n", pOptionalHeader->AddressOfEntryPoint + pOptionalHeader->ImageBase);
printf("SectionAlignment 【内存大小】: %X \n FileAlignment【文件偏移】: %X \n", pOptionalHeader->SectionAlignment, pOptionalHeader->FileAlignment);
SectionAlignment = pOptionalHeader->SectionAlignment;
printf("SizeOfImage 【内存大小】: %X \n SizeOfHeaders 【文件大小】: %X \n", pOptionalHeader->SizeOfImage, pOptionalHeader->SizeOfHeaders);
printf("NumberOfRvaAndSizes : 【项目表类型数量】%X \n", pOptionalHeader->NumberOfRvaAndSizes);
PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionalHeader->DataDirectory;
for (int i = 0;i < pOptionalHeader->NumberOfRvaAndSizes;i++) {
printf("index 【%d】 address 【%X】 size 【%X】\n", i, pDataDirectory.VirtualAddress, pDataDirectory.Size);
}
FILE_ANALY_WRAP
/**
节表
*/
nodeLength = pFileHeader->NumberOfSections;
PIMAGE_SECTION_HEADER pNodeStart = (PIMAGE_SECTION_HEADER)((UINT)NT_PeHeader + sizeof(_IMAGE_NT_HEADERS));
nodeArr = new IMAGE_SECTION_HEADER;
memcpy(nodeArr, pNodeStart, nodeLength * sizeof(IMAGE_SECTION_HEADER));
for (int i = 0;i < nodeLength;i++) {
char* name = new char.Name)];
memcpy(name, nodeArr.Name, sizeof(nodeArr.Name));
printf("PE NODE 【%s】 virtualAddress 【%X】 virtualSize:【%X】 fileAddress【%X】 fileSize【%X】\n", name,
nodeArr.VirtualAddress + pOptionalHeader->ImageBase,
nodeArr.Misc.VirtualSize,
nodeArr.PointerToRawData,
nodeArr.SizeOfRawData);
delete [] name;
}
FILE_ANALY_WRAP
/*
* 项目表信息
*/
for (int i = 0; i < pOptionalHeader->NumberOfRvaAndSizes; i++)
{
if (pDataDirectory.VirtualAddress == 0x0) {
continue;
}
/* int foa = 0;
for (int i = 0;i < nodelength;i++) {
if (nodearr.virtualaddress < pdatadirectory.virtualaddress &&
(nodearr.virtualaddress + nodearr.misc.virtualsize) > pdatadirectory.virtualaddress) {
foa = nodearr.pointertorawdata + (pdatadirectory.virtualaddress - nodearr.virtualaddress);
}
}*/
int FOA= getFoa(pDataDirectory.VirtualAddress);
switch (i) {
case IMAGE_DIRECTORY_ENTRY_EXPORT:
printf("this pe file has IMAGE_DIRECTORY_ENTRY_EXPORT\n");
break;
case IMAGE_DIRECTORY_ENTRY_IMPORT:
printf("this pe file has IMAGE_DIRECTORY_ENTRY_IMPORT\n");
AnalyEntryImportFile(FOA, pFile);
break;
case IMAGE_DIRECTORY_ENTRY_BASERELOC:
printf("this pe file has IMAGE_DIRECTORY_ENTRY_BASERELOC\n");
break;
};
}
delete[] nodeArr;
return 0;
}
页:
[1]