1212 * MIT License
1313 *
1414 */
15- #include <stdio.h>
16- #include <malloc.h>
17- #include <string.h>
18- #include <stdint.h>
19- #include <errno.h>
20- #include "patcher.h"
15+
16+ #include "utils.h"
2117
2218/**
2319 * The main function will check and read given files,
3127 */
3228int main (int argc , char * argv []) {
3329 // Print hello message.
34- printf ("WOA-msmnile DualBoot Kernel Image Patcher v1.1 .0.0\n" );
30+ printf ("WOA-msmnile DualBoot Kernel Image Patcher v1.2 .0.0\n" );
3531 printf ("Copyright (c) 2021-2024 The DuoWoA authors\n\n" );
3632 if (argc != 6 ) {
3733 // Print usage if arg numbers not meet.
@@ -96,92 +92,7 @@ int main(int argc, char *argv[]) {
9692
9793 // Print end message.
9894 printf ("Image successfully patched.\n" );
99- printf ("Please find the newly made kernel image at %s.\n" , outputImage .filePath );
100- return 0 ;
101- }
102-
103- /**
104- * Get file size based on given fileContent.
105- *
106- * @param fileContent provide filePath, will also set fileSize in it.
107- * @retval 0 File does not exist.
108- * @retval size_t File size
109- *
110- */
111- size_t get_file_size (FileContent * fileContent ) {
112- FILE * pFile = fopen (fileContent -> filePath , "r" );
113- if (pFile == NULL ) {
114- printf ("Error: %s not found\n" , fileContent -> filePath );
115- return 0 ;
116- }
117- fseek (pFile , 0 , SEEK_END );
118- size_t len = ftell (pFile );
119- fclose (pFile );
120- fileContent -> fileSize = len ;
121- return len ;
122- }
123-
124- /**
125- * Read File buffer based on given fileContent.
126- *
127- * @param fileContent provide filePath, will also set fileBuffer in it.
128- * @return Buffer read from file.
129- */
130- uint8_t * read_file_content (FileContent * fileContent ) {
131- if (fileContent -> fileBuffer == NULL )
132- return NULL ;
133- FILE * pFile = fopen (fileContent -> filePath , "rb" );
134- if (pFile == NULL )
135- return NULL ;
136- fread (fileContent -> fileBuffer , fileContent -> fileSize , 1 , pFile );
137- fclose (pFile );
138- return fileContent -> fileBuffer ;
139- }
140-
141- /**
142- * Write buffer to filePath given by fileContent.
143- *
144- * @param fileContent Contains file information.
145- * @retval -EBADF Failed to write file
146- *
147- */
148- int write_file_content (pFileContent fileContent ) {
149- FILE * pFile = fopen (fileContent -> filePath , "wb" );
150- if (pFile == NULL )
151- return - EBADF ;
152- fwrite (fileContent -> fileBuffer , fileContent -> fileSize , 1 , pFile );
153- fclose (pFile );
154- return 0 ;
155- }
156-
157- /**
158- * Parse given config.
159- *
160- * @param fileContent
161- * @param config Config info read from config file
162- * @retval -EINVAL Give File not found.
163- *
164- */
165- int parse_config (FileContent * fileContent , pConfig config ) {
166- // Check file size
167- if (!get_file_size (fileContent ))
168- return - EINVAL ;
169-
170- // Open config file
171- FILE * pConfigFile = fopen (fileContent -> filePath , "r" );
172- char key [256 ];
173- uint32_t value = 0 ;
174-
175- // Parse
176- while (fscanf (pConfigFile , "%[^=]=%x\n" , key , & value ) != EOF ) {
177- if (strcmp (key , "StackBase" ) == 0 ) {
178- config -> StackBase = value ;
179- } else if (strcmp (key , "StackSize" ) == 0 ) {
180- config -> StackSize = value ;
181- }
182- }
183-
184- fclose (pConfigFile );
95+ printf ("Please check the patched kernel image at %s.\n" , outputImage .filePath );
18596 return 0 ;
18697}
18798
@@ -209,7 +120,7 @@ uint8_t *PatchKernel(pFileContent kernel, pFileContent uefi, pFileContent shellC
209120 memcpy (patchedKernel -> fileBuffer + kernel -> fileSize , uefi -> fileBuffer , uefi -> fileSize );
210121
211122 // Check ShellCode binary magic.
212- if (uefi -> fileSize > 0x40 && strcmp ((char * ) (shellCode -> fileBuffer + 8 ), "SHLLCOD" ) != 0 ) {
123+ if (shellCode -> fileSize > 0x40 && strcmp ((char * ) (shellCode -> fileBuffer + 8 ), "SHLLCOD" ) != 0 ) {
213124 printf ("Error: shell code binary format not recognize.\n" );
214125 return NULL ;
215126 }
@@ -224,45 +135,65 @@ uint8_t *PatchKernel(pFileContent kernel, pFileContent uefi, pFileContent shellC
224135 hasHeader |= 0b1 ;
225136 }
226137
227- // Check if kernel size % 0x10 == 0, which will cause copy loop issue.
228- if (kernel -> fileSize % 0x10 != 0 ) {
138+ // Check if kernel size % 0x10 == 0, which will cause copy loop(in shellcode) issue.
139+ if (kernel -> fileSize % 0x10 ) {
229140 printf ("Align kernel size to 0x10.\n" );
141+
142+ // Calculate align padding
143+ uint8_t padding = 0x10 - (kernel -> fileSize % 0x10 );
144+
145+ // New kernel size and output size
146+ kernel -> fileSize += padding ;
147+ patchedKernel -> fileSize += padding ;
148+
230149 // Reallocate patched kernel.
231- void * ptr = realloc (patchedKernel -> fileBuffer , patchedKernel -> fileSize + ( kernel -> fileSize % 10 ) );
150+ void * ptr = realloc (patchedKernel -> fileBuffer , patchedKernel -> fileSize );
232151 if (ptr == NULL ) {
233152 printf ("Failed to reallocate patched kernel buffer." );
234153 return NULL ;
235154 } else patchedKernel -> fileBuffer = ptr ;
236- // Copy uefi image to 0x10 align place.
237- uint8_t padding = 0x10 - (kernel -> fileSize % 0x10 );
238- memmove (patchedKernel -> fileBuffer + kernel -> fileSize + padding ,
239- patchedKernel -> fileBuffer + kernel -> fileSize , uefi -> fileSize );
240- kernel -> fileSize += padding ;
241- patchedKernel -> fileSize += padding ;
242- }
243155
244- // Check if kernel has EFI Stub, 4D5A0091, "MZ"
245- // Note: This magic is part of kernel
246- // We wil rewrite file header here.
247- // For kernel with EFI stub, we only need to patch the efi header.
248- memcpy (kernelHeader , kernel -> fileBuffer , 0x4 );
249- if (* (uint32_t * ) kernelHeader == 0x91005A4D ) {
250- printf ("Kernel has EFI header.\n" );
251- hasHeader |= 0b10 ;
156+ // Copy uefi image to 0x10 align place and fill padding part to 0.
157+ if (hasHeader & 0b1 ) // Kernel has header, need to add 0x14 offset while copying.
158+ {
159+ memmove (patchedKernel -> fileBuffer + kernel -> fileSize + 0x14 ,
160+ patchedKernel -> fileBuffer + kernel -> fileSize - padding + 0x14 , uefi -> fileSize );
161+ memset (patchedKernel -> fileBuffer + kernel -> fileSize - padding + 0x14 , 0 , padding );
162+ } else {
163+ memmove (patchedKernel -> fileBuffer + kernel -> fileSize ,
164+ patchedKernel -> fileBuffer + kernel -> fileSize - padding , uefi -> fileSize );
165+ memset (patchedKernel -> fileBuffer + kernel -> fileSize - padding , 0 , padding );
166+ }
252167 }
253168
254169 // Kernel has uncompressed_img header,
255- if (hasHeader & 1 )
170+ if (hasHeader & 1 )
256171 // Move our pointer after UNCOMPRESSED_IMG header before further processing,
257172 patchedKernel -> fileBuffer += 0x14 ;
258173
174+ /* Reserved for feature use */
175+ // Check if kernel was already patched.
176+ // if config in kernel was same with the config provided here,
177+ // set kernel size to previous kernel size. (which skipped copying previously uefi fd)
178+ // if (*(uint64_t *) (kernel->fileBuffer + 0x20) == config->StackBase &&
179+ // *(uint64_t *) (kernel->fileBuffer + 0x28) == config->StackSize) {
180+ // printf("Kernel was already patched previously!\n"
181+ // "Re-patching with new UEFI...\n");
182+ // kernel->fileSize = *(uint64_t *) (kernel->fileBuffer + 0x30);
183+ // patchedKernel->fileSize = kernel->fileSize + uefi->fileSize; // Update output kernel size
184+ // printf("Old kernel size %llx\n", *(uint64_t *) (kernel->fileBuffer + 0x30));
185+ // hasHeader |= 0b10;
186+ // }
187+
259188 // Determine the loading offset of the kernel first,
260189 // we are either going to find a b instruction on the
261190 // first instruction or the second one. First is problematic,
262191 // second is fine.
263192
264193 // 0x14 is AArch64 b opcode
265- if (patchedKernel -> fileBuffer [3 ] == 0x14 ) {
194+ // If Code1 is jump instruction, the kernel is an original kernel or a patched kernel.
195+ // However, if Code2 is also jump instruction, the kernel should be a patched kernel.
196+ if (patchedKernel -> fileBuffer [3 ] == 0x14 && patchedKernel -> fileBuffer [7 ] != 0x14 ) {
266197 // For kernel without EFI stub, we have to move the jump kernel instruction forward to Code2.
267198 // We have a branch instruction first, we need to fix things a bit.
268199
@@ -282,8 +213,21 @@ uint8_t *PatchKernel(pFileContent kernel, pFileContent uefi, pFileContent shellC
282213 patchedKernel -> fileBuffer [5 ] = offsetInstructionBuffer [1 ];
283214 patchedKernel -> fileBuffer [6 ] = offsetInstructionBuffer [2 ];
284215 patchedKernel -> fileBuffer [7 ] = 0x14 ;
285- }
286- else if (patchedKernel -> fileBuffer [7 ] != 0x14 ) {
216+ } else // Patched Kernel
217+ if (patchedKernel -> fileBuffer [3 ] == 0x14 && patchedKernel -> fileBuffer [7 ] == 0x14 ) {
218+ printf ("Patched kernel detected, redo patch with new fd.\n" );
219+ kernel -> fileSize = * (uint64_t * ) (kernel -> fileBuffer + 0x30 );
220+ patchedKernel -> fileSize = kernel -> fileSize + uefi -> fileSize ; // Update output kernel size
221+ } else // Kernel with EFI Stub
222+ if (* (uint16_t * ) (patchedKernel -> fileBuffer ) == 0x5A4D && patchedKernel -> fileBuffer [7 ] == 0x14 ) {
223+ // Check if kernel has EFI Stub, 4D5A, "MZ"
224+ // Note:
225+ // The magic is also an arm64 instruction, and the second instruction jump to kernel.
226+ // We will only rewrite EFI header here. (This will break the kernel)
227+ // For kernel with EFI stub, we only need to patch the efi header.
228+ printf ("Kernel has EFI header.\n" );
229+ } else // Unknown stuff
230+ if (patchedKernel -> fileBuffer [7 ] != 0x14 ) {
287231 // There is no branch instruction!
288232 printf ("Error: Invalid Kernel Image. Branch instruction not found within first two instruction slots.\n" );
289233 return NULL ;
0 commit comments