| /* |
| genpeimg - Modify Portable Executable flags and properties. |
| Copyright (C) 2009-2016 mingw-w64 project |
| |
| This program is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| #include <inttypes.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "img.h" |
| |
| pe_image * |
| peimg_load (const char *fname) |
| { |
| pe_image *r; |
| file_image *fi = fimg_create (); |
| if (!fi) |
| return NULL; |
| if (!fimg_load (fi, fname)) |
| { |
| fimg_free (fi); |
| return NULL; |
| } |
| if ((r = peimg_create (fi)) != NULL) |
| return r; |
| fimg_free (fi); |
| return NULL; |
| } |
| |
| static size_t |
| find_pe_hdr (file_image *fi) |
| { |
| unsigned char m1, m2; |
| int lfanew; |
| m1 = fimg_get_uchar_at (fi, 0); |
| m2 = fimg_get_uchar_at (fi, 1); |
| if (m1 == 'P' && m2 == 'E') |
| { |
| fprintf (stderr, "Starts with PE\n"); |
| return 0; |
| } |
| if (m1 != 'M' || m2 != 'Z') |
| return FIMG_POS_END; |
| if (fi->data_len < 256) |
| return FIMG_POS_END; |
| lfanew = (int) fimg_get_uint_at (fi, 60, 0); |
| if (lfanew <= 0 || (size_t) lfanew >= fi->data_len) |
| return FIMG_POS_END; |
| m1 = fimg_get_uchar_at (fi, lfanew); |
| m2 = fimg_get_uchar_at (fi, lfanew + 1); |
| if (m1 != 'P' || m2 != 'E') |
| return FIMG_POS_END; |
| m1 = fimg_get_uchar_at (fi, lfanew + 2); |
| m2 = fimg_get_uchar_at (fi, lfanew + 3); |
| if (m1 != 0 || m1 != m2) |
| return FIMG_POS_END; |
| return (size_t) lfanew; |
| } |
| |
| void |
| peimg_set_hdr_characeristics (pe_image *pe, unsigned short set, unsigned short mask) |
| { |
| unsigned short flgs; |
| if (pe->is_64bit && (mask & 0x20) == 0) |
| { |
| fprintf (stderr, " Can't remove for PE+ the large-address-aware flag\n"); |
| mask |= 0x20; |
| } |
| flgs = pe->pe_filehdr.characteristics; |
| flgs &= mask; |
| flgs |= set; |
| if (flgs == pe->pe_filehdr.characteristics) |
| return; |
| PEIMG_SET_USHORT (pe, 22, flgs); |
| } |
| |
| static int |
| fill_pe_info (pe_image *pe) |
| { |
| /* File header is 24 bytes long. */ |
| pe->pe_filehdr.machine = PEIMG_GET_USHORT (pe, 4); |
| pe->pe_filehdr.numsecs = PEIMG_GET_USHORT (pe, 6); |
| pe->pe_filehdr.timestamp = PEIMG_GET_UINT (pe, 8); |
| pe->pe_filehdr.pointer2SymTab = PEIMG_GET_UINT (pe, 12); |
| pe->pe_filehdr.numSyms = PEIMG_GET_UINT (pe, 16); |
| pe->pe_filehdr.szOptHdr = PEIMG_GET_USHORT (pe, 20); |
| pe->pe_filehdr.characteristics = PEIMG_GET_USHORT (pe, 22); |
| switch (pe->pe_filehdr.machine) |
| { |
| case 0x14c: /* i386 */ |
| pe->is_64bit = 0; |
| pe->is_bigendian = 0; |
| break; |
| case 0x8664: |
| pe->is_64bit = 1; |
| pe->is_bigendian = 0; |
| break; |
| default: |
| fprintf (stderr, "PE image for machince 0x%x not supported\n", pe->pe_filehdr.machine); |
| return 0; |
| } |
| pe->optional_hdr_pos = 24; |
| switch (PEIMG_GET_USHORT (pe, 24)) |
| { |
| case 0x10b: |
| if (pe->is_64bit == 0) |
| break; |
| fprintf (stderr, "PE+ image has invalid 32-bit optional header.\n"); |
| return 0; |
| case 0x20b: |
| if (pe->is_64bit) |
| break; |
| fprintf (stderr, "PE image has invalid 64-bit optional header.\n"); |
| return 0; |
| default: |
| fprintf (stderr, "PE image has unknown optional header with magic 0x%x.\n", |
| PEIMG_GET_USHORT (pe, 24)); |
| return 0; |
| } |
| pe->section_list = pe->optional_hdr_pos + pe->pe_filehdr.szOptHdr; |
| pe->section_list_sz = ((size_t) pe->pe_filehdr.numsecs) * (4 * 9); |
| return 1; |
| } |
| |
| pe_image * |
| peimg_create (file_image *pimg) |
| { |
| size_t pe_hdr; |
| pe_image *r; |
| if (!pimg) |
| return NULL; |
| pe_hdr = find_pe_hdr (pimg); |
| if (pe_hdr == FIMG_POS_END) |
| return NULL; |
| /* So we might have found a PE-image. */ |
| r = (pe_image *) malloc (sizeof (pe_image)); |
| if (!r) |
| return NULL; |
| memset (r, 0, sizeof (pe_image)); |
| r->pimg = pimg; |
| r->start_pe = pe_hdr; |
| r->size_pe = pimg->data_len - pe_hdr; |
| if (!fill_pe_info (r)) |
| { |
| free (r); |
| r = NULL; |
| } |
| return r; |
| } |
| |
| void |
| peimg_free (pe_image *ppeimg) |
| { |
| if (!ppeimg) |
| return; |
| if (ppeimg->pimg) |
| fimg_free (ppeimg->pimg); |
| memset (ppeimg, 0, sizeof (pe_image)); |
| free (ppeimg); |
| } |
| |
| void |
| peimg_show (pe_image *ppeimg, FILE *outfp) |
| { |
| unsigned short hdr_cha; |
| if (!ppeimg || !outfp) |
| return; |
| fprintf (outfp, "PE image \"%s\"\n found at position %#"PRIxPTR" in file-image\n", |
| ppeimg->pimg->filename, ppeimg->start_pe); |
| fprintf (outfp, " Image has size of %#"PRIxPTR" byte(s)\n", ppeimg->size_pe); |
| fprintf (outfp, " Image machine kind is: %#x (%s)\n", |
| ppeimg->pe_filehdr.machine, ppeimg->is_64bit ? "64-bit" : "32-bit"); |
| fprintf (outfp, " Image contains %u section(s)\n", ppeimg->pe_filehdr.numsecs); |
| fprintf (outfp, " Optional header-size is %u\n", ppeimg->pe_filehdr.szOptHdr); |
| hdr_cha = ppeimg->pe_filehdr.characteristics; |
| if (hdr_cha != 0) |
| { |
| fprintf (outfp, " Characterstics:"); |
| if ((hdr_cha & 1) != 0) |
| fprintf (outfp, " relocs-stripped"); |
| if ((hdr_cha & 2) != 0) |
| fprintf (outfp, " executable"); |
| if ((hdr_cha & 4) != 0) |
| fprintf (outfp, " line-numbers-stripped"); |
| if ((hdr_cha & 8) != 0) |
| fprintf (outfp, " local-syms-stripped"); |
| if ((hdr_cha & 16) != 0) |
| fprintf (outfp, " aggressive-ws-trim"); |
| if ((hdr_cha & 32) != 0) |
| fprintf (outfp, " large-address-aware"); |
| if ((hdr_cha & 0x80) != 0) |
| fprintf (outfp, " bytes-reversed"); |
| if ((hdr_cha & 0x100) != 0) |
| fprintf (outfp, " 32-bit-machine"); |
| if ((hdr_cha & 0x200) != 0) |
| fprintf (outfp, " debug-stripped"); |
| if ((hdr_cha & 0x400) != 0) |
| fprintf (outfp, " removable-run-from-swap"); |
| if ((hdr_cha & 0x800) != 0) |
| fprintf (outfp, " net-run-from-swap"); |
| if ((hdr_cha & 0x1000) != 0) |
| fprintf (outfp, " system"); |
| if ((hdr_cha & 0x2000) != 0) |
| fprintf (outfp, " DLL"); |
| if ((hdr_cha & 0x4000) != 0) |
| fprintf (outfp, " up-system-only"); |
| if ((hdr_cha & 0x8000) != 0) |
| fprintf (outfp, " bytes-reversed-high"); |
| hdr_cha &= 0x40; |
| if (hdr_cha != 0) |
| fprintf (outfp, " unknown-flag-0x40"); |
| fprintf (outfp, "\n"); |
| } |
| fprintf (outfp, "PE+ optional header information\n" |
| " Linker version %u.%u, Code size: 0x%x, Intialized Data size: 0x%x\n" |
| " Uninitialized Data size: 0x%x, Entry-point 0x%x\n", |
| PEIMG_GET_UCHAR (ppeimg, ppeimg->optional_hdr_pos + 2), |
| PEIMG_GET_UCHAR (ppeimg, ppeimg->optional_hdr_pos + 3), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 4), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 8), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 12), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 16)); |
| if (ppeimg->is_64bit) |
| { |
| fprintf (outfp, |
| " Bases: Code=0x%x ImageBase=%#"PRIxPTR"\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 20), |
| (size_t)PEIMG_GET_UQUAD (ppeimg, ppeimg->optional_hdr_pos + 24)); |
| } |
| else |
| { |
| fprintf (outfp, |
| " Bases: Code=0x%x Data=0x%x ImageBase=0x%x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 20), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 24), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 28)); |
| } |
| fprintf (outfp, " Alignments: Section: 0x%x File:0x%x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 32), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 36)); |
| fprintf (outfp, " Versions: OS:%u.%u Image:%u.%u SubSystem:%u.%u, win32:0x%x\n", |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 40), |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 42), |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 44), |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 46), |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 48), |
| PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 50), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 52)); |
| fprintf (outfp, " Size of: Image:0x%x Headers:0x%x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 56), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 60)); |
| fprintf (outfp, " Checksum: 0x%x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 64)); |
| fprintf (outfp, " SubSystem: "); |
| switch (PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 68)) |
| { |
| case 0: fprintf (outfp, "Unknown (0)\n"); break; |
| case 1: fprintf (outfp, "Native (1)\n"); break; |
| case 2: fprintf (outfp, "Windows GUI (2)\n"); break; |
| case 3: fprintf (outfp, "Windows CUI (3)\n"); break; |
| case 5: fprintf (outfp, "OS/2 CUI (5)\n"); break; |
| case 7: fprintf (outfp, "Posix CUI (4)\n"); break; |
| case 8: fprintf (outfp, "Native Windows (8)\n"); break; |
| case 9: fprintf (outfp, "Windows CE GUI (9)\n"); break; |
| case 10: fprintf (outfp, "EFI Application (10)\n"); break; |
| case 11: fprintf (outfp, "EFI Service Driver (11)\n"); break; |
| case 12: fprintf (outfp, "EFI Runtime Driver (12)\n"); break; |
| case 13: fprintf (outfp, "EFI ROM (13)\n"); break; |
| case 14: fprintf (outfp, "XBOX\n"); break; |
| case 16: fprintf (outfp, "Windows Boot Application (16)\n"); break; |
| default: |
| fprintf (outfp, "Unkown (%u)\n", PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 68)); |
| break; |
| } |
| hdr_cha = PEIMG_GET_USHORT (ppeimg, ppeimg->optional_hdr_pos + 70); |
| if (hdr_cha != 0) |
| { |
| fprintf (outfp, " Optional Characteristics:\n "); |
| if ((hdr_cha & 0x20) != 0) |
| fprintf (outfp, " large-address-aware"); |
| if ((hdr_cha & 0x40) != 0) |
| fprintf (outfp, " dynamic-base"); |
| if ((hdr_cha & 0x80) != 0) |
| fprintf (outfp, " force-integrity"); |
| if ((hdr_cha & 0x100) != 0) |
| fprintf (outfp, " nx-compatible"); |
| if ((hdr_cha & 0x200) != 0) |
| fprintf (outfp, " no-isolation"); |
| if ((hdr_cha & 0x400) != 0) |
| fprintf (outfp, " no-SEH"); |
| if ((hdr_cha & 0x800) != 0) |
| fprintf (outfp, " no-BIND"); |
| if ((hdr_cha & 0x1000) != 0) |
| fprintf (outfp, " app-container"); |
| if ((hdr_cha & 0x2000) != 0) |
| fprintf (outfp, " wdm-Driver"); |
| if ((hdr_cha & 0x8000) != 0) |
| fprintf (outfp, " terminal-server-aware"); |
| hdr_cha &= ~(0xbfef); |
| if (hdr_cha) |
| fprintf (outfp, " unknown(0x%x)", hdr_cha); |
| fprintf (outfp, "\n"); |
| } |
| if (ppeimg->is_64bit) |
| { |
| fprintf (outfp, "Sizes Stack: Reserved:%#"PRIxPTR" Commit:%#"PRIxPTR"\n", |
| (size_t)PEIMG_GET_UQUAD (ppeimg, ppeimg->optional_hdr_pos + 72), |
| (size_t)PEIMG_GET_UQUAD (ppeimg, ppeimg->optional_hdr_pos + 80)); |
| fprintf (outfp, "Sizes Heap: Reserved:%#"PRIxPTR" Commit:%#"PRIxPTR"\n", |
| (size_t)PEIMG_GET_UQUAD (ppeimg, ppeimg->optional_hdr_pos + 88), |
| (size_t)PEIMG_GET_UQUAD (ppeimg, ppeimg->optional_hdr_pos + 96)); |
| fprintf (outfp, "LoaderFlags: 0x%x, # of rva&sizes: %u\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 104), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 108)); |
| } |
| else |
| { |
| fprintf (outfp, "Sizes Stack: Reserved:%#x Commit:%#x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 72), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 76)); |
| fprintf (outfp, "Sizes Heap: Reserved:%#x Commit:%#x\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 80), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 84)); |
| fprintf (outfp, "LoaderFlags: %#x, # of rva&sizes: %u\n", |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 88), |
| PEIMG_GET_UINT (ppeimg, ppeimg->optional_hdr_pos + 92)); |
| } |
| } |
| |
| void |
| peimg_set_hdr_opt_dll_characteristics (pe_image *pe, unsigned short set, unsigned short mask) |
| { |
| unsigned short flgs; |
| |
| flgs = PEIMG_GET_USHORT (pe, pe->optional_hdr_pos + 70); |
| flgs &= mask; |
| flgs |= set; |
| if (flgs == PEIMG_GET_USHORT (pe, pe->optional_hdr_pos + 70)) |
| return; |
| PEIMG_SET_USHORT (pe, pe->optional_hdr_pos + 70, flgs); |
| } |
| |
| #if 0 |
| int main(int argc, char **argv) |
| { |
| pe_image *pe; |
| pe = peimg_load (argv[0]); |
| if (!pe) |
| { |
| fprintf (stderr, "File not found, or no PE-image\n"); |
| return 0; |
| } |
| peimg_show (pe, stderr); |
| peimg_free (pe); |
| return 1; |
| } |
| #endif |