Skip to content

Instantly share code, notes, and snippets.

@Zheaoli
Last active August 30, 2023 11:19
Show Gist options
  • Save Zheaoli/f37bc1fb04917fdfac36d644ee69f7e9 to your computer and use it in GitHub Desktop.
Save Zheaoli/f37bc1fb04917fdfac36d644ee69f7e9 to your computer and use it in GitHub Desktop.
.global _start
.section .text
_start:
# Setup stack frame
movq %rsp, %rbp
# Load argc
movq (%rbp), %r8 # %r8 now holds argc
# Load argv
leaq 8(%rbp), %r9 # %r9 now points to argv[0]
# Find envp by iterating through argv until NULL is found
movq %r9, %r10 # %r10 will be used to find envp
find_envp:
movq (%r10), %rdi # Load the current pointer in argv
cmpq $0, %rdi # Compare it to NULL
je envp_found # If NULL, we've found the end of argv
addq $8, %r10 # Otherwise, move to the next pointer in argv
jmp find_envp
envp_found:
addq $8, %r10 # Move one more step to point to the start of envp
# Allocate space on the stack for the new argv array
subq $8, %rsp # Space for NULL termination
subq %r8, %rsp
subq %r8, %rsp # Space for argc pointers (including argv[0])
movq %rsp, %r11 # %r11 now points to the start of the new argv array
# Copy argv pointers to the new array
movq $0, %rcx # Counter
copy_loop:
cmpq %rcx, %r8
je copy_done
movq (%r9, %rcx, 8), %rdi
movq %rdi, (%r11, %rcx, 8)
incq %rcx
jmp copy_loop
copy_done:
movq $0, (%r11, %rcx, 8) # NULL-terminate the new argv array
# Check if argc > 0
cmpq $0, %r8
jle .Lexit
# Execute execve syscall
movq $59, %rax # syscall number for execve
movq (%r11), %rdi # filename is argv[0]
movq %r11, %rsi # New argv array
movq %r10, %rdx # envp
syscall
.Lexit:
# Exit the program using the exit syscall
movq $60, %rax
xorq %rdi, %rdi
syscall
@Zheaoli
Copy link
Author

Zheaoli commented Aug 29, 2023

.global _start

.section .text
_start:
    # Setup stack frame
    mov x29, sp

    # Load argc
    ldr x8, [x29]        # x8 now holds argc

    # Load argv
    add x9, x29, #8      # x9 now points to argv[0]

    # Find envp by iterating through argv until NULL is found
    mov x10, x9          # x10 will be used to find envp
find_envp:
    ldr x19, [x10]       # Load the current pointer in argv
    cbz x19, envp_found  # If NULL, we've found the end of argv
    add x10, x10, #8     # Otherwise, move to the next pointer in argv
    b find_envp

envp_found:
    add x10, x10, #8     # Move one more step to point to the start of envp

    # Allocate space on the stack for the new argv array
    sub sp, sp, #8       # Space for NULL termination
    sub sp, sp, x8, lsl #3
    sub sp, sp, x8, lsl #3      # Space for argc pointers (including argv[0])
    mov x11, sp          # x11 now points to the start of the new argv array

    # Copy argv pointers to the new array
    mov x12, #0          # Counter
copy_loop:
    cmp x12, x8
    b.eq copy_done
    ldr x19, [x9, x12, lsl #3]
    str x19, [x11, x12, lsl #3]
    add x12, x12, #1
    b copy_loop

copy_done:
    mov x19, #0
    str x19, [x11, x12, lsl #3]   # NULL-terminate the new argv array

    # Check if argc > 0
    cmp x8, #0
    b.le .Lexit

    # Execute execve syscall
    mov x8, #221         # syscall number for execve
    ldr x0, [x11]        # filename is argv[0]
    mov x1, x11          # New argv array
    mov x2, x10          # envp
    svc #0

.Lexit:
    # Exit the program using the exit syscall
    mov x8, #93
    mov x0, #0
    svc #0

@eiffel-fl
Copy link

eiffel-fl commented Aug 30, 2023

Quite cool! You can nonetheless speed up the whole thing by jumping directly to environment which is basically &argv[argc + 1] (you can test in C code if you want to be sure about it).
I would say something like this should do the trick but I am not an expert in amd64 assembly (or assembly at all):

movq r9, r11
add $1, r11 # r11 is argc + 1
movq (%r9, %r11, 8), r10 # r10 is &argv[argc + 1], i.e. environment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment