# SPDX-FileCopyrightText: 2022 Andrius Štikonas # SPDX-FileCopyrightText: 2017 Jeremiah Orians # # SPDX-License-Identifier: GPL-3.0-or-later DEFINE add_al, 04 DEFINE add_ebx, 83C3 DEFINE add_rax, 4805 DEFINE add_rbx, 4881C3 DEFINE add_rcx, 4881C1 DEFINE add_rdx, 4881C2 DEFINE add_rsp, 4883C4 DEFINE add_rax,rcx 4801C8 DEFINE add_r12,rax 4901C4 DEFINE add_rbx,[rdi+BYTE] 48035F DEFINE and_rax, 4883E0 DEFINE and_rsp, 4883E4 DEFINE cmp_al, 3C DEFINE cmp_rax, 483D DEFINE cmp_rbx, 4881FB DEFINE cmp_rcx, 4881F9 DEFINE cmp_rdx, 4881FA DEFINE cmp_rsi, 4881FE DEFINE cmp_r8, 4983F8 DEFINE cmp_rax,rbx 4839D8 DEFINE cmp_rax,rcx 4839C8 DEFINE cmp_rax,r12 4C39E0 DEFINE cmp_rbx,rdx 4839D3 DEFINE cmp_rcx,rbx 4839D9 DEFINE call E8 DEFINE call_[rcx+BYTE] FF51 DEFINE call_[r14+BYTE] 41FF56 DEFINE call_[r14+DWORD] 41FF96 DEFINE dec_rax 48FFC8 DEFINE imul_rax, 486BC0 DEFINE jbe8 76 DEFINE je8 74 DEFINE jg8 7F DEFINE jl8 7C DEFINE jmp8 EB DEFINE jne8 75 DEFINE je 0F84 DEFINE jl 0F8C DEFINE jmp E9 DEFINE jne 0F85 DEFINE lea_rbx,[rip+DWORD] 488D1D DEFINE lea_rdx,[rip+DWORD] 488D15 DEFINE mov_rax, 48C7C0 DEFINE mov_rcx, 48C7C1 DEFINE mov_rdx, 48C7C2 DEFINE mov_rsi, 48C7C6 DEFINE mov_rax,rbx 4889D8 DEFINE mov_rax,rcx 4889C8 DEFINE mov_rax,rdx 4889D0 DEFINE mov_rax,r13 4C89E8 DEFINE mov_rbx,rax 4889C3 DEFINE mov_rbx,rcx 4889CB DEFINE mov_rbx,r13 4C89EB DEFINE mov_rbp,rsp 4889E5 DEFINE mov_rcx,rax 4889C1 DEFINE mov_rcx,rbx 4889D9 DEFINE mov_rcx,r8 4C89C1 DEFINE mov_rcx,r9 4C89C9 DEFINE mov_rdi,rax 4889C7 DEFINE mov_rdx,rax 4889C2 DEFINE mov_rdx,rbx 4889DA DEFINE mov_rdx,rsp 4889E2 DEFINE mov_rsp,rbp 4889EC DEFINE mov_r8,rsp 4989E0 DEFINE mov_r8,r12 4D89E0 DEFINE mov_r12,rax 4989C4 DEFINE mov_r13,rax 4989C5 DEFINE mov_r13,rdx 4989D5 DEFINE mov_al,[rbx] 8A03 DEFINE mov_al,[rbx+rcx] 8A040B DEFINE mov_al,[rcx] 8A01 DEFINE mov_al,[rdx] 8A02 DEFINE mov_bl,[rax] 8A18 DEFINE mov_bl,[rdx] 8A1A DEFINE mov_cl,[rax] 8A08 DEFINE mov_cl,[rbx] 8A0B DEFINE mov_cl,[rbx+BYTE] 8A4B DEFINE mov_rax,[rax] 488B00 DEFINE mov_rax,[rcx] 488B01 DEFINE mov_rbx,[rbx] 488B1B DEFINE mov_rcx,[rbx] 488B0B DEFINE mov_rcx,[rcx] 488B09 DEFINE mov_rdx,[rdx] 488B12 DEFINE mov_[ebx],al 678803 DEFINE mov_[rbx], C603 DEFINE mov_[rdx],cl 880A DEFINE mov_[rbx],rax 488903 DEFINE mov_[rcx],rax 488901 DEFINE mov_[rdx],r13 4C892A DEFINE mov_[rax],BYTE C600 DEFINE mov_rax,[rax+BYTE] 488B40 DEFINE mov_rax,[rbx+BYTE] 488B43 DEFINE mov_rax,[rcx+BYTE] 488B41 DEFINE mov_rax,[rdx+BYTE] 488B42 DEFINE mov_rbx,[rax+BYTE] 488B58 DEFINE mov_rbx,[rcx+BYTE] 488B59 DEFINE mov_rbx,[rdi+BYTE] 488B5F DEFINE mov_rcx,[rax+BYTE] 488B48 DEFINE mov_rcx,[rdi+BYTE] 488B4F DEFINE mov_rsp,[rsp+BYTE] 488B6424 DEFINE mov_r14,[rdx+BYTE] 4C8B72 DEFINE mov_rcx,[rip+DWORD] 488B0D DEFINE mov_r8,[rip+DWORD] 4C8B05 DEFINE mov_r9,[rip+DWORD] 4C8B0D DEFINE mov_[rax+BYTE],rbx 488958 DEFINE mov_[rcx+BYTE],rax 488941 DEFINE mov_[rcx+BYTE],rbx 488959 DEFINE mov_[rdx+BYTE],rax 488942 DEFINE mov_[rdx+BYTE],rcx 48894A DEFINE mov_[rip+DWORD],rax 488905 DEFINE mov_[rip+DWORD],rcx 48890D DEFINE movzx_rax,al 480FB6C0 DEFINE movzx_rbx,bl 480FB6DB DEFINE movzx_rcx,cl 480FB6C9 DEFINE popf 9D DEFINE pop_rax 58 DEFINE pop_rbp 5D DEFINE pop_rbx 5B DEFINE pop_rcx 59 DEFINE pop_rdi 5F DEFINE pop_rdx 5A DEFINE pop_rsi 5E DEFINE pop_r8 4158 DEFINE pop_r9 4159 DEFINE pop_r12 415C DEFINE pop_r13 415D DEFINE pop_r14 415E DEFINE pop_r15 415F DEFINE push 6A DEFINE pushf 9C DEFINE push_rax 50 DEFINE push_rbp 55 DEFINE push_rbx 53 DEFINE push_rcx 51 DEFINE push_rdi 57 DEFINE push_rdx 52 DEFINE push_rsi 56 DEFINE push_rsp 54 DEFINE push_r12 4154 DEFINE push_r13 4155 DEFINE push_r14 4156 DEFINE push_r15 4157 DEFINE push_[rsp] FF3424 DEFINE ret C3 DEFINE ror_r9 49D1C9 DEFINE shl_rax, 48C1E0 DEFINE shr_rax, 48C1E8 DEFINE sub_rbx, 4883EB DEFINE sub_rcx, 4883E9 DEFINE sub_rsp, 4883EC DEFINE xchg_rax,rbx 4893 DEFINE xor_eax,eax 31C0 DEFINE xor_esi,esi 31F6 DEFINE xor_r9,r9 4D31C9 DEFINE xor_r13,r13 4D31ED # Register usage: # RAX, RSI, RDI => Temps # R12 => MALLOC # R13 => HEAD # R14 => system->boot # Struct format: (size 32) # NEXT => 0 # TYPE => 8 # TEXT => 16 # EXPRESSION => 24 # Types # None => 0 # MACRO => 1 # STRING => 2 # efi_main(void *image_handle, struct efi_system_table *system) :_start # Save non-volatile registers push_rbp push_rbx push_rdi push_rsi push_r12 push_r13 push_r14 push_r15 mov_rbp,rsp # save stack pointer mov_[rip+DWORD],rcx %image_handle # save image_handle mov_r14,[rdx+BYTE] !96 # 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 sub_rsp, !40 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) add_rsp, !40 # 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 je8 !loop_options_done # We are done sub_rbx, !2 # --options mov_al,[rbx] # *options cmp_al, !0x20 # if *options != ' ' jne8 !loop_options # then continue looping mov_[rbx], !0 # zero it add_rbx, %2 # ++options push_rbx # push another argument onto stack jmp8 !loop_options # next argument :loop_options_done pop_r8 # arg3 = in pop_r12 # file out and_rsp, !-16 # align stack to 16 bytes # Open file for reading 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 mov_r8,r12 # 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 32 MiB of memory mov_rdx, %0x2000000 # allocate 32 MiB of memory for malloc pool call %allocate_pool # allocate memory mov_r12,rax # save malloc pointer mov_[rip+DWORD],rax %malloc_pool # save the beginning of malloc pool # Zero allocated memory buffer add_rax, %0x2000000 # end of malloc area :zero_loop dec_rax # next byte mov_[rax],BYTE !0 # zero it cmp_rax,r12 # if we are not done yet jne8 !zero_loop # then continue looping xor_r13,r13 # Set HEAD = NULL call %Tokenize_Line # Process it mov_rax,r13 # prepare for Reverse_List call %Reverse_List # Correct order mov_r13,rax # Update HEAD call %Identify_Macros # Find the DEFINEs call %Line_Macro # Apply the DEFINEs call %Process_String # Handle strings call %Eval_Immediates # Handle Numbers call %Preserve_Other # Collect the remaining call %Print_Hex # Output our results :Done xor_eax,eax # Set exit code 0 # Free pool push_rax # save exit code mov_rcx,[rip+DWORD] %malloc_pool # arg1 = malloc_pool call %free_pool # system->boot->free_pool(malloc_pool) 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 # Restore non-volatile registers mov_rsp,rbp pop_r15 pop_r14 pop_r13 pop_r12 pop_rsi pop_rdi pop_rbx pop_rbp ret # return to UEFI # Tokenize_Line Function # Using Head R13 # Creates a linked list of structs # Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p :Tokenize_Line push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX :restart call %fgetc # Read a char cmp_rax, %-4 # Check for EOF je8 !done # File is collected movzx_rax,al # We have to zero extend it to use it mov_rcx,rax # Protect C lea_rbx,[rip+DWORD] %comments # Get pointer to "#;" call %In_Set # Check for comments cmp_rax, %1 # If comments je %Purge_LineComment # try again mov_rax,rcx # put C in place for check lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " call %In_Set # Check for terminators cmp_rax, %1 # If terminator je8 !restart # try again mov_rax, %32 # Malloc the struct P call %malloc # Get pointer to P mov_rdx,rax # Protect P mov_[rdx],r13 # P->NEXT = HEAD mov_r13,rdx # HEAD = P mov_rax,rcx # put C in place for check lea_rbx,[rip+DWORD] %string_char # Get pointer to "\"'" call %In_Set # Check for string chars cmp_rax, %1 # If string char je %Store_String # Get string call %Store_Atom # Get whole token jmp8 !restart :done pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX ret # fgetc function # Returns -4 (EOF) or char in RAX :fgetc push_rcx # Protect RCX push_rdx # Protect RDX mov_rcx,[rip+DWORD] %fin # arg1 = fin push !1 # size = 1 mov_rdx,rsp # arg2 = &size xor_esi,esi # zero rsi push_rsi # allocate stack mov_r8,rsp # arg3 = &input push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes sub_rsp, !32 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !32 # fin->read() mov_rsp,[rsp+BYTE] !40 # deallocate stack pop_rax # save input to rax pop_rsi # save size to rsi # If the file ended (0 bytes read) return EOF cmp_rsi, %0 # if size == 0 jne8 !fgetc_1 mov_rax, %-4 # Put EOF in rax :fgetc_1 pop_rdx # Restore RDX pop_rcx # Restore RCX ret # return # Malloc isn't actually reserving memory here. # It just updates the pointer in our already reserved storage pool. :malloc push_r12 # Save current malloc pointer add_r12,rax # Request number of desired bytes pop_rax # Return pointer ret # Purge_LineComment function # Reads chars until LF and jumps to restart :Purge_LineComment call %fgetc # Get a char cmp_rax, %10 # While not LF jne8 !Purge_LineComment # Keep reading jmp %restart # Store_String Function # Receives C in RCX, HEAD in RDX and Input file in R15 # Uses RBX for terminator, RCX for C and RDX for string :Store_String push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rax, %2 # Using TYPE STRING mov_[rdx+BYTE],rax !8 # HEAD->TYPE = STRING mov_rax, %256 # Malloc the string call %malloc # Get pointer to P mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING mov_rbx,rcx # Protect terminator mov_rdx,rax # Protect string pointer :Store_String_Loop mov_[rdx],cl # write byte call %fgetc # read next char mov_rcx,rax # Update C add_rdx, %1 # STRING = STRING + 1 cmp_rcx,rbx # See if we hit terminator jne8 !Store_String_Loop # Otherwise keep looping pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX mov_rax,rdx # return HEAD jmp %restart # Store_Atom Function # Receives C in RCX, HEAD in RDX and Input file in R15 # Uses RBX for in_set strings, RCX for C and RDX for string :Store_Atom push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rax, %256 # Malloc the string call %malloc # Get pointer to P mov_[rdx+BYTE],rax !16 # HEAD->TEXT = STRING lea_rbx,[rip+DWORD] %terminators # Get pointer to "\n\t " mov_rdx,rax # Protect string pointer :Store_Atom_loop mov_[rdx],cl # write byte call %fgetc # read next char mov_rcx,rax # Update C add_rdx, %1 # STRING = STRING + 1 call %In_Set # Check for terminators cmp_rax, %0 # Check for "\n\t " je8 !Store_Atom_loop # Loop otherwise pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX mov_rax,rdx # return HEAD ret # In_Set function # Receives Char C in AL and CHAR* in RBX # Returns 1 if true, zero if false in RAX :In_Set push_rbx # Protect RBX push_rcx # Protect RCX :In_Set_loop mov_cl,[rbx] # Read char movzx_rcx,cl # Zero extend it cmp_rax,rcx # See if they match je8 !In_Set_True # return true cmp_rcx, %0 # Check for NULL je8 !In_Set_False # return false add_rbx, %1 # s = s + 1 jmp8 !In_Set_loop # Keep looping :In_Set_True mov_rax, %1 # Set True pop_rcx # Restore RCX pop_rbx # Restore RBX ret :In_Set_False mov_rax, %0 # Set FALSE pop_rcx # Restore RCX pop_rbx # Restore RBX ret # Char sets :terminators !10 !9 !32 !0 # "\n\t \0" :comments !35 !59 !0 # "#;\0" :string_char !34 !39 !0 # "\"'\0" # Reverse_List function # Receives List in RAX # Returns the list reversed in RAX :Reverse_List push_rbx # Protect RBX push_rcx # Protect RCX mov_rbx,rax # Set HEAD mov_rax, %0 # ROOT = NULL :Reverse_List_Loop cmp_rbx, %0 # WHILE HEAD != NULL je8 !Reverse_List_Done # Stop otherwise mov_rcx,[rbx] # NEXT = HEAD->NEXT mov_[rbx],rax # HEAD->NEXT = ROOT mov_rax,rbx # ROOT = HEAD mov_rbx,rcx # HEAD = NEXT jmp8 !Reverse_List_Loop # Keep Going :Reverse_List_Done pop_rcx # Restore RCX pop_rbx # Restore RBX ret # Identify_Macros function # Receives List in RAX # Updates the list in place; does not modify registers # Uses RBX for DEFINE, RCX for I :Identify_Macros push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX lea_rbx,[rip+DWORD] %DEFINE_str # Setup define string mov_rcx,rax # I = HEAD :Identify_Macros_Loop mov_rax,[rcx+BYTE] !16 # I->TEXT call %match # IF "DEFINE" == I->TEXT cmp_rax, %0 # Check if match jne8 !Identify_Macros_Next # Skip the work # Deal with MACRO mov_rax, %1 # Using MACRO mov_[rcx+BYTE],rax !8 # I->TYPE = MACRO mov_rax,[rcx] # I->NEXT mov_rax,[rax+BYTE] !16 # I->NEXT->TEXT mov_[rcx+BYTE],rax !16 # I->TEXT = I->NEXT->TEXT mov_rax,[rcx] # I->NEXT mov_rax,[rax] # I->NEXT->NEXT mov_rax,[rax+BYTE] !16 # I->NEXT->NEXT->TEXT mov_[rcx+BYTE],rax !24 # I->EXPRESSION = I->NEXT->NEXT->TEXT mov_rax,[rcx] # I->NEXT mov_rax,[rax] # I->NEXT->NEXT mov_rax,[rax] # I->NEXT->NEXT->NEXT mov_[rcx],rax # I->NEXT = I->NEXT->NEXT->NEXT :Identify_Macros_Next mov_rcx,[rcx] # I = I->NEXT cmp_rcx, %0 # Check for NULL jne8 !Identify_Macros_Loop # Keep looping otherwise pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret :DEFINE_str !68 !69 !70 !73 !78 !69 !0 # "DEFINE" # match function # Receives CHAR* in RAX and CHAR* in RBX # Returns 0 (TRUE) or 1 (FALSE) in RAX :match push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rcx,rax # S1 in place mov_rdx,rbx # S2 in place :match_Loop mov_al,[rcx] # S1[0] movzx_rax,al # Make it useful mov_bl,[rdx] # S2[0] movzx_rbx,bl # Make it useful cmp_rax,rbx # See if they match jne8 !match_False # If not add_rcx, %1 # S1 = S1 + 1 add_rdx, %1 # S2 = S2 + 1 cmp_rax, %0 # If reached end of string je8 !match_Done # Perfect match jmp8 !match_Loop # Otherwise keep looping :match_False mov_rax, %1 # Return false :match_Done pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX ret # Line_Macro function # Receives List in RAX # Updates the list in place; does not modify registers # Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION :Line_Macro push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX :Line_Macro_Loop mov_rbx,[rax+BYTE] !8 # I->TYPE cmp_rbx, %1 # IF MACRO == I->TYPE jne8 !Line_Macro_Next # Otherwise move on # Is a macro apply mov_rbx,[rax+BYTE] !16 # I->TEXT mov_rcx,[rax+BYTE] !24 # I->EXPRESSION mov_rax,[rax] # I->NEXT call %Set_Expression # Apply it jmp8 !Line_Macro_Loop # Move on to next :Line_Macro_Next mov_rax,[rax] # I->NEXT cmp_rax, %0 # Check for NULL jne8 !Line_Macro_Loop # Keep going pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret # Set_Expression function # Receives List in RAX, CHAR* in RBX and CHAR* in RCX # Updates the list in place; does not modify registers # Uses RBX for C, RCX for EXP and RDX for I :Set_Expression push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rdx,rax # Set I :Set_Expression_Loop mov_rax,[rdx+BYTE] !8 # I->TYPE cmp_rax, %1 # IF MACRO == I->TYPE je8 !Set_Expression_Next # Ignore and move on mov_rax,[rdx+BYTE] !16 # I->TEXT call %match # Check for match cmp_rax, %0 # If match jne8 !Set_Expression_Next # Otherwise next # We have a non-macro match mov_[rdx+BYTE],rcx !24 # I->EXPRESSION = EXP :Set_Expression_Next mov_rdx,[rdx] # I = I->NEXT cmp_rdx, %0 # IF NULL == I jne8 !Set_Expression_Loop # Otherwise keep looping pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret # Process_String function # Receives List in RAX # Update the list in place; does not modify registers # Uses RBX for I->TEXT, RCX for I and RDX for S :Process_String push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rcx,rax # I = HEAD :Process_String_loop mov_rax,[rcx+BYTE] !8 # I->TYPE cmp_rax, %2 # IF STRING == I->TYPE jne8 !Process_String_Next # Skip to next mov_rbx,[rcx+BYTE] !16 # I->TEXT mov_al,[rbx] # I->TEXT[0] movzx_rax,al # make it useful cmp_rax, %39 # IF '\'' == I->TEXT[0] jne8 !Process_String_Raw # Deal with '"' # Deal with '\'' add_rbx, %1 # I->TEXT + 1 mov_[rcx+BYTE],rbx !24 # I->EXPRESSION = I->TEXT + 1 jmp8 !Process_String_Next # Move on to next :Process_String_Raw mov_rax,rbx # Get length of I->TEXT call %string_length # Do it shr_rax, !2 # LENGTH = LENGTH >> 2 add_rax, %1 # LENGTH = LENGTH + 1 shl_rax, !3 # LENGTH = LENGTH << 3 call %malloc # Get string mov_rdx,rbx # S = I->TEXT add_rdx, %1 # S = S + 1 mov_[rcx+BYTE],rax !24 # I->EXPRESSION = hexify mov_rbx,rax # Put hexify buffer in rbx :Process_String_Raw_Loop mov_al,[rdx] # Read 1 chars movzx_rax,al # Make it useful add_rdx, %1 # S = S + 1 cmp_al, !0 # Check for NULL pushf # Protect condition call %hex8 # write them all popf # restore condition jne8 !Process_String_Raw_Loop # Keep looping :Process_String_Next mov_rcx,[rcx] # I = I->NEXT cmp_rcx, %0 # IF NULL == I jne8 !Process_String_loop # Otherwise keep looping pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret # string_length function # Receives CHAR* in RAX # Returns INT in RAX # Uses RAX for CH, RBX for S and RCX for INDEX :string_length push_rbx # Protect RBX push_rcx # Protect RCX mov_rbx,rax # Set S mov_rcx, %0 # INDEX = 0 :string_length_loop mov_al,[rbx+rcx] # S[0] movzx_rax,al # make it useful cmp_rax, %0 # IF NULL == S[0] je8 !string_length_done # Stop add_rcx, %1 # INDEX = INDEX + 1 jmp8 !string_length_loop # Keep going :string_length_done mov_rax,rcx # RETURN INDEX pop_rcx # Restore RCX pop_rbx # Restore RBX ret # Eval_Immediates function # Receives List in RAX # Updates the list in place; does not modify registers # Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I :Eval_Immediates push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rdx,rax # I = HEAD :Eval_Immediates_Loop # Check for MACRO mov_rax,[rdx+BYTE] !8 # I->TYPE cmp_rax, %1 # IF MACRO == I->TYPE je8 !Eval_Immediates_Next # Skip to next # Check for NULL EXPRESSION mov_rax,[rdx+BYTE] !24 # I->EXPRESSION cmp_rax, %0 # IF NULL == I->EXPRESSION jne8 !Eval_Immediates_Next # Skip to next # Check if number mov_rax,[rdx+BYTE] !16 # I->TEXT mov_bl,[rax] # I->TEXT[0] movzx_rbx,bl # Extend to use add_rax, %1 # I->TEXT + 1 mov_cl,[rax] # I->TEXT[1] movzx_rcx,cl # Extend to use call %numerate_string # Convert string to INT cmp_rax, %0 # IF 0 == numerate_string(I->TEXT + 1) jne8 !Eval_Immediates_value # Has a value # Last chance for Immediate cmp_rcx, %48 # If '0' == I->TEXT[1] jne8 !Eval_Immediates_Next # Skip to next :Eval_Immediates_value call %express_number # Convert value to hex string mov_[rdx+BYTE],rax !24 # I->EXPRESSION = express_number(value, I-TEXT[0]) :Eval_Immediates_Next mov_rdx,[rdx] # I = I->NEXT cmp_rdx, %0 # IF NULL == I jne8 !Eval_Immediates_Loop # Otherwise keep looping pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret # numerate_string function # Receives CHAR* in RAX # Returns value of CHAR* in RAX # Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE? :numerate_string push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX push_rsi # Protect RSI mov_rbx,rax # put S in correct place mov_rax, %0 # Initialize to Zero :numerate_string_loop mov_cl,[rbx+BYTE] !1 # S[1] movzx_rcx,cl # make it useful cmp_rcx, %120 # IF 'x' == S[1] je8 !numerate_hex # Deal with hex input # Assume decimal input mov_rsi, %0 # Assume no negation mov_cl,[rbx] # S[0] movzx_rcx,cl # make it useful cmp_rcx, %45 # IF '-' == S[0] jne8 !numerate_decimal # Skip negation mov_rsi, %1 # Set FLAG add_rbx, %1 # S = S + 1 :numerate_decimal mov_cl,[rbx] # S[0] movzx_rcx,cl # make it useful cmp_rcx, %0 # IF NULL == S[0] je8 !numerate_decimal_done # We are done imul_rax, !10 # VALUE = VALUE * 10 sub_rcx, !48 # CH = CH - '0' cmp_rcx, %9 # Check for illegal jg8 !numerate_string_fail # If CH > '9' cmp_rcx, %0 # Check for illegal jl8 !numerate_string_fail # IF CH < 0 add_rax,rcx # VALUE = VALUE + CH add_rbx, %1 # S = S + 1 jmp8 !numerate_decimal # Keep looping :numerate_decimal_done cmp_rsi, %1 # Check if need to negate jne8 !numerate_string_done # Nope imul_rax, !-1 # VALUE = VALUE * -1 jmp8 !numerate_string_done # Done :numerate_hex add_rbx, %2 # S = S + 2 :numerate_hex_loop mov_cl,[rbx] # S[0] movzx_rcx,cl # make it useful cmp_rcx, %0 # IF NULL == S[0] je8 !numerate_string_done # We are done shl_rax, !4 # VALUE = VALUE << 4 sub_rcx, !48 # CH = CH - '0' cmp_rcx, %10 # IF 10 >= CH jl8 !numerate_hex_digit # NO sub_rcx, !7 # Push A-F into range :numerate_hex_digit cmp_rcx, %15 # Check for illegal jg8 !numerate_string_fail # If CH > 'F' cmp_rcx, %0 # Check for illegal jl8 !numerate_string_fail # IF CH < 0 add_rax,rcx # VALUE = VALUE + CH add_rbx, %1 # S = S + 1 jmp8 !numerate_hex_loop # Keep looping :numerate_string_fail mov_rax, %0 # return ZERO :numerate_string_done pop_rsi # Restore RSI pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX ret # express_number function # Receives INT in RAX and CHAR in RBX # Allocates a string and expresses the value in hex # Returns string in RAX # Uses RAX for VALUE, RBX for S and RCX for CH :express_number push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX mov_rcx,rbx # Put CH in right place mov_rbx,rax # Protect VALUE cmp_rcx, %37 # IF '%' == CH jne8 !express_number2 # Otherwise try @ mov_rax, %9 # We need 9 bytes call %malloc # Get S pointer xchg_rax,rbx # Put S and VALUE in place push_rbx # Protect S call %hex32l # Store 32bits jmp8 !express_number_done # done :express_number2 cmp_rcx, %64 # IF '@' == CH jne8 !express_number1 # Othrewise try ! mov_rax, %5 # We need 5 bytes call %malloc # Get S pointer xchg_rax,rbx # Put S and VALUE in place push_rbx # Protect S call %hex16l # Store 16bits jmp8 !express_number_done # done :express_number1 mov_rax, %3 # We need 3 bytes call %malloc # Get S pointer xchg_rax,rbx # Put S and VALUE in place push_rbx # Protect S call %hex8 # Store 8bit :express_number_done pop_rax # Restore S pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX ret # HEX to ascii routine # Receives INT in RAX and CHAR* in RBX # Stores ascii of INT in CHAR* # Returns only modifying RAX :hex64l push_rax # Protect top 32 call %hex32l # Store it pop_rax # do top 32 shr_rax, !32 # do bottom 32 first :hex32l push_rax # Protect top 16 call %hex16l # Store it pop_rax # do top 16 shr_rax, !16 # do bottom 16 first :hex16l push_rax # Protect top byte call %hex8 # Store it pop_rax # do high byte shr_rax, !8 # do bottom byte first :hex8 push_rax # Protect bottom nibble shr_rax, !4 # do high nibble first call %hex4 # Store it pop_rax # do low nibble :hex4 and_rax, !0xF # isolate nibble add_al, !0x30 # convert to ascii (add '0') cmp_al, !0x39 # valid digit? (compare to '9') jbe8 !hex1 # yes add_al, !7 # use alpha range :hex1 mov_[ebx],al # store result add_ebx, !1 # next position ret # Preserve_Other function # Receives List in RAX # Updates the list in place; does not modify registers # Uses RAX for I, RBX for I->TEXT :Preserve_Other push_rax # Protect RAX push_rbx # Protect RBX push_rcx # Protect RCX push_rdx # Protect RDX :Preserve_Other_Loop mov_rbx,[rax+BYTE] !24 # I->EXPRESSION cmp_rbx, %0 # IF NULL == I->EXPRESSION jne8 !Preserve_Other_Next # Otherwise next # Needs preserving mov_rbx,[rax+BYTE] !16 # I->TEXT mov_[rax+BYTE],rbx !24 # I->EXPRESSION = I->TEXT :Preserve_Other_Next mov_rax,[rax] # I = I->NEXT cmp_rax, %0 # IF NULL == I jne8 !Preserve_Other_Loop # Otherwise keep looping pop_rdx # Restore RDX pop_rcx # Restore RCX pop_rbx # Restore RBX pop_rax # Restore RAX ret # Print_Hex function # Receives list in RAX # walks the list and prints the I->EXPRESSION for all nodes followed by newline # Uses RBX for I :Print_Hex push_rbx # Protect RBX mov_rbx,r13 # I = Head :Print_Hex_Loop mov_rax,[rbx+BYTE] !8 # I->TYPE cmp_rax, %1 # IF MACRO == I->TYPE je8 !Print_Hex_Next # Skip mov_rax,[rbx+BYTE] !24 # Using EXPRESSION call %File_Print # Print it mov_rax, %10 # NEWLINE call %fputc # Append it :Print_Hex_Next mov_rbx,[rbx] # Iterate to next Token cmp_rbx, %0 # Check for NULL jne8 !Print_Hex_Loop # Otherwise keep looping pop_rbx # Restore RBX ret # File_Print function # Receives CHAR* in RAX # calls fputc for every non-null char :File_Print push_rbx # Protect RBX mov_rbx,rax # Protect S cmp_rax, %0 # Protect against nulls je8 !File_Print_Done # Simply don't try to print them :File_Print_Loop mov_al,[rbx] # Read byte movzx_rax,al # zero extend cmp_rax, %0 # Check for NULL je8 !File_Print_Done # Stop at NULL call %fputc # write it add_rbx, %1 # S = S + 1 jmp8 !File_Print_Loop # Keep going :File_Print_Done pop_rbx # Restore RBX ret # fputc function # receives CHAR in RAX # writes char and returns :fputc push_rcx # Protect RCX push_rdx # Protect RDX push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes mov_rcx,[rip+DWORD] %fout # arg1 = fout push !1 # set size mov_rdx,rsp # arg2 = &size push_rax # allocate stack mov_r8,rsp # arg3 = &output sub_rsp, !32 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !40 # fout->write() mov_rsp,[rsp+BYTE] !56 # deallocate stack pop_rdx # Restore RDX pop_rcx # Restore RCX ret # return # rcx: file handle :close_file push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes sub_rsp, !32 # allocate shadow stack space for UEFI function call_[rcx+BYTE] !16 # file_handle->close(file_handle) mov_rsp,[rsp+BYTE] !40 # 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_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes 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) mov_rsp,[rsp+BYTE] !56 # deallocate stack pop_rax # get interface ret # rcx: handle # rdx: &guid # r8: agent_handle :close_protocol push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes 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) mov_rsp,[rsp+BYTE] !40 # 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 push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes sub_rsp, !32 # allocate shadow stack space for UEFI function call_[r14+BYTE] !64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool) mov_rsp,[rsp+BYTE] !40 # deallocate stack pop_rax # get pool ret # rcx: memory pool # r14: system->boot :free_pool push_rsp # align stack to 16 bytes push_[rsp] # align stack to 16 bytes and_rsp, !-16 # align stack to 16 bytes sub_rsp, !32 # allocate shadow stack space for UEFI function call_[r14+BYTE] !72 # system->boot->free_pool(pool) mov_rsp,[rsp+BYTE] !40 # deallocate stack ret # Protocol GUIDs :LOADED_IMAGE_PROTOCOL %0x5B1B31A1 $0x9562 $0x11D2 !0x8E !0x3F !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B :SIMPLE_FS_PROTOCOL %0x964E5B22 $0x6459 $0x11D2 !0x8E !0x39 !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B :malloc_pool %0 %0 :fin %0 %0 :fout %0 %0 :rootdir %0 %0 :image_handle %0 %0 :root_device %0 %0 :ELF_end