Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpefixup.c
Go to the documentation of this file.
00001 /* 00002 * PE Fixup Utility 00003 * Copyright (C) 2005 Filip Navara 00004 * 00005 * The purpose of this utility is fix PE binaries generated by binutils and 00006 * to manipulate flags that can't be set by binutils. 00007 * 00008 * Currently two features are implemented: 00009 * 00010 * - Setting flags on PE sections for use by drivers. The sections 00011 * .text, .data, .idata, .bss are marked as non-pageable and 00012 * non-discarable, section PAGE is marked as pageable and section 00013 * INIT is marked as discaradable. 00014 * 00015 * - Sorting of export name table in executables. DLLTOOL has bug 00016 * in sorting algorithm when the --kill-at flag is used. The exports 00017 * are sorted in the decorated form and so the fastcall symbols are 00018 * incorrectly put at the beginning of export table. This option 00019 * allow to correct sort the table, so binary search can be used 00020 * to process them. 00021 */ 00022 00023 #include <stdio.h> 00024 #include <stdlib.h> 00025 #include <string.h> 00026 #include <fcntl.h> 00027 #include <unistd.h> 00028 00029 #ifndef O_BINARY 00030 #define O_BINARY 0 00031 #endif 00032 00033 /* The following definitions are ripped from MinGW W32API headers. We don't 00034 use these headers directly in order to allow compilation on Linux hosts. */ 00035 00036 typedef unsigned char BYTE, *PBYTE; 00037 typedef unsigned short WORD; 00038 typedef unsigned int DWORD; 00039 typedef int LONG; 00040 typedef long LONG_PTR; 00041 00042 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 00043 #define IMAGE_SIZEOF_SHORT_NAME 8 00044 #define IMAGE_DOS_SIGNATURE 0x5A4D 00045 #define IMAGE_NT_SIGNATURE 0x00004550 00046 #define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 00047 #define IMAGE_SCN_MEM_NOT_PAGED 0x8000000 00048 #define FIELD_OFFSET(t,f) ((LONG)(LONG_PTR)&(((t*)0)->f)) 00049 #define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((unsigned long)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader)) 00050 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 00051 00052 #pragma pack(2) 00053 typedef struct _IMAGE_DOS_HEADER { 00054 WORD e_magic; 00055 WORD e_cblp; 00056 WORD e_cp; 00057 WORD e_crlc; 00058 WORD e_cparhdr; 00059 WORD e_minalloc; 00060 WORD e_maxalloc; 00061 WORD e_ss; 00062 WORD e_sp; 00063 WORD e_csum; 00064 WORD e_ip; 00065 WORD e_cs; 00066 WORD e_lfarlc; 00067 WORD e_ovno; 00068 WORD e_res[4]; 00069 WORD e_oemid; 00070 WORD e_oeminfo; 00071 WORD e_res2[10]; 00072 LONG e_lfanew; 00073 } IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER; 00074 #pragma pack(4) 00075 #pragma pack(4) 00076 typedef struct _IMAGE_EXPORT_DIRECTORY { 00077 DWORD Characteristics; 00078 DWORD TimeDateStamp; 00079 WORD MajorVersion; 00080 WORD MinorVersion; 00081 DWORD Name; 00082 DWORD Base; 00083 DWORD NumberOfFunctions; 00084 DWORD NumberOfNames; 00085 DWORD AddressOfFunctions; 00086 DWORD AddressOfNames; 00087 DWORD AddressOfNameOrdinals; 00088 } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; 00089 typedef struct _IMAGE_FILE_HEADER { 00090 WORD Machine; 00091 WORD NumberOfSections; 00092 DWORD TimeDateStamp; 00093 DWORD PointerToSymbolTable; 00094 DWORD NumberOfSymbols; 00095 WORD SizeOfOptionalHeader; 00096 WORD Characteristics; 00097 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 00098 typedef struct _IMAGE_DATA_DIRECTORY { 00099 DWORD VirtualAddress; 00100 DWORD Size; 00101 } IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY; 00102 typedef struct _IMAGE_OPTIONAL_HEADER { 00103 WORD Magic; 00104 BYTE MajorLinkerVersion; 00105 BYTE MinorLinkerVersion; 00106 DWORD SizeOfCode; 00107 DWORD SizeOfInitializedData; 00108 DWORD SizeOfUninitializedData; 00109 DWORD AddressOfEntryPoint; 00110 DWORD BaseOfCode; 00111 DWORD BaseOfData; 00112 DWORD ImageBase; 00113 DWORD SectionAlignment; 00114 DWORD FileAlignment; 00115 WORD MajorOperatingSystemVersion; 00116 WORD MinorOperatingSystemVersion; 00117 WORD MajorImageVersion; 00118 WORD MinorImageVersion; 00119 WORD MajorSubsystemVersion; 00120 WORD MinorSubsystemVersion; 00121 DWORD Reserved1; 00122 DWORD SizeOfImage; 00123 DWORD SizeOfHeaders; 00124 DWORD CheckSum; 00125 WORD Subsystem; 00126 WORD DllCharacteristics; 00127 DWORD SizeOfStackReserve; 00128 DWORD SizeOfStackCommit; 00129 DWORD SizeOfHeapReserve; 00130 DWORD SizeOfHeapCommit; 00131 DWORD LoaderFlags; 00132 DWORD NumberOfRvaAndSizes; 00133 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 00134 } IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER; 00135 typedef struct _IMAGE_NT_HEADERS { 00136 DWORD Signature; 00137 IMAGE_FILE_HEADER FileHeader; 00138 IMAGE_OPTIONAL_HEADER OptionalHeader; 00139 } IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS; 00140 typedef struct _IMAGE_SECTION_HEADER { 00141 BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; 00142 union { 00143 DWORD PhysicalAddress; 00144 DWORD VirtualSize; 00145 } Misc; 00146 DWORD VirtualAddress; 00147 DWORD SizeOfRawData; 00148 DWORD PointerToRawData; 00149 DWORD PointerToRelocations; 00150 DWORD PointerToLinenumbers; 00151 WORD NumberOfRelocations; 00152 WORD NumberOfLinenumbers; 00153 DWORD Characteristics; 00154 } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; 00155 #pragma pack(4) 00156 00157 /* End of ripped definitions */ 00158 00159 typedef struct _export_t { 00160 DWORD name; 00161 WORD ordinal; 00162 } export_t; 00163 00164 unsigned char *buffer; 00165 PIMAGE_DOS_HEADER dos_header; 00166 PIMAGE_NT_HEADERS nt_header; 00167 00168 static inline WORD dtohs(WORD in) 00169 { 00170 PBYTE in_ptr = (PBYTE)∈ 00171 return in_ptr[0] | (in_ptr[1] << 8); 00172 } 00173 00174 static inline WORD htods(WORD in) 00175 { 00176 WORD out; 00177 PBYTE out_ptr = (PBYTE)&out; 00178 out_ptr[0] = in; out_ptr[1] = in >> 8; 00179 return out; 00180 } 00181 00182 static inline DWORD dtohl(DWORD in) 00183 { 00184 PBYTE in_ptr = (PBYTE)∈ 00185 return in_ptr[0] | (in_ptr[1] << 8) | (in_ptr[2] << 16) | (in_ptr[3] << 24); 00186 } 00187 00188 static inline DWORD htodl(DWORD in) 00189 { 00190 DWORD out; 00191 PBYTE out_ptr = (PBYTE)&out; 00192 out_ptr[0] = in ; out_ptr[1] = in >> 8; 00193 out_ptr[2] = in >> 16; out_ptr[3] = in >> 24; 00194 return out; 00195 } 00196 00197 void *rva_to_ptr(DWORD rva) 00198 { 00199 PIMAGE_SECTION_HEADER section_header; 00200 unsigned int i; 00201 00202 for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header); 00203 i < dtohl(nt_header->FileHeader.NumberOfSections); 00204 i++, section_header++) 00205 { 00206 if (rva >= dtohl(section_header->VirtualAddress) && 00207 rva < dtohl(section_header->VirtualAddress) + 00208 dtohl(section_header->Misc.VirtualSize)) 00209 { 00210 return buffer + rva - dtohl(section_header->VirtualAddress) + 00211 dtohl(section_header->PointerToRawData); 00212 } 00213 } 00214 00215 return NULL; 00216 } 00217 00218 int export_compare_func(const void *a, const void *b) 00219 { 00220 const export_t *ap = a; 00221 const export_t *bp = b; 00222 char *an = rva_to_ptr(ap->name); 00223 char *bn = rva_to_ptr(bp->name); 00224 return strcmp(an, bn); 00225 } 00226 00227 int main(int argc, char **argv) 00228 { 00229 int fd_in, fd_out; 00230 long len; 00231 char hdrbuf[4] = { }, elfhdr[4] = { '\177', 'E', 'L', 'F' }; 00232 PIMAGE_SECTION_HEADER section_header; 00233 PIMAGE_DATA_DIRECTORY data_dir; 00234 unsigned int i; 00235 unsigned long checksum; 00236 int fixup_exports = 0; 00237 int fixup_sections = 0; 00238 00239 /* 00240 * Process parameters. 00241 */ 00242 00243 if (argc < 2) 00244 { 00245 printf("Usage: %s <filename> <options>\n" 00246 "Options:\n" 00247 " -sections Sets section flags for PE image.\n" 00248 " -exports Sort the names in export table.\n", 00249 argv[0]); 00250 return 1; 00251 } 00252 00253 for (i = 2; i < argc; i++) 00254 { 00255 if (!strcmp(argv[i], "-sections")) 00256 fixup_sections = 1; 00257 else if (!strcmp(argv[i], "-exports")) 00258 fixup_exports = 1; 00259 else 00260 { fprintf(stderr, "Invalid option: %s\n", argv[i]); return 1; } 00261 } 00262 00263 /* 00264 * Nothing to do. 00265 */ 00266 if (fixup_sections == 0 && fixup_exports == 0) 00267 return 0; 00268 00269 /* 00270 * Read the whole file to memory. 00271 */ 00272 00273 fd_in = open(argv[1], O_RDONLY | O_BINARY); 00274 if (fd_in == 0) 00275 { 00276 fprintf(stderr, "Can't open input file.\n"); 00277 return 1; 00278 } 00279 00280 /* 00281 * PowerPC ReactOS uses elf, so doesn't need pefixup 00282 */ 00283 len = read(fd_in, hdrbuf, sizeof(elfhdr)); 00284 if (!memcmp(hdrbuf, elfhdr, sizeof(elfhdr))) 00285 { 00286 close(fd_in); 00287 return 0; 00288 } 00289 00290 len = lseek(fd_in, 0, SEEK_END); 00291 if (len < sizeof(IMAGE_DOS_HEADER)) 00292 { 00293 close(fd_in); 00294 fprintf(stderr, "'%s' isn't a PE image (too short)\n", argv[1]); 00295 return 1; 00296 } 00297 00298 /* Lower down we overwrite the byte at len, so here, we need at least 00299 * one more byte than len. We'll be guaranteed one or two now. */ 00300 buffer = malloc((len + 2) & ~1); 00301 if (buffer == NULL) 00302 { 00303 close(fd_in); 00304 fprintf(stderr, "Not enough memory available.\n"); 00305 return 1; 00306 } 00307 00308 /* Read the whole input file into a buffer */ 00309 lseek(fd_in, 0, SEEK_SET); 00310 read(fd_in, buffer, len); 00311 /* Here is where the block end overwrite was */ 00312 if (len & 1) 00313 buffer[len] = 0; 00314 00315 close(fd_in); 00316 00317 /* 00318 * Check the headers and save pointers to them. 00319 */ 00320 00321 dos_header = (PIMAGE_DOS_HEADER)buffer; 00322 nt_header = (PIMAGE_NT_HEADERS)(buffer + dtohl(dos_header->e_lfanew)); 00323 00324 if (dtohs(dos_header->e_magic) != IMAGE_DOS_SIGNATURE || 00325 dtohl(nt_header->Signature) != IMAGE_NT_SIGNATURE) 00326 { 00327 fprintf(stderr, "'%s' isn't a PE image (bad headers)\n", argv[1]); 00328 free(buffer); 00329 return 1; 00330 } 00331 00332 if (fixup_exports) 00333 { 00334 /* Sort export directory */ 00335 data_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 00336 if (dtohl(data_dir->Size) != 0) 00337 { 00338 PIMAGE_EXPORT_DIRECTORY export_directory; 00339 DWORD *name_ptr; 00340 WORD *ordinal_ptr; 00341 export_t *exports; 00342 00343 export_directory = (PIMAGE_EXPORT_DIRECTORY)rva_to_ptr(dtohl(data_dir->VirtualAddress)); 00344 if (export_directory != NULL) 00345 { 00346 exports = malloc(sizeof(export_t) * dtohl(export_directory->NumberOfNames)); 00347 if (exports == NULL) 00348 { 00349 fprintf(stderr, "Not enough memory.\n"); 00350 free(buffer); 00351 return 1; 00352 } 00353 00354 name_ptr = (DWORD *)rva_to_ptr(dtohl(export_directory->AddressOfNames)); 00355 ordinal_ptr = (WORD *)rva_to_ptr(dtohl(export_directory->AddressOfNameOrdinals)); 00356 00357 for (i = 0; i < dtohl(export_directory->NumberOfNames); i++) 00358 { 00359 exports[i].name = dtohl(name_ptr[i]); 00360 exports[i].ordinal = dtohl(ordinal_ptr[i]); 00361 } 00362 00363 qsort(exports, dtohl(export_directory->NumberOfNames), sizeof(export_t), 00364 export_compare_func); 00365 00366 for (i = 0; i < dtohl(export_directory->NumberOfNames); i++) 00367 { 00368 name_ptr[i] = htodl(exports[i].name); 00369 ordinal_ptr[i] = htodl(exports[i].ordinal); 00370 } 00371 00372 free(exports); 00373 } 00374 } 00375 } 00376 00377 if (fixup_sections) 00378 { 00379 /* Update section flags */ 00380 for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header); 00381 i < dtohl(nt_header->OptionalHeader.NumberOfRvaAndSizes); 00382 i++, section_header++) 00383 { 00384 if (!strcmp((char*)section_header->Name, ".text") || 00385 !strcmp((char*)section_header->Name, ".data") || 00386 !strcmp((char*)section_header->Name, ".idata") || 00387 !strcmp((char*)section_header->Name, ".rdata") || 00388 !strcmp((char*)section_header->Name, ".bss")) 00389 { 00390 section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED); 00391 section_header->Characteristics &= htodl(~IMAGE_SCN_MEM_DISCARDABLE); 00392 } 00393 else if (!strcmp((char*)section_header->Name, "INIT")) 00394 { 00395 section_header->Characteristics |= htodl(IMAGE_SCN_MEM_DISCARDABLE); 00396 } 00397 else if (!strcmp((char*)section_header->Name, "PAGE")) 00398 { 00399 section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED); 00400 } 00401 } 00402 } 00403 00404 /* Recalculate checksum */ 00405 nt_header->OptionalHeader.CheckSum = 0; 00406 checksum = 0; 00407 for (i = 0; i < len; i += 2) 00408 { 00409 checksum += *(unsigned short *)(buffer + i); 00410 checksum = (checksum + (checksum >> 16)) & 0xffff; 00411 } 00412 checksum += len; 00413 nt_header->OptionalHeader.CheckSum = htods(checksum); 00414 00415 /* Write the output file */ 00416 fd_out = open(argv[1], O_WRONLY | O_BINARY); 00417 write(fd_out, buffer, len); 00418 close(fd_out); 00419 00420 return 0; 00421 } Generated on Sat May 26 2012 04:36:36 for ReactOS by
1.7.6.1
|