okboy 发表于 2023-3-15 23:55

滴水三期 3.13号(节表)程序解析课后作业记录

大家好,第一次发帖,记录一下学习过程.
不知道大家入门是不是学的滴水三期的,我在pe结构里面折腾了很久,c语言还没到入门级别,写出来的代码一部分是参考网络上的,可能里面的代码写的不对,但是它还是奶牛能挤奶.希望得到各位大佬的拍砖
```cpp
#define _CRT_SRCURE_NO_DEPRECATE
#pragma warning(disable:4996)
#include <Windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
//获取文件的大小,返回文件的大小
//打开文件到内存
//打印信息
// 1.获取文件的路径,返回文件指针
FILE* file_path() {
        printf("请输入文件的路径\n");
        char file_name = { '\0' };
        scanf("%s", file_name);
        FILE* fp = fopen(file_name, "rb");
        if (!fp) {
                printf("打开文件失败啦~~~~");
                return NULL;
        }
        return fp;
}
//1.获取文件的大小
unsigned int getsize(FILE*fp) {
        if (fp==NULL) {
                return 0;
        }
        fseek(fp, 0, SEEK_END);
        unsigned int file_length = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        return file_length;

}
//2:打开文件,传入文件字节数,然后根据这个大小申请内存空间,然后读到内存中,返回一个内存地址空间
PVOID mem_adress(unsigned int file_length,FILE*fp) {
        if (file_length == 0) {
                printf("申请内存空间失败啦~~~~");
                return NULL;
        }
        PVOID adress = malloc(file_length);
        if (adress == NULL) {
                printf("申请内存空间失败!!!!");
        }
        memset(adress, 0, file_length);
        fread(adress, file_length, 1, fp);
        //把getsize的文件关闭掉
        fclose(fp);
        printf("内存地址为**********%p**************\n", adress);
        return adress;

}
/*
#define IMAGE_DOS_SIGNATURE               0x5A4D      // MZ
#define IMAGE_OS2_SIGNATURE               0x454E      // NE
#define IMAGE_OS2_SIGNATURE_LE            0x454C      // LE
#define IMAGE_VXD_SIGNATURE               0x454C      // LE
#define IMAGE_NT_SIGNATURE                  0x00004550// PE00
这是系统自带的define 在winnt.h里面
*/

//用windows 自带的结构体 打印dos文件的信息
void pe_DOS_info(char* adress) {
        PIMAGE_DOS_HEADER pdos = NULL;//dos头结构体指针,这是一个结构体指针
        pdos = (PIMAGE_DOS_HEADER)adress;
        printf("%x", pdos->e_magic);
        printf("%08x", pdos->e_lfanew);
}
//用偏移的方法打印pe标志符
void pe_NT_info(char* adress) {
        PIMAGE_NT_HEADERS32 pnt = (PIMAGE_NT_HEADERS32)(adress + 0xE0);
        printf("%08x", pnt->Signature);
                //IMAGE_NT_SIGNATURE
}
//不通过偏移的方法打印pe fileheader的内容
void pe_FILEHEADER_info(char* adress) {
        PIMAGE_FILE_HEADER pfile = (PIMAGE_FILE_HEADER)(adress + 0xe0 + 0x4);
        printf("********machine机器码为(word):\n");
        printf("%04x\n", pfile->Machine);
        printf("********numberofsections节的数量为(word):\n");
        printf("%04x\n", pfile->NumberOfSections);
        printf("********time of stamp时间戳为(dword):\n");
        printf("%08x\n", pfile->TimeDateStamp);
        printf("********pointer to symbol table未知为(dword):\n");
        printf("%08x\n", pfile->PointerToSymbolTable);
        printf("********numberofstmbols未知为(dword):\n");
        printf("%08x\n", pfile->NumberOfSymbols);
        printf("********size of optional header可选pe头的大小为(word):\n");
        printf("%04x\n", pfile->SizeOfOptionalHeader);//可选pe头的大小
        printf("********character ristics文件属性为(word):\n");
        printf("%04x\n", pfile->Characteristics);
        if (pfile->SizeOfOptionalHeader != 0xE0) {
                printf("是32位的软件\n");
        }
        //printf("%x", sizeof(_IMAGE_FILE_HEADER));
        printf("%p\n", &(pfile->Characteristics) + 1);//良字节的地址,加1,就是过去两个字节
        PIMAGE_OPTIONAL_HEADER32 pop = (PIMAGE_OPTIONAL_HEADER32)((&pfile->Characteristics) + 0x1);
        printf("%04x\n", pop->Magic);
        printf(" sizeOfCode\n");
        printf("%x\n", pop->SizeOfCode);
        printf(" BaseOfCode\n");
        printf("%x\n", pop->BaseOfCode);
}
        //3.打印节表的内容.adress+ifanew的内容+4字节+file_header+结构体fileheader中的sizeofoptionalheader =节表的
        //开始位置
void pe_section_iofo(PVOID adress) {
        //先把adress的地址偏移到section节表的位置
        //读取ifanew (4字节)的内容,然后和adress相加,就到了pe标志了
        //不用上面的结构体来.定义一个dword 的变量,从第60位开始读取
        /*DWORD ifanew = DWORD( * (adress + 60));
        printf("%08x", ifanew);*/
        //printf("%08x",(DWORD)( * ((char*)adress + 64)));
        DWORD i = 0;//定义一个dword类型的变量,接收ifanew的内容
        i = *((DWORD*)adress + 15);//把void星 强制类型转换成ulong*,加15个long长度(4字节)就是60字节
        //
        PVOID pe_section_adress = NULL;
        pe_section_adress = (BYTE*)adress + i;//把void*类型的adress,强制转换成byte*,然后加上ifanew,.现在指针
        //1.指到了pe标志
        //printf("%x", *(DWORD*)pe_section_adress);//强制转换成dword*类型,然后读取pe的四字节标志
        //2.看一下sizeof(IMAGE_FILE_HEADER)的大小
        //printf("%d", sizeof(IMAGE_FILE_HEADER));
        //把adress强转为一个FILE_HEADER的结构体变量
        PIMAGE_FILE_HEADER PFILE = (PIMAGE_FILE_HEADER)((BYTE*)pe_section_adress + 4);//可以获取到optionalheader的大小
        //printf("%x",PFILE->SizeOfOptionalHeader);//大小为E0(32位程序)
        //pe_section_adress = (DWORD)pe_section_adress + PFILE->SizeOfOptionalHeader)+4+20;
        pe_section_adress = ((DWORD*)pe_section_adress + 1);//指到FILE_HEADER
        pe_section_adress = (DWORD*)pe_section_adress + 5;//指到option_header
        pe_section_adress = (BYTE*)pe_section_adress +PFILE->SizeOfOptionalHeader ;
        PIMAGE_SECTION_HEADER PSEC = NULL;
                PSEC=(PIMAGE_SECTION_HEADER)pe_section_adress;
        /*BYTE name = {};
        int j;
        for (j = 0; i < 9; i++) {
                name =* PSEC->Name;
                printf("%c", name);
        }*///草,不会写了

       
        //printf("%s", PSEC->Name);//成功打印,但是8个字节可能全都是字符,没有/0结尾.这样就有问题
//循环读取psec->name的值给一个数组,然后打印出来
        char name = { 0 };
        int j;
        for (j = 0; j < 8; j++) {
                name =PSEC->Name;//IMAGE_SECTION_HEADER结构体里面的Name数组的j元素
                //name =&*(PSEC->Name);
                printf("%c", name);
        }
        printf("\n节的数据实际大小(没有对齐)\n");
        printf("virtual size:\t%x\n", PSEC->Misc);
        printf("节的数据开始的地方相对于imagebase的偏移量(必须是内存对齐的整数\n");
        printf("virtual adress:\t%x\n", PSEC->VirtualAddress);
        printf("节在文件中对齐的后的大小\n");
        printf("sizeof rawdata:\t%x\n", PSEC->SizeOfRawData);
        printf("在文件中的偏移\n");
        printf("pointertorawdata:\t%x\n\n\n", PSEC->PointerToRawData);
//再来一个循环遍历整个节表内容.用第一个节表去偏移,获取下一个节表
        //有没有一种可能使用SECTION_HEADER结构体指针来获取呢?????
        //试试,先把section_adress指向第一个SECTION_HEADER结构体,然后结构体自增
        //等等,好像上面已经定义了一个PIMAGE_SECTION_HEADER结构体指针.把他加1会怎么样
       
        //for (j = 0; j < 4; j++) {
        //        //复制上面的代码
        //        name = PSEC++->Name;
        //        printf("%c", name);
        //}++可以跳转过去,但是给name的值不对.什么原因呢????
        //试试先++
        //memset(name, 0, 9);
        for (i = 0; i < 2; i++) {

                for (j = 0; j < 8; j++) {
                        //复制上面的代码

                        name = PSEC->Name;
                        printf("%c", name);
                }

                printf("\n节的数据实际大小(没有对齐)\n");
                printf("virtual size:\t%x\n", PSEC->Misc);
                printf("节的数据开始的地方相对于imagebase的偏移量(必须是内存对齐的整数\n");
                printf("virtual adress:\t%x\n", PSEC->VirtualAddress);
                printf("节在文件中对齐的后的大小\n");
                printf("sizeof rawdata:\t%x\n", PSEC->SizeOfRawData);
                printf("在文件中的偏移\n");
                printf("pointertorawdata:\t%x\n\n\n", PSEC->PointerToRawData);
               
                memset(name, 0, 8);
                PSEC++;
        }
}
int main()
{
        PVOID adress = NULL;
        FILE* FP = NULL;
        FP = file_path();
        adress = mem_adress(getsize(FP), FP);//传入函数getsize的返回值
        //pe_NT_info(adress);//打印nt头信息
        //printf("文件大小为=%u字节", i);
        //pe_FILEHEADER_info(adress);
        pe_section_iofo(adress);
        free(adress);
        return 0;
}
```

xixicoco 发表于 2023-3-16 05:09

不错,坚持到底就是大牛

faxrain 发表于 2023-3-16 06:43


不错,坚持到底就是大牛

dmhyvip 发表于 2023-3-16 07:01

好主意,感谢分享

Moondevil 发表于 2023-3-16 08:09

坚持到底{:1_921:}

ljl727ljl 发表于 2023-3-16 08:37


好主意,感谢分享

onlyougao 发表于 2023-3-16 08:47

惭愧,看不懂

wzbAwxl 发表于 2023-3-16 08:48

加油,坚持到底!!

jinzhu160 发表于 2023-3-16 09:17

逆劫古修 发表于 2023-3-16 09:44

坚持就是胜利✌
页: [1] 2
查看完整版本: 滴水三期 3.13号(节表)程序解析课后作业记录