Signed-off-by: Jeff Smith whydoubt@gmail.com --- As mentioned in dlls/mspatcha/tests/apply_patch.c, it is difficult to create good test cases for PA19 deltas suitable for the test suite. So no test cases for this yet. I am working on additional mspatcha changes, and I hope to get something in there that covers the changes in this patch.
dlls/mspatcha/pa19.c | 45 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-)
diff --git a/dlls/mspatcha/pa19.c b/dlls/mspatcha/pa19.c index 0ed60f4981..20729e94f0 100644 --- a/dlls/mspatcha/pa19.c +++ b/dlls/mspatcha/pa19.c @@ -43,6 +43,7 @@ #include "patchapi.h"
#include "pa19.h" +#include "signature.h" #include "lzxd_dec.h"
WINE_DEFAULT_DEBUG_CHANNEL(mspatcha); @@ -69,7 +70,9 @@ static UINT32 compute_zero_crc32(UINT32 crc, INT_PTR len) * UINT32 options; * UINT32 options_2; (present if PATCH_OPTION_EXTRA_FLAGS set) * UINT32 timestamp; (if PATCH_OPTION_NO_TIMESTAMP is SET in options) - * UVLI rebase; (present if PATCH_OPTION_NO_REBASE is not set; used on 32-bit executables) + * rebase fields: (present if PATCH_OPTION_NO_REBASE is not set; used on 32-bit executables) + * UINT16 image_base; (PE ImageBase of new file >> 16) + * SVLI time_delta; (timestamp - time_delta: PE TimeDateStamp of new file) * UVLI unpatched_size; * UINT32 crc32_patched; * BYTE input_file_count; @@ -118,6 +121,8 @@ struct input_file_info { struct patch_file_header { DWORD flags; DWORD timestamp; + DWORD image_base; + DWORD pe_timestamp; size_t patched_size; DWORD patched_crc32; unsigned input_file_count; @@ -163,6 +168,19 @@ static inline UINT32 read_raw_uint32(struct patch_file_header *ph) | (src[3] << 24); }
+static inline UINT16 read_raw_uint16(struct patch_file_header *ph) +{ + const BYTE *src = ph->src; + + ph->src += 2; + if (ph->src > ph->end) + { + ph->err = ERROR_PATCH_CORRUPT; + return 0; + } + return src[0] | (src[1] << 8); +} + /* Read a variable-length integer from a sequence of bytes terminated by * a value with bit 7 set. Set error if invalid or eof */ static UINT64 read_uvli(struct patch_file_header *ph) @@ -294,12 +312,15 @@ static int read_header(struct patch_file_header *ph, const BYTE *buf, size_t siz if(ph->flags & PATCH_OPTION_NO_TIMESTAMP) ph->timestamp = read_raw_uint32(ph);
- /* not sure what this value is for, but its absence seems to mean only that timestamps - * in the decompressed 32-bit exe are not modified */ if (!(ph->flags & PATCH_OPTION_NO_REBASE)) { - TRACE("skipping rebase field\n"); - (void)read_uvli(ph); + ph->image_base = (ULONG)read_raw_uint16(ph) << 16; + ph->pe_timestamp = ph->timestamp - (LONG)read_svli(ph); + } + else + { + ph->image_base = 0; + ph->pe_timestamp = 0; }
ph->patched_size = (size_t)read_uvli(ph); @@ -635,6 +656,8 @@ DWORD apply_patch_to_file_by_buffers(const BYTE *patch_file_view, const ULONG pa size_t buf_size; BYTE *new_file_buf = NULL; BYTE *decode_buf = NULL; + BYTE *norm_file_view = NULL; + DWORD pe_offset;
if (pnew_file_buf == NULL) { @@ -664,6 +687,16 @@ DWORD apply_patch_to_file_by_buffers(const BYTE *patch_file_view, const ULONG pa goto free_patch_header; }
+ pe_offset = get_pe_offset(old_file_view, old_file_size); + if (pe_offset) + { + norm_file_view = heap_alloc(old_file_size); + memcpy(norm_file_view, old_file_view, old_file_size); + normalize_pe(norm_file_view, old_file_size, pe_offset, + ph.flags, ph.image_base, ph.pe_timestamp); + old_file_view = norm_file_view; + } + file_info = find_matching_old_file(&ph, old_file_view, old_file_size); if (file_info == NULL) { @@ -788,6 +821,8 @@ free_decode_buf:
free_patch_header: free_header(&ph); + if (norm_file_view) + heap_free(norm_file_view);
return err; }