1use super::*;
2use metadata::*;
3use std::mem::*;
4
5pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> Vec<u8> {
6 if [tables.len(), strings.len(), blobs.len()].iter().any(|len| *len > u32::MAX as usize) {
7 panic!("heap too large");
8 }
9
10 unsafe {
11 let mut guids = vec![0; 16]; // zero guid
12 let size_of_streams = tables.len() + guids.len() + strings.len() + blobs.len();
13
14 let mut dos: IMAGE_DOS_HEADER = zeroed();
15 dos.e_magic = IMAGE_DOS_SIGNATURE;
16 dos.e_lfarlc = 64;
17 dos.e_lfanew = size_of::<IMAGE_DOS_HEADER>() as i32;
18
19 let mut file: IMAGE_FILE_HEADER = zeroed();
20 file.Machine = IMAGE_FILE_MACHINE_I386;
21 file.NumberOfSections = 1;
22 file.SizeOfOptionalHeader = size_of::<IMAGE_OPTIONAL_HEADER32>() as u16;
23 file.Characteristics = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE;
24
25 let mut optional: IMAGE_OPTIONAL_HEADER32 = zeroed();
26 optional.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
27 optional.MajorLinkerVersion = 11;
28 optional.SizeOfInitializedData = 1024;
29 optional.ImageBase = 0x400000;
30 optional.SectionAlignment = SECTION_ALIGNMENT;
31 optional.FileAlignment = 512;
32 optional.MajorOperatingSystemVersion = 6;
33 optional.MinorOperatingSystemVersion = 2;
34 optional.MajorSubsystemVersion = 6;
35 optional.MinorSubsystemVersion = 2;
36 optional.SizeOfHeaders = 512;
37 optional.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
38 optional.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
39 optional.SizeOfStackReserve = 0x100000;
40 optional.SizeOfHeapReserve = 4096;
41 optional.LoaderFlags = 0x100000;
42 optional.NumberOfRvaAndSizes = 16;
43
44 let mut section: IMAGE_SECTION_HEADER = zeroed();
45 section.Name = *b".text\0\0\0";
46 section.Characteristics = 0x4000_0020;
47 section.VirtualAddress = SECTION_ALIGNMENT;
48
49 let mut clr: IMAGE_COR20_HEADER = zeroed();
50 clr.cb = size_of::<IMAGE_COR20_HEADER>() as u32;
51 clr.MajorRuntimeVersion = 2;
52 clr.MinorRuntimeVersion = 5;
53 clr.Flags = 1;
54
55 let metadata = METADATA_HEADER {
56 signature: METADATA_SIGNATURE,
57 major_version: 1,
58 minor_version: 1,
59 length: 20,
60 version: *b"WindowsRuntime 1.4\0\0",
61 streams: 4,
62 ..Default::default()
63 };
64
65 type TablesHeader = StreamHeader<4>;
66 type StringsHeader = StreamHeader<12>;
67 type GuidsHeader = StreamHeader<8>;
68 type BlobsHeader = StreamHeader<8>;
69
70 let size_of_stream_headers = size_of::<TablesHeader>() + size_of::<StringsHeader>() + size_of::<GuidsHeader>() + size_of::<BlobsHeader>();
71 let size_of_image = optional.FileAlignment as usize + size_of::<IMAGE_COR20_HEADER>() + size_of::<METADATA_HEADER>() + size_of_stream_headers + size_of_streams;
72
73 optional.SizeOfImage = round(size_of_image, optional.SectionAlignment as usize) as u32;
74 section.Misc.VirtualSize = size_of_image as u32 - optional.FileAlignment;
75 section.SizeOfRawData = round(section.Misc.VirtualSize as usize, optional.FileAlignment as usize) as u32;
76
77 optional.DataDirectory[14] = IMAGE_DATA_DIRECTORY { VirtualAddress: SECTION_ALIGNMENT, Size: size_of::<IMAGE_COR20_HEADER>() as u32 };
78 section.PointerToRawData = optional.FileAlignment;
79 clr.MetaData.VirtualAddress = SECTION_ALIGNMENT + size_of::<IMAGE_COR20_HEADER>() as u32;
80 clr.MetaData.Size = section.Misc.VirtualSize - size_of::<IMAGE_COR20_HEADER>() as u32;
81
82 let mut buffer = Vec::<u8>::new();
83
84 buffer.write_header(&dos);
85 buffer.write_u32(IMAGE_NT_SIGNATURE);
86 buffer.write_header(&file);
87 buffer.write_header(&optional);
88 buffer.write_header(&section);
89 debug_assert!(buffer.len() < optional.FileAlignment as usize);
90 buffer.resize(optional.FileAlignment as usize, 0);
91 buffer.write_header(&clr);
92 let metadata_offset = buffer.len();
93 buffer.write_header(&metadata);
94
95 let stream_offset = buffer.len() - metadata_offset + size_of_stream_headers;
96 let tables_header = TablesHeader::new(stream_offset as u32, tables.len() as u32, b"#~\0\0");
97 let strings_header = StringsHeader::new(tables_header.next_offset(), strings.len() as u32, b"#Strings\0\0\0\0");
98 let guids_header = GuidsHeader::new(strings_header.next_offset(), guids.len() as u32, b"#GUID\0\0\0");
99 let blobs_header = BlobsHeader::new(guids_header.next_offset(), blobs.len() as u32, b"#Blob\0\0\0");
100
101 buffer.write_header(&tables_header);
102 buffer.write_header(&strings_header);
103 buffer.write_header(&guids_header);
104 buffer.write_header(&blobs_header);
105
106 buffer.append(&mut tables);
107 buffer.append(&mut strings);
108 buffer.append(&mut guids);
109 buffer.append(&mut blobs);
110
111 assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset);
112 assert_eq!(size_of_image, buffer.len());
113
114 buffer
115 }
116}
117
118const SECTION_ALIGNMENT: u32 = 4096;
119
120#[repr(C)]
121struct StreamHeader<const LEN: usize> {
122 offset: u32,
123 size: u32,
124 name: [u8; LEN],
125}
126
127impl<const LEN: usize> StreamHeader<LEN> {
128 fn new(offset: u32, size: u32, name: &[u8; LEN]) -> Self {
129 Self { offset, size, name: *name }
130 }
131 fn next_offset(&self) -> u32 {
132 self.offset + self.size
133 }
134}
135