Introduction to x64
从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS红队专家)!
支持HackTricks的其他方式:
如果您想看到您的公司在HackTricks中做广告或下载PDF格式的HackTricks,请查看订阅计划!
加入 💬 Discord群 或 电报群 或在Twitter上关注我们 🐦 @carlospolopm。
通过向HackTricks和HackTricks Cloud github仓库提交PR来分享您的黑客技巧。
x64简介
x64,也称为x86-64,是一种主要用于台式机和服务器计算的64位处理器架构。起源于由英特尔生产的x86架构,后来被AMD采用并命名为AMD64,是今天个人计算机和服务器中普遍采用的架构。
寄存器
x64扩展了x86架构,具有16个通用寄存器,标记为rax、rbx、rcx、rdx、rbp、rsp、rsi、rdi,以及r8到r15。每个寄存器可以存储64位(8字节)的值。这些寄存器还具有32位、16位和8位的子寄存器,用于兼容性和特定任务。
rax- 传统上用于从函数中返回值。rbx- 经常用作内存操作的基址寄存器。rcx- 通常用于循环计数器。rdx- 用于包括扩展算术运算在内的各种角色。rbp- 栈帧的基指针。rsp- 栈指针,跟踪栈的顶部。rsi和rdi- 用于字符串/内存操作中的源和目的索引。r8到r15- x64中引入的额外通用寄存器。
调用约定
x64的调用约定在操作系统之间有所不同。例如:
Windows:前四个参数通过寄存器**
rcx、rdx、r8和r9传递。额外的参数被推送到栈上。返回值在rax**中。System V(在类UNIX系统中常用):前六个整数或指针参数通过寄存器**
rdi、rsi、rdx、rcx、r8和r9传递。返回值也在rax**中。
如果函数有超过六个输入,则其余参数将通过栈传递。RSP,即栈指针,必须是16字节对齐,这意味着在进行任何调用之前,它指向的地址必须能被16整除。这意味着通常我们需要确保我们的shellcode在进行函数调用之前RSP被正确对齐。然而,在实践中,即使不满足这一要求,系统调用也经常能够正常工作。
Swift中的调用约定
Swift有自己的调用约定,可以在https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#x86-64找到。
常见指令
x64指令具有丰富的集合,保持与早期x86指令的兼容性并引入新指令。
mov:将一个值从一个寄存器或内存位置移动到另一个。示例:
mov rax, rbx— 将rbx中的值移动到rax。push和pop:将值推送到/从栈中弹出。示例:
push rax— 将rax中的值推送到栈上。示例:
pop rax— 将栈顶值弹出到rax中。add和sub:加法和减法操作。示例:
add rax, rcx— 将rax和rcx中的值相加,并将结果存储在rax中。mul和div:乘法和除法操作。注意:这些操作对操作数的使用有特定行为。call和ret:用于调用和从函数返回。int:用于触发软件中断。例如,在32位x86 Linux中,int 0x80用于系统调用。cmp:比较两个值并根据结果设置CPU的标志。示例:
cmp rax, rdx— 比较rax和rdx。je、jne、jl、jge等:条件跳转指令,根据先前的cmp或测试结果改变控制流。示例:在
cmp rax, rdx指令之后,je label— 如果rax等于rdx,则跳转到label。syscall:在一些x64系统(如现代Unix)中用于系统调用。sysenter:在某些平台上优化的系统调用指令。
函数序言
推送旧的基指针:
push rbp(保存调用者的基指针)将当前栈指针移动到基指针:
mov rbp, rsp(为当前函数设置新的基指针)为本地变量在栈上分配空间:
sub rsp, <size>(其中<size>是所需字节数)
函数结语
将当前基指针移动到栈指针:
mov rsp, rbp(释放本地变量)从栈中弹出旧的基指针:
pop rbp(恢复调用者的基指针)返回:
ret(将控制返回给调用者)
macOS
系统调用
有不同类别的系统调用,你可以在这里找到它们:
然后,您可以在此网址中找到每个系统调用号:
因此,为了从Unix/BSD类调用open系统调用(5),您需要将其添加为:0x2000000
因此,调用open的系统调用号将是0x2000005
Shellcodes
要编译:
提取字节:
用于测试shellcode的C代码
```c // code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c // gcc loader.c -o loader #include #include #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; }
使用 cat 命令读取
目标是执行 execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL),因此第二个参数 (x1) 是一个参数数组 (在内存中意味着地址的堆栈)。
使用 sh 调用命令
绑定 shell
绑定 shell 来自 https://packetstormsecurity.com/files/151731/macOS-TCP-4444-Bind-Shell-Null-Free-Shellcode.html 在 端口 4444 上。
反向Shell
从https://packetstormsecurity.com/files/151727/macOS-127.0.0.1-4444-Reverse-Shell-Shellcode.html获取反向shell。反向shell连接到127.0.0.1:4444
最后更新于