Skip to main content

InnoInstaller

Struct InnoInstaller 

Source
pub struct InnoInstaller<'a> { /* private fields */ }
Expand description

High-level view of an Inno Setup installer.

Identification accessors (version, variant, offset_table, compression, encryption, pe_locator_mode) work on every supported version. The decompressed_setup0 accessor exposes the decompressed setup-0 bytes; the typed-record iterators borrow from this buffer.

Implementations§

Source§

impl<'a> InnoInstaller<'a>

Source

pub fn from_bytes(data: &'a [u8]) -> Result<Self, Error>

Parses an Inno Setup installer from a byte slice. Does not attempt to decrypt — encrypted chunks remain observable as ChunkEncrypted data-entry flags, and Self::extract returns Error::Encrypted for them. Use Self::from_bytes_with_passwords to additionally derive the decryption key from candidate passwords.

§Errors

See Error variants. The common “this isn’t an Inno Setup installer” outcomes are Error::NotPe and Error::NotInnoSetup; everything else indicates broken or unfamiliar input.

Examples found in repository?
examples/dump.rs (line 20)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn from_bytes_with_passwords( data: &'a [u8], passwords: &[&str], ) -> Result<Self, Error>

Parses an Inno Setup installer and tries each candidate password against the on-disk verifier (password_test); the first match is recorded and used to decrypt file chunks during Self::extract.

§Errors
Source

pub fn decompressed_setup0(&self) -> &[u8]

Returns the decompressed setup-0 bytes. Empty when the block could not be decompressed (encrypted-euFull, or older pre-4.0.9 layout pending full support).

Examples found in repository?
examples/dump.rs (line 55)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn data_block(&self) -> &[u8]

Returns the decompressed bytes of the second block stream in setup-0, which holds the TSetupFileLocationEntry records. Empty when Self::decompressed_setup0 is empty.

Examples found in repository?
examples/dump.rs (line 171)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn header(&self) -> Option<&SetupHeader>

Returns the parsed setup header, when available. Absent when decompressed_setup0() is empty.

Examples found in repository?
examples/dump.rs (line 67)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn version(&self) -> &Version

Returns the parsed Inno Setup version.

Examples found in repository?
examples/dump.rs (line 25)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn variant(&self) -> Variant

Returns the detected installer variant.

Examples found in repository?
examples/dump.rs (line 30)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn offset_table(&self) -> &OffsetTable

Returns the parsed SetupLdrOffsetTable.

Examples found in repository?
examples/dump.rs (line 37)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn setup_ldr_family(&self) -> SetupLdrFamily

Returns the SetupLdr 12-byte magic family.

Examples found in repository?
examples/dump.rs (line 33)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn pe_locator_mode(&self) -> LocatorMode

Returns whether the offset table was found via PE resource (5.1.5+) or the legacy 0x30 file-offset path.

Examples found in repository?
examples/dump.rs (line 34)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn encryption(&self) -> Option<&EncryptionInfo>

Returns the encryption metadata for 6.4.0+ installers, or None if not encrypted (or if the version is older than 6.4 — pre-6.4 encryption is per-chunk, surfaced through the DataEntry::ChunkEncrypted flag on each affected chunk).

Examples found in repository?
examples/dump.rs (line 53)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn compression(&self) -> Compression

Block-compression method for the setup-0 header block.

Examples found in repository?
examples/dump.rs (line 50)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn architecture(&self) -> Option<HashSet<Architecture>>

Returns the set of processor architectures the installer permits via its ArchitecturesAllowed directive, or None when the field isn’t on the wire (pre-5.1.0 installers).

Two underlying wire forms are unified here:

  • 5.1.0..6.3 store the field as packed Architecture flag bits on the crate::header::HeaderTail; this accessor returns those bits verbatim.
  • 6.3+ store it as a boolean expression string (e.g. "x64compatible or arm64") which this accessor scans best-effort for known architecture atoms (x86, x86os, x86compatible, x64, x64os, x64compatible, arm32compatible, arm64, ia64). Boolean operators (and, or, not) are NOT evaluated — any atom that appears in the expression produces its architecture in the result, so not x64 reports Amd64 the same as bare x64. Callers that need a faithful evaluation should consume the raw expression via SetupHeader::string with HeaderString::ArchitecturesAllowed.

An empty set in the result means the installer left the directive at its Inno default, which Inno treats as “any architecture allowed”. Callers that want this default expressed explicitly should treat Some(set) where set.is_empty() the same as “all architectures allowed”.

Source

pub fn input(&self) -> &'a [u8]

Returns the original input slice.

Source

pub fn license_text(&self) -> Option<&[u8]>

Returns the LicenseFile blob (the [Setup] LicenseFile=… directive’s contents, stored verbatim in the setup header), or None if the installer does not ship a license screen.

Modern Inno builds always carry the LicenseText AnsiString slot, but populate it with an empty string when no license is configured. This accessor folds that empty case into NoneSome(bytes) always has bytes.len() > 0.

The bytes are codepage-encoded per the installer’s language table; callers that need a String should run them through the appropriate decoder.

Source

pub fn info_before(&self) -> Option<&[u8]>

Returns the InfoBeforeFile blob (text shown on the wizard page before installation), or None if absent or empty.

See Self::license_text for the empty-folding rule and encoding notes.

Source

pub fn info_after(&self) -> Option<&[u8]>

Returns the InfoAfterFile blob (text shown on the wizard page after installation), or None if absent or empty.

See Self::license_text for the empty-folding rule and encoding notes.

Source

pub fn compiled_code_bytes(&self) -> Option<&[u8]>

Returns the compiled [Code] PascalScript blob, or None if the installer does not ship a [Code] section.

The blob is an IFPS container — IFPS-magic followed by a header, name table, type table, globals, procedures, and bytecode. This accessor surfaces the raw bytes; the parsed container view lives at Self::compiledcode. Empty blobs fold into None per the same rule as Self::license_text.

Source

pub fn compiledcode(&self) -> Option<Result<Container<'_>, Error>>

Returns a parsed Container view over the IFPS blob at Self::compiled_code_bytes, or None if no [Code] blob is present.

The full pascalscript::Container surface is exposed — header, types, procs (script-defined and imported externals), vars. The container’s API is Inno-agnostic (designed for an eventual standalone-crate split); see Self::inno_api_description for the Inno-side name lookup.

§Errors

Some(Err(_)) when the blob is present but malformed — bad magic, unsupported PSBuildNo, truncated table, or out-of-range type / bytecode reference. The error wraps a pascalscript::Error inside Error::PascalScript.

Source

pub fn inno_api_description(&self, name: &str) -> Option<&'static str>

Looks up an imported PascalScript external name (as it appears in pascalscript::Container::procs entries that are pascalscript::ProcKind::External) against Inno’s runtime-registered API table.

Returns a one-line description for the security-relevant subset of registered functions (registry mutations, command execution, file operations, network downloads, privilege checks). Returns None for names outside that subset — see crate::analysis::compiledcode::INNO_API for the curated list.

Source

pub fn languages(&self) -> &[LanguageEntry]

Parsed [Languages] entries, in declaration order.

Examples found in repository?
examples/dump.rs (line 177)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn messages(&self) -> &[MessageEntry]

Parsed [CustomMessages] entries.

Examples found in repository?
examples/dump.rs (line 178)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn permissions(&self) -> &[PermissionEntry]

Parsed [Permissions] entries (raw TGrantPermissionEntry[] blobs).

Examples found in repository?
examples/dump.rs (line 179)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn types(&self) -> &[TypeEntry]

Parsed [Types] entries.

Examples found in repository?
examples/dump.rs (line 180)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn components(&self) -> &[ComponentEntry]

Parsed [Components] entries.

Examples found in repository?
examples/dump.rs (line 181)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn tasks(&self) -> &[TaskEntry]

Parsed [Tasks] entries.

Examples found in repository?
examples/dump.rs (line 182)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn directories(&self) -> &[DirectoryEntry]

Parsed [Dirs] entries.

Examples found in repository?
examples/dump.rs (line 205)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn iss_sig_keys(&self) -> &[ISSigKeyEntry]

Parsed [ISSigKeys] entries (6.5.0+; empty on older installers).

Source

pub fn files(&self) -> &[FileEntry]

Parsed [Files] entries.

Examples found in repository?
examples/dump.rs (line 206)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn icons(&self) -> &[IconEntry]

Parsed [Icons] entries.

Examples found in repository?
examples/dump.rs (line 207)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn ini_entries(&self) -> &[IniEntry]

Parsed [INI] entries.

Examples found in repository?
examples/dump.rs (line 208)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn registry_entries(&self) -> &[RegistryEntry]

Parsed [Registry] entries.

Examples found in repository?
examples/dump.rs (line 209)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn install_deletes(&self) -> &[DeleteEntry]

Parsed [InstallDelete] entries.

Examples found in repository?
examples/dump.rs (line 210)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn uninstall_deletes(&self) -> &[DeleteEntry]

Parsed [UninstallDelete] entries.

Examples found in repository?
examples/dump.rs (line 211)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn run_entries(&self) -> &[RunEntry]

Parsed [Run] entries.

Examples found in repository?
examples/dump.rs (line 212)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn uninstall_runs(&self) -> &[RunEntry]

Parsed [UninstallRun] entries.

Examples found in repository?
examples/dump.rs (line 213)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn file_locations(&self) -> &[DataEntry]

Parsed file-location records — bookkeeping for the chunks of setup-1 payload (one per file-content slot, including embedded files like the uninstaller). Lives in setup-0’s second decompressed block.

Examples found in repository?
examples/dump.rs (line 214)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn exec_commands(&self) -> ExecIter<'_>

Iterates the install + uninstall command-execution stream as a single sequence, with each item tagged crate::analysis::ExecPhase::Install or crate::analysis::ExecPhase::Uninstall.

Visit order is [Run] declaration order followed by [UninstallRun] declaration order. See crate::analysis::exec for the view shape.

Source

pub fn registry_ops(&self) -> RegistryOpIter<'_>

Iterates [Registry] entries with each one classified as crate::analysis::RegistryOpKind::Write, WriteIfMissing, DeleteValue, or DeleteKey based on the entry’s flag bitset.

Uninstall-time effects are not classified here — inspect the underlying entry’s flags for UninsDeleteValue, UninsDeleteEntireKey, etc.

Source

pub fn shortcuts(&self) -> ShortcutIter<'_>

Iterates [Icons] entries joined to their target [Files] entry where the icon’s filename matches a file’s destination. Icons that point at system paths or arbitrary URIs surface as a crate::analysis::Shortcut with target = None.

Source

pub fn is_encrypted(&self) -> bool

Returns true when the installer carries any kind of encryption — modern (6.4+ XChaCha20) or legacy (pre-6.4 ARC4-via-shPassword flag).

Source

pub fn password_used(&self) -> Option<&str>

Returns the password (verbatim from the candidate list passed to Self::from_bytes_with_passwords) that matched the on-disk verifier, or None if the installer is not encrypted (or wasn’t unlocked).

Source

pub fn extract(&self, file: &FileEntry) -> Result<FileReader<'_>, Error>

Streaming primary extraction API. Returns a FileReader that yields the file’s post-BCJ, post-decompression bytes and verifies the recorded checksum at EOF (mismatch surfaces as io::Error on the next read call after exhaustion).

§Errors
Source

pub fn extract_by_location( &self, location_index: u32, ) -> Result<FileReader<'_>, Error>

Extract by file-location index (for advanced callers inspecting the raw FileEntry → DataEntry mapping).

Source

pub fn extract_to_vec(&self, file: &FileEntry) -> Result<Vec<u8>, Error>

Eager convenience: drains the streaming reader into a Vec<u8>. The returned vector is exactly data.original_size bytes and has been checksum-verified.

§Errors

Same as Self::extract.

Examples found in repository?
examples/dump.rs (line 263)
8fn main() {
9    let args: Vec<String> = env::args().collect();
10    let Some(path) = args.get(1) else {
11        eprintln!("usage: dump <setup.exe>");
12        process::exit(1);
13    };
14
15    let data = fs::read(path).unwrap_or_else(|e| {
16        eprintln!("error reading {path}: {e}");
17        process::exit(1);
18    });
19
20    let installer = innospect::InnoInstaller::from_bytes(&data).unwrap_or_else(|e| {
21        eprintln!("error parsing Inno Setup installer: {e}");
22        process::exit(1);
23    });
24
25    let v = installer.version();
26    println!("== Identification ==");
27    println!("  marker:        {:?}", v.marker_str());
28    println!("  version:       {}.{}.{}.{}", v.a, v.b, v.c, v.d);
29    println!("  flags:         {:?}", v.flags);
30    println!("  variant:       {:?}", installer.variant());
31    println!(
32        "  setupldr:      {:?} (locator: {:?})",
33        installer.setup_ldr_family(),
34        installer.pe_locator_mode(),
35    );
36
37    let ot = installer.offset_table();
38    println!();
39    println!("== Offset table ==");
40    println!("  generation:    {:?}", ot.source.generation);
41    println!("  version_id:    {}", ot.version_id);
42    println!("  start:         {:#x}", ot.source.start);
43    println!("  Offset0:       {:#x}", ot.offset_setup0);
44    println!("  Offset1:       {:#x}", ot.offset_setup1);
45    println!("  OffsetEXE:     {:#x}", ot.offset_exe);
46    println!("  TotalSize:     {} bytes", ot.total_size,);
47
48    println!();
49    println!("== Setup-0 ==");
50    println!("  compression:   {:?}", installer.compression());
51    println!(
52        "  encryption:    {:?}",
53        installer.encryption().map(|e| e.mode)
54    );
55    let setup0 = installer.decompressed_setup0();
56    println!("  decompressed:  {} bytes", setup0.len());
57    if !setup0.is_empty() {
58        let preview_len = 128.min(setup0.len());
59        let preview: Vec<u8> = setup0
60            .iter()
61            .take(preview_len)
62            .map(|&b| if (32..127).contains(&b) { b } else { b'.' })
63            .collect();
64        println!("  preview:       {:?}", String::from_utf8_lossy(&preview),);
65    }
66
67    if let Some(header) = installer.header() {
68        println!();
69        println!("== Setup header ==");
70        println!("  AppName:        {:?}", header.app_name().unwrap_or(""));
71        println!("  AppId:          {:?}", header.app_id().unwrap_or(""));
72        println!("  AppVersion:     {:?}", header.app_version().unwrap_or(""));
73        println!(
74            "  AppPublisher:   {:?}",
75            header.app_publisher().unwrap_or(""),
76        );
77        println!(
78            "  DefaultDirName: {:?}",
79            header.default_dir_name().unwrap_or(""),
80        );
81
82        let counts = header.counts();
83        println!();
84        println!("== Entry counts ==");
85        println!("  languages:        {}", counts.languages);
86        println!("  custom_messages:  {}", counts.custom_messages);
87        println!("  permissions:      {}", counts.permissions);
88        println!("  types:            {}", counts.types);
89        println!("  components:       {}", counts.components);
90        println!("  tasks:            {}", counts.tasks);
91        println!("  directories:      {}", counts.directories);
92        if let Some(n) = counts.iss_sig_keys {
93            println!("  iss_sig_keys:     {n}");
94        }
95        println!("  files:            {}", counts.files);
96        println!("  file_locations:   {}", counts.file_locations);
97        println!("  icons:            {}", counts.icons);
98        println!("  ini_entries:      {}", counts.ini_entries);
99        println!("  registry:         {}", counts.registry);
100        println!("  install_deletes:  {}", counts.install_deletes);
101        println!("  uninstall_deletes:{}", counts.uninstall_deletes,);
102        println!("  run:              {}", counts.run);
103        println!("  uninstall_run:    {}", counts.uninstall_run);
104
105        let license_len = installer
106            .header()
107            .and_then(|h| h.ansi(innospect::HeaderAnsi::LicenseText))
108            .map_or(0, <[u8]>::len);
109        let info_before_len = installer
110            .header()
111            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoBeforeText))
112            .map_or(0, <[u8]>::len);
113        let info_after_len = installer
114            .header()
115            .and_then(|h| h.ansi(innospect::HeaderAnsi::InfoAfterText))
116            .map_or(0, <[u8]>::len);
117        let compiled_len = installer
118            .header()
119            .and_then(|h| h.ansi(innospect::HeaderAnsi::CompiledCodeText))
120            .map_or(0, <[u8]>::len);
121        println!();
122        println!("== Embedded blobs ==");
123        println!("  license_text:        {license_len} bytes");
124        println!("  info_before:         {info_before_len} bytes");
125        println!("  info_after:          {info_after_len} bytes");
126        println!("  compiled_code_text:  {compiled_len} bytes");
127
128        let tail = header.tail();
129        let tail_size = header
130            .records_offset()
131            .saturating_sub(header.tail_start_offset());
132        println!();
133        println!("== Fixed numeric tail ({tail_size} bytes) ==");
134        println!(
135            "  MinVersion (Win):       {}.{} build {}",
136            tail.windows_version_range.min.windows.major,
137            tail.windows_version_range.min.windows.minor,
138            tail.windows_version_range.min.windows.build,
139        );
140        println!(
141            "  OnlyBelowVersion (Win): {}.{} build {}",
142            tail.windows_version_range.only_below.windows.major,
143            tail.windows_version_range.only_below.windows.minor,
144            tail.windows_version_range.only_below.windows.build,
145        );
146        println!("  WizardStyle:            {:?}", tail.wizard_style);
147        println!(
148            "  WizardSizePercent:      ({}, {})",
149            tail.wizard_size_percent_x, tail.wizard_size_percent_y,
150        );
151        println!("  PrivilegesRequired:     {:?}", tail.privileges_required);
152        println!("  CompressMethod:         {:?}", tail.compress_method);
153        println!(
154            "  ExtraDiskSpaceRequired: {} bytes",
155            tail.extra_disk_space_required,
156        );
157        println!(
158            "  UninstallDisplaySize:   {} bytes",
159            tail.uninstall_display_size,
160        );
161        println!("  Options ({} set):", tail.options.len());
162        let mut sorted: Vec<_> = tail.options.iter().collect();
163        sorted.sort_by_key(|o| format!("{o:?}"));
164        for opt in sorted {
165            println!("    - {opt:?}");
166        }
167    }
168
169    println!();
170    println!("== Data block (file-location records) ==");
171    let data = installer.data_block();
172    println!("  decompressed:  {} bytes", data.len());
173
174    println!();
175    println!(
176        "== Records (3c lightweight) — languages={} messages={} permissions={} types={} components={} tasks={} ==",
177        installer.languages().len(),
178        installer.messages().len(),
179        installer.permissions().len(),
180        installer.types().len(),
181        installer.components().len(),
182        installer.tasks().len(),
183    );
184    for (i, l) in installer.languages().iter().enumerate().take(5) {
185        let name = l.name_string().unwrap_or_default();
186        let pretty = l.language_name_string().unwrap_or_default();
187        println!(
188            "  language[{i}]: id={:#06x} cp={:?} name={:?} ({:?})",
189            l.language_id, l.codepage, name, pretty,
190        );
191    }
192    if installer.languages().len() > 5 {
193        println!("    … {} more", installer.languages().len() - 5);
194    }
195    for (i, t) in installer.tasks().iter().enumerate().take(8) {
196        println!(
197            "  task[{i}]: name={:?} flags={:?} level={}",
198            t.name, t.flags, t.level,
199        );
200    }
201
202    println!();
203    println!(
204        "== Records (3d heavy) — dirs={} files={} icons={} ini={} reg={} ins_del={} unins_del={} run={} unins_run={} file_loc={} ==",
205        installer.directories().len(),
206        installer.files().len(),
207        installer.icons().len(),
208        installer.ini_entries().len(),
209        installer.registry_entries().len(),
210        installer.install_deletes().len(),
211        installer.uninstall_deletes().len(),
212        installer.run_entries().len(),
213        installer.uninstall_runs().len(),
214        installer.file_locations().len(),
215    );
216    for (i, f) in installer.files().iter().enumerate().take(4) {
217        println!(
218            "  file[{i}]: src={:?} dst={:?} loc={} ext_size={} flags={}",
219            f.source,
220            f.destination,
221            f.location_index,
222            f.external_size,
223            f.flags.len(),
224        );
225    }
226    if installer.files().len() > 4 {
227        println!("    … {} more", installer.files().len() - 4);
228    }
229    for (i, r) in installer.registry_entries().iter().enumerate() {
230        println!(
231            "  reg[{i}]: hive={:?} subkey={:?} name={:?} type={:?}",
232            r.hive, r.subkey, r.value_name, r.value_type,
233        );
234    }
235    for (i, ic) in installer.icons().iter().enumerate().take(4) {
236        println!(
237            "  icon[{i}]: name={:?} target={:?} args={:?}",
238            ic.name, ic.filename, ic.parameters,
239        );
240    }
241    for (i, r) in installer.run_entries().iter().enumerate().take(4) {
242        println!(
243            "  run[{i}]: cmd={:?} args={:?} wait={:?} flags={:?}",
244            r.name, r.parameters, r.wait, r.flags,
245        );
246    }
247    for (i, d) in installer.file_locations().iter().enumerate().take(2) {
248        println!(
249            "  file_loc[{i}]: orig_size={} compressed={} chunk_offset={} flags={:?}",
250            d.original_size, d.chunk_compressed_size, d.chunk_sub_offset, d.flags,
251        );
252    }
253
254    println!();
255    println!("== Extraction ==");
256    let mut extracted = 0usize;
257    let mut total_bytes: u64 = 0;
258    let mut errors = 0usize;
259    for f in installer.files() {
260        if f.location_index == u32::MAX {
261            continue;
262        }
263        match installer.extract_to_vec(f) {
264            Ok(bytes) => {
265                total_bytes = total_bytes.saturating_add(bytes.len() as u64);
266                extracted = extracted.saturating_add(1);
267            }
268            Err(e) => {
269                errors = errors.saturating_add(1);
270                if errors <= 3 {
271                    println!("  ! {:?}: {e}", f.destination);
272                }
273            }
274        }
275    }
276    println!("  extracted: {extracted} files / {total_bytes} bytes / {errors} errors");
277}
Source

pub fn extract_uninstaller(&self) -> Result<Vec<u8>, Error>

Reconstructs the embedded uninstaller (unins000.exe) by duplicating the input bytes and patching the SetupExeMode slot to the uninstaller magic.

Inno’s uninstaller stub isn’t a separately-packaged file in the chunk stream — at install time Setup.exe copies its own bytes (NewParamStr(0) in Setup.Install.pas:1629-1631) and overwrites the four-byte mode marker at offset 0x30 with 0x6E556E49 (LE: b"InUn") via MarkExeHeader (Setup.Install.HelperFunc.pas:469-473). On launch the same EXE reads that marker (Setup.Start.pas:148) and dispatches into uninstaller mode rather than installer mode. Both constants — SetupExeModeOffset = $30 and SetupExeModeUninstaller = $6E556E49 — have been stable across the version range we cover (verified at is-5_5_5 through is-7_0_0_2, Shared.Struct.pas).

What this method does not do: append the localized- messages tail (BindUninstallMsgDataToExe, Setup.Install.pas:485-503). Real installs append a TUninstallerMsgTail record on top of the patched bytes using runtime state (selected language, expanded AppId) that we can’t fully reconstruct from a static parse. The produced binary is still a valid uninstaller for inspection / triage; it just won’t display Inno’s localized “Are you sure you want to uninstall…?” prompts the way an installed-and-bound copy would.

§Errors
  • Error::NoLocation when the installer ships no uninstaller stub (Uninstallable=no builds; older installers without an ftUninstExe [Files] entry).
  • Error::Truncated when the input is too short to contain the mode marker at offset 0x30.
Source

pub fn extract_files( &self, ) -> impl Iterator<Item = Result<(&FileEntry, Vec<u8>), Error>> + '_

Bulk extraction iterator over every file entry that carries a chunk payload.

Yields (file, bytes) for each FileEntry whose location_index resolves to a real setup-1 chunk; entries with location_index == u32::MAX (the embedded uninstaller stub, certain external-file placeholders) are filtered out rather than producing Error::NoLocation mid-stream.

Iteration order matches Self::files declaration order. When solid-LZMA mode places multiple files in the same chunk, the per-chunk OnceLock cache makes the second and subsequent extractions from that chunk free — i.e. running the iterator end-to-end touches each chunk’s decompression path exactly once even though there are many file extractions.

Each item is a Result so a single malformed chunk doesn’t poison the rest of the stream.

Trait Implementations§

Source§

impl<'a> Debug for InnoInstaller<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for InnoInstaller<'a>

§

impl<'a> RefUnwindSafe for InnoInstaller<'a>

§

impl<'a> Send for InnoInstaller<'a>

§

impl<'a> Sync for InnoInstaller<'a>

§

impl<'a> Unpin for InnoInstaller<'a>

§

impl<'a> UnsafeUnpin for InnoInstaller<'a>

§

impl<'a> UnwindSafe for InnoInstaller<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.