ReactOS  0.4.13-dev-52-g0efcfec
pefixup.c
Go to the documentation of this file.
1 /*
2  * PE Fixup Utility
3  * Copyright (C) 2005 Filip Navara
4  *
5  * The purpose of this utility is fix PE binaries generated by binutils and
6  * to manipulate flags that can't be set by binutils.
7  *
8  * Currently two features are implemented:
9  *
10  * - Setting flags on PE sections for use by drivers. The sections
11  * .text, .data, .idata, .bss are marked as non-pageable and
12  * non-discarable, section PAGE is marked as pageable and section
13  * INIT is marked as discaradable.
14  *
15  * - Sorting of export name table in executables. DLLTOOL has bug
16  * in sorting algorithm when the --kill-at flag is used. The exports
17  * are sorted in the decorated form and so the fastcall symbols are
18  * incorrectly put at the beginning of export table. This option
19  * allow to correct sort the table, so binary search can be used
20  * to process them.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 
29 #ifndef O_BINARY
30 #define O_BINARY 0
31 #endif
32 
33 /* The following definitions are ripped from MinGW W32API headers. We don't
34  use these headers directly in order to allow compilation on Linux hosts. */
35 
36 typedef unsigned char BYTE, *PBYTE;
37 typedef unsigned short WORD;
38 typedef unsigned int DWORD;
39 typedef int LONG;
40 typedef long LONG_PTR;
41 
42 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
43 #define IMAGE_SIZEOF_SHORT_NAME 8
44 #define IMAGE_DOS_SIGNATURE 0x5A4D
45 #define IMAGE_NT_SIGNATURE 0x00004550
46 #define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
47 #define IMAGE_SCN_MEM_NOT_PAGED 0x8000000
48 #define FIELD_OFFSET(t,f) ((LONG)(LONG_PTR)&(((t*)0)->f))
49 #define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((unsigned long)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))
50 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0
51 
52 #pragma pack(2)
53 typedef struct _IMAGE_DOS_HEADER {
54  WORD e_magic;
55  WORD e_cblp;
56  WORD e_cp;
57  WORD e_crlc;
61  WORD e_ss;
62  WORD e_sp;
63  WORD e_csum;
64  WORD e_ip;
65  WORD e_cs;
66  WORD e_lfarlc;
67  WORD e_ovno;
68  WORD e_res[4];
69  WORD e_oemid;
71  WORD e_res2[10];
72  LONG e_lfanew;
74 #pragma pack(4)
75 #pragma pack(4)
76 typedef struct _IMAGE_EXPORT_DIRECTORY {
81  DWORD Name;
82  DWORD Base;
89 typedef struct _IMAGE_FILE_HEADER {
90  WORD Machine;
98 typedef struct _IMAGE_DATA_DIRECTORY {
100  DWORD Size;
102 typedef struct _IMAGE_OPTIONAL_HEADER {
103  WORD Magic;
124  DWORD CheckSum;
125  WORD Subsystem;
135 typedef struct _IMAGE_NT_HEADERS {
140 typedef struct _IMAGE_SECTION_HEADER {
142  union {
145  } Misc;
155 #pragma pack(4)
156 
157 /* End of ripped definitions */
158 
159 typedef struct _export_t {
162 } export_t;
163 
164 unsigned char *buffer;
167 
168 static inline WORD dtohs(WORD in)
169 {
170  PBYTE in_ptr = (PBYTE)&in;
171  return in_ptr[0] | (in_ptr[1] << 8);
172 }
173 
174 static inline WORD htods(WORD in)
175 {
176  WORD out;
177  PBYTE out_ptr = (PBYTE)&out;
178  out_ptr[0] = in; out_ptr[1] = in >> 8;
179  return out;
180 }
181 
182 static inline DWORD dtohl(DWORD in)
183 {
184  PBYTE in_ptr = (PBYTE)&in;
185  return in_ptr[0] | (in_ptr[1] << 8) | (in_ptr[2] << 16) | (in_ptr[3] << 24);
186 }
187 
188 static inline DWORD htodl(DWORD in)
189 {
190  DWORD out;
191  PBYTE out_ptr = (PBYTE)&out;
192  out_ptr[0] = in ; out_ptr[1] = in >> 8;
193  out_ptr[2] = in >> 16; out_ptr[3] = in >> 24;
194  return out;
195 }
196 
197 void *rva_to_ptr(DWORD rva)
198 {
199  PIMAGE_SECTION_HEADER section_header;
200  unsigned int i;
201 
202  for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
204  i++, section_header++)
205  {
206  if (rva >= dtohl(section_header->VirtualAddress) &&
207  rva < dtohl(section_header->VirtualAddress) +
208  dtohl(section_header->Misc.VirtualSize))
209  {
210  return buffer + rva - dtohl(section_header->VirtualAddress) +
211  dtohl(section_header->PointerToRawData);
212  }
213  }
214 
215  return NULL;
216 }
217 
218 int export_compare_func(const void *a, const void *b)
219 {
220  const export_t *ap = a;
221  const export_t *bp = b;
222  char *an = rva_to_ptr(ap->name);
223  char *bn = rva_to_ptr(bp->name);
224  return strcmp(an, bn);
225 }
226 
227 int main(int argc, char **argv)
228 {
229  int fd_in, fd_out;
230  long len;
231  char hdrbuf[4] = { }, elfhdr[4] = { '\177', 'E', 'L', 'F' };
232  PIMAGE_SECTION_HEADER section_header;
233  PIMAGE_DATA_DIRECTORY data_dir;
234  unsigned int i;
235  unsigned long checksum;
236  int fixup_exports = 0;
237  int fixup_sections = 0;
238 
239  /*
240  * Process parameters.
241  */
242 
243  if (argc < 2)
244  {
245  printf("Usage: %s <filename> <options>\n"
246  "Options:\n"
247  " -sections Sets section flags for PE image.\n"
248  " -exports Sort the names in export table.\n",
249  argv[0]);
250  return 1;
251  }
252 
253  for (i = 2; i < argc; i++)
254  {
255  if (!strcmp(argv[i], "-sections"))
256  fixup_sections = 1;
257  else if (!strcmp(argv[i], "-exports"))
258  fixup_exports = 1;
259  else
260  { fprintf(stderr, "Invalid option: %s\n", argv[i]); return 1; }
261  }
262 
263  /*
264  * Nothing to do.
265  */
266  if (fixup_sections == 0 && fixup_exports == 0)
267  return 0;
268 
269  /*
270  * Read the whole file to memory.
271  */
272 
273  fd_in = open(argv[1], O_RDONLY | O_BINARY);
274  if (fd_in == 0)
275  {
276  fprintf(stderr, "Can't open input file.\n");
277  return 1;
278  }
279 
280  /*
281  * PowerPC ReactOS uses elf, so doesn't need pefixup
282  */
283  len = read(fd_in, hdrbuf, sizeof(elfhdr));
284  if (!memcmp(hdrbuf, elfhdr, sizeof(elfhdr)))
285  {
286  close(fd_in);
287  return 0;
288  }
289 
290  len = lseek(fd_in, 0, SEEK_END);
291  if (len < sizeof(IMAGE_DOS_HEADER))
292  {
293  close(fd_in);
294  fprintf(stderr, "'%s' isn't a PE image (too short)\n", argv[1]);
295  return 1;
296  }
297 
298  /* Lower down we overwrite the byte at len, so here, we need at least
299  * one more byte than len. We'll be guaranteed one or two now. */
300  buffer = malloc((len + 2) & ~1);
301  if (buffer == NULL)
302  {
303  close(fd_in);
304  fprintf(stderr, "Not enough memory available.\n");
305  return 1;
306  }
307 
308  /* Read the whole input file into a buffer */
309  lseek(fd_in, 0, SEEK_SET);
310  read(fd_in, buffer, len);
311  /* Here is where the block end overwrite was */
312  if (len & 1)
313  buffer[len] = 0;
314 
315  close(fd_in);
316 
317  /*
318  * Check the headers and save pointers to them.
319  */
320 
323 
326  {
327  fprintf(stderr, "'%s' isn't a PE image (bad headers)\n", argv[1]);
328  free(buffer);
329  return 1;
330  }
331 
332  if (fixup_exports)
333  {
334  /* Sort export directory */
336  if (dtohl(data_dir->Size) != 0)
337  {
338  PIMAGE_EXPORT_DIRECTORY export_directory;
339  DWORD *name_ptr;
340  WORD *ordinal_ptr;
341  export_t *exports;
342 
343  export_directory = (PIMAGE_EXPORT_DIRECTORY)rva_to_ptr(dtohl(data_dir->VirtualAddress));
344  if (export_directory != NULL)
345  {
346  exports = malloc(sizeof(export_t) * dtohl(export_directory->NumberOfNames));
347  if (exports == NULL)
348  {
349  fprintf(stderr, "Not enough memory.\n");
350  free(buffer);
351  return 1;
352  }
353 
354  name_ptr = (DWORD *)rva_to_ptr(dtohl(export_directory->AddressOfNames));
355  ordinal_ptr = (WORD *)rva_to_ptr(dtohl(export_directory->AddressOfNameOrdinals));
356 
357  for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
358  {
359  exports[i].name = dtohl(name_ptr[i]);
360  exports[i].ordinal = dtohl(ordinal_ptr[i]);
361  }
362 
363  qsort(exports, dtohl(export_directory->NumberOfNames), sizeof(export_t),
365 
366  for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
367  {
368  name_ptr[i] = htodl(exports[i].name);
369  ordinal_ptr[i] = htodl(exports[i].ordinal);
370  }
371 
372  free(exports);
373  }
374  }
375  }
376 
377  if (fixup_sections)
378  {
379  /* Update section flags */
380  for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
382  i++, section_header++)
383  {
384  if (!strcmp((char*)section_header->Name, ".text") ||
385  !strcmp((char*)section_header->Name, ".data") ||
386  !strcmp((char*)section_header->Name, ".idata") ||
387  !strcmp((char*)section_header->Name, ".rdata") ||
388  !strcmp((char*)section_header->Name, ".bss"))
389  {
390  section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
391  section_header->Characteristics &= htodl(~IMAGE_SCN_MEM_DISCARDABLE);
392  }
393  else if (!strcmp((char*)section_header->Name, "INIT"))
394  {
395  section_header->Characteristics |= htodl(IMAGE_SCN_MEM_DISCARDABLE);
396  }
397  else if (!strcmp((char*)section_header->Name, "PAGE"))
398  {
399  section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
400  }
401  }
402  }
403 
404  /* Recalculate checksum */
406  checksum = 0;
407  for (i = 0; i < len; i += 2)
408  {
409  checksum += *(unsigned short *)(buffer + i);
410  checksum = (checksum + (checksum >> 16)) & 0xffff;
411  }
412  checksum += len;
414 
415  /* Write the output file */
416  fd_out = open(argv[1], O_WRONLY | O_BINARY);
417  write(fd_out, buffer, len);
418  close(fd_out);
419 
420  return 0;
421 }
int main(int argc, char **argv)
Definition: pefixup.c:227
struct _IMAGE_DOS_HEADER IMAGE_DOS_HEADER
static int argc
Definition: ServiceArgs.c:12
struct _IMAGE_FILE_HEADER * PIMAGE_FILE_HEADER
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
Definition: ntddk_ex.h:178
static DWORD dtohl(DWORD in)
Definition: pefixup.c:182
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
WORD NumberOfRelocations
Definition: pedump.c:293
#define open
Definition: acwin.h:71
#define O_BINARY
Definition: pefixup.c:30
#define free
Definition: debug_ros.c:5
#define IMAGE_FIRST_SECTION(h)
Definition: pefixup.c:49
struct _IMAGE_SECTION_HEADER IMAGE_SECTION_HEADER
GLuint buffer
Definition: glext.h:5915
_Check_return_opt_ _CRTIMP long __cdecl lseek(_In_ int _FileHandle, _In_ long _Offset, _In_ int _Origin)
WORD MinorOperatingSystemVersion
Definition: ntddk_ex.h:161
struct _IMAGE_DATA_DIRECTORY IMAGE_DATA_DIRECTORY
#define IMAGE_DOS_SIGNATURE
Definition: pefixup.c:44
DWORD PointerToRawData
Definition: pedump.c:290
#define argv
Definition: mplay32.c:18
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
DWORD AddressOfNameOrdinals
Definition: compat.h:155
WORD MajorOperatingSystemVersion
Definition: ntddk_ex.h:160
unsigned char * PBYTE
Definition: pefixup.c:36
struct _IMAGE_EXPORT_DIRECTORY * PIMAGE_EXPORT_DIRECTORY
#define write
Definition: acwin.h:73
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
struct _IMAGE_SECTION_HEADER * PIMAGE_SECTION_HEADER
PIMAGE_NT_HEADERS nt_header
Definition: pefixup.c:166
long LONG
Definition: pedump.c:60
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define a
Definition: ke_i.h:78
#define O_WRONLY
Definition: acwin.h:85
DWORD SizeOfUninitializedData
Definition: ntddk_ex.h:148
void __cdecl qsort(_Inout_updates_bytes_(_NumOfElements *_SizeOfElements) void *_Base, _In_ size_t _NumOfElements, _In_ size_t _SizeOfElements, _In_ int(__cdecl *_PtFuncCompare)(const void *, const void *))
unsigned short WORD
Definition: pefixup.c:37
union _IMAGE_SECTION_HEADER::@1519 Misc
smooth NULL
Definition: ftsmooth.c:416
void * rva_to_ptr(DWORD rva)
Definition: pefixup.c:197
WORD SizeOfOptionalHeader
Definition: ntddk_ex.h:127
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
#define b
Definition: ke_i.h:79
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: pefixup.c:50
struct _IMAGE_NT_HEADERS * PIMAGE_NT_HEADERS
#define SEEK_SET
Definition: jmemansi.c:26
WORD NumberOfLinenumbers
Definition: pedump.c:294
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
struct _IMAGE_FILE_HEADER IMAGE_FILE_HEADER
DWORD NumberOfSymbols
Definition: ntddk_ex.h:126
DWORD PointerToLinenumbers
Definition: pedump.c:292
static WORD dtohs(WORD in)
Definition: pefixup.c:168
unsigned char BYTE
Definition: pefixup.c:36
unsigned char * buffer
Definition: pefixup.c:164
#define IMAGE_SIZEOF_SHORT_NAME
Definition: pefixup.c:43
long LONG_PTR
Definition: pefixup.c:40
unsigned short WORD
Definition: ntddk_ex.h:93
static FILE * out
Definition: regtests2xml.c:44
unsigned long DWORD
Definition: ntddk_ex.h:95
static DWORD htodl(DWORD in)
Definition: pefixup.c:188
#define IMAGE_NT_SIGNATURE
Definition: pefixup.c:45
WORD e_res2[10]
Definition: ntddk_ex.h:117
struct _IMAGE_DOS_HEADER * PIMAGE_DOS_HEADER
static WORD htods(WORD in)
Definition: pefixup.c:174
#define IMAGE_SCN_MEM_NOT_PAGED
Definition: pefixup.c:47
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
struct _export_t export_t
static cab_ULONG checksum(const cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum)
Definition: fdi.c:353
#define close
Definition: acwin.h:74
struct _IMAGE_NT_HEADERS IMAGE_NT_HEADERS
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES
Definition: pefixup.c:42
WORD ordinal
Definition: pefixup.c:161
struct _IMAGE_EXPORT_DIRECTORY IMAGE_EXPORT_DIRECTORY
struct _IMAGE_DATA_DIRECTORY * PIMAGE_DATA_DIRECTORY
GLuint in
Definition: glext.h:9616
DWORD PointerToSymbolTable
Definition: ntddk_ex.h:125
unsigned int DWORD
Definition: pefixup.c:38
struct _IMAGE_OPTIONAL_HEADER * PIMAGE_OPTIONAL_HEADER
#define fd_out
Definition: auth_sspi.c:858
BYTE Name[IMAGE_SIZEOF_SHORT_NAME]
Definition: pedump.c:281
PIMAGE_DOS_HEADER dos_header
Definition: pefixup.c:165
Definition: name.c:36
void int int ULONGLONG int va_list * ap
Definition: winesup.h:32
FILE * stderr
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define SEEK_END
Definition: cabinet.c:27
#define malloc
Definition: debug_ros.c:4
int LONG
Definition: pefixup.c:39
DWORD name
Definition: pefixup.c:160
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
int export_compare_func(const void *a, const void *b)
Definition: pefixup.c:218
BYTE * PBYTE
Definition: pedump.c:66
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
DWORD PointerToRelocations
Definition: pedump.c:291
#define IMAGE_SCN_MEM_DISCARDABLE
Definition: pefixup.c:46
struct _IMAGE_OPTIONAL_HEADER IMAGE_OPTIONAL_HEADER
#define printf
Definition: config.h:203
#define O_RDONLY
Definition: acwin.h:82