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>
impl<'a> InnoInstaller<'a>
Sourcepub fn from_bytes(data: &'a [u8]) -> Result<Self, Error>
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?
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}Sourcepub fn from_bytes_with_passwords(
data: &'a [u8],
passwords: &[&str],
) -> Result<Self, Error>
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
Error::PasswordRequired— installer is encrypted butpasswordsis empty.Error::WrongPassword— no candidate matched.- All standard parse errors per
Self::from_bytes.
Sourcepub fn decompressed_setup0(&self) -> &[u8] ⓘ
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?
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}Sourcepub fn data_block(&self) -> &[u8] ⓘ
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?
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}Sourcepub fn header(&self) -> Option<&SetupHeader>
pub fn header(&self) -> Option<&SetupHeader>
Returns the parsed setup header, when available. Absent when
decompressed_setup0() is empty.
Examples found in repository?
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}Sourcepub fn version(&self) -> &Version
pub fn version(&self) -> &Version
Returns the parsed Inno Setup version.
Examples found in repository?
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}Sourcepub fn variant(&self) -> Variant
pub fn variant(&self) -> Variant
Returns the detected installer variant.
Examples found in repository?
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}Sourcepub fn offset_table(&self) -> &OffsetTable
pub fn offset_table(&self) -> &OffsetTable
Returns the parsed SetupLdrOffsetTable.
Examples found in repository?
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}Sourcepub fn setup_ldr_family(&self) -> SetupLdrFamily
pub fn setup_ldr_family(&self) -> SetupLdrFamily
Returns the SetupLdr 12-byte magic family.
Examples found in repository?
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}Sourcepub fn pe_locator_mode(&self) -> LocatorMode
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?
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}Sourcepub fn encryption(&self) -> Option<&EncryptionInfo>
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?
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}Sourcepub fn compression(&self) -> Compression
pub fn compression(&self) -> Compression
Block-compression method for the setup-0 header block.
Examples found in repository?
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}Sourcepub fn architecture(&self) -> Option<HashSet<Architecture>>
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
Architectureflag bits on thecrate::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, sonot x64reportsAmd64the same as barex64. Callers that need a faithful evaluation should consume the raw expression viaSetupHeader::stringwithHeaderString::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”.
Sourcepub fn license_text(&self) -> Option<&[u8]>
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
None — Some(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.
Sourcepub fn info_before(&self) -> Option<&[u8]>
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.
Sourcepub fn info_after(&self) -> Option<&[u8]>
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.
Sourcepub fn compiled_code_bytes(&self) -> Option<&[u8]>
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.
Sourcepub fn compiledcode(&self) -> Option<Result<Container<'_>, Error>>
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.
Sourcepub fn inno_api_description(&self, name: &str) -> Option<&'static str>
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.
Sourcepub fn languages(&self) -> &[LanguageEntry]
pub fn languages(&self) -> &[LanguageEntry]
Parsed [Languages] entries, in declaration order.
Examples found in repository?
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}Sourcepub fn messages(&self) -> &[MessageEntry]
pub fn messages(&self) -> &[MessageEntry]
Parsed [CustomMessages] entries.
Examples found in repository?
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}Sourcepub fn permissions(&self) -> &[PermissionEntry]
pub fn permissions(&self) -> &[PermissionEntry]
Parsed [Permissions] entries (raw TGrantPermissionEntry[]
blobs).
Examples found in repository?
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}Sourcepub fn types(&self) -> &[TypeEntry]
pub fn types(&self) -> &[TypeEntry]
Parsed [Types] entries.
Examples found in repository?
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}Sourcepub fn components(&self) -> &[ComponentEntry]
pub fn components(&self) -> &[ComponentEntry]
Parsed [Components] entries.
Examples found in repository?
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}Sourcepub fn tasks(&self) -> &[TaskEntry]
pub fn tasks(&self) -> &[TaskEntry]
Parsed [Tasks] entries.
Examples found in repository?
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}Sourcepub fn directories(&self) -> &[DirectoryEntry]
pub fn directories(&self) -> &[DirectoryEntry]
Parsed [Dirs] entries.
Examples found in repository?
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}Sourcepub fn iss_sig_keys(&self) -> &[ISSigKeyEntry]
pub fn iss_sig_keys(&self) -> &[ISSigKeyEntry]
Parsed [ISSigKeys] entries (6.5.0+; empty on older
installers).
Sourcepub fn files(&self) -> &[FileEntry]
pub fn files(&self) -> &[FileEntry]
Parsed [Files] entries.
Examples found in repository?
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}Sourcepub fn icons(&self) -> &[IconEntry]
pub fn icons(&self) -> &[IconEntry]
Parsed [Icons] entries.
Examples found in repository?
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}Sourcepub fn ini_entries(&self) -> &[IniEntry]
pub fn ini_entries(&self) -> &[IniEntry]
Parsed [INI] entries.
Examples found in repository?
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}Sourcepub fn registry_entries(&self) -> &[RegistryEntry]
pub fn registry_entries(&self) -> &[RegistryEntry]
Parsed [Registry] entries.
Examples found in repository?
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}Sourcepub fn install_deletes(&self) -> &[DeleteEntry]
pub fn install_deletes(&self) -> &[DeleteEntry]
Parsed [InstallDelete] entries.
Examples found in repository?
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}Sourcepub fn uninstall_deletes(&self) -> &[DeleteEntry]
pub fn uninstall_deletes(&self) -> &[DeleteEntry]
Parsed [UninstallDelete] entries.
Examples found in repository?
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}Sourcepub fn run_entries(&self) -> &[RunEntry]
pub fn run_entries(&self) -> &[RunEntry]
Parsed [Run] entries.
Examples found in repository?
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}Sourcepub fn uninstall_runs(&self) -> &[RunEntry]
pub fn uninstall_runs(&self) -> &[RunEntry]
Parsed [UninstallRun] entries.
Examples found in repository?
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}Sourcepub fn file_locations(&self) -> &[DataEntry]
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?
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}Sourcepub fn exec_commands(&self) -> ExecIter<'_> ⓘ
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.
Sourcepub fn registry_ops(&self) -> RegistryOpIter<'_> ⓘ
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.
Sourcepub fn shortcuts(&self) -> ShortcutIter<'_> ⓘ
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.
Sourcepub fn is_encrypted(&self) -> bool
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).
Sourcepub fn password_used(&self) -> Option<&str>
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).
Sourcepub fn extract(&self, file: &FileEntry) -> Result<FileReader<'_>, Error>
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
Error::NoLocationfor the embedded uninstaller (location_index == u32::MAX).Error::Encryptedwhen the chunk is encrypted and no key has been supplied viaInnoInstaller::from_bytes_with_passwords.Error::ExternalSlicewhen the chunk lives in an externalsetup-N.binfile.Error::MultiSliceChunkwhen the chunk spans slices.Error::Decompress,Error::BadChunkMagic, etc. on format errors.
Sourcepub fn extract_by_location(
&self,
location_index: u32,
) -> Result<FileReader<'_>, Error>
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).
Sourcepub fn extract_to_vec(&self, file: &FileEntry) -> Result<Vec<u8>, Error>
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?
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}Sourcepub fn extract_uninstaller(&self) -> Result<Vec<u8>, Error>
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::NoLocationwhen the installer ships no uninstaller stub (Uninstallable=nobuilds; older installers without anftUninstExe[Files]entry).Error::Truncatedwhen the input is too short to contain the mode marker at offset0x30.
Sourcepub fn extract_files(
&self,
) -> impl Iterator<Item = Result<(&FileEntry, Vec<u8>), Error>> + '_
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.