-
Notifications
You must be signed in to change notification settings - Fork 21
Description
Problem
When trying to insert information into a table (that already exists), the table can become unreadable by msiexec.exe. The table that is affected also causes attempting to open the table in orca.exe to result in an error with the message An invalid argument was encountered. (when the table would open properly before the insert) and both InstEd and MSI Viewer give generic errors stating that the MSI couldn't be opened.
Minimum Reproducible Example
This code is also available here and can be run by running cargo run --example mre -- Schema.msi
use std::{fs::File, io::Write, str::FromStr};
use clap::{App, Arg};
use msi::Value;
fn main() {
let matches = App::new("mre")
.arg(Arg::with_name("schema").required(true))
.arg(Arg::with_name("output").required(true).default_value("out.msi"))
.get_matches();
let schema = matches.value_of("schema").unwrap();
let output = matches.value_of("output").unwrap();
let mut template = File::open(schema).unwrap();
let mut file = File::options()
.create(true)
.read(true)
.write(true)
.truncate(true)
.open(output)
.expect("Failed to open broken.msi");
// Copy the template data into our new MSI
std::io::copy(&mut template, &mut file).unwrap();
// Probably not needed but whatever
file.flush().unwrap();
let mut package = msi::Package::open(file).expect("Failed to create MSI");
// Summary Information
let sum = package.summary_info_mut();
// Have to set the PackageCode or we get an even more generic error saying "The parameter is incorrect".
// This is the only SummaryInfo field not set that appears to be necessary.
sum.set_uuid(
*uuid::fmt::Braced::from_str("{11111111-1111-1111-1111-111111111111}")
.unwrap()
.as_uuid(),
); // PID 9
package.flush().unwrap();
// Required Property Information
package
.insert_rows(msi::Insert::into("Property").rows(vec![
vec![Value::from("ProductName"), Value::from("MyProduct")],
vec![
Value::from("ProductCode"),
Value::from("{11111111-1111-1111-1111-111111111113}"),
],
vec![Value::from("ProductVersion"), Value::from("0.0.0")],
vec![Value::from("ProductLanguage"), Value::from("1033")],
vec![Value::from("Manufacturer"), Value::from("MyManufacturer")],
]))
.unwrap();
package.flush().unwrap();
}Troubleshooting
Install Logging
I tried running msiexec.exe with verbose logs msiexec -L*vx 'C:\TEMP\msi.log' 'C:\Users\User\Downloads\test.msi' and got the output below:
=== Verbose logging started: 12/1/2025 14:24:36 Build type: SHIP UNICODE 5.00.10011.00 Calling process: C:\Windows\System32\msiexec.exe ===
MSI (c) (D0:38) [14:24:36:333]: Font created. Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg
MSI (c) (D0:38) [14:24:36:334]: Font created. Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg
MSI (c) (D0:C0) [14:24:36:349]: Resetting cached policy values
MSI (c) (D0:C0) [14:24:36:349]: Machine policy value 'Debug' is 0
MSI (c) (D0:C0) [14:24:36:349]: ******* RunEngine:
******* Product: C:\Users\User\Downloads\test.msi
******* Action:
******* CommandLine: **********
MSI (c) (D0:C0) [14:24:36:354]: Machine policy value 'DisableUserInstalls' is 0
MSI (c) (D0:C0) [14:24:36:402]: Access database with Impersonation
MSI (c) (D0:C0) [14:24:36:403]: SOFTWARE RESTRICTION POLICY: Verifying package --> 'C:\Users\User\Downloads\test.msi' against software restriction policy
MSI (c) (D0:C0) [14:24:36:403]: Note: 1: 2262 2: �DigitalSignature 3: -2147287038
MSI (c) (D0:C0) [14:24:36:403]: SOFTWARE RESTRICTION POLICY: C:\Users\User\Downloads\test.msi is not digitally signed
MSI (c) (D0:C0) [14:24:36:404]: SOFTWARE RESTRICTION POLICY: C:\Users\User\Downloads\test.msi is permitted to run at the 'unrestricted' authorization level.
MSI (c) (D0:C0) [14:24:36:427]: Cloaking enabled.
MSI (c) (D0:C0) [14:24:36:427]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (D0:C0) [14:24:36:429]: End dialog not enabled
MSI (c) (D0:C0) [14:24:36:429]: Original package ==> C:\Users\User\Downloads\test.msi
MSI (c) (D0:C0) [14:24:36:429]: Package we're running from ==> C:\Users\User\Downloads\test.msi
MSI (c) (D0:C0) [14:24:36:430]: Note: 1: 2211 2: 3: Property
MSI (c) (D0:C0) [14:24:36:430]: MSI_DBG: Provided descriptor less than minimum size
MSI (c) (D0:C0) [14:24:36:430]: APPCOMPAT: Compatibility mode property overrides found.
MSI (c) (D0:C0) [14:24:36:430]: APPCOMPAT: looking for appcompat database entry with ProductCode ''.
MSI (c) (D0:C0) [14:24:36:430]: APPCOMPAT: no matching ProductCode found in database.
MSI (c) (D0:C0) [14:24:36:433]: MSCOREE not loaded loading copy from system32
MSI (c) (D0:C0) [14:24:36:434]: Machine policy value 'TransformsSecure' is 0
MSI (c) (D0:C0) [14:24:36:434]: User policy value 'TransformsAtSource' is 0
MSI (c) (D0:C0) [14:24:36:435]: APPCOMPAT: looking for appcompat database entry with ProductCode ''.
MSI (c) (D0:C0) [14:24:36:435]: APPCOMPAT: no matching ProductCode found in database.
MSI (c) (D0:C0) [14:24:36:435]: Transforms are not secure.
MSI (c) (D0:C0) [14:24:36:435]: Note: 1: 2211 2: 3: Property
MSI (c) (D0:C0) [14:24:36:435]: Note: 1: 2262 2: Control 3: -2147287038
MSI (c) (D0:C0) [14:24:36:435]: PROPERTY CHANGE: Adding MsiLogFileLocation property. Its value is 'C:\TEMP\msi.log'.
MSI (c) (D0:C0) [14:24:36:435]: Command Line: CURRENTDIRECTORY=\\wsl.localhost\dev\home\dom\rust-msi\examples CLIENTUILEVEL=0 CLIENTPROCESSID=22736
MSI (c) (D0:C0) [14:24:36:435]: PROPERTY CHANGE: Adding PackageCode property. Its value is '{11111111-1111-1111-1111-111111111111}'.
MSI (c) (D0:C0) [14:24:36:435]: Product Code passed to Engine.Initialize: ''
MSI (c) (D0:C0) [14:24:36:435]: Product Code from property table before transforms: ''
MSI (c) (D0:C0) [14:24:36:435]: Product Code from property table after transforms: ''
MSI (c) (D0:C0) [14:24:36:435]: Failing install, missing product code
This action is only valid for products that are currently installed.
C:\Users\User\Downloads\test.msi
MSI (c) (D0:C0) [14:24:36:435]: Note: 1: 1708
MSI (c) (D0:C0) [14:24:36:435]: Product: -- Installation failed.
MSI (c) (D0:C0) [14:24:36:436]: Windows Installer installed the product. Product Name: . Product Version: . Product Language: . Manufacturer: . Installation success or error status: 1605.
MSI (c) (D0:C0) [14:24:36:437]: MainEngineThread is returning 1605
=== Verbose logging stopped: 12/1/2025 14:24:36 ===
I did try running the same command in a regular PowerShell prompt rather than from WSL and got the same result.
MSIInfo.exe
Running the command MsiInfo.exe [MSI_PATH] /D for both Schema.msi and test.msi both show no StringPool errors, and adding \B to the command shows that the specified property information was appended to the end of the StringPool and I can't see any other oddities of note with a diff.
msitools
The information is readable both by the rust-msi crate and the msitools' msiinfo command. Running the command msiinfo export -s test.msi Property results in the expected output shown below:
Property Value
s72 l0
Property Property
Manufacturer MyManufacturer
ProductCode {11111111-1111-1111-1111-111111111113}
ProductLanguage 1033
ProductName MyProduct
ProductVersion 0.0.0
Thoughts
I'm still unsure whether this is actually an issue in the rust-msi crate or the rust-cfb crate, though I'm leaning towards the former. I tries parsing through the data using a CFB parser I made in 010 Editor to see if I could find where the encoding is going wrong while comparing it to the unchanged Schema.msi, and while there aren't that many differences, nothing too obvious stuck out.
I figured I would ask here before I continued any further to see if you had any insight as to what might be happening. If not I'll have to continue trying to reverse engineer how the StringPool and table information is laid out in the CFB streams since I could only find the CFB and PropertySet documents and couldn't find any documentation that mentions StringPools at all on Microsoft's end.