Appendix 1: A Program for Investigating the PE Header


The program provided in Listing A1 carries out a simple investigation of the PE header. It doesn't pretend to be an example of good programming style. My only goal when writing it was to demonstrate how to work with the structures of PE modules.

Listing A1: Sample program demonstrating methods of working with PE module structures

image from book

 #include <windows.h> include <stdio.h> HANDLE openf(char * ); DWORD getoffs(DWORD ); HANDLE hf; DWORD n; WORD m; IMAGE_DOS_HEADER id; IMAGE_NT_HEADERS iw; IMAGE_SECTION_HEADER is; IMAGE_SECTION_HEADER ais[100]; IMAGE_IMPORT_DESCRIPTOR im[1000]; IMAGE_THUNK_DATA it[1000]; IMAGE_IMPORT_BY_NAME in; IMAGE_EXPORT_DIRECTORY ex; IMAGE_RESOURCE_DIRECTORY rdl; IMAGE_RESOURCE_DIRECTORY_ENTRY rdel[30]; IMAGE_RESOURCE_DIRECTORY rd2; IMAGE_RESOURCE_DIRECTORY_ENTRY rde2[500]; IMAGE_COFF_SYMBOLS_HEADER ih; IMAGE_DEBUG_DIRECTORY idd; char *subs[] = {"Unknown subsystem\n", "Subsystem driver\n", "Subsystem GUI\n", "Subsystem console\n", "Subsystem ?\n", "Subsystem ?\n", "Subsystem OS/2\n", "Subsystem Posix\n"}; char   buf[300], bufl[300]; DWORD im_n = 0, it_n = 0; DWORD exn[5000]; WORD exo[5000]; DWORD exa[5000]; // The main function int main(int argc, char* argv[]) {  int er = 0, i;  LARGE_INTEGER 1; // Check for the presence of parameters.  if(argc < 2){printf("No parameters!\n"); er = 1; goto _exit}; // The first parameter in the list is the file name.  printf("File: %s\n", argv[l]);  if((hf = openf(argv[1])) == INVALID_HANDLE_VALUE)  {        printf("No file!\n");        er = 2;        goto _exit}; // Determine the file length.  GetFileSizeEx(hf, &1); // Read the MS-DOS header.  if(!ReadFile(hf, &id, sizeof(id), &n, NULL))  {        printf("Read DOS_HEADER error 1!\n");        er = 3;        goto _exit;};  if(n < sizeof(id))  {        printf("Read DOS_HEADER error 2!\n");        er = 4;        goto _exit}; // Check the MS-DOS signature ('MZ')  if(id.e_magic ! = IMAGE_DOS_SIGNATURE)  {        printf("No DOS signature!\n");        er = 5;        goto _exit;}  printf("DOS signature is OK!\n");  if(id.e_lfanew > l.QuadPart)  {        printf("No NT signature!\n");        er = 6;        goto _exit;}; // Move the pointer.  SetFilePointer(hf, id.e_lfanew, NULL, FILE_BEGIN); // Read the NT header.  if(!ReadFile(hf, &iw, sizeof(iw), &n, NULL))  {        printf("Read NT_HEADER error 1!\n");        er = 7;        goto _exit;};  if(n < sizeof(iw))  {        printf("Read NT_HEADER error 2!\n");        er = 8;        goto _exit;}; // Check the NT signature ('PE').  if(iw.Signature != IMAGE_NT_SIGNATURE)  {        printf("No NT signature!\n");        er = 9;        goto _exit;}  printf("NT signature is OK!\n"); // Work with the structure.  printf("Number of sections %d\n", iw.FileHeader.NumberOfSections);  printf("Size of optional header %d\n",        iw.FileHeader.SizeOfOptionalHeader);  if((iw.FileHeader.Characteristics&0x2000) != 0)        printf("DLL-modul\n");  else  {  if(((iw.FileHeader.Characteristics&0x1000) != 0))  printf("System module\n");        printf("EXE-modul\n");  };  if(iw.FileHeader.Machine == 0x014c)printf("Processor Intel\n");  else printf("Unknown processor\n"); // Read the optional header.  printf("Linker version %d.%d\n",    iw.OptionalHeader.MajorLinkerVersion,    iw.OptionalHeader.MinorLinkerVersion);  printf("Size of code %d\n", iw.OptionalHeader.SizeOfCode);  printf("Size of initialized data %d\n",    iw.OptionalHeader.SizeOfInitializedData);  printf("Size of uninitialized data %d\n",    iw.OptionalHeader.SizeOfUninitializedData);  printf("Address Of Entry Point (RVA) %xh\n",    iw.OptionalHeader.AddressOfEntryPoint);  printf("Address of code (RVA) %xh\n", iw.OptionalHeader.BaseOfCode);  printf("Address of data (RVA) %xh\n", iw.OptionalHeader.BaseOfData);  printf("Image Base %xh\n", iw.OptionalHeader.ImageBase);  printf("Size Of Image %xh\n", iw.OptionalHeader.SizeOfImage);  printf("Size of Headers %xh\n", iw.OptionalHeader.SizeOfHeaders);  printf("Section Alignment %xh\n", iw.OptionalHeader.SectionAlignment);  printf("File Alignment %xh\n", iw.OptionalHeader.FileAlignment);   printf("Size Of Stack Reserve %d\n",    iw.OptionalHeader.SizeOfStackReserve);  printf("Size Of Stack Commit %d\n", iw.OptionalHeader.SizeOfStackCommit);  printf("Size Of Heap Reserve %d\n", iw.OptionalHeader.SizeOfHeapReserve);  printf("Size Of Heap Commit %d\n", iw.OptionalHeader.SizeOfHeapCommit);  printf("%s", subs[iw.OptionalHeader.Subsystem]); // List of sections // Virtual addresses of some PE tables  DWORD vi = iw.OptionalHeader.DataDirectory[1].VirtualAddress;  DWORD ve = iw.OptionalHeader.DataDirectory[0].VirtualAddress;  DWORD vr = iw.OptionalHeader.DataDirectory[2].VirtualAddress;  DWORD vg = iw.OptionalHeader.DataDirectory[6].VirtualAddress; // printf("Sections:\n");  printf("    Name   sizev    sizef     adrf     adrv\n");  printf( ------------------------------------------ \n");  int j = 0;  for(i =0; i < iw.FileHeader.NumberOfSections; i++)  {        if(!ReadFile(hf, &is, sizeof(is), &n, NULL))        {               printf("IMAGE_SECTION_HEADER error!\n");               er = 10;               goto _exit;        };        printf("%8s %6xh  %6xh  %6xh  %6xh\n",               is.Name, is.Misc.VirtualSize, is.SizeOfRawData,               is.PointerToRawData, is.VirtualAddress);        ais[i].VirtualAddress = is.VirtualAddress;        ais[i].PointerToRawData = is.PointerToRawData;  };  printf("-------------------------------------------\n");  printf("\n"); // Import table  if(!vi)  {        printf("No import!\n");  } else  {       printf("Import section offset %xh virtual %xh\n", getoffs(vi), vi); // Move the pointer.        SetFilePointer(hf, getoffs(vi), NULL, FILE_BEGIN);        while(TRUE)        {               if(!ReadFile(hf, &im[im_n], sizeof(im[im_n]), &n, NULL))        {               printf("IMAGE_IMPORT_DESCRIPTOR error!\n");               er = 11;               goto _exit;         };               if(im[im_n].Characteristics == 0 && im[im_n].Name == 0)break;               im_n++;        }; // Libraries        printf("Import objects: \n");        for(i = 0; i < (int)im_n; i++)        {        // DLLs go first.        SetFilePointer(hf, getoffs(im[i].Name), NULL, FILE_BEGIN);               ReadFile(hf, buf, 100, &n, NULL);               printf("%s\n", buf);        // Next are function names.               if(im[i].OriginalFirstThunk != 0)               SetFilePointer(hf,               getoffs(im[i].OriginalFirstThunk), NULL, FILE_BEGIN);               else        SetFilePointer(hf, getoffs(im[i].FirstThunk), NULL, FILE_BEGIN);               it_n = 0;                 printf("Offset of AdresImpArray %xh RVA of AdresImpArray %xh\n",               getoffs(im[i].FirstThunk), im[i].FirstThunk);               while(TRUE)                     {                       ReadFile(hf, &it[it_n], sizeof(it[it_n]), &n, NULL);                              if(it[it_n].ul.AddressOfData == 0) break;                              it_n++;        };        for(j =  0; j < (int)it_n; j++)        {                if((it[j].ul.AddressOfData&IMAGE_ORDINAL_FLAG32) == 0)                {                SetFilePointer(hf,                getoffs(it[j].ul.ForwarderString + 2),                       NULL, FILE_BEGIN);                       ReadFile(hf, buf, 100, &n, NULL);                printf("     %s %xh %xh\n",                       buf, getoffs(it[j].ul.ForwarderString + 2),                       it[j].ul.ForwarderString + 2);                       } else printf("   Ordinal %d\n",                       it[j].ul.AddressOfData&0x0000ffff);                };        };         }; // Export table  printf("\n");  if(!ve)  {         printf("No export!\n");  } else  {        printf("Export section offset %xh virtual %xh\n", getoffs(ve), ve);        SetFilePointer(hf, getoffs(ve), NULL, FILE_BEGIN);        if(!ReadFile(hf, &ex, sizeof(ex), &n, NULL))        {               printf("IMAGE_EXPORT_DIRECTORY error!\n");               er = 12;               goto _exit;        };        SetFilePointer(hf,getoffs(ex.Name), NULL, FILE_BEGIN);        ReadFile(hf, buf, 100, &n, NULL);        printf("Export modul: %s\n", buf);        printf("Number of functions: %d\n", ex.NumberOfFunctions);        printf("Number of names: %d\n", ex.NumberOfNames);        printf("Ordinal base %d\n", ex.Base); // Array of pointers to the names of exported functions  SetFilePointer(hf, getoffs(ex.AddressOfNames), NULL, FILE_BEGIN);        for(i =0; i < ex.NumberOfNames; i++)              ReadFile(hf, &exn[i], 4, &n, NULL); // Array of pointers to the ordinals of exported functions  SetFilePointer(hf, getoffs(ex.AddressOfNameOrdinals), NULL, FILE_BEGIN);        for(i = 0; i < ex.NumberOfNames; i++)               ReadFile(hf, &exo[i], 2, &n, NULL); // Array of pointers to the addresses of exported functions  SetFilePointer(hf, getoffs(ex.AddressOfFunctions), NULL, FILE_BEGIN);        for(i = 0; i < ex.NumberOfFunctions; i++)               ReadFile(hf, &exa[i], 4, &n, NULL);        printf("\n");        printf("Name of function                Ord     VAdr\n");        printf("---------------------------------------------\n"); // Input exported function names.        for(i = 0; i < ex.NumberOfNames; i++)        {               SetFilePointer(hf, getoffs(exn[i]), NULL, FILE_BEGIN);               ReadFile(hf, buf, 300, &n, NULL);               printf("%30s %4d %8xh\n", buf, exo[i] + ex.Base, exa[exo[i]]);        };        printf("------------------------------------------------\n");  }; // Work with resources.  printf("\n");  if(!vr)  {        printf("No resource!\n");  } else {       DWORD offres = getoffs(vr);       printf("Resource: offset %xh virtual %xh \n", offres, vr);       SetFilePointer(hf, offres, NULL, FILE_BEGIN);              ReadFile(hf, &rdl, sizeof(rdl), &n, NULL);       // Level 1       printf("Number of type %d \n", rd1.NumberOfIdEntries);       // Skip rd.NumberOfNamedEntries records.       for(i = 0; i < rdl.NumberOfNamedEntries; i++)              ReadFile(hf, &rdel[i], sizeof(rdel[i]), &n, NULL);       // Store the list of resource types in an array.       for(i = 0; i < rd1.NumberOfIdEntries; i++)              ReadFile(hf, &rdel[i], sizeof(rdel[i]), &n, NULL);       // Output resource types.       for(i = 0; i < rd1.NumberOfIdEntries; i++)              printf("Type identify: %d\n", rdel[i].Name);       // Level 2       printf("List of resource:\n")       for(i = 0; i < rd1.NumberOfIdEntries; i++)       {              SetFilePointer(hf, (rdel[i].OffsetToData &                     0x7fffffff) + offres, NULL, FILE_BEGIN);              ReadFile(hf, &rd2, sizeof(rd2), &n, NULL);              printf("*Type of resource: %d\n", rdel[i].Id);       for(j = 0; j < rd2.NumberOfNameEntries+rd2.NunberOfIdEntries; j++)              ReadFile(hf, &rde2[j], sizeof(rde2[j]), &n, NULL);       for(j = 0; j < rd2.NumberOfNamedEntries + rd2.NumberOfIdEntries; j++)              {              if(!(rde2[j].Name & 0x80000000))                {                printf(" -Resource identify %d\n", rde2[j].Name);                }              else                {                 SetFilePointer(                      hf, (rde2[j].Name & 0x7fffffff) + offres,                      NULL, FILE_BEGIN);                 ReadFile(hf, &m, 2, &n, NULL);                 ReadFile(hf, buf, 2*m, &n, NULL);                 // Conversion from Unicode                 WideCharToMultiByte(                      CP_UTF7, 0, (LPCWSTR)(buf),                      m, buf1, 300, NULL, NULL);                      printf(" -Name of resource: %s\n", buf1);                 }                 };         };  }; // Check the debug information.  printf("\n");  if (!vg)  {        printf("No debug table!\n");  } else        {        DWORD offdbg = getoffs(vg);        printf("Debug table: offset %xh virtual %xh \n", offdbg, vg);        SetFilePointer(hf, offdbg, NULL, FILE_BEGIN);        ReadFile(hf, &idd, sizeof(idd), &n, NULL);        printf("Type of debug information: %d\n", idd.Type);        // For COFF information        if(idd.Type = 1)        {        SetFilePointer(hf, idd.PointerToRawData, NULL, FILE_BEGIN);        ReadFile(hf, &ih, sizeof(ih), &n, NULL);        printf("RVA of first line number: %xh\n",               idd.PointerToRawData + ih.LvaToFirstLinenumber);        }  }  if(!iw.FileHeader.PointerToSymbolTable )  {        printf("No symbol table!\n");  } else        {        DWORD offsym = getoffs(iw.FileHeader.PointerToSymbolTable);        printf("Symbol table: offset %xh virtual %xh\n",               offsym, iw.FileHeader.PointerToSymbolTable);        }; // Close the file descriptor. _exit:  CloseHandle(hf);  return er; }; // The function opens the file for reading. HANDLE openf(char *nf) {  return CreateFile(nf,  GENERIC_READ,  FILE_SHARE_WRITE | FILE_SHARE_READ,  NULL,  OPEN_EXISTING,  NULL,  NULL); }; // Determine the offset within the PE file at the relative // virtual address. DWORD getoffs(DWORD vsm) {  DWORD fi = 0;  if(vsm < ais[0].VirtualAddress) return fi;  for(int i = 0; i < iw.FileHeader.NumberOfSections; i++)        {        if(vsm < ais[i].VirtualAddress && i > 0) {        fi = ais[i - 1].PointerToRawData + (vsm - ais[i - 1].VirtualAddress);             break;};        };  if(i == iw.FileHeader.NumberOfSections)        fi = ais[i - 1].PointerToRawData + (vsm - ais[i - 1].VirtualAddress);  return fi;  }; 

image from book

Listing A2 presents an example of program output when working with one of the loadable modules.

Listing A2: Example of output of the program in Listing A1

image from book

 File: primer42.exe DOS signature is OK! NT signature is OK! Number of sections 4 Size of optional header 224 EXE-modul Processor Intel Linker version 5.12 Size of code 1024 Size of initialized data 2048 Size of uninitialized data 0 Address Of Entry Point (RVA) 1000h Address of code (RVA) 1000h Address of data (RVA) 2000h Image Base 400000h Size of Image 5000h Size of Headers 400h Section Alignment 1000h File Alignment 200h Size of Stack Reserve 1048576 Size of Stack Commit 4096 Size of Heap Reserve 1048576 Size of Heap Commit 4096 Subsystem GUI Sections:     Name      sizev    sizef    adrf    adrv --------------------------------------------    .text       214h     400h    400h   1000h   .rdata       23eh     400h    800h   2000h    .data        91h     200h    c00h   3000h    .rsrc       150h     200h    e00h   4000h -------------------------------------------- Import section offset 8a4h virtual 20a4h Import objects: user32.dll Offset of AdresImpArray 80ch RVA of AdresImpArray 200ch      CreateWindowExA 94eh 214eh      DefWindowProcA 960h 2160h      DispatchMessageA 972h 2172h      GetMessageA 986h 2186h      LoadCursorA 994h 2194h      MessageBoxA 940h 2140h      PostQuitMessage 9aeh 21aeh      RegisterClassA 9cOh 21c0h      ShowWindow 9d2h 21d2h      TranslateMessage 9eOh 21e0h      UpdateWindow 9f4h 21f4h      LoadMenuA 934h 2134h      LoadIconA 9a2h 21a2h      SetMenu 92ah 212ah kernel32.dll Offset of AdresImpArray 800h RVA of AdresImpArray 2000h      ExitProcess al0h 2210h       GetModuleHandleA aleh 221eh No export! Resource: offset e00h virtual 4000h Number of type 1 Type identify: 4 List of resource: *Type of resource: 4  -Name of resource: MENUP Debug table: offset 850h virtual 2050h Type of debug information: 1 RVA of first line number: 1000h Symbol table: offset 420h virtual 1020h 

image from book




Disassembling Code. IDA Pro and SoftICE
Disassembling Code: IDA Pro and SoftICE
ISBN: 1931769516
EAN: 2147483647
Year: 2006
Pages: 63
Authors: Vlad Pirogov

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net