# SPDX-FileCopyrightText: 2022 Andrius Štikonas # SPDX-FileCopyrightText: 2017 Jeremiah Orians # # SPDX-License-Identifier: GPL-3.0-or-later DEFINE add_rax, 4805 DEFINE add_rbx, 4883C3 DEFINE add_rbx,[rdi+BYTE] 48035F DEFINE add_rdi, 4883C7 DEFINE add_rdx, 4881C2 DEFINE add_rsi, 4883C6 DEFINE add_rsp, 4883C4 DEFINE add_r12, 4983C4 DEFINE add_r13, 4983C5 DEFINE add_rax,r14 4C01F0 DEFINE call E8 DEFINE call_[rcx+BYTE] FF51 DEFINE call_[r14+BYTE] 41FF56 DEFINE call_[r14+DWORD] 41FF96 DEFINE cmp_al, 3C DEFINE cmp_rax, 4883F8 DEFINE cmp_rbx, 4883FB DEFINE cmp_rcx, 4883F9 DEFINE cmp_r8, 4983F8 DEFINE cmp_r15, 4983FF DEFINE cmp_al,bl 38D8 DEFINE cmp_rbx,rdx 4839D3 DEFINE je 0F84 DEFINE jl 0F8C DEFINE jmp E9 DEFINE jne 0F85 DEFINE lea_rdx,[rip+DWORD] 488D15 DEFINE mov_al, B0 DEFINE mov_rax, 48C7C0 DEFINE mov_rcx, 48C7C1 DEFINE mov_rdx, 48C7C2 DEFINE mov_r11, 49C7C3 DEFINE mov_r13, 49C7C5 DEFINE mov_r14, 49C7C6 DEFINE mov_r15, 49C7C7 DEFINE mov_rax,r12 4C89E0 DEFINE mov_rbp,rsp 4889E5 DEFINE mov_rbx,r12 4C89E3 DEFINE mov_rcx,rax 4889C1 DEFINE mov_rcx,r9 4C89C9 DEFINE mov_rcx,r8 4C89C1 DEFINE mov_rcx,r11 4C89D9 DEFINE mov_rdi,rax 4889C7 DEFINE mov_rdx,rax 4889C2 DEFINE mov_rdx,rbx 4889DA DEFINE mov_rdx,rsb 4889E2 DEFINE mov_rdx,rsp 4889E2 DEFINE mov_rdx,r13 4C89EA DEFINE mov_rsp,rbp 4889EC DEFINE mov_rsp,r8 4989E0 DEFINE mov_r8,rsp 4989E0 DEFINE mov_r11,rax 4989C3 DEFINE mov_r12,rax 4989C4 DEFINE mov_r12,rbx 4989DC DEFINE mov_r14,rax 4989C6 DEFINE mov_al,[rbx] 8A03 DEFINE mov_al,[rsi] 8A06 DEFINE mov_bl,[rdi] 8A1F DEFINE mov_rcx,[rbx] 488B0B DEFINE mov_rcx,[rcx] 488B09 DEFINE mov_[rax],r11 4C8918 DEFINE mov_[rbx], C603 DEFINE mov_[rbx],al 8803 DEFINE mov_[rbx],rcx 48890B DEFINE mov_rax,[rcx+BYTE] 488B41 DEFINE mov_rbx,[rdi+BYTE] 488B5F DEFINE mov_rcx,[rdi+BYTE] 488B4F DEFINE mov_r14,[rdx+BYTE] 4C8B72 DEFINE mov_rsi,[rcx+BYTE] 488B71 DEFINE mov_rax,[rip+DWORD] 488B05 DEFINE mov_rbx,[rip+DWORD] 488B1D DEFINE mov_rcx,[rip+DWORD] 488B0D DEFINE mov_rdi,[rip+DWORD] 488B3D DEFINE mov_r14,[rip+DWORD] 4C8B35 DEFINE mov_r8,[rip+DWORD] 4C8B05 DEFINE mov_r9,[rip+DWORD] 4C8B0D DEFINE mov_[rax+BYTE],r13 4C8968 DEFINE mov_[r11+BYTE],r12 4D8963 DEFINE mov_[rip+DWORD],rax 488905 DEFINE mov_[rip+DWORD],rcx 48890D DEFINE mov_[rip+DWORD],r14 4C8935 DEFINE movzx_rax,al 480FB6C0 DEFINE movzx_rbx,bl 480FB6DB DEFINE not_r15 49F7D7 DEFINE pop_rax 58 DEFINE pop_rbx 5B DEFINE pop_rcx 59 DEFINE pop_rdx 5A DEFINE pop_rsi 5E DEFINE pop_r8 4158 DEFINE pop_r9 4159 DEFINE pop_r11 415B DEFINE push 6A DEFINE push_rax 50 DEFINE push_rbx 53 DEFINE push_rcx 51 DEFINE push_rdx 52 DEFINE push_rsi 56 DEFINE push_r11 4153 DEFINE ret C3 DEFINE ror_r9 49D1C9 DEFINE shl_r14, 49C1E6 DEFINE sub_rax, 83E8 DEFINE sub_rbx, 4883EB DEFINE sub_rsp, 4883EC DEFINE sub_rax,rdx 4829D0 DEFINE test_esi_esi 85F6 DEFINE xor_eax_eax 31C0 DEFINE xor_edx_edx 31D2 DEFINE xor_esi_esi 31F6 DEFINE xor_r9,r9 4D31C9 # Register usage: # r15 => Flag # r14 => High bits # r13 => IP # r12 => MALLOC # r11 => HEAD # Struct format: (size 24) # NEXT => 0 # TARGET => 8 # NAME => 16 # efi_main(void *image_handle, struct efi_system_table *system) :_start mov_rbp,rsp # save stack pointer mov_[rip+DWORD],rcx %image_handle # save image_handle mov_r14,[rdx+BYTE] !96 # system->boot mov_[rip+DWORD],r14 %SystemBoot # save system->boot # Open Loaded Image protocol mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL mov_rcx,r9 # arg1 = image_handle call %open_protocol # open protocol mov_rdi,rax # save image # Get root file system mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device mov_[rip+DWORD],rcx %root_device # save root_device call %open_protocol # open protocol mov_rcx,rax # get rootfs # Get root directory lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) pop_rax # deallocate stack pop_rax # deallocate stack # Push command line arguments onto stack mov_rbx,[rdi+BYTE] !56 # options = image->load_options mov_rdx,rbx # save beginning of load_options add_rbx,[rdi+BYTE] !48 # go to the end of load_options push !0 # Save end of arguments (NULL) onto stack :loop_options cmp_rbx,rdx # Check if we are done je %loop_options_done # We are done sub_rbx, !2 # --options mov_al,[rbx] # *options cmp_al, !0x20 # if *options != ' ' jne %loop_options # then continue looping mov_[rbx], !0 # zero it add_rbx, !2 # ++options push_rbx # push another argument onto stack jmp %loop_options # next argument :loop_options_done # Open file for reading pop_r8 # arg3 = in push !1 # Set exit code in case of failure cmp_r8, !0 # If NULL je %failed_input # then exit lea_rdx,[rip+DWORD] %fin # arg2 = &fin push !1 # arg5 = EFI_FILE_READ_ONLY push !1 # prepare to set arg4 to EFI_FILE_MODE_READ pop_r9 # arg4 = EFI_FILE_MODE_READ mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir sub_rsp, !32 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !8 # rootdir->open() cmp_rax, !0 # If failed to open jne %failed_input # then exit add_rsp, !48 # deallocate stack # Open file for writing pop_r8 # arg3 = out push !1 # Set exit code in case of failure cmp_r8, !0 # If NULL je %failed_output # then exit lea_rdx,[rip+DWORD] %fout # arg2 = &fout push !0 # arg5 = 0 push !7 # to get 0x8000000000000003 we set the rightmost 3 bits pop_r9 # and then do right rotation by 1 ror_r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir sub_rsp, !32 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !8 # rootdir->open() add_rsp, !48 # deallocate stack # Allocate ourselves 16 MiB of memory mov_rdx, %0x1000000 # allocate 16 MiB of memory call %allocate_pool mov_[rip+DWORD],rax %scratch # Allocate space for scratch area add_rax, %0x800 # 2 KiB of scratch mov_r12,rax # save structs pointer call %ClearScratch # Zero scratch mov_r15, %-1 # Our flag for byte processing mov_r14, %0 # temp storage for the sum mov_r13, %0x00600000 # Our starting IP mov_r11, %0 # HEAD = NULL call %First_pass # Process it # rewind input file push_r11 # Protect r11 mov_rcx,[rip+DWORD] %fin # Using our input file xor_edx_edx # Offset Zero push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function call_[rcx+BYTE] !56 # fin->set_position(fin, 0) pop_rax # deallocate stack pop_rax # deallocate stack pop_r11 # restore r11 mov_r15, %-1 # Our flag for byte processing mov_r14, %0 # temp storage for the sum mov_r13, %0x00600000 # Our starting IP call %Second_pass # Process it jmp %Done :First_pass call %Read_byte # Deal with EOF cmp_rax, !-4 je %First_pass_done # Check for : cmp_rax, !0x3A jne %First_pass_0 # Deal with label call %StoreLabel :First_pass_0 # Check for ! cmp_rax, !0x21 je %First_pass_pointer # Check for @ cmp_rax, !0x40 je %First_pass_pointer # Check for $ cmp_rax, !0x24 je %First_pass_pointer # Check for % cmp_rax, !0x25 je %First_pass_pointer # Check for & cmp_rax, !0x26 je %First_pass_pointer # Deal with everything else call %hex # Process our char # Deal with EOF cmp_rax, !-4 je %First_pass_done # deal with -1 values cmp_rax, !0 jl %First_pass # deal with toggle cmp_r15, !0 je %First_pass_1 add_r13, !1 # Increment IP :First_pass_1 not_r15 jmp %First_pass :Update_Pointer # Check for ! cmp_rax, !0x21 je %Update_Pointer_1 # Check for @ cmp_rax, !0x40 je %Update_Pointer_2 # Check for $ cmp_rax, !0x24 je %Update_Pointer_2 # Check for % cmp_rax, !0x25 je %Update_Pointer_4 # Check for & cmp_rax, !0x26 je %Update_Pointer_4 # deal with bad input call %fail :Update_Pointer_4 add_r13, !2 # Increment IP :Update_Pointer_2 add_r13, !1 # Increment IP :Update_Pointer_1 add_r13, !1 # Increment IP ret :First_pass_pointer # Deal with Pointer to label call %Update_Pointer # Increment IP mov_rbx,[rip+DWORD] %scratch # Using scratch call %consume_token # Read token call %ClearScratch # Throw away token cmp_rax, !0x3E # check for '>' jne %First_pass # Loop again # Deal with %label>label case mov_rbx,[rip+DWORD] %scratch # Write to scratch call %consume_token # get token call %ClearScratch # Clean up after ourselves jmp %First_pass # Loop again :First_pass_done ret :hex # deal with EOF cmp_rax, !-4 je %EOF # deal with line comments starting with # cmp_rax, !0x23 je %ascii_comment # deal with line comments starting with ; cmp_rax, !0x3B je %ascii_comment # deal all ascii less than 0 cmp_rax, !0x30 jl %ascii_other # deal with 0-9 cmp_rax, !0x3A jl %ascii_num # deal with all ascii less than A cmp_rax, !0x41 jl %ascii_other # deal with A-F cmp_rax, !0x47 jl %ascii_high # deal with all ascii less than a cmp_rax, !0x61 jl %ascii_other # deal with a-f cmp_rax, !0x67 jl %ascii_low # The rest that remains needs to be ignored jmp %ascii_other :Second_pass call %Read_byte # Deal with EOF cmp_rax, !-4 je %Second_pass_done # Simply drop the label cmp_rax, !0x3A jne %Second_pass_0 mov_rbx,[rip+DWORD] %scratch # Using scratch call %consume_token # Read token call %ClearScratch # Throw away token jmp %Second_pass :Second_pass_0 # Deal with % pointer cmp_rax, !0x25 je %StorePointer_rel4 # Deal with @ pointer cmp_rax, !0x40 je %StorePointer_rel2 # Deal with ! pointer cmp_rax, !0x21 je %StorePointer_rel1 # Deal with & pointer cmp_rax, !0x26 je %StorePointer_abs4 # Deal with $ pointer cmp_rax, !0x24 je %StorePointer_abs2 :Second_pass_1 # Deal with everything else call %hex # Process our char # Deal with EOF cmp_rax, !-4 je %Second_pass_done # deal with -1 values cmp_rax, !0 jl %Second_pass # deal with toggle cmp_r15, !0 je %print # process first byte of pair mov_r14,rax mov_r15, %0 jmp %Second_pass :Second_pass_done :EOF ret :ascii_num sub_rax, !0x30 ret :ascii_low sub_rax, !0x57 ret :ascii_high sub_rax, !0x37 ret :ascii_other mov_rax, %-1 ret :ascii_comment call %Read_byte cmp_rax, !0x0D je %ascii_comment_cr cmp_rax, !0x0A jne %ascii_comment :ascii_comment_cr mov_rax, %-1 ret # process second byte of pair :print # update the sum and store in output shl_r14, !4 add_rax,r14 # flip the toggle not_r15 # r15 = -1 # Print our first Hex mov_rdx, %1 # set the size of chars we want call %print_chars add_r13, !1 # Increment IP jmp %Second_pass :Read_byte push_r11 # Protect r11 mov_rcx,[rip+DWORD] %fin # arg1 = fin push !1 # size = 1 mov_rdx,rsb # arg2 = &size xor_esi_esi # zero rsi push_rsi # allocate stack mov_rsp,r8 # arg3 = &input push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function call_[rcx+BYTE] !32 # fin->read() pop_rax # deallocate stack pop_rax # deallocate stack pop_rax # deallocate stack pop_rax # save input to rax pop_rsi # save size to rsi pop_r11 # restore r11 # If the file ended (0 bytes read) return EOF test_esi_esi jne %Read_byte_1 mov_rax, %-4 # Put EOF in rax :Read_byte_1 ret # Writes bytes stored in rax :print_chars push_r11 # Protect r11 mov_rcx,[rip+DWORD] %fout # arg1 = fout push_rdx # set size mov_rdx,rsp # arg2 = &size push_rax # allocate stack mov_rsp,r8 # arg3 = &output push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function push_rax # allocate shadow stack space for UEFI function call_[rcx+BYTE] !40 # fout->write() add_rsp, !40 # deallocate stack pop_r11 # restore r11 ret # return # Receives pointer in RBX # Writes out char and updates RBX :consume_token call %Read_byte # Consume_token # Check for \t cmp_rax, !0x09 je %consume_token_done # Check for \n cmp_rax, !0x0A je %consume_token_done # Check for ' ' cmp_rax, !0x20 je %consume_token_done # Check for '>' cmp_rax, !0x3E je %consume_token_done # Looks like we are still reading token mov_[rbx],al # Store char add_rbx, !1 # Point to next spot jmp %consume_token # loop until done :consume_token_done mov_rcx, %0 # Pad with nulls mov_[rbx],rcx add_rbx, !8 ret :StoreLabel mov_rax,r12 # ENTRY add_r12, !24 # CALLOC mov_[rax+BYTE],r13 !8 # ENTRY->TARGET = IP mov_[rax],r11 # ENTRY->NEXT = JUMP_TABLE mov_r11,rax # JUMP_TABLE = ENTRY mov_[r11+BYTE],r12 !16 # ENTRY->NAME = TOKEN mov_rbx,r12 # Write Starting after struct call %consume_token # Collect whole string mov_r12,rbx # Update HEAP jmp %First_pass :GetTarget mov_rdi,[rip+DWORD] %scratch # Reset scratch mov_rcx,r11 # Grab JUMP_TABLE mov_rsi,[rcx+BYTE] !16 # I->NAME :GetTarget_loop mov_al,[rsi] # I->NAME[0] mov_bl,[rdi] # scratch[0] movzx_rbx,bl # Zero extend movzx_rax,al # Zero extend cmp_al,bl # IF TOKEN == I->NAME jne %GetTarget_miss # Oops add_rsi, !1 add_rdi, !1 cmp_al, !0 jne %GetTarget_loop # Loop until jmp %GetTarget_done # Match # Miss :GetTarget_miss mov_rcx,[rcx] # I = I->NEXT cmp_rcx, !0 # IF NULL == I je %fail # Abort hard mov_rsi,[rcx+BYTE] !16 # I->NAME mov_rdi,[rip+DWORD] %scratch # Reset scratch jmp %GetTarget_loop :GetTarget_done mov_rax,[rcx+BYTE] !8 # Get address ret :ClearScratch push_rax # Protect against changes push_rbx # And overwrites push_rcx push_rdx # While we work mov_rbx,[rip+DWORD] %scratch # Where our table is mov_al, !0 # Using null mov_rdx,rbx # Get scratch add_rdx, %0x800 # end of scratch area :ClearScratch_loop cmp_rbx,rdx # Make sure je %ClearScratch_end # we do not overflow mov_rcx,[rbx] # Get current value mov_[rbx],al # Because we want null add_rbx, !1 # Increment cmp_rcx, !0 # Check if we hit null jne %ClearScratch_loop # Keep looping :ClearScratch_end pop_rdx pop_rcx # Don't Forget to pop_rbx # Restore Damage pop_rax # Entirely ret :StorePointer call %Update_Pointer # Increment IP mov_rbx,[rip+DWORD] %scratch # Write to scratch call %consume_token # get token push_rax # Protect base_sep_p mov_rax,[rip+DWORD] %scratch # Pointer to scratch call %GetTarget # Get address of pointer call %ClearScratch # Clean up after ourselves mov_rdx,r13 # base = IP pop_rbx # Restore base_sep_p cmp_rbx, !0x3E # If base_sep_p == '>' jne %StorePointer_done # If not # Deal with %label>label case push_rax # We need to preserve main target mov_rbx,[rip+DWORD] %scratch # Write to scratch call %consume_token # get token mov_rax,[rip+DWORD] %scratch # Pointer to scratch call %GetTarget # Get address of pointer call %ClearScratch # Clean up after ourselves mov_rdx,rax # Use our new base pop_rax # Restore main target :StorePointer_done ret :StorePointer_rel4 call %StorePointer # Do Common sub_rax,rdx # target - ip mov_rdx, %4 # set the size of chars we want call %print_chars jmp %Second_pass :StorePointer_rel2 call %StorePointer # Do Common sub_rax,rdx # target - ip mov_rdx, %2 # set the size of chars we want call %print_chars jmp %Second_pass :StorePointer_rel1 call %StorePointer # Do Common sub_rax,rdx # target - ip mov_rdx, %1 # set the size of chars we want call %print_chars jmp %Second_pass :StorePointer_abs4 call %StorePointer # Do Common mov_rdx, %4 # set the size of chars we want call %print_chars jmp %Second_pass :StorePointer_abs2 call %StorePointer # Do Common mov_rdx, %2 # set the size of chars we want call %print_chars jmp %Second_pass :fail mov_rax, %1 # Set exit code 1 jmp %terminate :Done xor_eax_eax # Set exit code 0 :terminate push_rax # save exit code mov_r14,[rip+DWORD] %SystemBoot # get system->boot mov_rcx,[rip+DWORD] %scratch # arg1 = scratch push_rax # allocate shadow stack space for UEFI function call_[r14+BYTE] !72 # system->boot->free_pool(scratch) pop_rax # deallocate stack mov_rcx,[rip+DWORD] %fout # get fout call %close_file # close fout :failed_output mov_rcx,[rip+DWORD] %fin # get fin call %close_file # close fin :failed_input mov_rcx,[rip+DWORD] %rootdir # get rootdir call %close_file # close rootdir mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL mov_rcx,[rip+DWORD] %root_device # arg1 = root_device call %close_protocol # close protocol mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL mov_rcx,r8 # arg1 = image_handle call %close_protocol # close protocol pop_rax # restore exit code :abort mov_rsp,rbp # restore stack ret # return to UEFI # rcx: file handle :close_file push_rax # allocate shadow stack space for UEFI function call_[rcx+BYTE] !16 # file_handle->close(file_handle) pop_rax # deallocate stack ret # rcx: handle # rdx: &guid # r9: agent_handle # returns interface :open_protocol push_rax # allocate stack for interface mov_r8,rsp # arg3 = &interface push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL push !0 # arg5 = NULL sub_rsp, !32 # allocate shadow stack space for UEFI function call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL) add_rsp, !48 # deallocate stack pop_rax # get interface ret # rcx: handle # rdx: &guid # r8: agent_handle :close_protocol xor_r9,r9 # arg4 = NULL sub_rsp, !32 # allocate shadow stack space for UEFI function call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0) add_rsp, !32 # deallocate stack ret # rdx: number of bytes to allocate # r14: system->boot # returns pointer in rax :allocate_pool push_rdx # allocate stack for pool pointer mov_r8,rsp # arg3 = &pool push !2 pop_rcx # arg1 = EFI_LOADER_DATA sub_rsp, !24 # allocate shadow stack space for UEFI call_[r14+BYTE] !64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool) add_rsp, !24 # deallocate stack pop_rax # get pool ret # Protocol GUIDs :LOADED_IMAGE_PROTOCOL %0x5b1b31a1 @0x9562 @0x11d2 :LOADED_IMAGE_PROTOCOL_8 !0x8e !0x3f !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b :SIMPLE_FS_PROTOCOL %0x0964e5b22 @0x6459 @0x11d2 :SIMPLE_FS_PROTOCOL_8 !0x8e !0x39 !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b :fin %0 %0 :fout %0 %0 :scratch %0 %0 :rootdir %0 %0 :SystemBoot %0 %0 :image_handle %0 %0 :root_device %0 %0 :PE32_end