@@ -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,92 @@ 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
+ // patching type_of_loader @0x210
59
+ buf[ 0x210 ] = 0xb0 ;
60
+
61
+ // patching loadflags @0x211
62
+ buf[ 0x211 ] = 0x81 ;
63
+
64
+ //patching heap_end_ptr @0x224 cmdline_addr - real_addr - 0x200 = 0xfe00
65
+ buf[ 0x224 ] = 0x00 ;
66
+ buf[ 0x225 ] = 0xfe ;
67
+
68
+ //patching cmd_line_ptr @0x228 cmdline_addr = 0x20000
69
+ buf[ 0x228 ] = 0x00 ;
70
+ buf[ 0x229 ] = 0x00 ;
71
+ buf[ 0x22A ] = 0x02 ;
72
+
73
+ let mut hasher = sha2:: Sha384 :: new ( ) ;
74
+ let image = buf. clone ( ) ;
75
+ let ( number_of_region_entry, regions_base, regions_size) = get_image_regions ( image) ;
76
+
77
+ for index in 0 ..number_of_region_entry {
78
+ hasher. update ( & buf[ regions_base[ index] ..regions_base[ index] + regions_size[ index] ] ) ;
79
+ }
80
+
81
+ let res = hasher. finalize ( ) ;
82
+ Ok ( hex:: encode ( res) )
83
+ }
84
+
85
+ fn get_image_regions ( buf : Vec < u8 > ) -> ( usize , Vec < usize > , Vec < usize > ) {
86
+ // These 3 regions are known.
87
+ let mut number_of_region_entry = 3 ;
88
+ let mut regions_base = vec ! [
89
+ IMGAE_BEGIN_CHECKSUM_ADDR ,
90
+ IMGAE_CERT_TABLE_ADDR ,
91
+ IMGAE_HEADERS_ADDR ,
92
+ ] ;
93
+ let mut regions_size = vec ! [
94
+ IMGAE_BEGIN_CHECKSUM_SIZE ,
95
+ IMGAE_CERT_TABLE_SIZE ,
96
+ IMGAE_HEADERS_SIZE ,
97
+ ] ;
98
+
99
+ // Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image,
100
+ // After the signature of an image file is COFF File Header
101
+ // the NumberOfSections' offset is 2
102
+ let coff_file_header_offset = ( ( buf[ IMAGE_PE_OFFSET + 3 ] as u32 ) << 24 )
103
+ | ( ( buf[ IMAGE_PE_OFFSET + 2 ] as u32 ) << 16 )
104
+ | ( ( buf[ IMAGE_PE_OFFSET + 1 ] as u32 ) << 8 )
105
+ | ( buf[ IMAGE_PE_OFFSET ] as u32 ) + PE_SIGNATURE_SIZE ;
106
+ let number_of_pecoff_entry = buf[ coff_file_header_offset as usize + 2 ] ;
107
+ number_of_region_entry += number_of_pecoff_entry as usize ;
108
+
109
+ // Refer to https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers
110
+ // SizeOfRawData Offset: 16 Size:4
111
+ // PointerToRawData Offset: 20 Size:4
112
+ // SizeOfSection Size:40
113
+ let mut p = IMGAE_HEADERS_ADDR + 8 ;
114
+ for _i in 0 ..number_of_pecoff_entry {
115
+ p += 16 ;
116
+ let size = ( ( buf[ p + 3 ] as u32 ) << 24 )
117
+ | ( ( buf[ p + 2 ] as u32 ) << 16 )
118
+ | ( ( buf[ p + 1 ] as u32 ) << 8 )
119
+ | buf[ p] as u32 ;
120
+ p += 4 ;
121
+ let base = ( ( buf[ p + 3 ] as u32 ) << 24 )
122
+ | ( ( buf[ p + 2 ] as u32 ) << 16 )
123
+ | ( ( buf[ p + 1 ] as u32 ) << 8 )
124
+ | buf[ p] as u32 ;
125
+ regions_base. push ( base as usize ) ;
126
+ regions_size. push ( size as usize ) ;
127
+ p += 20 ;
128
+ }
129
+ ( number_of_region_entry, regions_base, regions_size)
130
+ }
131
+
34
132
fn padding_digest ( mut buf : Vec < u8 > , len : usize ) -> Result < String > {
35
133
let diff = len - buf. len ( ) ;
36
134
@@ -56,7 +154,8 @@ fn main() {
56
154
. required ( false )
57
155
. default_value ( KERNEL_SIZE )
58
156
. action ( ArgAction :: Set ) ,
59
- ) ,
157
+ )
158
+ . arg ( arg ! ( -q --"qemu" "QEMU Kernel Direct Boot patch string" ) . required ( false ) ) ,
60
159
)
61
160
. subcommand (
62
161
command ! ( "param" )
@@ -78,7 +177,12 @@ fn main() {
78
177
Some ( ( "kernel" , args) ) => {
79
178
let path = args. get_one :: < String > ( "kernel" ) . unwrap ( ) ;
80
179
let siz = args. get_one :: < String > ( "size" ) . unwrap ( ) ;
81
- kernel ( path, siz)
180
+ // let qflag = args.get_one::<String>("qemu").unwrap();
181
+ if args. get_flag ( "qemu" ) {
182
+ qemu ( path, siz)
183
+ } else {
184
+ kernel ( path, siz)
185
+ }
82
186
}
83
187
Some ( ( "param" , args) ) => {
84
188
let parameter = args. get_one :: < String > ( "parameter" ) . unwrap ( ) ;
0 commit comments