用C语言读取二进制PE文件

用C语言读取二进制PE文件,c,file,io,binary,portable-executable,C,File,Io,Binary,Portable Executable,我正在尝试用C阅读一个PE文件。在阅读了相关的Microsoft文档和其他关于OSDev的文章之后,我仍然对如何处理文件中的偏移量感到困惑 文件头的MS-DOS存根包含0x3c处的标志,该标志提供实际PE头开始的偏移量(PE签名,字面上是一个4字节的“PE\0\0”) 我试着用指针算法来解释PE文件中给出的地址——一个地址,但恐怕我不太知道怎么做 此外,我知道这是通过Win32 API实现的;然而,我想从中学习,并学会如何做自己 非常感谢您事先提供的任何帮助 #include <stdio

我正在尝试用C阅读一个PE文件。在阅读了相关的Microsoft文档和其他关于OSDev的文章之后,我仍然对如何处理文件中的偏移量感到困惑

文件头的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感谢您的快速回复。我正在研究我的解决方案的结构打包,但问题是MS-DOS存根可能大小不一,因为它本身就是一个MS-DOS程序。我所知道的是,在
0x3c
中,它告诉我实际PE签名的地址(这是实际PE文件的开始)。看看我如何实际解释指针?我如何告诉C取什么在代码> EyLFANEW ,把它当作一个地址,然后指向它?简单的方法是将一个字符数组的大小与头结构结合起来。使用c99,您可以用一个可变长度的数组结束结构,但是由于需要考虑头的大小,计算会变得更加复杂。
#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;
  }
}