考验C语言编程能力的题
大家好,我又来了,今天遇到一个比较考验C语言编程的问题,大家听说过pe吧,这是可执行程序最重要的一个文件了,现在有一个要求就是,用C语言编写一个程序用来显示任意exe程序的pe头,包括(dos头,NT头(标准pe头,可选pe头)),以及里面的内容打印出来虽然网上有些编程例子,但是那些并不是很好,有一些错误,所以就考考大家了,(ps:本人菜鸟,自然不会做,丢人了{:10_266:} ),顺便也想试试小甲鱼,你会不会做呢??@小甲鱼
附上pe结构文件表
其实只要输出这些内容就可以了。
PE头都是有结构的。用C写也很简单吧,先把所需要的结构声明出来,然后用二进制读文件,读入结构体中。
#include <stdio.h>
#include <stdlib.h>
typedef unsigned short WORD; // 声明 WORD 类型
typedef unsigned int DWORD; // 声明 DWORD 类型
// 声明 IMAGE_DOS_HEADER 结构体
typedef struct IDosHeader
{
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res;
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2;
DWORD e_lfanew;
} IDosHeader;
int main()
{
IDosHeader DosHeader;
FILE *fp = NULL;
char szFileName;
// 获取文件名(如:c:\2.exe)
printf("请输入文件名:");
gets(szFileName);
// 打开文件
if ( (fp=fopen(szFileName, "rb"))==NULL )
{
printf("文件打开失败!\n");
exit(EXIT_FAILURE);
}
// 读取内容
if (fread(&DosHeader, sizeof(IDosHeader),1 , fp) != 1)
{
printf("文件读取失败!\n");
exit(EXIT_FAILURE);
}
printf("e_magic:%#x\n", DosHeader.e_magic); // 以16进制输出
printf("e_cblp:%#x\n", DosHeader.e_cblp); // 以16进制输出
return 0;
} #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <windows.h>
size_t get_file_size(const char *filename)
{
FILE *file = fopen(filename, "r");
if(!file)
return -1;
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fclose(file);
return size;
}
bool read_file(const char *filename, uint8_t *buff, size_t size)
{
FILE *file = fopen(filename, "rb");
if(!file)
return false;
fread(buff, 1, size, file);
fclose(file);
return true;
}
void print_image_dos_header(IMAGE_DOS_HEADER *idh)
{
printf("IMAGE_DOS_HEADER\n");
printf("e_magic: %.4x\n", idh->e_magic);
printf("e_cblp: %.4x\n", idh->e_cblp);
printf("e_cp: %.4x\n", idh->e_cp);
printf("e_crlc: %.4x\n", idh->e_crlc);
printf("e_cparhdr: %.4x\n", idh->e_cparhdr);
printf("e_minalloc: %.4x\n", idh->e_minalloc);
printf("e_maxalloc: %.4x\n", idh->e_maxalloc);
printf("e_ss: %.4x\n", idh->e_ss);
printf("e_sp: %.4x\n", idh->e_sp);
printf("e_csum: %.4x\n", idh->e_csum);
printf("e_ip: %.4x\n", idh->e_ip);
printf("e_cs: %.4x\n", idh->e_cs);
printf("e_lfarlc: %.4x\n", idh->e_lfarlc);
printf("e_ovno: %.4x\n", idh->e_ovno);
printf("e_res: %.2x\n", idh->e_res);
printf("e_res: %.2x\n", idh->e_res);
printf("e_res: %.2x\n", idh->e_res);
printf("e_res: %.2x\n", idh->e_res);
printf("e_oemid: %.4x\n", idh->e_oemid);
printf("e_oeminfo: %.4x\n", idh->e_oeminfo);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_res2: %.2x\n", idh->e_res2);
printf("e_lfanew: %.8x\n", idh->e_lfanew);
}
void print_image_nt_headers(IMAGE_NT_HEADERS *inh, uint8_t *base)
{
printf("IMAGE_NT_HEADERS\n");
printf("Signature: %.8x\n", inh->Signature);
// 下面这两个结构,这里只打印出在文件中的偏移
printf("FileHeader: %.8x\n", (uint8_t *)&inh->FileHeader - base);
printf("OptionalHeader: %.8x\n", (uint8_t *)&inh->OptionalHeader - base);
}
void print_image_file_header(IMAGE_FILE_HEADER *ifh)
{
printf("IMAGE_FILE_HEADER\n");
printf("Machine: %.4x\n", ifh->Machine);
printf("NumberOfSections: %.4x\n", ifh->NumberOfSections);
printf("TimeDateStamp: %.8x\n", ifh->TimeDateStamp);
printf("PointerToSymbolTable: %.8x\n", ifh->PointerToSymbolTable);
printf("NumberOfSymbols: %.8x\n", ifh->NumberOfSymbols);
printf("SizeOfOptionalHeader: %.4x\n", ifh->SizeOfOptionalHeader);
printf("Characteristics: %.4x\n", ifh->Characteristics);
}
void print_image_optional_header(IMAGE_OPTIONAL_HEADER *ioh, uint8_t *base)
{
printf("IMAGE_OPTIONAL_HEADER\n");
printf("Magic: %.4x\n", ioh->Magic);
printf("MajorLinkerVersion: %.2x\n", ioh->MajorLinkerVersion);
printf("MinorLinkerVersion: %.2x\n", ioh->MinorLinkerVersion);
printf("SizeOfCode: %.8x\n", ioh->SizeOfCode);
printf("SizeOfInitializedData: %.8x\n", ioh->SizeOfInitializedData);
printf("SizeOfUninitializedData: %.8x\n", ioh->SizeOfUninitializedData);
printf("AddressOfEntryPoint: %.8x\n", ioh->AddressOfEntryPoint);
printf("BaseOfCode: %.8x\n", ioh->BaseOfCode);
printf("BaseOfData: %.8x\n", ioh->BaseOfData);
printf("ImageBase: %.8x\n", ioh->ImageBase);
printf("SectionAlignment: %.8x\n", ioh->SectionAlignment);
printf("FileAlignment: %.8x\n", ioh->FileAlignment);
printf("MajorOperatingSystemVersion: %.4x\n", ioh->MajorOperatingSystemVersion);
printf("MinorOperatingSystemVersion: %.4x\n", ioh->MinorOperatingSystemVersion);
printf("MajorImageVersion: %.4x\n", ioh->MajorImageVersion);
printf("MinorImageVersion: %.4x\n", ioh->MinorImageVersion);
printf("MajorSubsystemVersion: %.4x\n", ioh->MajorSubsystemVersion);
printf("MinorSubsystemVersion: %.4x\n", ioh->MinorSubsystemVersion);
printf("Win32VersionValue: %.8x\n", ioh->Win32VersionValue);
printf("SizeOfImage: %.8x\n", ioh->SizeOfImage);
printf("SizeOfHeaders: %.8x\n", ioh->SizeOfHeaders);
printf("CheckSum: %.8x\n", ioh->CheckSum);
printf("Subsystem: %.4x\n", ioh->Subsystem);
printf("DllCharacteristics: %.4x\n", ioh->DllCharacteristics);
printf("SizeOfStackReserve: %.8x\n", ioh->SizeOfStackReserve);
printf("SizeOfStackCommit: %.8x\n", ioh->SizeOfStackCommit);
printf("SizeOfHeapReserve: %.8x\n", ioh->SizeOfHeapReserve);
printf("SizeOfHeapCommit: %.8x\n", ioh->SizeOfHeapCommit);
printf("LoaderFlags: %.8x\n", ioh->LoaderFlags);
printf("NumberOfRvaAndSizes: %.8x\n", ioh->NumberOfRvaAndSizes);
// 下面这个数组,我还没有想好要以什么样的形式展开,如何展开,现在只是打印文件偏移
printf("DataDirectory: %.8x\n", (uint8_t *)&ioh->DataDirectory - base);
}
int main(void)
{
const char *filename = "print_pe.exe";
size_t size = get_file_size(filename);
uint8_t *buff = malloc(size);
read_file(filename, buff, size);
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER *)buff;
IMAGE_NT_HEADERS *inh = (IMAGE_NT_HEADERS *)(buff + idh->e_lfanew);
print_image_dos_header(idh); printf("\n");
print_image_nt_headers(inh, buff); printf("\n");
print_image_file_header(&inh->FileHeader); printf("\n");
print_image_optional_header(&inh->OptionalHeader, buff); printf("\n");
free(buff);
return 0;
}
IMAGE_DOS_HEADER
e_magic: 5a4d
e_cblp: 0090
e_cp: 0003
e_crlc: 0000
e_cparhdr: 0004
e_minalloc: 0000
e_maxalloc: ffff
e_ss: 0000
e_sp: 00b8
e_csum: 0000
e_ip: 0000
e_cs: 0000
e_lfarlc: 0040
e_ovno: 0000
e_res: 00
e_res: 00
e_res: 00
e_res: 00
e_oemid: 0000
e_oeminfo: 0000
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_res2: 00
e_lfanew: 000000f0
IMAGE_NT_HEADERS
Signature: 00004550
FileHeader: 000000f4
OptionalHeader: 00000108
IMAGE_FILE_HEADER
Machine: 014c
NumberOfSections: 0009
TimeDateStamp: 5c86674e
PointerToSymbolTable: 00000000
NumberOfSymbols: 00000000
SizeOfOptionalHeader: 00e0
Characteristics: 0102
IMAGE_OPTIONAL_HEADER
Magic: 010b
MajorLinkerVersion: 0e
MinorLinkerVersion: 10
SizeOfCode: 00005200
SizeOfInitializedData: 00004400
SizeOfUninitializedData: 00000000
AddressOfEntryPoint: 00011343
BaseOfCode: 00001000
BaseOfData: 00001000
ImageBase: 00400000
SectionAlignment: 00001000
FileAlignment: 00000200
MajorOperatingSystemVersion: 0006
MinorOperatingSystemVersion: 0000
MajorImageVersion: 0000
MinorImageVersion: 0000
MajorSubsystemVersion: 0006
MinorSubsystemVersion: 0000
Win32VersionValue: 00000000
SizeOfImage: 00020000
SizeOfHeaders: 00000400
CheckSum: 00000000
Subsystem: 0003
DllCharacteristics: 8140
SizeOfStackReserve: 00100000
SizeOfStackCommit: 00001000
SizeOfHeapReserve: 00100000
SizeOfHeapCommit: 00001000
LoaderFlags: 00000000
NumberOfRvaAndSizes: 00000010
DataDirectory: 00000168
请按任意键继续. . . 仅仅解析出值是不够的,如果这个程序还要继续写下去,那就要去解析值所对应的含义
例如
e_magic: 5a4d
应该解析为
e_magic: IMAGE_DOS_SIGNATURE
IMAGE_DOS_SIGNATURE这个宏定义的值就是 0x5a4d
#include "pshpack4.h" // 4 byte packing is the default
#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 ba21 发表于 2019-3-11 20:37
PE头都是有结构的。用C写也很简单吧,先把所需要的结构声明出来,然后用二进制读文件,读入结构体中。
哇,大哥好厉害,我只能膜拜了,我还以为是很高大上的呢{:10_266:} 人造人 发表于 2019-3-11 23:16
我什么时候,能达到你的一半啊,感觉你的编程能力好厉害啊
页:
[1]