# SPDX-FileCopyrightText: 2022 Andrius Štikonas # SPDX-FileCopyrightText: 2017 Jeremiah Orians # # SPDX-License-Identifier: GPL-3.0-or-later # efi_main(void *image_handle, struct efi_system_table *system) :_start 4889E5 ; mov_rbp,rsp # save stack pointer 48890D %image_handle ; mov_[rip+DWORD],rcx %image_handle # save image_handle 4889CB ; mov_rbx,rcx # save image_handle 488B42 40 ; mov_rax,[rdx+BYTE] !64 # system->out 488905 %system_out ; mov_[rip+DWORD],rax %system_out # save system->out 4C8B72 60 ; mov_r14,[rdx+BYTE] !96 # system->boot 31C9 ; xor_ecx,ecx # timeout = 0 31D2 ; xor_edx,edx # watchdog_code = 0 4D31C0 ; xor_r8,r8 # data_size = 0 4D31C9 ; xor_r9,r9 # watchdog_data = 0 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function 41FF96 F0000000 ; call_[r14+DWORD] %240 # system->boot->set_watchdog_timer # Open Loaded Image protocol 4989D9 ; mov_r9,rbx # arg4 = image_handle 488D15 %LOADED_IMAGE_PROTOCOL ; lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL 4889D9 ; mov_rcx,rbx # arg1 = image_handle E8 %open_protocol ; call %open_protocol # open protocol 4889C7 ; mov_rdi,rax # save image 488905 %image ; mov_[rip+DWORD],rax %image # save image # Get root file system 4989D9 ; mov_r9,rbx # arg4 = image_handle 488D15 %SIMPLE_FS_PROTOCOL ; lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL 488B4F 18 ; mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device 48890D %root_device ; mov_[rip+DWORD],rcx %root_device # save root_device E8 %open_protocol ; call %open_protocol # open protocol 4889C1 ; mov_rcx,rax # get rootfs # Get root directory 488D15 %rootdir ; lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir 50 ; push_rax # allocate shadow stack space for UEFI function space for UEFI function 50 ; push_rax # allocate shadow stack space for UEFI function space for UEFI function FF51 08 ; call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack # Push command line arguments onto stack 488B5F 38 ; mov_rbx,[rdi+BYTE] !56 # options = image->load_options 4889DA ; mov_rdx,rbx # save beginning of load_options 48035F 30 ; add_rbx,[rdi+BYTE] !48 # go to the end of load_options 6A 00 ; push !0 # Save end of arguments (NULL) onto stack :loop_options 4839D3 ; cmp_rbx,rdx # Check if we are done 74 !loop_options_done ; je8 !loop_options_done # We are done 4883EB 02 ; sub_rbx, !2 # --options 8A03 ; mov_al,[rbx] # *options 3C 20 ; cmp_al, !0x20 # if *options != ' ' 75 !loop_options ; jne8 !loop_options # then continue looping C603 00 ; mov_[rbx], !0 # zero it 4883C3 02 ; add_rbx, !2 # ++options 53 ; push_rbx # push another argument onto stack EB !loop_options ; jmp8 !loop_options # next argument :loop_options_done 4158 ; pop_r8 # get input file 4D85C0 ; test_r8,r8 # Check if argument is specified 75 !arg_done ; jne8 !arg_done # then use it # Else use default_file 4C8D05 %default_file ; lea_r8,[rip+DWORD] %default_file # Use "kaem.amd64" :arg_done # Open file for reading 52 ; push_rdx # allocate stack for fin 4889E2 ; mov_rdx,rsp # arg2 = &fin 6A 01 ; push !1 # arg5 = EFI_FILE_READ_ONLY 6A 01 ; push !1 # prepare to set arg4 to EFI_FILE_MODE_READ 4159 ; pop_r9 # arg4 = EFI_FILE_MODE_READ # arg3 = in 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function FF51 08 ; call_[rcx+BYTE] !8 # rootdir->open() 85C0 ; test_eax,eax # if status != EFI_SUCCESS 0F85 %abort ; jne %abort # then exit without closing file 4C8B6424 28 ; mov_r12,[rsp+BYTE] !40 # get fin # Allocate pool for command 31D2 ; xor_edx,edx # zero RDX B6 10 ; mov_dh, !0x10 # arg2 = 4096 = 0x1000 E8 %allocate_pool ; call %allocate_pool # allocate memory 4889C3 ; mov_rbx,rax # get command :next_command 31F6 ; xor_esi,esi # i = 0 4D31FF ; xor_r15,r15 # command_length = 0 :read_command E8 %read_byte ; call %read_byte # read another byte c 3C 0A ; cmp_al, !0xa # if c == '\n' 74 !read_command_done ; je8 !read_command_done # then we are done with this command command 3C 20 ; cmp_al, !0x20 # if c == ' ' 75 !read_command_comments ; jne8 !read_command_comments 4D85FF ; test_r15,r15 # and command_length == 0 75 !read_command_comments ; jne8 !read_command_comments 4989F7 ; mov_r15,rsi # command_length = i :read_command_comments 3C 23 ; cmp_al, !0x23 # if c == '#' then process comment 75 !read_command_store_char ; jne8 !read_command_store_char # else store char :read_command_skip_comment E8 %read_byte ; call %read_byte # get another char 3C 0A ; cmp_al, !0xa # if c == '\n' 75 !read_command_skip_comment ; jne8 !read_command_skip_comment # continue reading until newline EB !next_command ; jmp8 !next_command # deal with another line :read_command_store_char 4801F3 ; add_rbx,rsi # rbx = &command[i] 668903 ; mov_[rbx],ax # command[i] = c 4829F3 ; sub_rbx,rsi # rbx = &command[0] 4883C6 02 ; add_rsi, !2 # location of the next char EB !read_command ; jmp8 !read_command # continue looping :read_command_done 4D85FF ; test_r15,r15 # if command_length == 0 74 !next_command ; je8 !next_command # deal with another line 4801F3 ; add_rbx,rsi # rbx = &command[i] 66C703 0000 ; mov_[rbx],WORD @0 # command[i] = 0 4829F3 ; sub_rbx,rsi # rbx = &command[0] 4883C6 02 ; add_rsi, !2 # add 2 to get string length with NULL terminator 488D15 %prefix ; lea_rdx,[rip+DWORD] %prefix # get prefix " +> " E8 %File_Print ; call %File_Print # print it 4889DA ; mov_rdx,rbx # get command E8 %File_Print ; call %File_Print # print it 488D15 %suffix ; lea_rdx,[rip+DWORD] %suffix # get suffix "\n\r" E8 %File_Print ; call %File_Print # print it # Remove command line options 4901DF ; add_r15,rbx # go to the space separating command and its options 6641C707 0000 ; mov_[r15],WORD @0 # zero it to hide command line options # Open executable file for reading 52 ; push_rdx # allocate stack for fcmd 4889E2 ; mov_rdx,rsp # arg2 = &fcmd 6A 01 ; push !1 # arg5 = EFI_FILE_READ_ONLY 6A 01 ; push !1 # prepare to set arg4 to EFI_FILE_MODE_READ 4159 ; pop_r9 # arg4 = EFI_FILE_MODE_READ 4989D8 ; mov_r8,rbx # arg3 = command 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function FF51 08 ; call_[rcx+BYTE] !8 # rootdir->open() 85C0 ; test_eax,eax # if status != EFI_SUCCESS 0F85 %print_error ; jne %print_error # then exit 4883C4 28 ; add_rsp, !40 # deallocate stack 5F ; pop_rdi # get fcmd # Restore command line arguments 6641C707 2000 ; mov_[r15],WORD @0x20 # restore command line options by readding ' ' # Allocate pool for file_info 31D2 ; xor_edx,edx # zero RDX B6 10 ; mov_dh, !0x10 # arg2 = 4096 = 0x1000 E8 %allocate_pool ; call %allocate pool # allocate memory 4989C1 ; mov_r9,rax # get file_info (arg4 for get_info) # Get file info 50 ; push_rax # save file_info 50 ; push_rax # allocate stack for file_size 4989E0 ; mov_r8,rsp # arg3 = &file_size 49C700 00100000 ; mov_[r8], %0x1000 # file_size = 0x1000 488D15 %FILE_INFO_PROTOCOL ; lea_rdx,[rip+DWORD] %FILE_INFO_PROTOCOL # arg2 = &EFI_FILE_INFO_PROTOCOL 4889F9 ; mov_rcx,rdi # arg1 = fcmd 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function FF51 40 ; call_[rcx+BYTE] !64 # fcmd->get_info(fcmd, &guid, &file_size, file_info) 4883C4 28 ; add_rsp, !40 # deallocate stack 59 ; pop_rcx # restore file_info 488B51 08 ; mov_rdx,[rcx+BYTE] !8 # get file_size # Free file_info pool 52 ; push_rdx # save file_size onto stack 50 ; push_rax # allocate shadow stack space for UEFI function 41FF56 48 ; call_[r14+BYTE] !72 # system->boot->free_pool(file_info) 58 ; pop_rax # deallocate stack 5A ; pop_rdx # restore file_size from stack (arg2 for allocate_pool) # Allocate pool for executable 52 ; push_rdx # save file_size onto stack E8 %allocate_pool ; call %allocate_pool # allocate memory 4989C7 ; mov_r15,rax # get executable 5A ; pop_rdx # restore file_size # Load executable into memory 52 ; push_rdx # save file_size onto stack 4D89F8 ; mov_r8,r15 # arg3 = executable 4889E2 ; mov_rdx,rsp # arg2 = &file_size 4889F9 ; mov_rcx,rdi # arg1 = fcmd 50 ; push_rax # allocate shadow stack space for UEFI 50 ; push_rax # allocate shadow stack space for UEFI 50 ; push_rax # allocate shadow stack space for UEFI FF51 20 ; call_[rcx+BYTE] !32 # fcmd->read(fcmd, &file_size, executable) 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack # Close fcmd 50 ; push_rax # allocate shadow stack space for UEFI 4889F9 ; mov_rcx,rdi # arg1 = fcmd FF51 10 ; call_[rcx+BYTE] !16 # fcmd->close(fcmd) 58 ; pop_rax # deallocate stack 5F ; pop_rdi # restore file_size # Allocate memory for device_path struct 6A 1C ; push !28 # 4 + sizeof(struct efi_device_path_protocol) 5A ; pop_rdx # arg2 = 28 E8 %allocate_pool ; call %allocate_pool # allocate memory 4989C0 ; mov_r8,rax # get device_path # Initialize struct C600 01 ; mov_[rax],BYTE !1 # device_path->type = HARDWARE_DEVICE_PATH 48FFC0 ; inc_rax # next member C600 03 ; mov_[rax],BYTE !3 # device_path->subtype = MEMORY_MAPPED 48FFC0 ; inc_rax # next member 66C700 1800 ; mov_[rax],WORD @24 # device_path->length = 24 4883C0 02 ; add_rax, !2 # next member C700 01000000 ; mov_[rax], %1 # device_path->memory_type = EFI_LOADER_CODE 4883C0 04 ; add_rax, !4 # next member 4C8938 ; mov_[rax],r15 # device_path->start_address = executable 4883C0 08 ; add_rax, !8 # next member 4901FF ; add_r15,rdi # end_address = executable + file_size 4C8938 ; mov_[rax],r15 # device_path->end_address = end_address 4929FF ; sub_r15,rdi # restore r15 = executable 4883C0 08 ; add_rax, !8 # next member C600 7F ; mov_[rax],BYTE !0x7f # device_path[1].type = END_HARDWARE_DEVICE_PATH 48FFC0 ; inc_rax # next member C600 FF ; mov_[rax],BYTE !0xff # device_path[1].subtype = END_ENTIRE_DEVICE_PATH 48FFC0 ; inc_rax # next member 66C700 0400 ; mov_[rax],WORD @4 # device_path[1].length = 4 # Load image 4150 ; push_r8 # save device_path 50 ; push_rax # allocate stack for child_ih 54 ; push_rsp # arg6 = &child_ih 57 ; push_rdi # arg5 = file size 4D89F9 ; mov_r9,r15 # arg4 = executable # arg3 = device_path 488B15 %image_handle ; mov_rdx,[rip+DWORD] %image_handle # arg2 = image_handle 31C9 ; xor_ecx,ecx # arg1 = 0 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function 41FF96 C8000000 ; call_[r14+DWORD] %200 # system->boot->load_image() 4883C4 30 ; add_rsp, !48 # deallocate stack 5F ; pop_rdi # save child_ih # Free device_path pool 59 ; pop_rcx # arg1 = device_path 50 ; push_rax # allocate shadow stack space for UEFI function 41FF56 48 ; call_[r14+BYTE] !72 # system->boot->free_pool(device_path) 58 ; pop_rax # deallocate stack # Free executable pool 4C89F9 ; mov_rcx,r15 # arg1 = executable 50 ; push_rax # allocate shadow stack space for UEFI function 41FF56 48 ; call_[r14+BYTE] !72 # system->boot->free_pool(executable) 58 ; pop_rax # deallocate stack # Open Child Image 4989F9 ; mov_r9,rdi # arg4 = child_ih 488D15 %LOADED_IMAGE_PROTOCOL ; lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL 52 ; push_rdx # save &LOADED_IMAGE_PROTOCOL 4C89C9 ; mov_rcx,r9 # arg1 = child_ih E8 %open_protocol ; call %open_protocol # open protocol 488958 38 ; mov_[rax+BYTE],rbx !56 # child_image->load_options = command 488970 30 ; mov_[rax+BYTE],rsi !48 # set child_image->load_options_size 488B0D %image ; mov_rcx,[rip+DWORD] %image # get image 488B49 18 ; mov_rcx,[rcx+BYTE] !24 # image->device 488948 18 ; mov_[rax+BYTE],rcx !24 # child_image->device = image->device 4989F8 ; mov_r8,rdi # arg3 = image_handle 5A ; pop_rdx # arg2 = &LOADED_IMAGE_PROTOCOL 4C89C1 ; mov_rcx,r8 # arg1 = image_handle E8 %close_protocol ; call %close_protocol # close protocol # Run command 4D31C0 ; xor_r8,r8 # arg3 = 0 (ExitData) 31D2 ; xor_edx,edx # arg2 = 0 (ExitData size) 4889F9 ; mov_rcx,rdi # arg1 = child_ih 50 ; push_rax # allocate shadow stack space for UEFI 50 ; push_rax # allocate shadow stack space for UEFI 50 ; push_rax # allocate shadow stack space for UEFI 41FF96 D0000000 ; call_[r14+DWORD] %208 # system->boot->start_image() 59 ; pop_rcx # deallocate stack 59 ; pop_rcx # deallocate stack 59 ; pop_rcx # deallocate stack 85C0 ; test_eax,eax # check if return code is 0 75 !print_error ; jne8 !print_error # print error and exit E9 %next_command ; jmp %next_command # process another line from kaem script :print_error 50 ; push_rax # save exit code 488D15 %subprocess_error ; lea_rdx,[rip+DWORD] %subprocess_error # get error message E8 %File_Print ; call %File_Print # print it 58 ; pop_rax # restore exit code # Close script file and exit :terminate # Free pool 4889D9 ; mov_rcx,rbx # arg1 = command 50 ; push_rax # save exit code 50 ; push_rax # allocate shadow stack space for UEFI function 41FF56 48 ; call_[r14+BYTE] !72 # system->boot->free_pool(commmand) 4C89E1 ; mov_rcx,r12 # arg1 = fin FF51 10 ; call_[rcx+BYTE] !16 # fin->close(fin) 488B0D %rootdir ; mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir FF51 10 ; call_[rcx+BYTE] !16 # rootdir->close(rootdir) 58 ; pop_rax # deallocate stack 58 ; pop_rax # restore exit code # Exit without closing script file :terminate_2 4C8B05 %image_handle ; mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle 4150 ; push_r8 # save image_handle 488D15 %SIMPLE_FS_PROTOCOL ; lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL 488B0D %root_device ; mov_rcx,[rip+DWORD] %root_device # arg1 = root_device E8 %close_protocol ; call %close_protocol # close protocol 4158 ; pop_r8 # arg3 = image_handle 488D15 %LOADED_IMAGE_PROTOCOL ; lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL 4C89C1 ; mov_rcx,r8 # arg1 = image_handle E8 %close_protocol ; call %close_protocol # close protocol :abort 4889EC ; mov_rsp,rbp # restore stack C3 ; ret # return to UEFI :File_Print 488B0D %system_out ; mov_rcx,[rip+DWORD] %system_out # get system_out 50 ; push_rax # allocate shadow stack space for UEFI function 50 ; push_rax # allocate shadow stack space for UEFI function for UEFI function FF51 08 ; call_[rcx+BYTE] !8 # system->out->output_string(system->out, WCHAR*) 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack C3 ; ret # read_byte function # reads a single character :read_byte 4C89E1 ; mov_rcx,r12 # arg1 = fin 6A 01 ; push !1 # size = 1 4889E2 ; mov_rdx,rsp # arg2 = &size 56 ; push_rsi # allocate stack 4989E0 ; mov_r8,rsp # arg3 = &c 50 ; push_rax # allocate shadow stack space for UEFI function 50 ; push_rax # allocate shadow stack space for UEFI function 50 ; push_rax # allocate shadow stack space for UEFI function FF51 20 ; call_[rcx+BYTE] !32 # fin->read() 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack 58 ; pop_rax # deallocate stack 58 ; pop_rax # save c to rax 59 ; pop_rcx # save size to rcx # If the file ended (0 bytes read) terminate 85C9 ; test_ecx,ecx # if size = 0 74 !terminate ; je8 !terminate # then we are done C3 ; ret # return # rcx: handle # rdx: &guid # r9: agent_handle # returns interface :open_protocol 50 ; push_rax # allocate stack for interface 4989E0 ; mov_r8,rsp # arg3 = &interface 6A 01 ; push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 6A 00 ; push !0 # arg5 = NULL 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function 41FF96 18010000 ; call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL) 4883C4 30 ; add_rsp, !48 # deallocate stack 58 ; pop_rax # get image C3 ; ret # rcx: handle # rdx: &guid # r8: agent_handle :close_protocol 4D31C9 ; xor_r9,r9 # arg4 = NULL 4883EC 20 ; sub_rsp, !32 # allocate shadow stack space for UEFI function 41FF96 20010000 ; call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0) 4883C4 20 ; add_rsp, !32 # deallocate stack C3 ; ret # rdx: number of bytes to allocate # r14: system->boot # returns pointer in rax :allocate_pool 52 ; push_rdx # allocate stack for pool pointer 4989E0 ; mov_r8,rsp # arg3 = &pool 6A 02 ; push !2 59 ; pop_rcx # arg1 = EFI_LOADER_DATA 4883EC 18 ; sub_rsp, !24 # allocate shadow stack space for UEFI 41FF56 40 ; call_[r14+BYTE] !64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool) 4883C4 18 ; add_rsp, !24 # deallocate stack 58 ; pop_rax # get pool C3 ; ret # Protocol GUIDs :LOADED_IMAGE_PROTOCOL A1 31 1B 5B ; %0x5b1b31a1:SIMPLE_FS_PROTOCOL 62 95 ; @0x9562 22 5B 4E 96 ; %0x0964e5b22 D2 11 ; @0x11d2 59 64 ; @0x6459 8E 3F 00 A0 C9 69 72 3B ; !0x8e !0x3f !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b :SIMPLE_FS_PROTOCOL 22 5B 4E 96 ; %0x0964e5b22 59 64 ; @0x6459 D2 11 ; @0x11d2 8E 39 00 A0 C9 69 72 3B ; !0x8e !0x39 !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b :FILE_INFO_PROTOCOL 92 6E 57 09 ; %0x09576e92 3F 6D ; @0x6d3f D2 11 ; @0x11d2 8E 39 00 A0 C9 69 72 3B ; !0x8e !0x39 !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b :default_file 6B 00 61 00 65 00 6D 00 2E 00 61 00 6D 00 64 00 36 00 34 00 00 00 ; L"kaem.amd64" :prefix 20 00 2B 00 3E 00 20 00 00 00 ; L" +> " :subprocess_error 53 00 75 00 62 00 70 00 72 00 6F 00 63 00 65 00 73 00 73 00 20 00 65 00 72 00 72 00 6F 00 72 00 :suffix 0A 00 0D 00 00 00 ; L"Subprocess error\n\r" :image_handle 00 00 00 00 00 00 00 00 :image 00 00 00 00 00 00 00 00 :rootdir 00 00 00 00 00 00 00 00 :root_device 00 00 00 00 00 00 00 00 :system_out 00 00 00 00 00 00 00 00 :PE32_end