From c16c4e4b522006d499b2a4d359578c741d9f2d3f Mon Sep 17 00:00:00 2001 From: rhcp011235 Date: Sat, 18 Apr 2026 17:48:48 -0400 Subject: [PATCH 1/2] Add initial Inno Setup 6.5.0 support --- README.md | 2 +- VERSION | 2 +- src/cli/extract.cpp | 2 +- src/loader/offsets.cpp | 63 ++++++++++++++++++++++------ src/setup/data.cpp | 93 +++++++++++++++++++++++------------------- src/setup/file.cpp | 36 +++++++++++++++- src/setup/file.hpp | 7 ++++ src/setup/header.cpp | 55 ++++++++++++++++++++++--- src/setup/header.hpp | 3 ++ src/setup/info.cpp | 80 +++++++++++++++++++++++++++++++++++- src/setup/registry.cpp | 3 +- src/setup/run.cpp | 4 +- src/setup/task.cpp | 1 - src/setup/version.cpp | 1 + 14 files changed, 284 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 3a5e8262..71f98ac4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # innoextract - A tool to unpack installers created by Inno Setup -[Inno Setup](https://jrsoftware.org/isinfo.php) is a tool to create installers for Microsoft Windows applications. innoextract allows to extract such installers under non-Windows systems without running the actual installer using wine. innoextract currently supports installers created by Inno Setup 1.2.10 to 6.3.3. +[Inno Setup](https://jrsoftware.org/isinfo.php) is a tool to create installers for Microsoft Windows applications. innoextract allows to extract such installers under non-Windows systems without running the actual installer using wine. innoextract currently supports installers created by Inno Setup 1.2.10 to 6.5.0. In addition to standard Inno Setup installers, innoextract also supports some modified Inno Setup variants including Martijn Laan's My Inno Setup Extensions 1.3.10 to 3.0.6.1 as well as GOG.com's Inno Setup-based game installers. innoextract is able to unpack Wadjet Eye Games installers (to play with AGS), Arx Fatalis patches (for use with Arx Libertatis) as well as various other Inno Setup executables. diff --git a/VERSION b/VERSION index e2b4fe9a..c866f958 100644 --- a/VERSION +++ b/VERSION @@ -1,7 +1,7 @@ innoextract 1.10-dev Known working Inno Setup versions: -Inno Setup 1.2.10 to 6.3.3 +Inno Setup 1.2.10 to 6.5.0 Bug tracker: https://innoextract.constexpr.org/issues diff --git a/src/cli/extract.cpp b/src/cli/extract.cpp index 49893117..bfdb8ba1 100644 --- a/src/cli/extract.cpp +++ b/src/cli/extract.cpp @@ -981,7 +981,7 @@ void process_file(const fs::path & installer, const extract_options & o) { } #ifdef DEBUG if(logger::debug) { - entries = setup::info::entry_types::all(); + entries = setup::info::entry_types::all() & ~setup::info::NoUnknownVersion; } #endif diff --git a/src/loader/offsets.cpp b/src/loader/offsets.cpp index 0c0d6a44..7c917959 100644 --- a/src/loader/offsets.cpp +++ b/src/loader/offsets.cpp @@ -142,19 +142,58 @@ bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) { checksum.init(); checksum.update(magic, sizeof(magic)); - if(version >= INNO_VERSION(5, 1, 5)) { - boost::uint32_t revision = checksum.load(is); - if(is.fail()) { - is.clear(); - debug("could not read loader header revision"); - return false; - } else if(revision != 1) { - log_warning << "Unexpected setup loader revision: " << revision; + boost::uint32_t revision = 0; + if(version >= INNO_VERSION(5, 1, 5)) { + revision = checksum.load(is); + if(is.fail()) { + is.clear(); + debug("could not read loader header revision"); + return false; + } else if(revision != 1 && revision != 2) { + log_warning << "Unexpected setup loader revision: " << revision; + } } - } - - (void)checksum.load(is); - exe_offset = checksum.load(is); + + if(revision == 2) { + boost::uint64_t total_size = checksum.load(is); + boost::uint64_t offset_exe = checksum.load(is); + exe_uncompressed_size = checksum.load(is); + exe_checksum.type = crypto::CRC32; + exe_checksum.crc32 = checksum.load(is); + boost::uint64_t offset0 = checksum.load(is); + boost::uint64_t offset1 = checksum.load(is); + (void)checksum.load(is); // ReservedPadding + if(is.fail()) { + is.clear(); + debug("could not read revision 2 loader header"); + return false; + } + if(total_size > std::numeric_limits::max() + || offset_exe > std::numeric_limits::max() + || offset0 > std::numeric_limits::max() + || offset1 > std::numeric_limits::max()) { + log_warning << "Unsupported large revision 2 setup loader offsets!"; + return false; + } + exe_offset = static_cast(offset_exe); + exe_compressed_size = 0; + message_offset = 0; + header_offset = static_cast(offset0); + data_offset = static_cast(offset1); + boost::uint32_t expected = util::load(is); + if(is.fail()) { + is.clear(); + debug("could not read revision 2 loader header checksum"); + return false; + } + if(checksum.finalize() != expected) { + log_warning << "Setup loader checksum mismatch!"; + } + return true; + } + + (void)checksum.load(is); + exe_offset = checksum.load(is); if(version >= INNO_VERSION(4, 1, 6)) { exe_compressed_size = 0; diff --git a/src/setup/data.cpp b/src/setup/data.cpp index 4444ce29..6326e80e 100644 --- a/src/setup/data.cpp +++ b/src/setup/data.cpp @@ -133,52 +133,63 @@ void data_entry::load(std::istream & is, const info & i) { options = 0; - stored_flag_reader flagreader(is, i.version.bits()); - - flagreader.add(VersionInfoValid); - flagreader.add(VersionInfoNotValid); - if(i.version >= INNO_VERSION(2, 0, 17) && i.version < INNO_VERSION(4, 0, 1)) { - flagreader.add(BZipped); - } - if(i.version >= INNO_VERSION(4, 0, 10)) { + if(i.version >= INNO_VERSION(6, 5, 0)) { + stored_flag_reader flagreader(is, i.version.bits()); + flagreader.add(VersionInfoValid); flagreader.add(TimeStampInUTC); - } - if(i.version >= INNO_VERSION(4, 1, 0)) { - flagreader.add(IsUninstallerExe); - } - if(i.version >= INNO_VERSION(4, 1, 8)) { flagreader.add(CallInstructionOptimized); - } - if(i.version >= INNO_VERSION(4, 2, 0)) { - flagreader.add(Touch); - } - if(i.version >= INNO_VERSION(4, 2, 2)) { flagreader.add(ChunkEncrypted); - } - if(i.version >= INNO_VERSION(4, 2, 5)) { flagreader.add(ChunkCompressed); - } else { - options |= ChunkCompressed; - } - if(i.version >= INNO_VERSION(5, 1, 13)) { - flagreader.add(SolidBreak); - } - if(i.version >= INNO_VERSION(5, 5, 7) && i.version < INNO_VERSION(6, 3, 0)) { - // Actually added in Inno Setup 5.5.9 but the data version was not bumped - flagreader.add(Sign); - flagreader.add(SignOnce); - } - - options |= flagreader.finalize(); - - if(i.version >= INNO_VERSION(6, 3, 0)) { - sign = stored_enum(is).get(); - } else if(options & SignOnce) { - sign = Once; - } else if(options & Sign) { - sign = Yes; - } else { + options |= flagreader.finalize(); sign = NoSetting; + } else { + stored_flag_reader flagreader(is, i.version.bits()); + + flagreader.add(VersionInfoValid); + flagreader.add(VersionInfoNotValid); + if(i.version >= INNO_VERSION(2, 0, 17) && i.version < INNO_VERSION(4, 0, 1)) { + flagreader.add(BZipped); + } + if(i.version >= INNO_VERSION(4, 0, 10)) { + flagreader.add(TimeStampInUTC); + } + if(i.version >= INNO_VERSION(4, 1, 0)) { + flagreader.add(IsUninstallerExe); + } + if(i.version >= INNO_VERSION(4, 1, 8)) { + flagreader.add(CallInstructionOptimized); + } + if(i.version >= INNO_VERSION(4, 2, 0)) { + flagreader.add(Touch); + } + if(i.version >= INNO_VERSION(4, 2, 2)) { + flagreader.add(ChunkEncrypted); + } + if(i.version >= INNO_VERSION(4, 2, 5)) { + flagreader.add(ChunkCompressed); + } else { + options |= ChunkCompressed; + } + if(i.version >= INNO_VERSION(5, 1, 13)) { + flagreader.add(SolidBreak); + } + if(i.version >= INNO_VERSION(5, 5, 7) && i.version < INNO_VERSION(6, 3, 0)) { + // Actually added in Inno Setup 5.5.9 but the data version was not bumped + flagreader.add(Sign); + flagreader.add(SignOnce); + } + + options |= flagreader.finalize(); + + if(i.version >= INNO_VERSION(6, 3, 0)) { + sign = stored_enum(is).get(); + } else if(options & SignOnce) { + sign = Once; + } else if(options & Sign) { + sign = Yes; + } else { + sign = NoSetting; + } } if(options & ChunkCompressed) { diff --git a/src/setup/file.cpp b/src/setup/file.cpp index a2e917e3..61f2d364 100644 --- a/src/setup/file.cpp +++ b/src/setup/file.cpp @@ -23,7 +23,6 @@ #include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" -#include "util/log.hpp" #include "util/storedenum.hpp" namespace setup { @@ -91,6 +90,34 @@ void file_entry::load(std::istream & is, const info & i) { } load_condition_data(is, i); + + excludes.clear(); + download_issig_source.clear(); + download_user_name.clear(); + download_password.clear(); + extract_archive_password.clear(); + checksum.type = crypto::None; + if(i.version >= INNO_VERSION(6, 5, 0)) { + is >> util::encoded_string(excludes, i.codepage); + is >> util::encoded_string(download_issig_source, i.codepage); + is >> util::encoded_string(download_user_name, i.codepage); + is >> util::encoded_string(download_password, i.codepage); + is >> util::encoded_string(extract_archive_password, i.codepage); + std::string issig_allowed_keys; + is >> util::binary_string(issig_allowed_keys); + (void)issig_allowed_keys; + is.read(checksum.sha256, std::streamsize(sizeof(checksum.sha256))); + switch(util::load(is)) { + case 1: + checksum.type = crypto::SHA256; + break; + case 0: + case 2: + default: + checksum.type = crypto::None; + break; + } + } load_version_data(is, i.version); @@ -189,6 +216,10 @@ void file_entry::load(std::istream & is, const info & i) { if(i.version >= INNO_VERSION(5, 2, 5)) { flagreader.add(GacInstall); } + if(i.version >= INNO_VERSION(6, 5, 0)) { + flagreader.add(Download); + flagreader.add(ExtractArchive); + } options |= flagreader.finalize(); @@ -199,7 +230,6 @@ void file_entry::load(std::istream & is, const info & i) { } additional_locations.clear(); - checksum.type = crypto::None; size = 0; } @@ -239,6 +269,8 @@ NAMES(setup::file_entry::flags, "File Option", "set ntfs compression", "unset ntfs compression", "gac install", + "download", + "extract archive", "readme", ) diff --git a/src/setup/file.hpp b/src/setup/file.hpp index 604b2ae8..c9be1fbf 100644 --- a/src/setup/file.hpp +++ b/src/setup/file.hpp @@ -77,6 +77,8 @@ struct file_entry : public item { SetNtfsCompression, UnsetNtfsCompression, GacInstall, + Download, + ExtractArchive, // obsolete options: IsReadmeFile @@ -96,6 +98,11 @@ struct file_entry : public item { std::string destination; std::string install_font_name; std::string strong_assembly_name; + std::string excludes; + std::string download_issig_source; + std::string download_user_name; + std::string download_password; + std::string extract_archive_password; boost::uint32_t location; //!< index into the data entry list boost::uint32_t attributes; diff --git a/src/setup/header.cpp b/src/setup/header.cpp index bbe9df9c..11975fb4 100644 --- a/src/setup/header.cpp +++ b/src/setup/header.cpp @@ -265,20 +265,28 @@ void header::load(std::istream & is, const version & version) { // Valid architectures: 'Unknown', 'x86', 'x64', 'Arm32', 'Arm64' is >> util::binary_string(architectures_allowed_expr); is >> util::binary_string(architectures_installed_in_64bit_mode_expr); + } else { + architectures_allowed_expr.clear(); + architectures_installed_in_64bit_mode_expr.clear(); + } + if(version >= INNO_VERSION(6, 5, 0)) { + is >> util::binary_string(close_applications_filter_excludes); + is >> util::binary_string(sevenzip_library_name); + } else { + close_applications_filter_excludes.clear(); + sevenzip_library_name.clear(); } if(version >= INNO_VERSION(5, 2, 5)) { is >> util::ansi_string(license_text); is >> util::ansi_string(info_before); is >> util::ansi_string(info_after); + is >> util::ansi_string(compiled_code); } if(version >= INNO_VERSION(5, 2, 1) && version < INNO_VERSION(5, 3, 10)) { is >> util::binary_string(uninstaller_signature); } else { uninstaller_signature.clear(); } - if(version >= INNO_VERSION(5, 2, 5)) { - is >> util::binary_string(compiled_code); - } if(version >= INNO_VERSION(2, 0, 6) && !version.is_unicode()) { lead_bytes = stored_char_set(is); @@ -319,8 +327,13 @@ void header::load(std::istream & is, const version & version) { } directory_count = util::load(is, version.bits()); + if(version >= INNO_VERSION(6, 5, 0)) { + issig_key_count = util::load(is, version.bits()); + } else { + issig_key_count = 0; + } file_count = util::load(is, version.bits()); - data_entry_count = util::load(is, version.bits()); + data_entry_count = util::load(is, version.bits()); // NumFileLocationEntries icon_count = util::load(is, version.bits()); ini_entry_count = util::load(is, version.bits()); registry_entry_count = util::load(is, version.bits()); @@ -328,7 +341,7 @@ void header::load(std::istream & is, const version & version) { uninstall_delete_entry_count = util::load(is, version.bits()); run_entry_count = util::load(is, version.bits()); uninstall_run_entry_count = util::load(is, version.bits()); - + boost::int32_t license_size = 0; boost::int32_t info_before_size = 0; boost::int32_t info_after_size = 0; @@ -338,6 +351,36 @@ void header::load(std::istream & is, const version & version) { info_after_size = util::load(is, version.bits()); } + if(version >= INNO_VERSION(6, 5, 0)) { + winver.load(is, version); + wizard_style = stored_enum(is).get(); + wizard_resize_percent_x = util::load(is); + wizard_resize_percent_y = util::load(is); + image_alpha_format = stored_enum(is).get(); + back_color = 0; + back_color2 = 0; + image_back_color = 0; + small_image_back_color = 0; + password.type = crypto::None; + password_salt.clear(); + extra_disk_space_required = util::load(is); + slices_per_disk = util::load(is); + install_mode = NormalInstallMode; + uninstall_log_mode = stored_enum(is).get(); + uninstall_style = wizard_style; + dir_exists_warning = stored_enum(is).get(); + privileges_required = stored_enum(is).get(); + privileges_required_override_allowed = stored_flags(is).get(); + show_language_dialog = stored_enum(is).get(); + language_detection = stored_enum(is).get(); + compression = stored_enum(is).get(); + disable_dir_page = stored_enum(is).get(); + disable_program_group_page = stored_enum(is).get(); + uninstall_display_size = util::load(is); + options |= load_flags(is, version); + return; + } + winver.load(is, version); if(version < INNO_VERSION_EXT(6, 4, 0, 1)) { @@ -765,6 +808,8 @@ void header::decode(util::codepage_id codepage) { util::to_utf8(setup_mutex, codepage, &lead_bytes); util::to_utf8(changes_environment, codepage); util::to_utf8(changes_associations, codepage); + util::to_utf8(close_applications_filter_excludes, codepage); + util::to_utf8(sevenzip_library_name, codepage, &lead_bytes); } diff --git a/src/setup/header.hpp b/src/setup/header.hpp index 78e5b64a..dac950b6 100644 --- a/src/setup/header.hpp +++ b/src/setup/header.hpp @@ -167,6 +167,8 @@ 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 sevenzip_library_name; std::string license_text; std::string info_before; std::string info_after; @@ -182,6 +184,7 @@ struct header { size_t component_count; size_t task_count; size_t directory_count; + size_t issig_key_count; size_t file_count; size_t data_entry_count; size_t icon_count; diff --git a/src/setup/info.cpp b/src/setup/info.cpp index d6969240..c2a59056 100644 --- a/src/setup/info.cpp +++ b/src/setup/info.cpp @@ -26,6 +26,7 @@ #include +#include "crypto/crc32.hpp" #include "crypto/hasher.hpp" #include "crypto/pbkdf2.hpp" #include "crypto/sha256.hpp" @@ -74,6 +75,15 @@ void info::load_entries(std::istream & is, entry_types entries, size_t count, namespace { +struct issig_key_entry { + void load(std::istream & is, const setup::info & info) { + std::string ignore; + is >> util::encoded_string(ignore, info.codepage); + is >> util::encoded_string(ignore, info.codepage); + is >> util::encoded_string(ignore, info.codepage); + } +}; + void load_wizard_images(std::istream & is, const setup::version & version, std::vector & images, info::entry_types entries) { @@ -98,12 +108,36 @@ void load_wizard_images(std::istream & is, const setup::version & version, } +void skip_stream(std::istream & is) { + std::string ignored; + is >> util::binary_string(ignored); +} + void load_wizard_and_decompressor(std::istream & is, const setup::version & version, const setup::header & header, setup::info & info, info::entry_types entries) { info.wizard_images.clear(); info.wizard_images_small.clear(); + + if(version >= INNO_VERSION(6, 5, 0)) { + load_wizard_images(is, version, info.wizard_images, entries); + load_wizard_images(is, version, info.wizard_images_small, entries); + if(header.compression == stream::Zlib || header.compression == stream::BZip2) { + if(entries & (info::DecompressorDll | info::NoSkip)) { + is >> util::binary_string(info.decompressor_dll); + } else { + skip_stream(is); + } + } else { + info.decompressor_dll.clear(); + } + if(!header.sevenzip_library_name.empty()) { + skip_stream(is); + } + info.decrypt_dll.clear(); + return; + } load_wizard_images(is, version, info.wizard_images, entries); @@ -143,6 +177,43 @@ void check_is_end(stream::block_reader::pointer & is, const char * what) { } } +std::streampos skip_setup_encryption_header(std::istream & is, const setup::version & version) { + + if(version < INNO_VERSION(6, 5, 0)) { + return is.tellg(); + } + + static const std::streamsize SetupEncryptionHeaderSize = 49; + std::streampos start = is.tellg(); + boost::uint32_t expected_crc = util::load(is); + char header[SetupEncryptionHeaderSize]; + is.read(header, SetupEncryptionHeaderSize); + if(is.fail()) { + is.clear(); + is.seekg(start); + return start; + } + + // TSetupEncryptionHeader.EncryptionUse is a packed enum with values 0..2. + if(static_cast(header[0]) > 2) { + is.clear(); + is.seekg(start); + return start; + } + + crypto::crc32 actual_crc; + actual_crc.init(); + actual_crc.update(header, SetupEncryptionHeaderSize); + if(actual_crc.finalize() != expected_crc) { + is.clear(); + is.seekg(start); + return start; + } + + debug("skipping setup encryption header"); + return is.tellg(); +} + } // anonymous namespace void info::try_load(std::istream & is, entry_types entries, util::codepage_id force_codepage) { @@ -204,6 +275,13 @@ void info::try_load(std::istream & is, entry_types entries, util::codepage_id fo load_entries(*reader, entries, header.task_count, tasks, Tasks); debug("loading directories"); load_entries(*reader, entries, header.directory_count, directories, Directories); + if(header.issig_key_count != 0) { + debug("loading issig keys"); + for(size_t i = 0; i < header.issig_key_count; i++) { + issig_key_entry entry; + entry.load(*reader, *this); + } + } debug("loading files"); load_entries(*reader, entries, header.file_count, files, Files); debug("loading icons"); @@ -241,6 +319,7 @@ void info::try_load(std::istream & is, entry_types entries, util::codepage_id fo void info::load(std::istream & is, entry_types entries, util::codepage_id force_codepage) { version.load(is); + std::streampos start = skip_setup_encryption_header(is, version); if(!version.known) { if(entries & NoUnknownVersion) { @@ -264,7 +343,6 @@ void info::load(std::istream & is, entry_types entries, util::codepage_id force_ } bool parsed_without_errors = false; - std::streampos start = is.tellg(); for(;;) { warning_suppressor warnings; diff --git a/src/setup/registry.cpp b/src/setup/registry.cpp index f5a1ef4c..ce1584e0 100644 --- a/src/setup/registry.cpp +++ b/src/setup/registry.cpp @@ -103,6 +103,7 @@ void registry_entry::load(std::istream & is, const info & i) { type = stored_enum(is).get(); } + options = 0; stored_flag_reader flagreader(is, i.version.bits()); if(i.version.bits() != 16) { @@ -130,7 +131,7 @@ void registry_entry::load(std::istream & is, const info & i) { flagreader.add(Bits64); } - options = flagreader.finalize(); + options |= flagreader.finalize(); } } // namespace setup diff --git a/src/setup/run.cpp b/src/setup/run.cpp index 9fe1bdf6..d99e2af9 100644 --- a/src/setup/run.cpp +++ b/src/setup/run.cpp @@ -66,7 +66,6 @@ void run_entry::load(std::istream & is, const info & i) { if(i.version >= INNO_VERSION(2, 0, 0) || i.version.is_isx()) { is >> util::encoded_string(description, i.codepage); } - load_condition_data(is, i); load_version_data(is, i.version); @@ -78,6 +77,7 @@ void run_entry::load(std::istream & is, const info & i) { } wait = stored_enum(is).get(); + options = 0; stored_flag_reader flagreader(is, i.version.bits()); @@ -110,7 +110,7 @@ void run_entry::load(std::istream & is, const info & i) { flagreader.add(LogOutput); } - options = flagreader.finalize(); + options |= flagreader.finalize(); } } // namespace setup diff --git a/src/setup/task.cpp b/src/setup/task.cpp index a0bbdd8c..a8ac88bb 100644 --- a/src/setup/task.cpp +++ b/src/setup/task.cpp @@ -55,7 +55,6 @@ void task_entry::load(std::istream & is, const info & i) { } else { used = true; } - winver.load(is, i.version); stored_flag_reader flagreader(is); diff --git a/src/setup/version.cpp b/src/setup/version.cpp index 7f68af26..a0ef8e25 100644 --- a/src/setup/version.cpp +++ b/src/setup/version.cpp @@ -186,6 +186,7 @@ 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.5.0)", INNO_VERSION_EXT(6, 5, 0, 0), version::Unicode }, }; } // anonymous namespace From 02ce2841a4551c1bf9a14ddab228f49f2d352b7f Mon Sep 17 00:00:00 2001 From: rhcp011235 Date: Sun, 19 Apr 2026 13:04:32 -0400 Subject: [PATCH 2/2] Fix loader revision block indentation --- src/loader/offsets.cpp | 100 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/loader/offsets.cpp b/src/loader/offsets.cpp index 7c917959..9965dedb 100644 --- a/src/loader/offsets.cpp +++ b/src/loader/offsets.cpp @@ -142,59 +142,59 @@ bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) { checksum.init(); checksum.update(magic, sizeof(magic)); - boost::uint32_t revision = 0; - if(version >= INNO_VERSION(5, 1, 5)) { - revision = checksum.load(is); - if(is.fail()) { - is.clear(); - debug("could not read loader header revision"); - return false; - } else if(revision != 1 && revision != 2) { - log_warning << "Unexpected setup loader revision: " << revision; - } + boost::uint32_t revision = 0; + if(version >= INNO_VERSION(5, 1, 5)) { + revision = checksum.load(is); + if(is.fail()) { + is.clear(); + debug("could not read loader header revision"); + return false; + } else if(revision != 1 && revision != 2) { + log_warning << "Unexpected setup loader revision: " << revision; + } + } + + if(revision == 2) { + boost::uint64_t total_size = checksum.load(is); + boost::uint64_t offset_exe = checksum.load(is); + exe_uncompressed_size = checksum.load(is); + exe_checksum.type = crypto::CRC32; + exe_checksum.crc32 = checksum.load(is); + boost::uint64_t offset0 = checksum.load(is); + boost::uint64_t offset1 = checksum.load(is); + (void)checksum.load(is); // ReservedPadding + if(is.fail()) { + is.clear(); + debug("could not read revision 2 loader header"); + return false; + } + if(total_size > std::numeric_limits::max() + || offset_exe > std::numeric_limits::max() + || offset0 > std::numeric_limits::max() + || offset1 > std::numeric_limits::max()) { + log_warning << "Unsupported large revision 2 setup loader offsets!"; + return false; + } + exe_offset = static_cast(offset_exe); + exe_compressed_size = 0; + message_offset = 0; + header_offset = static_cast(offset0); + data_offset = static_cast(offset1); + boost::uint32_t expected = util::load(is); + if(is.fail()) { + is.clear(); + debug("could not read revision 2 loader header checksum"); + return false; } - - if(revision == 2) { - boost::uint64_t total_size = checksum.load(is); - boost::uint64_t offset_exe = checksum.load(is); - exe_uncompressed_size = checksum.load(is); - exe_checksum.type = crypto::CRC32; - exe_checksum.crc32 = checksum.load(is); - boost::uint64_t offset0 = checksum.load(is); - boost::uint64_t offset1 = checksum.load(is); - (void)checksum.load(is); // ReservedPadding - if(is.fail()) { - is.clear(); - debug("could not read revision 2 loader header"); - return false; - } - if(total_size > std::numeric_limits::max() - || offset_exe > std::numeric_limits::max() - || offset0 > std::numeric_limits::max() - || offset1 > std::numeric_limits::max()) { - log_warning << "Unsupported large revision 2 setup loader offsets!"; - return false; - } - exe_offset = static_cast(offset_exe); - exe_compressed_size = 0; - message_offset = 0; - header_offset = static_cast(offset0); - data_offset = static_cast(offset1); - boost::uint32_t expected = util::load(is); - if(is.fail()) { - is.clear(); - debug("could not read revision 2 loader header checksum"); - return false; - } - if(checksum.finalize() != expected) { - log_warning << "Setup loader checksum mismatch!"; - } - return true; + if(checksum.finalize() != expected) { + log_warning << "Setup loader checksum mismatch!"; } - - (void)checksum.load(is); - exe_offset = checksum.load(is); + return true; + } + (void)checksum.load(is); + exe_offset = checksum.load(is); + if(version >= INNO_VERSION(4, 1, 6)) { exe_compressed_size = 0; } else {