mirror of
https://github.com/reactos/reactos.git
synced 2024-05-29 00:31:45 +00:00
[SDK][HOST-TOOLS] Add load_config workaround for gcc builds
Since binutils can not add this, we re-introduce pefixup. It searches for the exported symbol '_load_config_used', and uses that to fill out the LOAD_CONFIG directory in the PE header
This commit is contained in:
parent
2ed06c9588
commit
0b948581fc
|
@ -98,7 +98,7 @@ if(NOT CMAKE_CROSSCOMPILING)
|
||||||
|
|
||||||
set(NATIVE_TARGETS bin2c widl gendib cabman fatten hpp isohybrid mkhive mkisofs obj2bin spec2def geninc mkshelllink utf16le xml2sdb)
|
set(NATIVE_TARGETS bin2c widl gendib cabman fatten hpp isohybrid mkhive mkisofs obj2bin spec2def geninc mkshelllink utf16le xml2sdb)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
list(APPEND NATIVE_TARGETS rsym)
|
list(APPEND NATIVE_TARGETS rsym pefixup)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
export(TARGETS ${NATIVE_TARGETS} FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake NAMESPACE native- )
|
export(TARGETS ${NATIVE_TARGETS} FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake NAMESPACE native- )
|
||||||
|
|
|
@ -22,11 +22,7 @@ add_subdirectory(gdi32)
|
||||||
add_subdirectory(gditools)
|
add_subdirectory(gditools)
|
||||||
add_subdirectory(iphlpapi)
|
add_subdirectory(iphlpapi)
|
||||||
add_subdirectory(kernel32)
|
add_subdirectory(kernel32)
|
||||||
if(NOT GCC)
|
add_subdirectory(loadconfig)
|
||||||
# gcc / binutils are unable to add an IMAGE_LOAD_CONFIG_DIRECTORY
|
|
||||||
# So maybe we should resuscitate sdk/tools/pefixup.c
|
|
||||||
add_subdirectory(loadconfig)
|
|
||||||
endif()
|
|
||||||
add_subdirectory(localspl)
|
add_subdirectory(localspl)
|
||||||
add_subdirectory(mountmgr)
|
add_subdirectory(mountmgr)
|
||||||
add_subdirectory(msgina)
|
add_subdirectory(msgina)
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
|
||||||
|
spec2def(loadconfig_apitest.exe loadconfig_apitest.spec)
|
||||||
|
|
||||||
list(APPEND SOURCE
|
list(APPEND SOURCE
|
||||||
common.c
|
common.c
|
||||||
stacktrace.c
|
stacktrace.c
|
||||||
loadconfig.h)
|
loadconfig.h)
|
||||||
|
|
||||||
add_executable(loadconfig_apitest ${SOURCE} testlist.c)
|
add_executable(loadconfig_apitest ${SOURCE} testlist.c ${CMAKE_CURRENT_BINARY_DIR}/loadconfig_apitest.def)
|
||||||
target_link_libraries(loadconfig_apitest wine ${PSEH_LIB})
|
target_link_libraries(loadconfig_apitest wine ${PSEH_LIB})
|
||||||
set_module_type(loadconfig_apitest win32cui)
|
set_module_type(loadconfig_apitest win32cui)
|
||||||
add_importlibs(loadconfig_apitest msvcrt kernel32 ntdll)
|
add_importlibs(loadconfig_apitest msvcrt kernel32 ntdll)
|
||||||
add_pch(loadconfig_apitest loadconfig.h SOURCE)
|
#add_pch(loadconfig_apitest loadconfig.h SOURCE)
|
||||||
add_rostests_file(TARGET loadconfig_apitest)
|
add_rostests_file(TARGET loadconfig_apitest)
|
||||||
|
|
||||||
|
fixup_load_config(loadconfig_apitest)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
# Export this symbol so we can do binutils job
|
||||||
|
@ extern _load_config_used
|
|
@ -345,6 +345,14 @@ if(NOT ARCH STREQUAL "i386")
|
||||||
set(DECO_OPTION "-@")
|
set(DECO_OPTION "-@")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
function(fixup_load_config _target)
|
||||||
|
get_target_property(PEFIXUP native-pefixup IMPORTED_LOCATION_NOCONFIG)
|
||||||
|
add_custom_command(TARGET ${_target} POST_BUILD
|
||||||
|
COMMAND "${PEFIXUP}"
|
||||||
|
"$<TARGET_FILE:${_target}>"
|
||||||
|
COMMENT "Patching in LOAD_CONFIG")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
function(generate_import_lib _libname _dllname _spec_file)
|
function(generate_import_lib _libname _dllname _spec_file)
|
||||||
# Generate the def for the import lib
|
# Generate the def for the import lib
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|
|
@ -371,6 +371,10 @@ function(add_delay_importlibs _module)
|
||||||
target_link_libraries(${_module} delayimp)
|
target_link_libraries(${_module} delayimp)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
function(fixup_load_config _target)
|
||||||
|
# msvc knows how to generate a load_config so no hacks here
|
||||||
|
endfunction()
|
||||||
|
|
||||||
function(generate_import_lib _libname _dllname _spec_file)
|
function(generate_import_lib _libname _dllname _spec_file)
|
||||||
|
|
||||||
set(_def_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_exp.def)
|
set(_def_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_exp.def)
|
||||||
|
|
|
@ -4,8 +4,6 @@ function(add_host_tool _tool)
|
||||||
set_target_properties(${_tool} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TOOLS_FOLDER})
|
set_target_properties(${_tool} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TOOLS_FOLDER})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
#add_executable(pefixup pefixup.c)
|
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -DHAVE_IO_H=1)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -DHAVE_IO_H=1)
|
||||||
add_compile_flags_language("/EHsc" "CXX")
|
add_compile_flags_language("/EHsc" "CXX")
|
||||||
|
@ -40,4 +38,7 @@ add_subdirectory(xml2sdb)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
add_subdirectory(log2lines)
|
add_subdirectory(log2lines)
|
||||||
add_subdirectory(rsym)
|
add_subdirectory(rsym)
|
||||||
|
|
||||||
|
add_host_tool(pefixup pefixup.c)
|
||||||
|
target_link_libraries(pefixup PRIVATE host_includes)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,421 +1,196 @@
|
||||||
/*
|
/*
|
||||||
* PE Fixup Utility
|
* PE Fixup Utility
|
||||||
* Copyright (C) 2005 Filip Navara
|
* Copyright (C) 2005 Filip Navara
|
||||||
|
* Copyright (C) 2020 Mark Jansen
|
||||||
*
|
*
|
||||||
* The purpose of this utility is fix PE binaries generated by binutils and
|
* The purpose of this utility is fix PE binaries generated by binutils and
|
||||||
* to manipulate flags that can't be set by binutils.
|
* to manipulate flags that can't be set by binutils.
|
||||||
*
|
*
|
||||||
* Currently two features are implemented:
|
* Currently one features is implemented:
|
||||||
*
|
*
|
||||||
* - Setting flags on PE sections for use by drivers. The sections
|
* - Updating the PE header to use a LOAD_CONFIG,
|
||||||
* .text, .data, .idata, .bss are marked as non-pageable and
|
* when the struct is exported with the name '_load_config_used'
|
||||||
* non-discarable, section PAGE is marked as pageable and section
|
|
||||||
* INIT is marked as discaradable.
|
|
||||||
*
|
|
||||||
* - Sorting of export name table in executables. DLLTOOL has bug
|
|
||||||
* in sorting algorithm when the --kill-at flag is used. The exports
|
|
||||||
* are sorted in the decorated form and so the fastcall symbols are
|
|
||||||
* incorrectly put at the beginning of export table. This option
|
|
||||||
* allow to correct sort the table, so binary search can be used
|
|
||||||
* to process them.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifndef O_BINARY
|
// host_includes
|
||||||
#define O_BINARY 0
|
#include <typedefs.h>
|
||||||
#endif
|
#include <pecoff.h>
|
||||||
|
#include "../../dll/win32/dbghelp/compat.h"
|
||||||
|
|
||||||
/* The following definitions are ripped from MinGW W32API headers. We don't
|
void *rva_to_ptr(unsigned char *buffer, PIMAGE_NT_HEADERS nt_header, DWORD rva)
|
||||||
use these headers directly in order to allow compilation on Linux hosts. */
|
|
||||||
|
|
||||||
typedef unsigned char BYTE, *PBYTE;
|
|
||||||
typedef unsigned short WORD;
|
|
||||||
typedef unsigned int DWORD;
|
|
||||||
typedef int LONG;
|
|
||||||
typedef long LONG_PTR;
|
|
||||||
|
|
||||||
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
|
||||||
#define IMAGE_SIZEOF_SHORT_NAME 8
|
|
||||||
#define IMAGE_DOS_SIGNATURE 0x5A4D
|
|
||||||
#define IMAGE_NT_SIGNATURE 0x00004550
|
|
||||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
|
|
||||||
#define IMAGE_SCN_MEM_NOT_PAGED 0x8000000
|
|
||||||
#define FIELD_OFFSET(t,f) ((LONG)(LONG_PTR)&(((t*)0)->f))
|
|
||||||
#define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((unsigned long)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))
|
|
||||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
|
||||||
|
|
||||||
#pragma pack(2)
|
|
||||||
typedef struct _IMAGE_DOS_HEADER {
|
|
||||||
WORD e_magic;
|
|
||||||
WORD e_cblp;
|
|
||||||
WORD e_cp;
|
|
||||||
WORD e_crlc;
|
|
||||||
WORD e_cparhdr;
|
|
||||||
WORD e_minalloc;
|
|
||||||
WORD e_maxalloc;
|
|
||||||
WORD e_ss;
|
|
||||||
WORD e_sp;
|
|
||||||
WORD e_csum;
|
|
||||||
WORD e_ip;
|
|
||||||
WORD e_cs;
|
|
||||||
WORD e_lfarlc;
|
|
||||||
WORD e_ovno;
|
|
||||||
WORD e_res[4];
|
|
||||||
WORD e_oemid;
|
|
||||||
WORD e_oeminfo;
|
|
||||||
WORD e_res2[10];
|
|
||||||
LONG e_lfanew;
|
|
||||||
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
|
|
||||||
#pragma pack(4)
|
|
||||||
#pragma pack(4)
|
|
||||||
typedef struct _IMAGE_EXPORT_DIRECTORY {
|
|
||||||
DWORD Characteristics;
|
|
||||||
DWORD TimeDateStamp;
|
|
||||||
WORD MajorVersion;
|
|
||||||
WORD MinorVersion;
|
|
||||||
DWORD Name;
|
|
||||||
DWORD Base;
|
|
||||||
DWORD NumberOfFunctions;
|
|
||||||
DWORD NumberOfNames;
|
|
||||||
DWORD AddressOfFunctions;
|
|
||||||
DWORD AddressOfNames;
|
|
||||||
DWORD AddressOfNameOrdinals;
|
|
||||||
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
|
|
||||||
typedef struct _IMAGE_FILE_HEADER {
|
|
||||||
WORD Machine;
|
|
||||||
WORD NumberOfSections;
|
|
||||||
DWORD TimeDateStamp;
|
|
||||||
DWORD PointerToSymbolTable;
|
|
||||||
DWORD NumberOfSymbols;
|
|
||||||
WORD SizeOfOptionalHeader;
|
|
||||||
WORD Characteristics;
|
|
||||||
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
|
|
||||||
typedef struct _IMAGE_DATA_DIRECTORY {
|
|
||||||
DWORD VirtualAddress;
|
|
||||||
DWORD Size;
|
|
||||||
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
|
|
||||||
typedef struct _IMAGE_OPTIONAL_HEADER {
|
|
||||||
WORD Magic;
|
|
||||||
BYTE MajorLinkerVersion;
|
|
||||||
BYTE MinorLinkerVersion;
|
|
||||||
DWORD SizeOfCode;
|
|
||||||
DWORD SizeOfInitializedData;
|
|
||||||
DWORD SizeOfUninitializedData;
|
|
||||||
DWORD AddressOfEntryPoint;
|
|
||||||
DWORD BaseOfCode;
|
|
||||||
DWORD BaseOfData;
|
|
||||||
DWORD ImageBase;
|
|
||||||
DWORD SectionAlignment;
|
|
||||||
DWORD FileAlignment;
|
|
||||||
WORD MajorOperatingSystemVersion;
|
|
||||||
WORD MinorOperatingSystemVersion;
|
|
||||||
WORD MajorImageVersion;
|
|
||||||
WORD MinorImageVersion;
|
|
||||||
WORD MajorSubsystemVersion;
|
|
||||||
WORD MinorSubsystemVersion;
|
|
||||||
DWORD Reserved1;
|
|
||||||
DWORD SizeOfImage;
|
|
||||||
DWORD SizeOfHeaders;
|
|
||||||
DWORD CheckSum;
|
|
||||||
WORD Subsystem;
|
|
||||||
WORD DllCharacteristics;
|
|
||||||
DWORD SizeOfStackReserve;
|
|
||||||
DWORD SizeOfStackCommit;
|
|
||||||
DWORD SizeOfHeapReserve;
|
|
||||||
DWORD SizeOfHeapCommit;
|
|
||||||
DWORD LoaderFlags;
|
|
||||||
DWORD NumberOfRvaAndSizes;
|
|
||||||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
|
|
||||||
} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;
|
|
||||||
typedef struct _IMAGE_NT_HEADERS {
|
|
||||||
DWORD Signature;
|
|
||||||
IMAGE_FILE_HEADER FileHeader;
|
|
||||||
IMAGE_OPTIONAL_HEADER OptionalHeader;
|
|
||||||
} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
|
|
||||||
typedef struct _IMAGE_SECTION_HEADER {
|
|
||||||
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
|
|
||||||
union {
|
|
||||||
DWORD PhysicalAddress;
|
|
||||||
DWORD VirtualSize;
|
|
||||||
} Misc;
|
|
||||||
DWORD VirtualAddress;
|
|
||||||
DWORD SizeOfRawData;
|
|
||||||
DWORD PointerToRawData;
|
|
||||||
DWORD PointerToRelocations;
|
|
||||||
DWORD PointerToLinenumbers;
|
|
||||||
WORD NumberOfRelocations;
|
|
||||||
WORD NumberOfLinenumbers;
|
|
||||||
DWORD Characteristics;
|
|
||||||
} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
|
|
||||||
#pragma pack(4)
|
|
||||||
|
|
||||||
/* End of ripped definitions */
|
|
||||||
|
|
||||||
typedef struct _export_t {
|
|
||||||
DWORD name;
|
|
||||||
WORD ordinal;
|
|
||||||
} export_t;
|
|
||||||
|
|
||||||
unsigned char *buffer;
|
|
||||||
PIMAGE_DOS_HEADER dos_header;
|
|
||||||
PIMAGE_NT_HEADERS nt_header;
|
|
||||||
|
|
||||||
static inline WORD dtohs(WORD in)
|
|
||||||
{
|
{
|
||||||
PBYTE in_ptr = (PBYTE)∈
|
unsigned int i;
|
||||||
return in_ptr[0] | (in_ptr[1] << 8);
|
PIMAGE_SECTION_HEADER section_header = IMAGE_FIRST_SECTION(nt_header);
|
||||||
|
|
||||||
|
for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section_header++)
|
||||||
|
{
|
||||||
|
if (rva >= section_header->VirtualAddress &&
|
||||||
|
rva < section_header->VirtualAddress + section_header->Misc.VirtualSize)
|
||||||
|
{
|
||||||
|
return buffer + rva - section_header->VirtualAddress + section_header->PointerToRawData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline WORD htods(WORD in)
|
|
||||||
|
static void fix_checksum(unsigned char *buffer, long len, PIMAGE_NT_HEADERS nt_header)
|
||||||
{
|
{
|
||||||
WORD out;
|
unsigned int checksum = 0;
|
||||||
PBYTE out_ptr = (PBYTE)&out;
|
long n;
|
||||||
out_ptr[0] = in; out_ptr[1] = in >> 8;
|
|
||||||
return out;
|
nt_header->OptionalHeader.CheckSum = 0;
|
||||||
|
|
||||||
|
for (n = 0; n < len; n += 2)
|
||||||
|
{
|
||||||
|
checksum += *(unsigned short *)(buffer + n);
|
||||||
|
checksum = (checksum + (checksum >> 16)) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum += len;
|
||||||
|
nt_header->OptionalHeader.CheckSum = checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline DWORD dtohl(DWORD in)
|
static int add_loadconfig(unsigned char *buffer, PIMAGE_NT_HEADERS nt_header)
|
||||||
{
|
{
|
||||||
PBYTE in_ptr = (PBYTE)∈
|
PIMAGE_DATA_DIRECTORY export_dir;
|
||||||
return in_ptr[0] | (in_ptr[1] << 8) | (in_ptr[2] << 16) | (in_ptr[3] << 24);
|
PIMAGE_EXPORT_DIRECTORY export_directory;
|
||||||
}
|
|
||||||
|
|
||||||
static inline DWORD htodl(DWORD in)
|
export_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
||||||
{
|
if (export_dir->Size != 0)
|
||||||
DWORD out;
|
{
|
||||||
PBYTE out_ptr = (PBYTE)&out;
|
export_directory = rva_to_ptr(buffer, nt_header, export_dir->VirtualAddress);
|
||||||
out_ptr[0] = in ; out_ptr[1] = in >> 8;
|
if (export_directory != NULL)
|
||||||
out_ptr[2] = in >> 16; out_ptr[3] = in >> 24;
|
{
|
||||||
return out;
|
DWORD *name_ptr, *function_ptr, n;
|
||||||
}
|
WORD *ordinal_ptr;
|
||||||
|
|
||||||
void *rva_to_ptr(DWORD rva)
|
name_ptr = rva_to_ptr(buffer, nt_header, export_directory->AddressOfNames);
|
||||||
{
|
ordinal_ptr = rva_to_ptr(buffer, nt_header, export_directory->AddressOfNameOrdinals);
|
||||||
PIMAGE_SECTION_HEADER section_header;
|
function_ptr = rva_to_ptr(buffer, nt_header, export_directory->AddressOfFunctions);
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
|
for (n = 0; n < export_directory->NumberOfNames; n++)
|
||||||
i < dtohl(nt_header->FileHeader.NumberOfSections);
|
{
|
||||||
i++, section_header++)
|
const char* name = rva_to_ptr(buffer, nt_header, name_ptr[n]);
|
||||||
{
|
if (!strcmp(name, "_load_config_used"))
|
||||||
if (rva >= dtohl(section_header->VirtualAddress) &&
|
{
|
||||||
rva < dtohl(section_header->VirtualAddress) +
|
PIMAGE_DATA_DIRECTORY load_config_dir;
|
||||||
dtohl(section_header->Misc.VirtualSize))
|
DWORD load_config_rva = function_ptr[ordinal_ptr[n]];
|
||||||
{
|
DWORD* load_config_ptr = rva_to_ptr(buffer, nt_header, load_config_rva);
|
||||||
return buffer + rva - dtohl(section_header->VirtualAddress) +
|
|
||||||
dtohl(section_header->PointerToRawData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
/* Update the DataDirectory pointer / size
|
||||||
}
|
The first entry of the LOAD_CONFIG struct is the size, use that as DataDirectory.Size */
|
||||||
|
load_config_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
|
||||||
|
load_config_dir->VirtualAddress = load_config_rva;
|
||||||
|
load_config_dir->Size = *load_config_ptr;
|
||||||
|
|
||||||
int export_compare_func(const void *a, const void *b)
|
return 0;
|
||||||
{
|
}
|
||||||
const export_t *ap = a;
|
}
|
||||||
const export_t *bp = b;
|
|
||||||
char *an = rva_to_ptr(ap->name);
|
fprintf(stderr, "Export '_load_config_used' not found\n");
|
||||||
char *bn = rva_to_ptr(bp->name);
|
}
|
||||||
return strcmp(an, bn);
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Invalid rva for export directory\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No export directory\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int fd_in, fd_out;
|
FILE* file;
|
||||||
long len;
|
long len;
|
||||||
char hdrbuf[4] = { }, elfhdr[4] = { '\177', 'E', 'L', 'F' };
|
unsigned char *buffer;
|
||||||
PIMAGE_SECTION_HEADER section_header;
|
PIMAGE_DOS_HEADER dos_header;
|
||||||
PIMAGE_DATA_DIRECTORY data_dir;
|
int result = 1;
|
||||||
unsigned int i;
|
|
||||||
unsigned long checksum;
|
|
||||||
int fixup_exports = 0;
|
|
||||||
int fixup_sections = 0;
|
|
||||||
|
|
||||||
/*
|
if (argc < 2)
|
||||||
* Process parameters.
|
{
|
||||||
*/
|
printf("Usage: %s <filename>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (argc < 2)
|
/* Read the whole file to memory. */
|
||||||
{
|
file = fopen(argv[1], "r+b");
|
||||||
printf("Usage: %s <filename> <options>\n"
|
if (!file)
|
||||||
"Options:\n"
|
{
|
||||||
" -sections Sets section flags for PE image.\n"
|
fprintf(stderr, "Can't open '%s'.\n", argv[1]);
|
||||||
" -exports Sort the names in export table.\n",
|
return 1;
|
||||||
argv[0]);
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 2; i < argc; i++)
|
fseek(file, 0, SEEK_END);
|
||||||
{
|
len = ftell(file);
|
||||||
if (!strcmp(argv[i], "-sections"))
|
if (len < sizeof(IMAGE_DOS_HEADER))
|
||||||
fixup_sections = 1;
|
{
|
||||||
else if (!strcmp(argv[i], "-exports"))
|
fclose(file);
|
||||||
fixup_exports = 1;
|
fprintf(stderr, "'%s' isn't a PE image (too short)\n", argv[1]);
|
||||||
else
|
return 1;
|
||||||
{ fprintf(stderr, "Invalid option: %s\n", argv[i]); return 1; }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/* Add one byte extra for the case where the input file size is odd.
|
||||||
* Nothing to do.
|
We rely on this in our crc calculation */
|
||||||
*/
|
buffer = calloc(len + 1, 1);
|
||||||
if (fixup_sections == 0 && fixup_exports == 0)
|
if (buffer == NULL)
|
||||||
return 0;
|
{
|
||||||
|
fclose(file);
|
||||||
|
fprintf(stderr, "Not enough memory available.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/* Read the whole input file into a buffer */
|
||||||
* Read the whole file to memory.
|
fseek(file, 0, SEEK_SET);
|
||||||
*/
|
fread(buffer, 1, len, file);
|
||||||
|
|
||||||
fd_in = open(argv[1], O_RDONLY | O_BINARY);
|
/* Check the headers and save pointers to them. */
|
||||||
if (fd_in == 0)
|
dos_header = (PIMAGE_DOS_HEADER)buffer;
|
||||||
{
|
if (dos_header->e_magic == IMAGE_DOS_SIGNATURE)
|
||||||
fprintf(stderr, "Can't open input file.\n");
|
{
|
||||||
return 1;
|
PIMAGE_NT_HEADERS nt_header;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
nt_header = (PIMAGE_NT_HEADERS)(buffer + dos_header->e_lfanew);
|
||||||
* PowerPC ReactOS uses elf, so doesn't need pefixup
|
|
||||||
*/
|
|
||||||
len = read(fd_in, hdrbuf, sizeof(elfhdr));
|
|
||||||
if (!memcmp(hdrbuf, elfhdr, sizeof(elfhdr)))
|
|
||||||
{
|
|
||||||
close(fd_in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = lseek(fd_in, 0, SEEK_END);
|
if (nt_header->Signature == IMAGE_NT_SIGNATURE)
|
||||||
if (len < sizeof(IMAGE_DOS_HEADER))
|
{
|
||||||
{
|
if (!add_loadconfig(buffer, nt_header))
|
||||||
close(fd_in);
|
|
||||||
fprintf(stderr, "'%s' isn't a PE image (too short)\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lower down we overwrite the byte at len, so here, we need at least
|
|
||||||
* one more byte than len. We'll be guaranteed one or two now. */
|
|
||||||
buffer = malloc((len + 2) & ~1);
|
|
||||||
if (buffer == NULL)
|
|
||||||
{
|
|
||||||
close(fd_in);
|
|
||||||
fprintf(stderr, "Not enough memory available.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the whole input file into a buffer */
|
|
||||||
lseek(fd_in, 0, SEEK_SET);
|
|
||||||
read(fd_in, buffer, len);
|
|
||||||
/* Here is where the block end overwrite was */
|
|
||||||
if (len & 1)
|
|
||||||
buffer[len] = 0;
|
|
||||||
|
|
||||||
close(fd_in);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the headers and save pointers to them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dos_header = (PIMAGE_DOS_HEADER)buffer;
|
|
||||||
nt_header = (PIMAGE_NT_HEADERS)(buffer + dtohl(dos_header->e_lfanew));
|
|
||||||
|
|
||||||
if (dtohs(dos_header->e_magic) != IMAGE_DOS_SIGNATURE ||
|
|
||||||
dtohl(nt_header->Signature) != IMAGE_NT_SIGNATURE)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "'%s' isn't a PE image (bad headers)\n", argv[1]);
|
|
||||||
free(buffer);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixup_exports)
|
|
||||||
{
|
|
||||||
/* Sort export directory */
|
|
||||||
data_dir = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
|
|
||||||
if (dtohl(data_dir->Size) != 0)
|
|
||||||
{
|
|
||||||
PIMAGE_EXPORT_DIRECTORY export_directory;
|
|
||||||
DWORD *name_ptr;
|
|
||||||
WORD *ordinal_ptr;
|
|
||||||
export_t *exports;
|
|
||||||
|
|
||||||
export_directory = (PIMAGE_EXPORT_DIRECTORY)rva_to_ptr(dtohl(data_dir->VirtualAddress));
|
|
||||||
if (export_directory != NULL)
|
|
||||||
{
|
|
||||||
exports = malloc(sizeof(export_t) * dtohl(export_directory->NumberOfNames));
|
|
||||||
if (exports == NULL)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Not enough memory.\n");
|
fix_checksum(buffer, len, nt_header);
|
||||||
free(buffer);
|
|
||||||
return 1;
|
/* We could 'optimize by only writing the changed parts, but keep it simple for now */
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
fwrite(buffer, 1, len, file);
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
name_ptr = (DWORD *)rva_to_ptr(dtohl(export_directory->AddressOfNames));
|
|
||||||
ordinal_ptr = (WORD *)rva_to_ptr(dtohl(export_directory->AddressOfNameOrdinals));
|
|
||||||
|
|
||||||
for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
|
|
||||||
{
|
{
|
||||||
exports[i].name = dtohl(name_ptr[i]);
|
/* Error already printed inside add_loadconfig */
|
||||||
exports[i].ordinal = dtohl(ordinal_ptr[i]);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "'%s' Invalid PE signature: %x\n", argv[1], nt_header->Signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "'%s' Invalid DOS signature: %x\n", argv[1], dos_header->e_magic);
|
||||||
|
}
|
||||||
|
|
||||||
qsort(exports, dtohl(export_directory->NumberOfNames), sizeof(export_t),
|
free(buffer);
|
||||||
export_compare_func);
|
fclose(file);
|
||||||
|
|
||||||
for (i = 0; i < dtohl(export_directory->NumberOfNames); i++)
|
return result;
|
||||||
{
|
|
||||||
name_ptr[i] = htodl(exports[i].name);
|
|
||||||
ordinal_ptr[i] = htodl(exports[i].ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(exports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fixup_sections)
|
|
||||||
{
|
|
||||||
/* Update section flags */
|
|
||||||
for (i = 0, section_header = IMAGE_FIRST_SECTION(nt_header);
|
|
||||||
i < dtohl(nt_header->FileHeader.NumberOfSections);
|
|
||||||
i++, section_header++)
|
|
||||||
{
|
|
||||||
if (!strcmp((char*)section_header->Name, ".text") ||
|
|
||||||
!strcmp((char*)section_header->Name, ".data") ||
|
|
||||||
!strcmp((char*)section_header->Name, ".idata") ||
|
|
||||||
!strcmp((char*)section_header->Name, ".rdata") ||
|
|
||||||
!strcmp((char*)section_header->Name, ".bss"))
|
|
||||||
{
|
|
||||||
section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
|
|
||||||
section_header->Characteristics &= htodl(~IMAGE_SCN_MEM_DISCARDABLE);
|
|
||||||
}
|
|
||||||
else if (!strcmp((char*)section_header->Name, "INIT"))
|
|
||||||
{
|
|
||||||
section_header->Characteristics |= htodl(IMAGE_SCN_MEM_DISCARDABLE);
|
|
||||||
}
|
|
||||||
else if (!strcmp((char*)section_header->Name, "PAGE"))
|
|
||||||
{
|
|
||||||
section_header->Characteristics |= htodl(IMAGE_SCN_MEM_NOT_PAGED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recalculate checksum */
|
|
||||||
nt_header->OptionalHeader.CheckSum = 0;
|
|
||||||
checksum = 0;
|
|
||||||
for (i = 0; i < len; i += 2)
|
|
||||||
{
|
|
||||||
checksum += *(unsigned short *)(buffer + i);
|
|
||||||
checksum = (checksum + (checksum >> 16)) & 0xffff;
|
|
||||||
}
|
|
||||||
checksum += len;
|
|
||||||
nt_header->OptionalHeader.CheckSum = htods(checksum);
|
|
||||||
|
|
||||||
/* Write the output file */
|
|
||||||
fd_out = open(argv[1], O_WRONLY | O_BINARY);
|
|
||||||
write(fd_out, buffer, len);
|
|
||||||
close(fd_out);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue