[PATCH 3/3] mspatcha: Rebase using image base and timestamp from delta.

Jeff Smith whydoubt at gmail.com
Fri May 22 11:21:36 CDT 2020


Signed-off-by: Jeff Smith <whydoubt at 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;
 }
-- 
2.23.0




More information about the wine-devel mailing list