Last patch for now.

Left for later: ReBaseImage64() unconditionally updates the timestamp in the file header.

--
Regards,
Christian

From 3973a92cf11056521552d9d3f87efe8e721e8c31 Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.fra...@t-online.de>
Date: Tue, 8 Aug 2023 12:04:25 +0200
Subject: [PATCH] rebase: Add -c, --checksum option

If specified, the file checksum in the PE header is updated after
rebasing.

Signed-off-by: Christian Franke <christian.fra...@t-online.de>
---
 Makefile.in |  4 ++--
 rebase.c    | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index adb7972..2f061ca 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -74,7 +74,7 @@ override CXX_LDFLAGS+=@EXTRA_CXX_LDFLAG_OVERRIDES@
 
 LIBIMAGEHELPER = imagehelper/libimagehelper.a
 
-REBASE_OBJS = rebase.$(O) rebase-db.$(O) $(LIBOBJS)
+REBASE_OBJS = rebase.$(O) rebase-db.$(O) pechecksum.$(O) $(LIBOBJS)
 REBASE_LIBS = $(LIBIMAGEHELPER)
 
 REBASE_DUMP_OBJS = rebase-dump.$(O) rebase-db.$(O) $(LIBOBJS)
@@ -100,7 +100,7 @@ $(LIBIMAGEHELPER):
 rebase$(EXEEXT): $(REBASE_LIBS) $(REBASE_OBJS)
        $(CXX) $(CXXFLAGS) $(LDFLAGS) $(CXX_LDFLAGS) -o $@ $(REBASE_OBJS) 
$(REBASE_LIBS)
 
-rebase.$(O):: rebase.c rebase-db.h Makefile
+rebase.$(O):: rebase.c pechecksum.h rebase-db.h Makefile
 
 rebase-db.$(O):: rebase-db.c rebase-db.h Makefile
 
diff --git a/rebase.c b/rebase.c
index 7417d4d..50cc79f 100644
--- a/rebase.c
+++ b/rebase.c
@@ -39,6 +39,7 @@
 #include <errno.h>
 #include <io.h>
 #include "imagehelper.h"
+#include "pechecksum.h"
 #include "rebase-db.h"
 #include <versionhelpers.h> /* requires <windows.h> */
 
@@ -74,6 +75,7 @@ WORD machine = IMAGE_FILE_MACHINE_I386;
 ULONG64 image_base = 0;
 ULONG64 low_addr;
 BOOL down_flag = FALSE;
+BOOL checksum_flag = FALSE;
 BOOL image_info_flag = FALSE;
 BOOL image_storage_flag = FALSE;
 BOOL image_oblivious_flag = FALSE;
@@ -1188,6 +1190,32 @@ print_overlapped ()
     }
 }
 
+static BOOL
+update_checksum (const char *pathname)
+{
+  int fd, err;
+  unsigned old_checksum, new_checksum;
+
+  if ((fd = open (pathname, O_RDWR | O_BINARY)) == -1)
+    {
+      fprintf (stderr, "%s: failed to reopen for checksum update: %s\n",
+              pathname, strerror (errno));
+      return FALSE;
+    }
+  new_checksum = pe32_checksum (fd, 1, &old_checksum);
+  err = errno;
+  close(fd);
+  if (!new_checksum)
+    {
+      fprintf (stderr, "%s: checksum update failed: %s\n", pathname,
+              strerror (err));
+      /* Assume file is unchanged. */
+      return FALSE;
+    }
+
+  return (new_checksum != old_checksum);
+}
+
 BOOL
 rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag)
 {
@@ -1279,13 +1307,18 @@ retry:
     }
 #endif
 
+  /* Update checksum, if requested. */
+  status = (checksum_flag ? update_checksum (pathname) : FALSE);
+
   /* Display rebase results, if verbose. */
   if (verbose)
     {
-      printf ("%s: new base = %" PRIx64 ", new size = %x\n",
+      printf ("%s: new base = %" PRIx64 ", new size = %x%s\n",
              pathname,
              (uint64_t) ((down_flag) ? *new_image_base : prev_new_image_base),
-             (uint32_t) (new_image_size + offset));
+             (uint32_t) (new_image_size + offset),
+             (checksum_flag ? (status ? ", checksum updated" :
+             ", checksum unchanged") : ""));
     }
 
   /* Calculate next base address, if rebasing up. */
@@ -1299,6 +1332,7 @@ static struct option long_options[] = {
   {"32",       no_argument,       NULL, '4'},
   {"64",       no_argument,       NULL, '8'},
   {"base",     required_argument, NULL, 'b'},
+  {"checksum", no_argument,       NULL, 'c'},
   {"down",     no_argument,       NULL, 'd'},
   {"help",     no_argument,       NULL, 'h'},
   {"usage",    no_argument,       NULL, 'h'},
@@ -1316,7 +1350,7 @@ static struct option long_options[] = {
   {NULL,       no_argument,       NULL,  0 }
 };
 
-static const char *short_options = "48b:dhiMno:OqstT:vV";
+static const char *short_options = "48b:cdhiMno:OqstT:vV";
 
 void
 parse_args (int argc, char *argv[])
@@ -1341,6 +1375,9 @@ parse_args (int argc, char *argv[])
          image_base = string_to_ulonglong (optarg);
          force_rebase_flag = TRUE;
          break;
+       case 'c':
+         checksum_flag = TRUE;
+         break;
        case 'd':
          down_flag = TRUE;
          break;
@@ -1625,6 +1662,10 @@ Rebase PE files, usually DLLs, to a specified address or 
address range.\n\
   One of the options -b, -s or -i is mandatory.  If no rebase database 
exists\n\
   yet, -b is required together with -s.\n\
 \n\
+  -c, --checksum          Update the file's checksum in the PE header if the\n\
+                          file has been successfully rebased.  This also 
bumps\n\
+                          the file's modification time (like -t) if the\n\
+                          checksum has been changed.\n\
   -d, --down              Treat the BaseAddress as upper ceiling and rebase\n\
                           files top-down from there.  Without this option 
the\n\
                           files are rebased from BaseAddress bottom-up.\n\
@@ -1634,7 +1675,8 @@ Rebase PE files, usually DLLs, to a specified address or 
address range.\n\
                           when rebasing.  Default is no offset.\n\
   -t, --touch             Use this option to make sure the file's 
modification\n\
                           time is bumped if it has been successfully 
rebased.\n\
-                          Usually rebase does not change the file's time.\n\
+                          Usually rebase does not change the file's time 
unless\n\
+                          the -c flag is also specified.\n\
   -T, --filelist=FILE     Also rebase the files specified in FILE.  The 
format\n\
                           of FILE is one DLL per line.\n\
   -q, --quiet             Be quiet about non-critical issues.\n\
-- 
2.39.0

Reply via email to