From 3317e845f5babf0d43a2a1599a6c55468bc003c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sat, 23 Jul 2022 18:40:41 +0100 Subject: [PATCH] Add hex0.M1. --- amd64/Development/hex0.M1 | 343 ++++++++++++++++++++++++++++++++++++++ amd64/Development/hex0.S | 17 +- 2 files changed, 351 insertions(+), 9 deletions(-) create mode 100644 amd64/Development/hex0.M1 diff --git a/amd64/Development/hex0.M1 b/amd64/Development/hex0.M1 new file mode 100644 index 0000000..1059fc5 --- /dev/null +++ b/amd64/Development/hex0.M1 @@ -0,0 +1,343 @@ +# SPDX-FileCopyrightText: 2022 Andrius Štikonas +# SPDX-FileCopyrightText: 2017 Jeremiah Orians +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# Usage: hex0 file.hex0 file +# Does not validate the arguments or check for success + +# Calling convention: +# First four arguments are passed via registers rcx, rdx, r8, r9 (if they fit in 64-bits) +# but we need to leave stack space +# rax, rcx, rdx, r8, r9, r10 and r11 are volatile and can be changed by called function + +# Registers: +# r12 in/fin: input file name, later reused for handle +# r13 out/fout: output file name, later reused for handle +# r14 system->boot->open_protocol from UEFI, later reused for rootdir +# r15 image_handle from UEFI + +# hex0 algorithm mostly follows stage0-posix version but uses rdi instead of rbp + + +DEFINE ADD_EAX_EDI 01F8 +DEFINE ADDI8_RBX 4883C3 +DEFINE ADDI8_RSP 4883C4 +DEFINE CALLI32 E8 +DEFINE CALL_R14 41FFD6 +DEFINE CALL_RCX_Immediate8 FF51 +DEFINE CMPI8_AL 3C +DEFINE COPY_EAX_to_EDI 89C7 +DEFINE COPY_RBX_to_R12 4989DC +DEFINE COPY_RBX_to_R13 4989DD +DEFINE COPY_RCX_to_RAX 4889C1 +DEFINE COPY_RDX_to_RSP 4889E2 +DEFINE COPY_RSP_to_RBP 4889E5 +DEFINE COPY_RBP_to_RSP 4889EC +DEFINE COPY_R8_to_RSP 4989E0 +DEFINE COPY_RCX_to_R9 4989C9 +DEFINE COPY_R12_to_RCX 4C89E1 +DEFINE COPY_R12_to_R8 4D89E0 +DEFINE COPY_R13_to_RCX 4C89E9 +DEFINE COPY_R13_to_R8 4D89E8 +DEFINE COPY_R14_to_RCX 4C89F1 +DEFINE COPY_R15_to_RCX 4889CF +DEFINE DEC_EBX FFCB +DEFINE JE8 74 +DEFINE JGE8 7D +DEFINE JL8 7C +DEFINE JMP8 EB +DEFINE JNE8 75 +DEFINE LOAD64_into_RBX_from_Address_RAX_Immediate8 488B58 +DEFINE LOAD64_into_RAX_from_Address_RSP_Immediate8 488B4424 +DEFINE LOAD64_into_RCX_from_Address_RSP_Immediate8 488B4C24 +DEFINE LOAD64_into_RCX_from_Address_RCX_Immediate8 488B49 +DEFINE LOAD64_into_R12_from_Address_RSP_Immediate8 4C8B6424 +DEFINE LOAD64_into_R13_from_Address_RSP_Immediate8 4C8B6C24 +DEFINE LOAD64_into_R14_from_Address_RDX_Immediate8 4C8B72 +DEFINE LOAD64_into_R14_from_Address_R14_Immediate32 4D8BB6 +DEFINE LOAD8_AL_from_Address_RBX 8A03 +DEFINE LOADI64_RDX 48C7C2 +DEFINE POP_RAX 50 +DEFINE POP_RBX 5B +DEFINE POP_RSI 5E +DEFINE POP_R9 4159 +DEFINE POP_R14 415E +DEFINE PUSH 6A +DEFINE PUSH_RAX 50 +DEFINE PUSH_RBX 53 +DEFINE PUSH_RDX 52 +DEFINE PUSH_RSI 56 +DEFINE RET C3 +DEFINE ROR_R9 49D1C9 +DEFINE SHL_EBP_Immediate8 C1E5 +DEFINE STOREI8_into_Address_RBX CB03 +DEFINE SUBI8_ESP 83EC +DEFINE SUBI8_AL 2C +DEFINE XOR_EBX_EBX 31DB +DEFINE XOR_EDI_EDI 31FF +DEFINE TEST_EAX_EAX 85C0 +DEFINE TEST_EBX_EBX 85DB +DEFINE TEST_ESI_ESI 85F6 + +# efi_main(void *image_handle, struct efi_system_table *system) +:_start + COPY_RSP_to_RBP # save stack pointer + COPY_R15_to_RCX # save image_handle + LOAD64_into_R14_from_Address_RDX_Immediate8 !96 # system->boot + LOAD64_into_R14_from_Address_R14_Immediate32 %280 # system->boot->open_protocol + + # Open Loaded Image protocol + PUSH_RAX # allocate stack for image + COPY_R8_to_RSP # arg3 = &image + LOADI64_RDX &LOADED_IMAGE_PROTOCOL_8 # EFI_LOADED_IMAGE_PROTOCOL_GUID (last 64 bits) + PUSH_RDX # push last 64 bits onto stack + LOADI64_RDX &LOADED_IMAGE_PROTOCOL # EFI_LOADED_IMAGE_PROTOCOL_GUID (first 64 bits) + PUSH_RDX # push first 64 bits onto stack + COPY_RDX_to_RSP # arg2 = &guid + PUSH !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + PUSH !0 # arg5 = NULL + COPY_R8_to_RSP # arg4 = image_handle + # arg1 = ImageHandle (already set) + SUBI8_ESP !32 # allocate shadow stack space for UEFI function + CALL_R14 # system->boot->open_protocol(image_handle, &guid, &image, image_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL) + LOAD64_into_RAX_from_Address_RSP_Immediate8 !64 # get_image + + # Command line args + COPY_RCX_to_RAX # save image + LOAD64_into_RBX_from_Address_RAX_Immediate8 !56 # options = image->load_options + +:loop_options1 # Skip application name + ADDI8_RBX !2 # ++options + LOAD8_AL_from_Address_RBX # *options + CMPI8_AL !0x20 # if *options != ' ' + JNE8 !loop_options1 # then jump + + ADDI8_RBX !2 # ++options + COPY_RBX_to_R12 # save input file + +:loop_options2 # Skip argv[1] + ADDI8_RBX !2 # ++options + LOAD8_AL_from_Address_RBX # *options + CMPI8_AL !0x20 # if *options != ' ' + JNE8 !loop_options2 # then jump + + STOREI8_into_Address_RBX # *options = 0; + ADDI8_RBX !2 # ++options + COPY_RBX_to_R13 # save output file + + # Get root device + PUSH_RAX # allocate stack for rootfs + COPY_R8_to_RSP # arg3 = &rootfs + LOADI64_RDX &SIMPLE_FS_PROTOCOL_8 # EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID (last 64 bits) + PUSH_RDX # push last 64 bits onto stack + LOADI64_RDX &SIMPLE_FS_PROTOCOL # EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID (first 64 bits) + PUSH_RDX # push first 64 bits onto stack + COPY_RDX_to_RSP # arg2 = &guid + PUSH !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + PUSH !0 # arg5 = NULL + COPY_R8_to_RSP # arg4 = image_handle + LOAD64_into_RCX_from_Address_RCX_Immediate8 !24 # arg1 = root_device = image->device + SUBI8_ESP !32 # allocate shadow stack space for UEFI function + CALL_R14 # system->boot->open_protocol(root_device, &guid, &rootfs, image_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL) + LOAD64_into_RCX_from_Address_RSP_Immediate8 !64 # get rootfs + + # Get root directory + PUSH_RDX # allocate stack for rootdir + COPY_RDX_to_RSP # arg2 = &rootdir + PUSH_RAX # allocate shadow stack space for UEFI function + PUSH_RAX # allocate shadow stack space for UEFI function + CALL_RCX_Immediate8 !8 # rootfs->open_volume(rootfs, &rootdir) + POP_RAX # deallocate stack + POP_RAX # deallocate stack + POP_R14 # save &rootdir + + # Open file for writing + PUSH_RDX # allocate stack for fout + COPY_RDX_to_RSP # 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 + COPY_R13_to_R8 # arg3 = out + COPY_R14_to_RCX # arg1 = rootdir + SUBI8_ESP !32 # allocate shadow stack space for UEFI function + CALL_RCX_Immediate8 !8 # rootdir->open() + LOAD64_into_R13_from_Address_RSP_Immediate8 !40 # get fout + + # Open file for reading + PUSH_RDX # allocate stack for fin + COPY_RDX_to_RSP # 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 + COPY_R12_to_R8 # arg3 = in + COPY_R14_to_RCX # arg1 = rootdir + SUBI8_ESP !32 # allocate shadow stack space for UEFI function + CALL_RCX_Immediate8 !8 # rootdir->open() + LOAD64_into_R12_from_Address_RSP_Immediate8 !40 # get fin + + # Our flag for byte processing + PUSH !-1 + POP_RBX # rbx = -1 + + # temp storage for the sum + XOR_EDI_EDI # rdi = 0 + +:loop + # Read a byte + CALLI32 %read_byte + + # process byte + CALLI32 %hex + + # deal with -1 values + TEST_EAX_EAX + JL8 !loop + + # deal with toggle + TEST_EBX_EBX # jump if ebx >= 0 + JGE8 !print + + # process first byte of pair + COPY_EAX_to_EDI + XOR_EBX_EBX # rbx = 0 + JMP8 !loop + +# process second byte of pair +:print + # update the sum and store in output + SHL_EBP_Immediate8 !4 + ADD_EAX_EDI + + # flip the toggle + DEC_EBX # rbx = -1 + + CALLI32 %write_byte + + JMP8 !loop + +:hex + # Purge Comment Lines (#) + CMPI8_AL !35 + JE8 !purge_comment + + # Purge Comment Lines (;) + CMPI8_AL !59 + JE8 !purge_comment + + # deal all ascii less than '0' + CMPI8_AL !48 + JL8 !ascii_other + + # deal with 0-9 + CMPI8_AL !58 + JL8 !ascii_num + + # deal with all ascii less than 'A' + CMPI8_AL !65 + JL8 !ascii_other + + # deal with 'A'-'F' + CMPI8_AL !71 + JL8 !ascii_high + + # deal with all ascii less than 'a' + CMPI8_AL !97 + JL8 !ascii_other + + #deal with 'a'-'f' + CMPI8_AL !103 + JL8 !ascii_low + + # The rest that remains needs to be ignored + JMP8 !ascii_other + +:purge_comment + # Read a byte + CALLI32 %read_byte + + # Loop if not LF + CMPI8_AL !10 + JNE8 !purge_comment + + # Otherwise return -1 + +:ascii_other + PUSH !-1 + POP_RAX # return = -1 + RET + +:ascii_num + SUBI8_AL !48 + RET + +:ascii_low + SUBI8_AL !32 # convert to uppercase + +:ascii_high + SUBI8_AL !55 + RET + +# Writes byte stored in al +:write_byte + COPY_R13_to_RCX # arg1 = fout + PUSH !1 # size = 1 + COPY_RDX_to_RSP # arg2 = &size + PUSH_RAX # allocate stack + COPY_R8_to_RSP # 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_Immediate8 !40 # fout->write() + ADDI8_RSP !40 # deallocate stack + + RET # return + +:read_byte + COPY_R12_to_RCX # arg1 = fin + PUSH !1 # size = 1 + COPY_RDX_to_RSP # arg2 = &size + PUSH_RSI # allocate stack + COPY_R8_to_RSP # 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_Immediate8 !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 + + # If the file ended (0 bytes read) terminate + TEST_ESI_ESI # if size = 0 + JE8 !terminate # then we are done + + RET # return + +:terminate + PUSH_RBX # allocate stack + COPY_R12_to_RCX # arg1 = fin + CALL_RCX_Immediate8 !16 # fin->close() + COPY_R13_to_RCX # arg1 = fout + CALL_RCX_Immediate8 !16 # fout->close() + + COPY_RBP_to_RSP # restore stack + RET # return to UEFI + + +# Protocol GUIDs +:LOADED_IMAGE_PROTOCOL + %0x5b1b31a1 + @0x9562 +:LOADED_IMAGE_PROTOCOL_8 + @0x11d2 + !0x8e !0x3f !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b + +:SIMPLE_FS_PROTOCOL + %0x0964e5b22 + @0x6459 +:SIMPLE_FS_PROTOCOL_8 + @0x11d2 + !0x8e !0x39 !0 !0xa0 !0xc9 !0x69 !0x72 !0x3b diff --git a/amd64/Development/hex0.S b/amd64/Development/hex0.S index f3aeb69..d3553c6 100644 --- a/amd64/Development/hex0.S +++ b/amd64/Development/hex0.S @@ -56,7 +56,7 @@ loop_options1: # Skip application name jne loop_options1 # then jump add rbx, 2 # ++options - mov r12, rbx + mov r12, rbx # save input file loop_options2: # Skip argv[1] add rbx, 2 # ++options @@ -66,7 +66,7 @@ loop_options2: # Skip argv[1] mov byte ptr [rbx], 0 # *options = 0; add rbx, 2 # ++options - mov r13, rbx + mov r13, rbx # save output file # Get root device push rax # allocate stack for rootfs @@ -84,7 +84,7 @@ loop_options2: # Skip argv[1] call r14 # system->boot->open_protocol(root_device, &guid, &rootfs, image_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); mov rcx, [rsp+64] # get rootfs - # Get rootfs + # Get root directory push rdx # allocate stack for rootdir mov rdx, rsp # arg2 = &rootdir push rax # allocate shadow stack space for UEFI function @@ -100,8 +100,7 @@ loop_options2: # Skip argv[1] 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, 1 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ - + ror r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ mov r8, r13 # arg3 = out mov rcx, r14 # arg1 = rootdir sub esp, 32 # allocate shadow stack space for UEFI function @@ -125,7 +124,7 @@ loop_options2: # Skip argv[1] pop rbx # rbx = -1 # temp storage for the sum - xor edi, edi # edi = 0 + xor edi, edi # rdi = 0 loop: # Read a byte @@ -144,7 +143,7 @@ loop: # process first byte of pair mov edi, eax - xor ebx, ebx # ebx = 0 + xor ebx, ebx # rbx = 0 jmp loop # process second byte of pair @@ -254,7 +253,7 @@ read_byte: pop rsi # save size to rsi # If the file ended (0 bytes read) terminate - test rsi, rsi # if size == 0 + test esi, esi # if size == 0 je terminate # then we are done ret # return @@ -263,7 +262,7 @@ terminate: push rbx # allocate stack mov rcx, r12 # arg1 = fin call [rcx+16] # fin->close() - mov rcx, r13 # arg1 = fin + mov rcx, r13 # arg1 = fout call [rcx+16] # fout->close() abort: # used for debugging only mov rsp, rbp # restore stack