dragon1996 发表于 2021-6-27 18:44

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]
查看完整版本: PE文件笔记-代码解析PE