use dotscope::{
metadata::{
signatures::TypeSignature,
tables::{CodedIndex, CodedIndexType, FieldAttributes, TableId, TypeAttributes},
},
prelude::*,
CilAssembly, CilAssemblyView,
};
use std::{env, path::Path};
fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
if args.len() < 3 {
eprintln!("Usage: {} <source-assembly> <output-assembly>", args[0]);
eprintln!();
eprintln!("This example demonstrates comprehensive .NET assembly modification:");
eprintln!(" - Adding strings, blobs, GUIDs, and user strings to heaps");
eprintln!(" - Using high-level builder APIs for type and method creation");
eprintln!(" - Adding native imports for P/Invoke scenarios");
eprintln!(" - Validating changes and writing modified assembly");
eprintln!();
eprintln!("Example:");
eprintln!(" {} input.dll modified.dll", args[0]);
return Ok(());
}
let source_path = Path::new(&args[1]);
let output_path = Path::new(&args[2]);
println!(".NET Assembly Modification Tool");
println!("Source: {}", source_path.display());
println!("Output: {}", output_path.display());
println!();
println!("Loading assembly for modification...");
let view = match CilAssemblyView::from_path(source_path) {
Ok(view) => view,
Err(e) => {
eprintln!("x Failed to load assembly: {e}");
eprintln!();
eprintln!("Common causes:");
eprintln!(" - File is not a valid .NET assembly");
eprintln!(" - File is corrupted or in an unsupported format");
eprintln!(" - Insufficient permissions to read the file");
return Err(e);
}
};
let mut assembly = CilAssembly::new(view);
println!(" Assembly loaded successfully");
println!();
println!("HEAP MODIFICATIONS");
println!("==================");
println!("Adding strings to #Strings heap...");
let hello_ref = assembly.string_add("Hello from modified assembly!")?;
let _debug_ref = assembly.string_add("DEBUG_MODIFIED")?;
let _version_ref = assembly.string_add("v2.0.0-modified")?;
println!(" Queued 3 strings for addition");
println!("Adding blobs to #Blob heap...");
let signature_blob = vec![0x07, 0x01, 0x0E]; let custom_data_blob = vec![0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE];
let _signature_ref = assembly.blob_add(&signature_blob)?;
let _custom_data_ref = assembly.blob_add(&custom_data_blob)?;
println!(" Queued 2 blobs for addition");
println!("Adding GUIDs to #GUID heap...");
let module_guid = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88,
];
let type_guid = [
0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x07, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x8F,
0x90,
];
let _module_guid_ref = assembly.guid_add(&module_guid)?;
let _type_guid_ref = assembly.guid_add(&type_guid)?;
println!(" Queued 2 GUIDs for addition");
println!("Adding user strings to #US heap...");
let _user_message_ref = assembly.userstring_add("This assembly has been modified!")?;
let _user_warning_ref = assembly.userstring_add("WARNING: MODIFIED ASSEMBLY")?;
println!(" Queued 2 user strings for addition");
println!();
println!("NATIVE IMPORT MANAGEMENT");
println!("========================");
println!("Adding native DLL imports...");
assembly.add_native_import_dll("kernel32.dll")?;
assembly.add_native_import_dll("user32.dll")?;
assembly.add_native_import_dll("advapi32.dll")?;
println!(" Added kernel32.dll, user32.dll, advapi32.dll");
println!("Adding native function imports...");
assembly.add_native_import_function("kernel32.dll", "GetCurrentProcessId")?;
assembly.add_native_import_function("kernel32.dll", "ExitProcess")?;
assembly.add_native_import_function("user32.dll", "MessageBoxW")?;
assembly.add_native_import_function("advapi32.dll", "RegOpenKeyExW")?;
println!(" Added 4 function imports");
println!("Adding ordinal-based imports...");
assembly.add_native_import_function_by_ordinal("user32.dll", 120)?;
println!(" Added ordinal import (120 from user32.dll)");
println!();
println!("METADATA TABLE OPERATIONS (Using Builder APIs)");
println!("===============================================");
println!("Creating assembly reference for System.Runtime...");
let system_runtime_ref = AssemblyRefBuilder::new()
.name("System.Runtime")
.version(8, 0, 0, 0)
.public_key_token(&[0xb0, 0x3f, 0x5f, 0x7f, 0x11, 0xd5, 0x0a, 0x3a])
.build(&mut assembly)?;
println!(" Created System.Runtime reference");
println!("Creating type reference for System.Object...");
let object_typeref = TypeRefBuilder::new()
.name("Object")
.namespace("System")
.resolution_scope(CodedIndex::new(
TableId::AssemblyRef,
system_runtime_ref.placeholder(),
CodedIndexType::ResolutionScope,
))
.build(&mut assembly)?;
println!(" Created System.Object reference");
println!("Adding new type 'DotScopeModifiedClass'...");
let new_type_ref = TypeDefBuilder::new()
.name("DotScopeModifiedClass")
.namespace("DotScope.Generated")
.flags(TypeAttributes::PUBLIC | TypeAttributes::CLASS | TypeAttributes::SEALED)
.extends(CodedIndex::new(
TableId::TypeRef,
object_typeref.placeholder(),
CodedIndexType::TypeDefOrRef,
))
.build(&mut assembly)?;
println!(
" Created type with placeholder token: {:#x}",
new_type_ref.placeholder()
);
println!("Adding field 'ModificationTimestamp'...");
let field_signature = &[0x06, 0x08]; let _field_ref = FieldBuilder::new()
.name("ModificationTimestamp")
.flags(FieldAttributes::PUBLIC | FieldAttributes::STATIC)
.signature(field_signature)
.build(&mut assembly)?;
println!(" Created static int field");
println!("Adding method 'GetModificationInfo'...");
let _method_ref = MethodBuilder::new("GetModificationInfo")
.public()
.static_method()
.returns(TypeSignature::I4)
.implementation(|body| {
body.implementation(|asm| {
asm.ldc_i4(42)? .ret()?; Ok(())
})
})
.build(&mut assembly)?;
println!(" Created static method returning int");
println!();
println!("WRITING ASSEMBLY");
println!("================");
println!("Writing modified assembly to disk...");
match assembly.to_file(output_path) {
Ok(()) => {
println!(
" Successfully wrote modified assembly to {}",
output_path.display()
);
}
Err(e) => {
eprintln!("x Failed to write assembly: {e}");
eprintln!();
eprintln!("Common write issues:");
eprintln!(" - Insufficient disk space or permissions");
eprintln!(" - Invalid output path");
eprintln!(" - PE structure generation errors");
return Err(e);
}
}
println!();
println!("VERIFICATION");
println!("============");
println!("Verifying the modified assembly can be loaded...");
let verify_view = CilAssemblyView::from_path(output_path)?;
println!(" Assembly loaded successfully");
if let Some(strings) = verify_view.strings() {
if let Some(offset) = hello_ref.offset() {
match strings.get(offset as usize) {
Ok(value) => {
let expected = "Hello from modified assembly!";
if value == expected {
println!(" ✓ Verified string at offset {:#x}: \"{}\"", offset, value);
} else {
println!(
" ✗ String mismatch at offset {:#x}: expected \"{}\", got \"{}\"",
offset, expected, value
);
}
}
Err(e) => {
println!(" ✗ Failed to read string at offset {:#x}: {}", offset, e);
}
}
} else {
println!(" ✗ String offset was not resolved after write");
}
}
if let Some(tables) = verify_view.tables() {
if let Some(typedef_table) = tables.table::<dotscope::metadata::tables::TypeDefRaw>() {
let found_type = typedef_table.iter().any(|t| {
verify_view.strings().is_some_and(|s| {
s.get(t.type_name as usize)
.is_ok_and(|name| name == "DotScopeModifiedClass")
})
});
if found_type {
println!(" Found 'DotScopeModifiedClass' type definition");
}
}
}
println!();
println!("MODIFICATION SUMMARY");
println!("====================");
println!("Successfully demonstrated:");
println!(" - String heap modifications");
println!(" - Blob heap operations");
println!(" - GUID heap management");
println!(" - User string heap operations");
println!(" - Native import additions");
println!(" - High-level builder APIs (TypeDefBuilder, FieldBuilder, MethodBuilder)");
println!(" - Modified assembly generation");
println!();
println!("NEXT STEPS");
println!("==========");
println!(" - Verify the modified assembly with tools like:");
println!(" ildasm.exe (Microsoft IL Disassembler)");
println!(" dotPeek (JetBrains .NET Decompiler)");
println!(" PEBear (PE structure analyzer)");
println!(" - Test loading the modified assembly in .NET runtime");
println!();
println!("IMPORTANT NOTES");
println!("===============");
println!(" - Modified assemblies may not load if metadata integrity is violated");
println!(" - Always validate assemblies before deployment");
println!(" - Backup original assemblies before modification");
println!(" - Some modifications may require code signing updates");
Ok(())
}