1 | use super::*; |
2 | use metadata::*; |
3 | use std::mem::*; |
4 | |
5 | pub 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(§ion); |
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 | |
118 | const SECTION_ALIGNMENT: u32 = 4096; |
119 | |
120 | #[repr (C)] |
121 | struct StreamHeader<const LEN: usize> { |
122 | offset: u32, |
123 | size: u32, |
124 | name: [u8; LEN], |
125 | } |
126 | |
127 | impl<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 | |