[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