From: ajkhoury aidankhoury@gmail.com
These changes add the implementation for the NormalizeFileForPatchSignature API, and lays the foundation for proper 32-bit image file patch support. --- dlls/mspatcha/Makefile.in | 3 +- dlls/mspatcha/mspatcha_main.c | 23 ++- dlls/mspatcha/pa19.c | 347 ++++++++++++++++++++++++++++++++++ dlls/mspatcha/pa19.h | 13 ++ dlls/mspatcha/pecoff.c | 155 +++++++++++++++ dlls/mspatcha/pecoff.h | 44 +++++ 6 files changed, 577 insertions(+), 8 deletions(-) create mode 100644 dlls/mspatcha/pecoff.c create mode 100644 dlls/mspatcha/pecoff.h
diff --git a/dlls/mspatcha/Makefile.in b/dlls/mspatcha/Makefile.in index 89d6367b39d..9358e7a9a2a 100644 --- a/dlls/mspatcha/Makefile.in +++ b/dlls/mspatcha/Makefile.in @@ -6,6 +6,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native C_SRCS = \ lzxd_dec.c \ mspatcha_main.c \ - pa19.c + pa19.c \ + pecoff.c
RC_SRCS = version.rc diff --git a/dlls/mspatcha/mspatcha_main.c b/dlls/mspatcha/mspatcha_main.c index 1f6653da161..4d24d4b573a 100644 --- a/dlls/mspatcha/mspatcha_main.c +++ b/dlls/mspatcha/mspatcha_main.c @@ -261,12 +261,21 @@ BOOL WINAPI GetFilePatchSignatureByBuffer(PBYTE file_buf, ULONG file_size, ULONG /***************************************************** * NormalizeFileForPatchSignature (MSPATCHA.@) */ -INT WINAPI NormalizeFileForPatchSignature(PVOID file_buffer, ULONG file_size, ULONG flags, PATCH_OPTION_DATA *options, - ULONG new_coff_base, ULONG new_coff_time, ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range, - ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range) +INT WINAPI NormalizeFileForPatchSignature( + PVOID file_buffer, ULONG file_size, + ULONG option_flags, PATCH_OPTION_DATA *option_data, + ULONG new_coff_base, ULONG new_coff_time, + ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range_array, + ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range_array) { - FIXME("stub - %p, %lu, %lx, %p, %lu, %lu, %lu, %p, %lu, %p\n", file_buffer, file_size, flags, options, new_coff_base, - new_coff_time, ignore_range_count, ignore_range, retain_range_count, retain_range); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + int result; + + result = normalize_old_file_image( + file_buffer, file_size, + option_flags, option_data, + new_coff_base, new_coff_time, + ignore_range_array, ignore_range_count, + retain_range_array, retain_range_count); + + return result; } diff --git a/dlls/mspatcha/pa19.c b/dlls/mspatcha/pa19.c index dc6ef79e2b2..529a4dee553 100644 --- a/dlls/mspatcha/pa19.c +++ b/dlls/mspatcha/pa19.c @@ -43,6 +43,7 @@ #include "patchapi.h"
#include "pa19.h" +#include "pecoff.h" #include "lzxd_dec.h"
WINE_DEFAULT_DEBUG_CHANNEL(mspatcha); @@ -621,6 +622,352 @@ static DWORD compute_target_crc32(struct input_file_info *fi, const BYTE *new_fi return crc32; }
+/* Fixup a given mapped image's relocation table for a new image base. */ +BOOL rebase_image( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, + PUCHAR mapped_image_base, ULONG mapped_image_size, ULONG new_image_base) +{ + BOOL result; + IMAGE_BASE_RELOCATION UNALIGNED *reloc_block; + IMAGE_BASE_RELOCATION UNALIGNED *reloc_block_base; + PUCHAR reloc_fixup; + LONG delta; + LONG reloc_dir_remaining; + ULONG reloc_dir_size; + USHORT UNALIGNED *reloc; + ULONG reloc_count; + PUCHAR mapped_image_end; + + result = FALSE; + mapped_image_end = &mapped_image_base[mapped_image_size]; + delta = (LONG)(new_image_base - nt_headers->OptionalHeader.ImageBase); + + reloc_dir_size = 0; + reloc_block = image_directory_mapped_address(nt_headers, IMAGE_DIRECTORY_ENTRY_BASERELOC, + &reloc_dir_size, mapped_image_base, mapped_image_size); + if (!reloc_block + || !reloc_dir_size + || ((PUCHAR)reloc_block > (mapped_image_end - sizeof(IMAGE_BASE_RELOCATION)))) { + return result; + } + + nt_headers->OptionalHeader.ImageBase = (DWORD)new_image_base; + result = TRUE; + + reloc_dir_remaining = (LONG)reloc_dir_size; + while (reloc_dir_remaining > 0) { + + if (reloc_block->SizeOfBlock <= (ULONG)reloc_dir_remaining + && reloc_block->SizeOfBlock > sizeof(IMAGE_BASE_RELOCATION)) + { + reloc_block_base = (IMAGE_BASE_RELOCATION UNALIGNED *)(mapped_image_base + + image_rva_to_file_offset(nt_headers, reloc_block->VirtualAddress, mapped_image_base, mapped_image_size)); + if (reloc_block_base) + { + reloc = (USHORT UNALIGNED *)((PUCHAR)reloc_block + sizeof(IMAGE_BASE_RELOCATION)); + reloc_count = (reloc_block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); + while (reloc_count--) { + if ((PUCHAR)reloc > mapped_image_end) { + break; + } + + reloc_fixup = (PUCHAR)reloc_block_base + (*reloc & 0x0FFF); + if (reloc_fixup < mapped_image_end) + { + switch (*reloc >> 12) + { + case IMAGE_REL_BASED_HIGH: + *(USHORT UNALIGNED *)reloc_fixup = (USHORT)(((*(USHORT UNALIGNED *)reloc_fixup << 16) + delta) >> 16); + break; + case IMAGE_REL_BASED_LOW: + *(USHORT UNALIGNED *)reloc_fixup = (USHORT)(*(SHORT UNALIGNED *)reloc_fixup + delta); + break; + case IMAGE_REL_BASED_HIGHLOW: + if (reloc_fixup + sizeof(USHORT) <= mapped_image_end) { + *(LONG UNALIGNED *)reloc_fixup += delta; + } + break; + case IMAGE_REL_BASED_HIGHADJ: + ++reloc; + --reloc_count; + if ((PUCHAR)reloc <= (mapped_image_end - sizeof(USHORT))) + *(USHORT UNALIGNED *)reloc_fixup = (USHORT)(((*(USHORT UNALIGNED *)reloc_fixup << 16) + (SHORT)*reloc + delta + 0x8000) >> 16); + break; + default: + + } + } + + ++reloc; + } + } + } + + reloc_dir_remaining -= reloc_block->SizeOfBlock; + reloc_block = (IMAGE_BASE_RELOCATION UNALIGNED *)((PUCHAR)reloc_block + reloc_block->SizeOfBlock); + + if ((PUCHAR)reloc_block > (mapped_image_end - sizeof(IMAGE_BASE_RELOCATION))) { + throw_pe_fmt_exception(); + } + } + + return result; +} + +/* Remove all bound imports for a given mapped image. */ +BOOL unbind_image( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, PUCHAR mapped_image, ULONG image_size) +{ + BOOL result; + PUCHAR mapped_image_end; + IMAGE_IMPORT_DESCRIPTOR UNALIGNED *import_desc; + IMAGE_BOUND_IMPORT_DESCRIPTOR UNALIGNED *bound_imports; + ULONG bound_imports_size; + IMAGE_DATA_DIRECTORY UNALIGNED *bound_import_data_dir; + IMAGE_THUNK_DATA32 UNALIGNED *original_thunk; + IMAGE_THUNK_DATA32 UNALIGNED *bound_thunk; + IMAGE_SECTION_HEADER UNALIGNED *section_table; + ULONG section_count; + + result = FALSE; + mapped_image_end = mapped_image + image_size; + + /* Erase bound import data directory. */ + bound_imports = image_directory_mapped_address(nt_headers, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, + &bound_imports_size, mapped_image, image_size); + if (bound_imports) + { + memset(bound_imports, 0, bound_imports_size); + + bound_import_data_dir = &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]; + if ((PUCHAR)bound_import_data_dir < mapped_image + || (PUCHAR)bound_import_data_dir > (mapped_image_end - sizeof(IMAGE_DATA_DIRECTORY))) { + throw_pe_fmt_exception(); + } + + bound_import_data_dir->VirtualAddress = 0; + bound_import_data_dir->Size = 0; + result = TRUE; + } + + /* Zero out needed import descriptor fields */ + import_desc = image_directory_mapped_address(nt_headers, IMAGE_DIRECTORY_ENTRY_IMPORT, NULL, mapped_image, image_size); + if (import_desc) + { + while ((PUCHAR)import_desc < (mapped_image_end - sizeof(IMAGE_IMPORT_DESCRIPTOR)) + && import_desc->Characteristics) + { + /* TimeDateStamp field is -1 if bound */ + if (import_desc->TimeDateStamp) { + import_desc->TimeDateStamp = 0; + result = TRUE; + + original_thunk = image_rva_to_mapped_address(nt_headers, import_desc->OriginalFirstThunk, mapped_image, image_size); + bound_thunk = image_rva_to_mapped_address(nt_headers, import_desc->FirstThunk, mapped_image, image_size); + if (original_thunk && bound_thunk) + { + for (; original_thunk->u1.AddressOfData; original_thunk++, bound_thunk++) + { + if ((PUCHAR)original_thunk >= mapped_image_end + || (PUCHAR)bound_thunk >= mapped_image_end) + break; + *bound_thunk = *original_thunk; + } + } + } + + if (import_desc->ForwarderChain) { + import_desc->ForwarderChain = 0; + result = TRUE; + } + + ++import_desc; + } + } + + /* Mark the .idata section as writable */ + section_table = IMAGE_FIRST_SECTION(nt_headers); + section_count = nt_headers->FileHeader.NumberOfSections; + for (ULONG i = 0; i < section_count; i++) + { + if ((PUCHAR)§ion_table[i] < mapped_image + || (PUCHAR)§ion_table[i] > (mapped_image_end - sizeof(IMAGE_SECTION_HEADER))) { + throw_pe_fmt_exception(); + } + + /* tolower hack check for ".idata " */ + if ((*((ULONGLONG UNALIGNED *)§ion_table[i].Name) | 0x2020202020202020) == 0x202061746164692E) { + if ((section_table[i].Characteristics & IMAGE_SCN_MEM_WRITE) == 0) { + result = TRUE; + section_table[i].Characteristics |= (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE); + } + + break; + } + } + + return result; +} + +/* Force all lock prefixes to the x86 LOCK (F0h) opcode in a given mapped image. */ +BOOL normalize_lock_prefixes_in_image( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, PUCHAR mapped_image, ULONG image_size) +{ + BOOL result = FALSE; + PUCHAR mapped_image_end; + IMAGE_LOAD_CONFIG_DIRECTORY32 UNALIGNED *loadcfg; + ULONG UNALIGNED *lock_prefix_table; + + mapped_image_end = &mapped_image[image_size]; + + loadcfg = image_directory_mapped_address(nt_headers, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, + NULL, mapped_image, image_size); + if (loadcfg && loadcfg->LockPrefixTable) + { + if (loadcfg->LockPrefixTable < nt_headers->OptionalHeader.ImageBase) { + throw_pe_fmt_exception(); + } + + lock_prefix_table = image_rva_to_mapped_address(nt_headers, + loadcfg->LockPrefixTable - nt_headers->OptionalHeader.ImageBase, mapped_image, image_size); + + if (lock_prefix_table) + { + while ((PUCHAR)lock_prefix_table <= (mapped_image_end - sizeof(ULONG)) + && *lock_prefix_table) + { + PUCHAR const p = image_rva_to_mapped_address(nt_headers, + *lock_prefix_table - nt_headers->OptionalHeader.ImageBase, mapped_image, image_size); + + if (p && *p != 0xF0) { + *p = 0xF0; + result = TRUE; + } + + ++lock_prefix_table; + } + } + } + + return result; +} + +/* derived from imagehlp for calculating a new coff image checksum. */ +static WORD calc_chksum( + DWORD initial_value, PUCHAR buffer, DWORD size_in_bytes) +{ + DWORD sum; + DWORD words_remaining; + DWORD partial_words; + DWORD partial_sum; + + sum = initial_value; + words_remaining = size_in_bytes / sizeof(WORD); + + for (; words_remaining; sum += HIWORD(partial_sum) + LOWORD(partial_sum)) + { + partial_words = words_remaining; + if (words_remaining > 0x10000) { + partial_words = 0x10000; + } + + words_remaining -= partial_words; + partial_sum = 0; + do { + partial_sum += *(WORD UNALIGNED *)buffer; + buffer += sizeof(WORD); + --partial_words; + } while (partial_words); + } + + if (size_in_bytes & 1) { + sum += *buffer; + } + + return (WORD)(HIWORD(sum) + LOWORD(sum)); +} + +/* Normalizes a given 32-bit PE image to render a stream that is common. */ +int normalize_old_file_image( + BYTE *old_file_buffer, ULONG old_file_size, + ULONG option_flags, PATCH_OPTION_DATA *option_data, + ULONG new_image_base, ULONG new_image_time, + const PATCH_IGNORE_RANGE *ignore_range_array, ULONG ignore_range_count, + const PATCH_RETAIN_RANGE *retain_range_array, ULONG retain_range_count) +{ + int result = 0; + ULONG i; + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers; + + UNREFERENCED_PARAMETER(option_data); + + TRACE("normalizing image at 0x%p with options 0x%lX, new base 0x%lX, new time %lu", + old_file_buffer, option_flags, new_image_base, new_image_time); + + if (old_file_buffer && old_file_size) + { + nt_headers = image_get_nt_headers(old_file_buffer, old_file_size); + if (nt_headers) + { + if ((option_flags & PATCH_OPTION_NO_REBASE) == 0) { + if (new_image_time != 0 && nt_headers->FileHeader.TimeDateStamp != new_image_time) { + nt_headers->FileHeader.TimeDateStamp = new_image_time; + result = NORMALIZE_RESULT_SUCCESS; + } + + if (new_image_base != 0 && nt_headers->OptionalHeader.ImageBase != new_image_base) { + result |= rebase_image(nt_headers, old_file_buffer, old_file_size, new_image_base); + } + } + + if ((option_flags & PATCH_OPTION_NO_BINDFIX) == 0) { + result |= unbind_image(nt_headers, old_file_buffer, old_file_size); + } + + if ((option_flags & PATCH_OPTION_NO_LOCKFIX) == 0) { + result |= normalize_lock_prefixes_in_image(nt_headers, old_file_buffer, old_file_size); + } + + if ((option_flags & PATCH_OPTION_NO_CHECKSUM) != 0) { + if (nt_headers->OptionalHeader.CheckSum) { + nt_headers->OptionalHeader.CheckSum = 0; + result = NORMALIZE_RESULT_SUCCESS; + } + + } else { + if (result) { + nt_headers->OptionalHeader.CheckSum = 0; + nt_headers->OptionalHeader.CheckSum = calc_chksum(0, old_file_buffer, old_file_size) + old_file_size; + } + } + } + + for (i = 0; i < ignore_range_count; ++i) { + if (ignore_range_array[i].OffsetInOldFile <= old_file_size + && (ignore_range_array[i].OffsetInOldFile + ignore_range_array[i].LengthInBytes) <= old_file_size) + { + memset(&old_file_buffer[ignore_range_array[i].OffsetInOldFile], + 0, + ignore_range_array[i].LengthInBytes); + result = NORMALIZE_RESULT_SUCCESS; + } + } + + for (i = 0; i < retain_range_count; ++i) { + if (retain_range_array[i].OffsetInOldFile <= old_file_size + && (retain_range_array[i].OffsetInOldFile + retain_range_array[i].LengthInBytes) <= old_file_size) + { + memset(&old_file_buffer[retain_range_array[i].OffsetInOldFile], + 0, + retain_range_array[i].LengthInBytes); + result = NORMALIZE_RESULT_SUCCESS; + } + } + } + + return result + 1; +} + DWORD apply_patch_to_file_by_buffers(const BYTE *patch_file_view, const ULONG patch_file_size, const BYTE *old_file_view, ULONG old_file_size, BYTE **pnew_file_buf, const ULONG new_file_buf_size, ULONG *new_file_size, diff --git a/dlls/mspatcha/pa19.h b/dlls/mspatcha/pa19.h index 0b368849267..e8a1fd3a51d 100644 --- a/dlls/mspatcha/pa19.h +++ b/dlls/mspatcha/pa19.h @@ -18,6 +18,19 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+enum NORMALIZE_RESULT { + NORMALIZE_RESULT_FAILURE = 0, + NORMALIZE_RESULT_SUCCESS = 1, + NORMALIZE_RESULT_SUCCESS_MODIFIED = 2 +}; + +int normalize_old_file_image( + BYTE *old_file_mapped, ULONG old_file_size, + ULONG option_flags, PATCH_OPTION_DATA *option_data, + ULONG new_image_base, ULONG new_image_time, + const PATCH_IGNORE_RANGE *ignore_range_array, ULONG ignore_range_count, + const PATCH_RETAIN_RANGE *retain_range_array, ULONG retain_range_count); + DWORD apply_patch_to_file_by_buffers(const BYTE *patch_file_view, const ULONG patch_file_size, const BYTE *old_file_view, ULONG old_file_size, BYTE **new_file_buf, const ULONG new_file_buf_size, ULONG *new_file_size, diff --git a/dlls/mspatcha/pecoff.c b/dlls/mspatcha/pecoff.c new file mode 100644 index 00000000000..0bb240250a7 --- /dev/null +++ b/dlls/mspatcha/pecoff.c @@ -0,0 +1,155 @@ +/* + * PatchAPI PE/COFF image helpers. + * + * Copyright 2023 Aidan Khoury + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "pecoff.h" +#include "winbase.h" + +void DECLSPEC_NORETURN throw_pe_fmt_exception(void) +{ + RaiseException(0xE0000001, 0, 0, NULL); + for (;;) { /* silence compiler warning */ } +} + +IMAGE_NT_HEADERS32 UNALIGNED *image_get_nt_headers(const void *image_base, size_t image_size) +{ + IMAGE_DOS_HEADER UNALIGNED *dos_hdr; + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers; + const UCHAR *const image_end = (PUCHAR)image_base + image_size; + + if (image_size >= 0x200) { + dos_hdr = (IMAGE_DOS_HEADER *)image_base; + if (dos_hdr->e_magic == IMAGE_DOS_SIGNATURE && dos_hdr->e_lfanew < image_size) { + nt_headers = (IMAGE_NT_HEADERS32 *)((ULONG_PTR)dos_hdr + dos_hdr->e_lfanew); + if (((PUCHAR)nt_headers + sizeof(IMAGE_NT_HEADERS32)) <= image_end) { + if (nt_headers->Signature == IMAGE_NT_SIGNATURE + && nt_headers->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + return nt_headers; + } + } + } + } + + return NULL; +} + +ULONG image_rva_to_file_offset( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, ULONG rva, PUCHAR image_base, ULONG image_size) +{ + IMAGE_SECTION_HEADER UNALIGNED *section_table; + ULONG section_count; + ULONG i; + + if ( rva < nt_headers->OptionalHeader.SizeOfHeaders ) { + return rva; + } + + section_table = IMAGE_FIRST_SECTION(nt_headers); + section_count = nt_headers->FileHeader.NumberOfSections; + for (i = 0; i < section_count; i++) { + if ((PUCHAR)§ion_table[i] < image_base + || ((PUCHAR)§ion_table[i] + sizeof(IMAGE_SECTION_HEADER)) > &image_base[image_size]) { + throw_pe_fmt_exception(); + } + + if (rva >= section_table[i].VirtualAddress + && rva < (section_table[i].VirtualAddress + section_table[i].SizeOfRawData)) { + return (section_table[i].PointerToRawData + (rva - section_table[i].VirtualAddress)); + } + } + + return 0; +} + +ULONG image_directory_rva_and_size( + IMAGE_NT_HEADERS32 UNALIGNED *nt_header, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size) +{ + IMAGE_DATA_DIRECTORY UNALIGNED *data_directory; + + if (directory_entry >= nt_header->OptionalHeader.NumberOfRvaAndSizes) { + return 0; + } + + data_directory = &nt_header->OptionalHeader.DataDirectory[directory_entry]; + if ((PUCHAR)data_directory < image_base + || ((PUCHAR)data_directory + sizeof(IMAGE_DATA_DIRECTORY)) > &image_base[image_size]) { + throw_pe_fmt_exception(); + } + + if (directory_size != NULL) { + *directory_size = data_directory->Size; + } + return data_directory->VirtualAddress; +} + +ULONG image_directory_offset_and_size( + IMAGE_NT_HEADERS32 UNALIGNED *nt_header, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size) +{ + ULONG rva, offset = 0; + rva = image_directory_rva_and_size(nt_header, directory_entry, directory_size, image_base, image_size); + if (rva) { + offset = image_rva_to_file_offset(nt_header, rva, image_base, image_size); + } + return offset; +} + +PVOID image_rva_to_mapped_address( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, ULONG rva, PVOID image_base, ULONG image_size) +{ + const ULONG offset = image_rva_to_file_offset(nt_headers, rva, image_base, image_size); + if (offset && offset < image_size) { + return (PVOID)((PUCHAR)image_base + offset); + } + return NULL; +} + +PVOID image_directory_mapped_address( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size) +{ + ULONG dir_rva; + ULONG dir_size; + PVOID mapped_address; + + dir_rva = image_directory_rva_and_size(nt_headers, directory_entry, &dir_size, image_base, image_size); + if (!dir_rva) { + return NULL; + } + + mapped_address = image_rva_to_mapped_address(nt_headers, dir_rva, image_base, image_size); + if (!mapped_address) { + return NULL; + } + + if (((PUCHAR)mapped_address + dir_size) < (PUCHAR)mapped_address) { + throw_pe_fmt_exception(); + } + + if (((PUCHAR)mapped_address + dir_size) > &image_base[image_size]) { + return NULL; + } + + if (directory_size != NULL) { + *directory_size = dir_size; + } + + return mapped_address; +} diff --git a/dlls/mspatcha/pecoff.h b/dlls/mspatcha/pecoff.h new file mode 100644 index 00000000000..1664a2fe777 --- /dev/null +++ b/dlls/mspatcha/pecoff.h @@ -0,0 +1,44 @@ +/* + * PatchAPI PE/COFF image helpers. + * + * Copyright 2023 Aidan Khoury + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include "windef.h" + +void DECLSPEC_NORETURN throw_pe_fmt_exception(void); + +IMAGE_NT_HEADERS32 UNALIGNED *image_get_nt_headers(const void *image_base, size_t image_size); + +ULONG image_rva_to_file_offset( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, ULONG rva, PUCHAR image_base, ULONG image_size); + +ULONG image_directory_rva_and_size( + IMAGE_NT_HEADERS32 UNALIGNED *nt_header, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size); + +ULONG image_directory_offset_and_size( + IMAGE_NT_HEADERS32 UNALIGNED *nt_header, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size); + +PVOID image_rva_to_mapped_address( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, ULONG rva, PVOID image_base, ULONG image_size); + +PVOID image_directory_mapped_address( + IMAGE_NT_HEADERS32 UNALIGNED *nt_headers, USHORT directory_entry, ULONG *directory_size, + PUCHAR image_base, ULONG image_size);