public inbox for cygwin-apps-cvs@sourceware.org
help / color / mirror / Atom feed
* [rebase - The rebase tool, core of the automatic rebase facility during postinstall] branch master, updated. c1f1fcc5a89c49dff85f84ba8b69c9b62aab65eb
@ 2023-08-15 10:01 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2023-08-15 10:01 UTC (permalink / raw)
  To: cygwin-apps-cvs




https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/rebase.git;h=c1f1fcc5a89c49dff85f84ba8b69c9b62aab65eb

commit c1f1fcc5a89c49dff85f84ba8b69c9b62aab65eb
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Tue Aug 15 11:58:14 2023 +0200

    Bump to version 4.6.6

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/rebase.git;h=2067d23151b3bd96fbc75a63f861b981e3098158

commit 2067d23151b3bd96fbc75a63f861b981e3098158
Author: Christian Franke <christian.franke@t-online.de>
Date:   Sat Aug 12 14:17:04 2023 +0200

    rebase: Don't update the PE header timestamp unless -t is used
    
    This enables reproducible rebase.
    
    Signed-off-by: Christian Franke <christian.franke@t-online.de>

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/rebase.git;h=0180f517df81e50c8e95aff9713b1c27d0547212

commit 0180f517df81e50c8e95aff9713b1c27d0547212
Author: Christian Franke <christian.franke@t-online.de>
Date:   Sat Aug 12 14:13:43 2023 +0200

    Always update the file checksum in the PE header
    
    Both peflags and rebase now update the checksum without reading
    the whole file under the assumption that the original checksum
    was correct.  Calculation is done by new module
    'imagehelper/pechecksum_update.c'.
    Slightly change the peflags -k, --checksum option accordingly.
    
    Signed-off-by: Christian Franke <christian.franke@t-online.de>


Diff:
---
 Makefile.in                     |   6 +--
 configure.ac                    |   2 +-
 imagehelper/Makefile.in         |   7 +--
 imagehelper/imagehelper.h       |   4 ++
 imagehelper/objectfile.cc       |  62 ++++++++++++++++++++---
 imagehelper/objectfile.h        |   7 +++
 imagehelper/pechecksum_update.c |  56 +++++++++++++++++++++
 imagehelper/pechecksum_update.h |  52 +++++++++++++++++++
 imagehelper/rebaseimage.cc      |  10 +++-
 imagehelper/sections.cc         |  20 ++++++--
 imagehelper/sections.h          |   8 ++-
 peflags.c                       | 107 ++++++++++++++++++++++++++--------------
 rebase.c                        |  42 ++++++++++------
 13 files changed, 312 insertions(+), 71 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index e7b7f6acfa76..edc9eda695e0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -81,7 +81,7 @@ REBASE_DUMP_OBJS = rebase-dump.$(O) rebase-db.$(O) $(LIBOBJS)
 REBASE_DUMP_LIBS =
 
 PEFLAGS_OBJS = peflags.$(O) pechecksum.$(O) $(LIBOBJS)
-PEFLAGS_LIBS =
+PEFLAGS_LIBS = $(LIBIMAGEHELPER)
 
 SRC_DISTFILES = configure.ac configure Makefile.in \
 	peflagsall.in rebaseall.in \
@@ -109,8 +109,8 @@ rebase-dump$(EXEEXT): $(REBASE_DUMP_OBJS)
 
 rebase-dump.$(O):: rebase-dump.c rebase-db.h Makefile
 
-peflags$(EXEEXT): $(PEFLAGS_OBJS)
-	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(PEFLAGS_OBJS)
+peflags$(EXEEXT): $(PEFLAGS_OBJS) $(PEFLAGS_LIBS)
+	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(CXX_LDFLAGS) -o $@ $(PEFLAGS_OBJS) $(PEFLAGS_LIBS)
 
 peflags.$(O):: peflags.c pechecksum.h Makefile
 
diff --git a/configure.ac b/configure.ac
index 071606864743..6a3d64dd5770 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # configure.ac for rebase
 
 AC_PREREQ([2.71])
-AC_INIT([rebase], [4.6.5], [cygwin@cygwin.com])
+AC_INIT([rebase], [4.6.6], [cygwin@cygwin.com])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_SRCDIR([peflags.c])
 AC_PREFIX_DEFAULT([/usr])
diff --git a/imagehelper/Makefile.in b/imagehelper/Makefile.in
index 0ed8e6c3727c..a40cd8c84770 100755
--- a/imagehelper/Makefile.in
+++ b/imagehelper/Makefile.in
@@ -75,11 +75,12 @@ LIB_TARGET=imagehelper
 LIB_TARGET_FILE=libimagehelper.a
 LIB_OBJS = objectfile.$(O) objectfilelist.$(O) sections.$(O) debug.$(O) \
 	rebaseimage.$(O) checkimage.$(O) fiximage.$(O) getimageinfos.$(O) \
-	bindimage.$(O)
+	bindimage.$(O) pechecksum_update.$(O)
 LIB_SRCS = objectfile.cc objectfilelist.cc sections.cc debug.cc \
 	rebaseimage.cc checkimage.cc fiximage.cc getimageinfos.cc \
-	bindimage.cc
-LIB_HDRS = objectfilelist.h imagehelper.h sections.h objectfile.h
+	bindimage.cc pechecksum_update.c
+LIB_HDRS = objectfilelist.h imagehelper.h sections.h objectfile.h \
+	pechecksum_update.h
 
 #
 # (obsolete) applications
diff --git a/imagehelper/imagehelper.h b/imagehelper/imagehelper.h
index bafc106347ef..8535311598bc 100755
--- a/imagehelper/imagehelper.h
+++ b/imagehelper/imagehelper.h
@@ -33,6 +33,10 @@ extern BOOL ReBaseChangeFileTime;
 /* Set to TRUE, if rebasing should also drop the /DYNAMICBASE flag
    from the PE flags. */
 extern BOOL ReBaseDropDynamicbaseFlag;
+/* Set to TRUE if ReBaseImage{64} should update the PE checksum.
+   Cleared if the update failed due to inconsistent original
+   checksum. */
+extern BOOL ReBaseUpdateCheckSum;
 
 BOOL ReBaseImage64(
   LPCSTR CurrentImageName,
diff --git a/imagehelper/objectfile.cc b/imagehelper/objectfile.cc
index 4dafa6a3f3ea..651fcce49d68 100755
--- a/imagehelper/objectfile.cc
+++ b/imagehelper/objectfile.cc
@@ -24,6 +24,7 @@
 #include <time.h>
 
 #include "objectfile.h"
+#include "pechecksum_update.h"
 
 // read a dll into the cache
 
@@ -109,6 +110,15 @@ ObjectFile::ObjectFile(const char *aFileName, bool writeable)
       FileName = strdup(name);
     }
 
+  LARGE_INTEGER fs;
+  if (!GetFileSizeEx(hfile, &fs))
+    {
+      CloseHandle(hfile);
+      Error = 2;
+      return;
+    }
+  FileSize = fs.QuadPart;
+
   hfilemapping = CreateFileMapping(hfile, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY , 0, 0,  NULL);
   if (hfilemapping == 0)
     {
@@ -139,8 +149,7 @@ ObjectFile::ObjectFile(const char *aFileName, bool writeable)
       return;
     }
   // filesize big enough to allow at least reading the NT header?
-  if (GetFileSize (hfile, NULL)
-      < (char *) ntheader - (char *) dosheader + sizeof *ntheader)
+  if (FileSize < (char *) ntheader - (char *) dosheader + sizeof *ntheader)
     {
       Error = 4;
       return;
@@ -178,9 +187,6 @@ ObjectFile::~ObjectFile()
     CloseHandle(hfile);
 }
 
-
-
-
 int LinkedObjectFile::level = 0;
 
 LinkedObjectFile::LinkedObjectFile(const char *aFileName, bool writable) : ObjectFile(aFileName,writable)
@@ -204,6 +210,12 @@ LinkedObjectFile::LinkedObjectFile(const char *aFileName, bool writable) : Objec
   PIMAGE_NT_HEADERS32 ntheader32 = getNTHeader32 ();
   PIMAGE_NT_HEADERS64 ntheader64 = getNTHeader64 ();
 
+  // Save original header for checksum update
+  if (is64bit ())
+    old_ntheader64 = *ntheader64;
+  else
+    old_ntheader32 = *ntheader32;
+
   Section *edata = sections->find(".edata");
   if (edata)
     exports = new Exports(*edata);
@@ -231,9 +243,13 @@ LinkedObjectFile::LinkedObjectFile(const char *aFileName, bool writable) : Objec
       imports = new Imports(*sections, dir);
     }
 
+  uint32_t checksum;
+  if (is64bit ())
+    checksum = getNTHeader64 ()->OptionalHeader.CheckSum;
+  else
+    checksum = getNTHeader32 ()->OptionalHeader.CheckSum;
 
-
-  relocs = new Relocations(*sections,".reloc");
+  relocs = new Relocations(*sections, ".reloc", pe32_checksum_update_begin(checksum, FileSize));
 
 }
 
@@ -474,6 +490,38 @@ bool LinkedObjectFile::unbind(void)
   return true;
 }
 
+BOOL LinkedObjectFile::updateCheckSum()
+{
+  ULONG *p_checksum;
+  if (is64bit ())
+    p_checksum = &getNTHeader64 ()->OptionalHeader.CheckSum;
+  else
+    p_checksum = &getNTHeader32 ()->OptionalHeader.CheckSum;
+
+  // Add changes from NT header to checksum updated by relocs
+  uint16_t checksum16;
+  if (relocs)
+    checksum16 = relocs->getCheckSum16();
+  else
+    checksum16 = pe32_checksum_update_begin(*p_checksum, FileSize);
+
+  if (is64bit ())
+    checksum16 = pe32_checksum_update_add(checksum16, &old_ntheader64,
+					  getNTHeader64 (),
+					  sizeof(old_ntheader64));
+  else
+    checksum16 = pe32_checksum_update_add(checksum16, &old_ntheader32,
+					 getNTHeader32 (),
+					 sizeof(old_ntheader32));
+
+  uint32_t checksum = pe32_checksum_update_end(checksum16, FileSize);
+  if (!checksum)
+    return FALSE;
+
+  // Update the PE header
+  *p_checksum = checksum;
+  return TRUE;
+}
 
 LinkedObjectFile::~LinkedObjectFile()
 {
diff --git a/imagehelper/objectfile.h b/imagehelper/objectfile.h
index cd9509c8d2c2..9deda1f45541 100755
--- a/imagehelper/objectfile.h
+++ b/imagehelper/objectfile.h
@@ -92,6 +92,7 @@ class ObjectFile : public Base
 
   protected:
     char *FileName;
+    ULONG64 FileSize;
     HANDLE hfile;
     HANDLE hfilemapping;
     LPVOID lpFileBase;
@@ -140,12 +141,18 @@ class LinkedObjectFile : public ObjectFile
       return exports;
     }
 
+    BOOL updateCheckSum();
+
   protected:
     Imports *imports;
     Exports *exports;
     Relocations *relocs;
     static int level;
     bool isPrinted;
+    union {
+      IMAGE_NT_HEADERS32 old_ntheader32;
+      IMAGE_NT_HEADERS64 old_ntheader64;
+    };
   };
 
 #include "objectfilelist.h"
diff --git a/imagehelper/pechecksum_update.c b/imagehelper/pechecksum_update.c
new file mode 100644
index 000000000000..c15579dda5d2
--- /dev/null
+++ b/imagehelper/pechecksum_update.c
@@ -0,0 +1,56 @@
+/*
+ * PE32 checksum update
+ *
+ * Copyright (C) 2023 Christian Franke
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pechecksum_update.h"
+
+uint16_t pe32_checksum_update_begin(uint32_t checksum, unsigned long long filesize)
+{
+  if (!(0 < checksum && filesize < checksum && checksum - filesize <= 0xffffULL))
+    return 0;
+  return (uint16_t)(checksum - filesize);
+}
+
+static inline uint16_t get_word(const void * p, unsigned i)
+{
+  const uint8_t * bp = p;
+  return bp[i] | (bp[i + 1] << 8);
+}
+
+uint16_t pe32_checksum_update_add(uint16_t checksum16, const void * old_block,
+                                  const void * new_block, unsigned size)
+{
+  if (!(checksum16 && !((uintptr_t)old_block & 1)
+        && !((uintptr_t)new_block & 1) && !(size & 1)))
+    return 0;
+  uint32_t sum = checksum16;
+
+  for (unsigned i = 0; i < size; i += 2) {
+    uint16_t old_word = get_word(old_block, i);
+    uint16_t new_word = get_word(new_block, i);
+    if (new_word == old_word)
+      continue;
+    // Note: This does not work for updates of the first nonzero word of the file.
+    // This does not matter because the first word "MZ" is never changed.
+    if (old_word < sum) // Never return to 0, so no '<='.
+      sum -= old_word;
+    else // Revert previous 16-bit overflow, skip 0.
+      sum += 0xffffU - old_word;
+    sum += new_word;
+    // If 16-bit overflow, skip 0.
+    sum = (sum + (sum >> 16)) & 0xffffU;
+  }
+
+  return (uint16_t)sum;
+}
+
+uint32_t pe32_checksum_update_end(uint16_t checksum16, unsigned long long filesize)
+{
+  if (!(checksum16 && checksum16 + filesize < 0xffffffffULL))
+    return 0;
+  return (uint32_t)(checksum16 + filesize);
+}
diff --git a/imagehelper/pechecksum_update.h b/imagehelper/pechecksum_update.h
new file mode 100644
index 000000000000..7a2c91138667
--- /dev/null
+++ b/imagehelper/pechecksum_update.h
@@ -0,0 +1,52 @@
+/*
+ * PE32 checksum update
+ *
+ * Copyright (C) 2023 Christian Franke
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PE_CHECKSUM_UPDATE_H
+#define PE_CHECKSUM_UPDATE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Begin checksum update sequence.
+ * checksum: Old 32-bit checksum from PE header.
+ * filesize: Size of PE file.
+ * return value: 16-bit checksum for p32_checksum_update_add()
+ * or 0 on error (the checksum itself is never 0).
+ */
+uint16_t pe32_checksum_update_begin(uint32_t checksum, unsigned long long filesize);
+
+/*
+ * Update checksum.
+ * checksum16: Current 16-bit checksum from p32_checksum_update_begin()
+ * or this function.
+ * old_block: Address of old (original) data block, must be word aligned.
+ * new_block: Address of new (changed) data block, must be word aligned.
+ * size: Number of bytes of both data blocks, must be even.
+ * The PE checksum field may be included if identical in both blocks.
+ * return value: Updated 16-bit checksum or 0 on error.
+ */
+uint16_t pe32_checksum_update_add(uint16_t checksum16, const void * old_block,
+                                  const void * new_block, unsigned size);
+
+/*
+ * End checksum update sequence.
+ * checksum16: New 16-bit checksum from pe32_checksum_update_add().
+ * filesize: Size of PE file.
+ * return value: New 32-bit checksum for PE header or 0 on error.
+ */
+uint32_t pe32_checksum_update_end(uint16_t checksum16, unsigned long long filesize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PE_CHECKSUM_UPDATE_H */
diff --git a/imagehelper/rebaseimage.cc b/imagehelper/rebaseimage.cc
index 2f1fb030d4ed..0dec93ca867c 100755
--- a/imagehelper/rebaseimage.cc
+++ b/imagehelper/rebaseimage.cc
@@ -32,6 +32,7 @@
 
 BOOL ReBaseChangeFileTime = FALSE;
 BOOL ReBaseDropDynamicbaseFlag = FALSE;
+BOOL ReBaseUpdateCheckSum = FALSE;
 
 BOOL ReBaseImage64 (
   LPCSTR CurrentImageName,
@@ -110,12 +111,14 @@ BOOL ReBaseImage64 (
   if (dll.is64bit ())
     {
       ntheader64->OptionalHeader.ImageBase = *NewImageBase;
-      ntheader64->FileHeader.TimeDateStamp = TimeStamp;
+      if (ReBaseChangeFileTime)
+	ntheader64->FileHeader.TimeDateStamp = TimeStamp;
     }
   else
     {
       ntheader32->OptionalHeader.ImageBase = *NewImageBase;
-      ntheader32->FileHeader.TimeDateStamp = TimeStamp;
+      if (ReBaseChangeFileTime)
+	ntheader32->FileHeader.TimeDateStamp = TimeStamp;
     }
 
   int64_t difference = *NewImageBase - *OldImageBase;
@@ -141,6 +144,9 @@ BOOL ReBaseImage64 (
 	  &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
     }
 
+  if (ReBaseUpdateCheckSum && !dll.updateCheckSum())
+    ReBaseUpdateCheckSum = FALSE;
+
   if (!fGoingDown)
     *NewImageBase += *NewImageSize;
 
diff --git a/imagehelper/sections.cc b/imagehelper/sections.cc
index dbf7da0c7d54..76f46ee94fe8 100755
--- a/imagehelper/sections.cc
+++ b/imagehelper/sections.cc
@@ -22,8 +22,10 @@
 
 #include <iostream>
 #include <iomanip>
+#include <string.h>
 
 #include "sections.h"
+#include "pechecksum_update.h"
 
 int Base::debug = 0;
 
@@ -270,10 +272,11 @@ void Imports::dump(const char *title)
 //----- class Imports --------------------------------------------------
 
 
-Relocations::Relocations(SectionList &sectionList, const char *sectionName)
+Relocations::Relocations(SectionList &sectionList, const char *sectionName, uint16_t checksum16_)
 {
   sections = &sectionList;
   Section *asection = sections->find(sectionName);
+  checksum16 = checksum16_;
   if (asection)
     {
       relocs = PIMAGE_BASE_RELOCATION (asection->getStartAddress());
@@ -363,8 +366,11 @@ bool Relocations::fix(void)
         std::cerr << "no errors found" << std::endl;
     }
   else
-    if (debug)
-      std::cerr << "corrupted relocation records fixed" << std::endl;
+    {
+      checksum16 = 0; // Checksum update not implemented.
+      if (debug)
+	std::cerr << "corrupted relocation records fixed" << std::endl;
+    }
   return true;
 }
 
@@ -425,7 +431,12 @@ bool Relocations::relocate(int64_t difference)
 		    << std::endl;
 		  }
 		int32_t *patch_adr = (int *)cursec->rva2real(location);
+		unsigned cs_offs = (uintptr_t)patch_adr & 1; // 32-bit relocations may be not word aligned.
+		const uint8_t *cs_adr = (const uint8_t *)patch_adr - cs_offs;
+		unsigned cs_size = sizeof(uint32_t) + cs_offs * 2;
+		uint8_t old_val[cs_size]; memcpy(old_val, cs_adr, cs_size);
 		*patch_adr += difference;
+		checksum16 = pe32_checksum_update_add(checksum16, old_val, cs_adr, cs_size);
 	      }
 	      break;
 	    case IMAGE_REL_BASED_DIR64:
@@ -440,7 +451,10 @@ bool Relocations::relocate(int64_t difference)
 		    << std::endl;
 		  }
 		int64_t *patch_adr = (int64_t *)cursec->rva2real(location);
+		int64_t old_val = *patch_adr;
 		*patch_adr += difference;
+		// Assume that 64-bit relocations are always word aligned.
+		checksum16 = pe32_checksum_update_add(checksum16, &old_val, patch_adr, sizeof(old_val));
 	      }
 	      break;
 	    default:
diff --git a/imagehelper/sections.h b/imagehelper/sections.h
index b317fa15cc1a..20dd24c8fee0 100755
--- a/imagehelper/sections.h
+++ b/imagehelper/sections.h
@@ -199,7 +199,7 @@ class Relocations : SectionBase
   {
   public:
     // create a relocation object using section named "section" from  the section list "sections"
-    Relocations(SectionList &sectionList, const char *sectionName);
+    Relocations(SectionList &sectionList, const char *sectionName, uint16_t checksum16_);
 
     // check for bad relocations
     bool check(void);
@@ -210,10 +210,16 @@ class Relocations : SectionBase
     // precondition: fixed dll
     bool relocate(int64_t difference);
 
+    uint16_t getCheckSum16() const
+      {
+	return checksum16;
+      }
+
   private:
     PIMAGE_BASE_RELOCATION relocs;
     SectionList *sections;
     int size;   // section size
+    uint16_t checksum16;
   };
 
 #endif
diff --git a/peflags.c b/peflags.c
index 1a61da714d73..917088b9fbb9 100644
--- a/peflags.c
+++ b/peflags.c
@@ -44,6 +44,7 @@
 #include <windows.h>
 
 #include "pechecksum.h"
+#include "imagehelper/pechecksum_update.h"
 
 #if defined(__MSYS__)
 /* MSYS has no strtoull */
@@ -67,12 +68,12 @@ static WORD coff_characteristics_show;
 static WORD pe_characteristics_set;
 static WORD pe_characteristics_clr;
 static WORD pe_characteristics_show;
-static short checksum_show;
-static short checksum_update; /* 1 = update after changes, 2 = fix always */
+static short checksum_option; /* 1 = show, 2 = verify, 3 = fix */
 
 typedef struct
 {
   const char *pathname;
+  unsigned long long filesize;
   PIMAGE_DOS_HEADER dosheader;
   union
     {
@@ -507,24 +508,48 @@ do_mark (const char *pathname)
 
     }
 
-  /* Any actual changes? */
-  if (pep->is_64bit)
-    {
-      changed = memcmp(&old_ntheader.ntheader64, pep->ntheader64,
-		       sizeof(old_ntheader.ntheader64));
-      hdr_checksum = pep->ntheader64->OptionalHeader.CheckSum;
-    }
-  else
-    {
-      changed = memcmp(&old_ntheader.ntheader32, pep->ntheader64,
-		       sizeof(old_ntheader.ntheader32));
-      hdr_checksum = pep->ntheader32->OptionalHeader.CheckSum;
-    }
+  /* Update the checksum. */
+  changed = FALSE;
+  {
+    const void *p_oldheader, *p_newheader;
+    unsigned headersize;
+    ULONG *p_checksum;
+    if (pep->is_64bit)
+      {
+	p_oldheader = &old_ntheader.ntheader64;
+	p_newheader = pep->ntheader64;
+	headersize = sizeof(old_ntheader.ntheader64);
+	p_checksum = &pep->ntheader64->OptionalHeader.CheckSum;
+      }
+    else
+      {
+	p_oldheader = &old_ntheader.ntheader32;
+	p_newheader = pep->ntheader32;
+	headersize = sizeof(old_ntheader.ntheader32);
+	p_checksum = &pep->ntheader32->OptionalHeader.CheckSum;
+      }
+
+    hdr_checksum = pe32_checksum_update_end(
+      pe32_checksum_update_add(
+	pe32_checksum_update_begin(*p_checksum, pep->filesize),
+	p_oldheader, p_newheader, headersize
+      ),
+      pep->filesize
+    );
+
+    if (!hdr_checksum)
+      fprintf(stderr, "%s: Checksum update failed\n", pathname);
+    else if (*p_checksum != hdr_checksum)
+      {
+	changed = TRUE;
+	*p_checksum = hdr_checksum;
+      }
+  }
 
   pe_close (pep);
 
-  /* Checksum calculation requires re-open as a regular file. */
-  if (checksum_show || checksum_update)
+  /* Checksum re-calculation requires re-open as a regular file. */
+  if (checksum_option)
     do_checksum (pathname, indent, changed, hdr_checksum);
   return 0;
 }
@@ -625,16 +650,16 @@ static void
 do_checksum (const char *pathname, int indent, int changed, ULONG hdr_checksum)
 {
   const char name[] = "PE file checksum";
-  if (checksum_show || (checksum_update && changed) || checksum_update > 1)
+  if (checksum_option > 1)
     {
       int fd;
       unsigned new_checksum, old_checksum;
-      if ((fd = open (pathname, (checksum_update ? O_RDWR : O_RDONLY) | O_BINARY)) == -1)
+      if ((fd = open (pathname, (checksum_option > 2 ? O_RDWR : O_RDONLY) | O_BINARY)) == -1)
 	{
 	  fprintf (stderr, "%s: Unable to reopen, errno=%d\n", pathname, errno);
 	  return;
 	}
-      new_checksum = pe32_checksum (fd, checksum_update, &old_checksum);
+      new_checksum = pe32_checksum (fd, checksum_option > 2, &old_checksum);
       close(fd);
       if (!new_checksum)
 	{
@@ -650,19 +675,19 @@ do_checksum (const char *pathname, int indent, int changed, ULONG hdr_checksum)
 	}
 
       if (new_checksum == old_checksum)
-	  printf ("%*s%-24s: 0x%08x (%sverified)\n", indent, "", name,
-		  old_checksum, (checksum_update ? "unchanged, " : ""));
-      else if (checksum_update)
+	  printf ("%*s%-24s: 0x%08x (%schanged, verified)\n", indent, "", name,
+	          old_checksum, (changed ? "" : "un"));
+      else if (checksum_option > 2)
 	  printf ("%*s%-24s: 0x%08x (updated from 0x%08x)\n", indent, "", name,
 		  new_checksum, old_checksum);
       else
 	  printf ("%*s%-24s: 0x%08x (*needs update to 0x%08x*)\n", indent, "", name,
 		  old_checksum, new_checksum);
     }
-  else /* (!checksum_show && checksum_update == 1 && !changed) */
+  else /* (checksum_option == 1) */
     {
-      printf ("%*s%-24s: 0x%08x (unchanged, not verified)\n", indent, "", name,
-	      hdr_checksum);
+      printf ("%*s%-24s: 0x%08x (%schanged, not verified)\n", indent, "", name,
+	      hdr_checksum, (changed ? "" : "un"));
     }
 }
 
@@ -767,11 +792,7 @@ handle_checksum_option (const char *option_name,
 {
   int bool_value;
   if (!option_arg)
-    {
-      checksum_show = 1;
-      if (handle_any_sizeof == DONT_HANDLE)
-	handle_any_sizeof = DO_READ;
-    }
+    checksum_option = 1;
   else
     {
       if (string_to_bool (option_arg, &bool_value) != 0)
@@ -781,9 +802,12 @@ handle_checksum_option (const char *option_name,
           short_usage (stderr);
           exit (1);
         }
-      checksum_update = (bool_value ? 2 : 1);
-      handle_any_sizeof = DO_WRITE;
+      checksum_option = (!bool_value ? 2 : 3);
     }
+  if (checksum_option > 2)
+    handle_any_sizeof = DO_WRITE;
+  else if (handle_any_sizeof == DONT_HANDLE)
+    handle_any_sizeof = DO_READ;
 }
 
 void
@@ -1042,6 +1066,11 @@ pe_open (const char *path, BOOL writing)
   int fd;
   void *map;
   
+  /* Get filesize for checksum update. */
+  struct stat st;
+  if (stat (path, &st))
+    return NULL;
+
   fd = open (path, O_BINARY | (writing ? O_RDWR : O_RDONLY));
   if (fd == -1)
     return NULL;
@@ -1053,6 +1082,7 @@ pe_open (const char *path, BOOL writing)
       return NULL;
     }
   pef.pathname = path;
+  pef.filesize = st.st_size;
   pef.dosheader = (PIMAGE_DOS_HEADER) map;
   pef.ntheader32 = (PIMAGE_NT_HEADERS32)
 		   ((PBYTE) pef.dosheader + pef.dosheader->e_lfanew);
@@ -1233,9 +1263,12 @@ help (FILE *f)
 "                              than 2 GB.\n"
 "  -S, --sepdbg       [BOOL]   Debugging information was removed and stored\n"
 "                              separately in another file.\n"
-"  -k, --checksum     [BOOL]   Displays (no argument), updates after changes\n"
-"                              only (false) or always fixes (true) the file\n"
-"                              checksum in the PE header.\n"
+"  -k, --checksum     [BOOL]   Displays (no argument), verifies (false) or\n"
+"                              always fixes (true) the file checksum in the PE\n"
+"                              header.  By default, the checksum is updated\n"
+"                              without reading the whole file under the\n"
+"                              assumption that the original checksum was\n"
+"                              correct.\n"
 "  -x, --stack-reserve [NUM]   Reserved stack size of the process in bytes.\n"
 "  -X, --stack-commit  [NUM]   Initial commited portion of the process stack\n"
 "                              in bytes.\n"
@@ -1272,7 +1305,7 @@ help (FILE *f)
 "For flag values, to set a value, and display the results symbolic, repeat the\n"
 "option:  --tsaware=true --tsaware -d0 -d\n"
 "The time of last modification of each file is preserved unless the checksum\n"
-"has been updated.\n"
+"has been fixed by option --checksum=true\n"
 "\n", f);
 }
 
diff --git a/rebase.c b/rebase.c
index 50cc79f8b9f7..6a531d0f306f 100644
--- a/rebase.c
+++ b/rebase.c
@@ -1190,7 +1190,7 @@ print_overlapped ()
     }
 }
 
-static BOOL
+static int
 update_checksum (const char *pathname)
 {
   int fd, err;
@@ -1200,7 +1200,7 @@ update_checksum (const char *pathname)
     {
       fprintf (stderr, "%s: failed to reopen for checksum update: %s\n",
 	       pathname, strerror (errno));
-      return FALSE;
+      return -1;
     }
   new_checksum = pe32_checksum (fd, 1, &old_checksum);
   err = errno;
@@ -1210,10 +1210,10 @@ update_checksum (const char *pathname)
       fprintf (stderr, "%s: checksum update failed: %s\n", pathname,
 	       strerror (err));
       /* Assume file is unchanged. */
-      return FALSE;
+      return -1;
     }
 
-  return (new_checksum != old_checksum);
+  return (new_checksum != old_checksum ? 1 : 0);
 }
 
 BOOL
@@ -1222,6 +1222,7 @@ rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag)
   ULONG64 old_image_base, prev_new_image_base;
   ULONG old_image_size, new_image_size;
   BOOL status;
+  const char *checksum_msg;
 
   /* Skip if not writable. */
   if (access (pathname, W_OK) == -1)
@@ -1231,6 +1232,9 @@ rebase (const char *pathname, ULONG64 *new_image_base, BOOL down_flag)
       return TRUE;
     }
 
+  /* Try to update the checksum. */
+  ReBaseUpdateCheckSum = TRUE;
+
   /* Calculate next base address, if rebasing down. */
   if (down_flag)
     *new_image_base -= offset;
@@ -1307,8 +1311,17 @@ retry:
     }
 #endif
 
-  /* Update checksum, if requested. */
-  status = (checksum_flag ? update_checksum (pathname) : FALSE);
+
+  /* Fix checksum, if requested or incremental update failed. */
+  if (checksum_flag || !ReBaseUpdateCheckSum)
+    switch (update_checksum (pathname))
+      {
+	case 0:  checksum_msg = ", checksum verified"; break;
+	case 1:  checksum_msg = ", checksum fixed"; break;
+	default: checksum_msg = ", checksum update failed"; break;
+      }
+  else
+    checksum_msg = "";
 
   /* Display rebase results, if verbose. */
   if (verbose)
@@ -1316,9 +1329,7 @@ retry:
       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),
-	      (checksum_flag ? (status ? ", checksum updated" :
-	      ", checksum unchanged") : ""));
+	      (uint32_t) (new_image_size + offset), checksum_msg);
     }
 
   /* Calculate next base address, if rebasing up. */
@@ -1662,10 +1673,12 @@ 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\
+  -c, --checksum          Fix the file's checksum in the PE header if the file\n\
+                          has been successfully rebased.  This also bumps the\n\
+                          file's modification time (like -t) if the checksum\n\
+                          has been changed.  By default, the checksum is\n\
+                          updated without reading the whole file under the\n\
+                          assumption that the original checksum was correct.\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\
@@ -1674,7 +1687,8 @@ Rebase PE files, usually DLLs, to a specified address or address range.\n\
   -o, --offset=OFFSET     Specify an additional offset between adjacent DLLs\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\
+                          time and the timestamp in the PE header are bumped if\n\
+                          the file has been successfully rebased.\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\


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-08-15 10:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-15 10:01 [rebase - The rebase tool, core of the automatic rebase facility during postinstall] branch master, updated. c1f1fcc5a89c49dff85f84ba8b69c9b62aab65eb Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).