@@ -14,6 +14,18 @@ use std::{convert::TryFrom, path::Path};
14
14
pub const KERNEL_SIZE : & str = "0x2000000" ;
15
15
pub const KERNEL_PARAM_SIZE : & str = "0x1000" ;
16
16
17
+ // Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#signature-image-only,
18
+ // file offset specified at offset 0x3c,
19
+ // size of PE signature is 4: "PE\0\0"
20
+ const IMAGE_PE_OFFSET : usize = 0x003c ;
21
+ const PE_SIGNATURE_SIZE : u32 = 4 ;
22
+ const IMGAE_BEGIN_CHECKSUM_ADDR : usize = 0x0000 ;
23
+ const IMGAE_BEGIN_CHECKSUM_SIZE : usize = 0x00da ;
24
+ const IMGAE_CERT_TABLE_ADDR : usize = 0x00de ;
25
+ const IMGAE_CERT_TABLE_SIZE : usize = 0x004c ;
26
+ const IMGAE_HEADERS_ADDR : usize = 0x0132 ;
27
+ const IMGAE_HEADERS_SIZE : usize = 0x00ce ;
28
+
17
29
fn kernel ( path : & str , size : & str ) -> Result < String > {
18
30
let path = Path :: new ( path) . to_path_buf ( ) ;
19
31
let siz = parse :: < u64 > ( size) ?;
@@ -31,6 +43,106 @@ fn param(param: &str, size: &str) -> Result<String> {
31
43
padding_digest ( param, siz)
32
44
}
33
45
46
+ fn qemu ( path : & str , size : & str ) -> Result < String > {
47
+ let path = Path :: new ( path) . to_path_buf ( ) ;
48
+ let siz = parse :: < u64 > ( size) ?;
49
+ let file_size = std:: fs:: metadata ( & path) ?. len ( ) ;
50
+ if file_size > siz {
51
+ bail ! ( "File size should be less than `kernel-size`" ) ;
52
+ }
53
+ let buf = std:: fs:: read ( path) ?;
54
+ qemu_patch ( buf)
55
+ }
56
+
57
+ fn qemu_patch ( mut buf : Vec < u8 > ) -> Result < String > {
58
+ // refer to https://github.com/qemu/qemu/blob/f48c205fb42be48e2e47b7e1cd9a2802e5ca17b0/hw/i386/x86.c#L999
59
+ // patching type_of_loader @0x210
60
+ buf[ 0x210 ] = 0xb0 ;
61
+
62
+ // refer to https://github.com/qemu/qemu/blob/f48c205fb42be48e2e47b7e1cd9a2802e5ca17b0/hw/i386/x86.c#L1003
63
+ // patching loadflags @0x211
64
+ buf[ 0x211 ] = 0x81 ;
65
+
66
+ // refer to https://github.com/qemu/qemu/blob/9c74490bff6c8886a922008d0c9ce6cae70dd17e/hw/i386/x86.c#L1004
67
+ // patching heap_end_ptr @0x224 cmdline_addr - real_addr - 0x200 = 0xfe00
68
+ buf[ 0x224 ] = 0x00 ;
69
+ buf[ 0x225 ] = 0xfe ;
70
+
71
+ // refer to https://github.com/qemu/qemu/blob/9c74490bff6c8886a922008d0c9ce6cae70dd17e/hw/i386/x86.c#L962
72
+ // patching cmd_line_ptr @0x228 cmdline_addr = 0x20000
73
+ buf[ 0x228 ] = 0x00 ;
74
+ buf[ 0x229 ] = 0x00 ;
75
+ buf[ 0x22A ] = 0x02 ;
76
+ buf[ 0x22B ] = 0x00 ;
77
+
78
+ let mut hasher = sha2:: Sha384 :: new ( ) ;
79
+ let ( number_of_region_entry, regions_base, regions_size) = get_image_regions ( & buf) ;
80
+
81
+ for index in 0 ..number_of_region_entry {
82
+ hasher. update ( & buf[ regions_base[ index] ..regions_base[ index] + regions_size[ index] ] ) ;
83
+ }
84
+
85
+ let res = hasher. finalize ( ) ;
86
+ Ok ( hex:: encode ( res) )
87
+ }
88
+
89
+ fn get_image_regions ( buf : & [ u8 ] ) -> ( usize , Vec < usize > , Vec < usize > ) {
90
+ // These 3 regions are known.
91
+ let mut number_of_region_entry = 3 ;
92
+ let mut regions_base = vec ! [
93
+ IMGAE_BEGIN_CHECKSUM_ADDR ,
94
+ IMGAE_CERT_TABLE_ADDR ,
95
+ IMGAE_HEADERS_ADDR ,
96
+ ] ;
97
+ let mut regions_size = vec ! [
98
+ IMGAE_BEGIN_CHECKSUM_SIZE ,
99
+ IMGAE_CERT_TABLE_SIZE ,
100
+ IMGAE_HEADERS_SIZE ,
101
+ ] ;
102
+
103
+ // Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image,
104
+ // After the signature of an image file is COFF File Header, size is 20 bytes.
105
+ // the NumberOfSections' offset is 2 and size is 2 bytes.
106
+ let size_of_coff_file_header: u32 = 20 ;
107
+
108
+ let coff_file_header_offset = ( ( buf[ IMAGE_PE_OFFSET + 3 ] as u32 ) << 24 )
109
+ | ( ( buf[ IMAGE_PE_OFFSET + 2 ] as u32 ) << 16 )
110
+ | ( ( buf[ IMAGE_PE_OFFSET + 1 ] as u32 ) << 8 )
111
+ | ( buf[ IMAGE_PE_OFFSET ] as u32 ) + PE_SIGNATURE_SIZE ;
112
+
113
+ let number_of_pecoff_entry = ( ( buf[ coff_file_header_offset as usize + 3 ] as u16 ) << 8 )
114
+ | buf[ coff_file_header_offset as usize + 2 ] as u16 ;
115
+ number_of_region_entry += number_of_pecoff_entry as usize ;
116
+
117
+ // the SizeOfOptionalHeader's offset is 16 and size is 2 bytes
118
+ let size_of_optional_header = ( ( buf[ coff_file_header_offset as usize + 17 ] as u16 ) << 8 )
119
+ | buf[ coff_file_header_offset as usize + 16 ] as u16 ;
120
+
121
+ // Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
122
+ // Size Of each Section is 40 bytes
123
+ // SizeOfRawData Offset: 16 Size:4
124
+ // PointerToRawData Offset: 20 Size:4
125
+ let mut p = ( coff_file_header_offset
126
+ + size_of_coff_file_header
127
+ + size_of_optional_header as u32 ) as usize ;
128
+ for _i in 0 ..number_of_pecoff_entry {
129
+ p += 16 ;
130
+ let size = ( ( buf[ p + 3 ] as u32 ) << 24 )
131
+ | ( ( buf[ p + 2 ] as u32 ) << 16 )
132
+ | ( ( buf[ p + 1 ] as u32 ) << 8 )
133
+ | buf[ p] as u32 ;
134
+ p += 4 ;
135
+ let base = ( ( buf[ p + 3 ] as u32 ) << 24 )
136
+ | ( ( buf[ p + 2 ] as u32 ) << 16 )
137
+ | ( ( buf[ p + 1 ] as u32 ) << 8 )
138
+ | buf[ p] as u32 ;
139
+ regions_base. push ( base as usize ) ;
140
+ regions_size. push ( size as usize ) ;
141
+ p += 20 ;
142
+ }
143
+ ( number_of_region_entry, regions_base, regions_size)
144
+ }
145
+
34
146
fn padding_digest ( mut buf : Vec < u8 > , len : usize ) -> Result < String > {
35
147
let diff = len - buf. len ( ) ;
36
148
@@ -56,7 +168,8 @@ fn main() {
56
168
. required ( false )
57
169
. default_value ( KERNEL_SIZE )
58
170
. action ( ArgAction :: Set ) ,
59
- ) ,
171
+ )
172
+ . arg ( arg ! ( -q --"qemu" "QEMU Kernel Direct Boot patch string" ) . required ( false ) ) ,
60
173
)
61
174
. subcommand (
62
175
command ! ( "param" )
@@ -78,7 +191,12 @@ fn main() {
78
191
Some ( ( "kernel" , args) ) => {
79
192
let path = args. get_one :: < String > ( "kernel" ) . unwrap ( ) ;
80
193
let siz = args. get_one :: < String > ( "size" ) . unwrap ( ) ;
81
- kernel ( path, siz)
194
+ // let qflag = args.get_one::<String>("qemu").unwrap();
195
+ if args. get_flag ( "qemu" ) {
196
+ qemu ( path, siz)
197
+ } else {
198
+ kernel ( path, siz)
199
+ }
82
200
}
83
201
Some ( ( "param" , args) ) => {
84
202
let parameter = args. get_one :: < String > ( "parameter" ) . unwrap ( ) ;
0 commit comments