Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
From 67d95c40e742ca68340d44e34b1a56e8e8795828 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Tue, 5 May 2026 01:13:19 +0200
Subject: [PATCH 01/11] loader: support setup loader offset table revision 2

Inno Setup 6.5.0 bumped SetupLdrOffsetTableVersion from 1 to 2 and
widened the on-disk TSetupLdrOffsetTable struct: TotalSize, OffsetEXE,
Offset0 and Offset1 each grew from 32-bit LongWord to Int64, and a
new ReservedPadding UInt32 was inserted before TableCRC. The record
also lost its `packed` qualifier, but with 32-bit Delphi default
alignment (Int64 is 4-byte aligned in 32-bit Delphi) the on-disk
layout remains contiguous, growing from 48 to 64 bytes total. See
Projects/Src/Shared.Struct.pas at tag is-6_5_0 in
https://github.com/jrsoftware/issrc.

Without this, every installer produced by Inno Setup 6.5.0 or newer
fails to load with:

Warning: Unexpected setup loader revision: 2
Warning: Setup loader checksum mismatch!
Could not determine setup data version!

Detect revision 2 specifically and parse the new layout. The fields
that innoextract actually consumes (exe_offset, header_offset,
data_offset) are still stored as 32-bit in the offsets struct, so
truncate the read 64-bit values to 32-bit and emit a warning if any
of them exceed 4 GiB. Real installers that large are rare in the
wild but possible, and widening the struct is left for a follow-up.

Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
src/loader/offsets.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/src/loader/offsets.cpp b/src/loader/offsets.cpp
index 0c0d6a4..80bcdc4 100644
--- a/src/loader/offsets.cpp
+++ b/src/loader/offsets.cpp
@@ -148,6 +148,54 @@ bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) {
is.clear();
debug("could not read loader header revision");
return false;
+ } else if(revision == 2) {
+ /*
+ * Inno Setup 6.5.0 introduced a wider TSetupLdrOffsetTable layout
+ * (revision 2). The fields previously stored as 32-bit LongWord
+ * are now Int64, allowing setup binaries larger than 4 GiB. A new
+ * ReservedPadding UInt32 sits between Offset1 and TableCRC. The
+ * record itself is no longer Delphi-`packed`, but with 32-bit
+ * Delphi default alignment the on-disk layout remains contiguous
+ * (Int64 has 4-byte alignment in 32-bit mode), so the total size
+ * goes from 48 to 64 bytes. See Projects/Src/Shared.Struct.pas in
+ * issrc.
+ */
+ (void)checksum.load<boost::int64_t>(is); // TotalSize
+ boost::int64_t offset_exe = checksum.load<boost::int64_t>(is);
+ boost::uint32_t uncompressed_exe = checksum.load<boost::uint32_t>(is);
+ boost::uint32_t crc_exe = checksum.load<boost::uint32_t>(is);
+ boost::int64_t offset0 = checksum.load<boost::int64_t>(is);
+ boost::int64_t offset1 = checksum.load<boost::int64_t>(is);
+ (void)checksum.load<boost::uint32_t>(is); // ReservedPadding
+ if(is.fail()) {
+ is.clear();
+ debug("could not read loader header (revision 2)");
+ return false;
+ }
+ boost::int64_t max_uint32 = boost::int64_t(std::numeric_limits<boost::uint32_t>::max());
+ if(offset_exe < 0 || offset_exe > max_uint32 ||
+ offset0 < 0 || offset0 > max_uint32 ||
+ offset1 < 0 || offset1 > max_uint32) {
+ log_warning << "Loader header offsets exceed 4 GiB; truncating to 32-bit";
+ }
+ exe_offset = boost::uint32_t(offset_exe);
+ exe_compressed_size = 0;
+ exe_uncompressed_size = uncompressed_exe;
+ exe_checksum.type = crypto::CRC32;
+ exe_checksum.crc32 = crc_exe;
+ message_offset = 0;
+ header_offset = boost::uint32_t(offset0);
+ data_offset = boost::uint32_t(offset1);
+ boost::uint32_t expected = util::load<boost::uint32_t>(is);
+ if(is.fail()) {
+ is.clear();
+ debug("could not read loader header checksum (revision 2)");
+ return false;
+ }
+ if(checksum.finalize() != expected) {
+ log_warning << "Setup loader checksum mismatch!";
+ }
+ return true;
} else if(revision != 1) {
log_warning << "Unexpected setup loader revision: " << revision;
}
--
2.54.0.windows.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
From 9f3cee2dd8e1c105d0bd280a3bac331ea3a0417d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Tue, 5 May 2026 01:24:06 +0200
Subject: [PATCH 02/11] Add support for Inno Setup 6.4.2 and 6.4.3

Inno Setup 6.4.2 added the new [Setup] section directive
CloseApplicationsFilterExcludes (see
https://jrsoftware.org/files/is6.4-whatsnew.htm). It is serialised as a
binary string immediately after architectures_installed_in_64bit_mode_expr
in TSetupHeader (Projects/Src/Shared.Struct.pas in
https://github.com/jrsoftware/issrc at tag is-6_4_2). Read it as a new
header field for installers from 6.4.2 onward; clear it for older
installers.

6.4.2 also bumped the SetupID magic to 'Inno Setup Setup Data (6.4.2)';
6.4.3 to 'Inno Setup Setup Data (6.4.3)'. Both versions are otherwise
on-disk-compatible with the post-6.4.2 layout, so add them to the known
versions table without further parsing changes.

This change is sourced from the prior-art PR #202 by itai-delphos
(https://github.com/dscharrer/innoextract/pull/202), which I am picking
up and extending to cover Inno Setup 6.5.x, 6.6.x and 6.7.x in the
follow-up commits in this series.

Helped-by: itai-delphos@github
Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
src/setup/header.cpp | 6 ++++++
src/setup/header.hpp | 1 +
src/setup/version.cpp | 2 ++
3 files changed, 9 insertions(+)

diff --git a/src/setup/header.cpp b/src/setup/header.cpp
index bbe9df9..6ed61cc 100644
--- a/src/setup/header.cpp
+++ b/src/setup/header.cpp
@@ -266,6 +266,11 @@ void header::load(std::istream & is, const version & version) {
is >> util::binary_string(architectures_allowed_expr);
is >> util::binary_string(architectures_installed_in_64bit_mode_expr);
}
+ if(version >= INNO_VERSION(6, 4, 2)) {
+ is >> util::binary_string(close_applications_filter_excludes);
+ } else {
+ close_applications_filter_excludes.clear();
+ }
if(version >= INNO_VERSION(5, 2, 5)) {
is >> util::ansi_string(license_text);
is >> util::ansi_string(info_before);
@@ -762,6 +767,7 @@ void header::decode(util::codepage_id codepage) {
util::to_utf8(create_uninstall_registry_key, codepage, &lead_bytes);
util::to_utf8(uninstallable, codepage);
util::to_utf8(close_applications_filter, codepage);
+ util::to_utf8(close_applications_filter_excludes, codepage);
util::to_utf8(setup_mutex, codepage, &lead_bytes);
util::to_utf8(changes_environment, codepage);
util::to_utf8(changes_associations, codepage);
diff --git a/src/setup/header.hpp b/src/setup/header.hpp
index 78e5b64..08d492c 100644
--- a/src/setup/header.hpp
+++ b/src/setup/header.hpp
@@ -167,6 +167,7 @@ struct header {
std::string changes_associations;
std::string architectures_allowed_expr;
std::string architectures_installed_in_64bit_mode_expr;
+ std::string close_applications_filter_excludes;
std::string license_text;
std::string info_before;
std::string info_after;
diff --git a/src/setup/version.cpp b/src/setup/version.cpp
index 7f68af2..be6682b 100644
--- a/src/setup/version.cpp
+++ b/src/setup/version.cpp
@@ -186,6 +186,8 @@ const known_version versions[] = {
{ "Inno Setup Setup Data (6.3.0)", INNO_VERSION_EXT(6, 3, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.0)", /* prerelease */ INNO_VERSION_EXT(6, 4, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.0.1)", /* 6.4.0 */ INNO_VERSION_EXT(6, 4, 0, 1), version::Unicode },
+ { "Inno Setup Setup Data (6.4.2)", INNO_VERSION_EXT(6, 4, 2, 0), version::Unicode },
+ { "Inno Setup Setup Data (6.4.3)", INNO_VERSION_EXT(6, 4, 3, 0), version::Unicode },
};

} // anonymous namespace
--
2.54.0.windows.1

Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
From 6c584226b9adc9decd64f621d36d267b7bc5026d Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Tue, 5 May 2026 01:44:12 +0200
Subject: [PATCH 03/11] Add support for Inno Setup 6.5.0, 6.5.1, 6.5.2, 6.5.3
and 6.5.4

Inno Setup 6.5.0 made two on-disk changes to TSetupHeader:

- A new SevenZipLibraryName: String, serialised right after
CloseApplicationsFilterExcludes (Projects/Src/Shared.Struct.pas
at tag is-6_5_0 in https://github.com/jrsoftware/issrc).
- A new NumISSigKeyEntries: Integer entry-count field, slotted
between NumDirEntries and NumFileEntries. ISSig (Inno Setup
Signature) key entries are part of the new ECDSA P-256 ISSigTool
technology preview added in 6.4.3 and turned into a serialised
table in 6.5.0. innoextract does not yet process the entries
themselves; for now consume the count so that NumFileEntries and
every entry count after it remains aligned.

6.5.0 also bumped the SetupLdrOffsetTableVersion from 1 to 2 and
widened the offset table; that part is handled in the previous
"loader: support setup loader offset table revision 2" commit.

Add SetupID magic strings:
- 6.5.0 covers 6.5.0 and 6.5.1, which share `Inno Setup Setup Data
(6.5.0)`.
- 6.5.2 covers 6.5.2, 6.5.3 and 6.5.4, which share
`Inno Setup Setup Data (6.5.2)`. The header changes (new wizard
image background colours and dynamic-dark-mode variants) are added
in a separate follow-up commit since they are not in the same
on-disk position as the older WizardImageBackColor field, so they
require a different branch in `header::load`.

This change continues the prior-art line started by PR #202
(https://github.com/dscharrer/innoextract/pull/202) by itai-delphos.

Helped-by: itai-delphos@github
Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
src/setup/header.cpp | 14 ++++++++++++++
src/setup/header.hpp | 1 +
src/setup/version.cpp | 2 ++
3 files changed, 17 insertions(+)

diff --git a/src/setup/header.cpp b/src/setup/header.cpp
index 6ed61cc..65c6603 100644
--- a/src/setup/header.cpp
+++ b/src/setup/header.cpp
@@ -271,6 +271,11 @@ void header::load(std::istream & is, const version & version) {
} else {
close_applications_filter_excludes.clear();
}
+ if(version >= INNO_VERSION(6, 5, 0)) {
+ is >> util::binary_string(seven_zip_library_name);
+ } else {
+ seven_zip_library_name.clear();
+ }
if(version >= INNO_VERSION(5, 2, 5)) {
is >> util::ansi_string(license_text);
is >> util::ansi_string(info_before);
@@ -324,6 +329,14 @@ void header::load(std::istream & is, const version & version) {
}

directory_count = util::load<boost::uint32_t>(is, version.bits());
+ if(version >= INNO_VERSION(6, 5, 0)) {
+ // Inno Setup 6.5.0 inserted a NumISSigKeyEntries: Integer field
+ // between NumDirEntries and NumFileEntries
+ // (Projects/Src/Shared.Struct.pas at tag is-6_5_0). innoextract
+ // does not yet use the count, but the bytes must be consumed to
+ // keep the stream position correct.
+ (void)util::load<boost::uint32_t>(is, version.bits());
+ }
file_count = util::load<boost::uint32_t>(is, version.bits());
data_entry_count = util::load<boost::uint32_t>(is, version.bits());
icon_count = util::load<boost::uint32_t>(is, version.bits());
@@ -768,6 +781,7 @@ void header::decode(util::codepage_id codepage) {
util::to_utf8(uninstallable, codepage);
util::to_utf8(close_applications_filter, codepage);
util::to_utf8(close_applications_filter_excludes, codepage);
+ util::to_utf8(seven_zip_library_name, codepage);
util::to_utf8(setup_mutex, codepage, &lead_bytes);
util::to_utf8(changes_environment, codepage);
util::to_utf8(changes_associations, codepage);
diff --git a/src/setup/header.hpp b/src/setup/header.hpp
index 08d492c..fa47892 100644
--- a/src/setup/header.hpp
+++ b/src/setup/header.hpp
@@ -168,6 +168,7 @@ struct header {
std::string architectures_allowed_expr;
std::string architectures_installed_in_64bit_mode_expr;
std::string close_applications_filter_excludes;
+ std::string seven_zip_library_name;
std::string license_text;
std::string info_before;
std::string info_after;
diff --git a/src/setup/version.cpp b/src/setup/version.cpp
index be6682b..2911396 100644
--- a/src/setup/version.cpp
+++ b/src/setup/version.cpp
@@ -188,6 +188,8 @@ const known_version versions[] = {
{ "Inno Setup Setup Data (6.4.0.1)", /* 6.4.0 */ INNO_VERSION_EXT(6, 4, 0, 1), version::Unicode },
{ "Inno Setup Setup Data (6.4.2)", INNO_VERSION_EXT(6, 4, 2, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.3)", INNO_VERSION_EXT(6, 4, 3, 0), version::Unicode },
+ { "Inno Setup Setup Data (6.5.0)", INNO_VERSION_EXT(6, 5, 0, 0), version::Unicode },
+ { "Inno Setup Setup Data (6.5.2)", INNO_VERSION_EXT(6, 5, 2, 0), version::Unicode },
};

} // anonymous namespace
--
2.54.0.windows.1

Loading