我试图在C中读取PE文件。在阅读相关的Microsoft文档和OSDev上的其他文章以及SO之后,我仍然对如何处理文件中的偏移感到困惑。
文件头部的MS-DOS存根包含一个0x3c的标志,它提供实际PE头的起始偏移量(PE签名,字面意思是4字节" PE \ 0 \ 0"。)
我尝试做的是使用指针算法将PE文件中给出的地址解释为 - 一个地址,但我担心我不知道如何做到这一点。
另外,我知道这可以通过Win32 API实现;但是,我想从中学习并学习如何自己动手。
非常感谢您提前提供任何帮助。
#include <stdio.h>
#include <stdlib.h>
#define PE_SIG_OFFSET_LOCATION 0x3c
int main(void)
{
const char* filepath = "sample.exe";
FILE* file = fopen(filepath, "rb");
int i, n = 0;
if(!file)
{
perror("Failed to open file");
return EXIT_FAILURE;
}
fpos_t start = fgetpos(file, &start);
int c;
while((c = fgetc(file)) != EOF)
{
n++;
// putchar(c);
}
if(ferror(file))
{
puts("I/O error when reading.");
}
else if(feof(file))
{
fsetpos(file, &start);
int c = 0;
char* contents = (char*)malloc(n * sizeof(char));
for(i=0;i<=n;i++)
{
if(c == EOF)
{
break;
}
c = fgetc(file);
contents[i] = c;
}
fclose(file);
i = 0;
char offset[4 * sizeof(char)] = {contents[PE_SIG_OFFSET_LOCATION * sizeof(char)], contents[(PE_SIG_OFFSET_LOCATION * sizeof(char))+ (1 * sizeof(char))], contents[(PE_SIG_OFFSET_LOCATION * sizeof(char))+ (2 * sizeof(char))], contents[(PE_SIG_OFFSET_LOCATION * sizeof(char))+ (3 * sizeof(char))]};
char* sig = &contents[PE_SIG_OFFSET_LOCATION * sizeof(char)];
printf("sig = %c \n", sig);
// somehow interpret the character the sig currently points to as a hex memory and get sig to point to that (i.e. the start of the PE header)
free(contents);
return EXIT_SUCCESS;
}
}
编辑:在technosaurus建议我联合一个表示DOS标题的打包结构与实际内容的char数组后,代码仍然没有正常运行(它读取和打印文件没关系,但是当它需要打印签名时,它会打印出垃圾而不是MZ
)。
#include <stdio.h>
#include <stdlib.h>
#define PE_SIG_OFFSET_LOCATION 0x3c
int main(void)
{
const char* filepath = "sample.exe";
FILE* file = fopen(filepath, "rb");
int i, n = 0;
if(!file)
{
perror("Failed to open file");
return EXIT_FAILURE;
}
fpos_t start = fgetpos(file, &start);
int c;
while((c = fgetc(file)) != EOF)
{
n++;
// putchar(c);
}
if(ferror(file))
{
puts("I/O error when reading.");
}
else if(feof(file))
{
fsetpos(file, &start);
int c = 0;
typedef struct DOS_Header
{
char signature[2];
short lastsize;
short nblocks;
short nreloc;
short hdrsize;
short minalloc;
short maxalloc;
void *ss;
void *sp;
short checksum;
void *ip;
void *cs;
short relocpos;
short noverlay;
short reserved1[4];
short oem_id;
short oem_info;
short reserved2[10];
long e_lfanew;
}DOS_Header;
union
{
DOS_Header header;
char* contents;
}u;
u.contents = (char*)malloc(n * sizeof(char));
for(i=0;i<=n;i++)
{
if(c == EOF)
{
break;
}
c = fgetc(file);
u.contents[i] = c;
}
fclose(file);
i = 0;
for(i=0;i<=n;i++)
{
printf("%c", u.contents[i]);
}
printf("\n DOS sig: %c%c \n", u.header.signature[0], u.header.signature[1]);
free(u.contents);
return EXIT_SUCCESS;
}
}