Aarch64 ASM

Aarch64 ASM

常见寄存器

https://wiki.cdot.senecacollege.ca/wiki/AArch64_Register_and_Instruction_Quick_Start

31个64bit通用寄存器 X0-X30(Wn是他们的低32位) 堆栈指针寄存器sp,指令指针寄存器pc

  • x0-x7 用于子程序调用时的参数传递,X0还用于返回值传递 ,多于参数通过栈传递
  • x8常用来存放系统调用号
  • x8-x15 临时寄存器,易变寄存器 子程序不需要保存
  • r16-r17子程序内部调用寄存器IPC(intra-procedure-call)
  • x18 平台寄存器,它的使用与平台相关,避免使用
  • x19-x28临时寄存器,子程序使用时必须保存
  • x29 栈帧寄存器fp(frame register)
  • x30 链接寄存器lr(link register)保存返回地址
  • 堆栈指针寄存器sp
  • 指令指针寄存器pcaarch64的pc不能直接读写了,但某些指令可以间接使用,如adr和br,adr指令时pc值是按当前指令pc值来算,而不是和arm32一样的+4或+8
  • XZR(32位WZR)零寄存器

指令助记符

整型
W/R 32bit整数
X 64bit整数
加载/存储、符号-0扩展
B 无符号8bit字节
SB 带符号8bit字节
H 无符号16bit半字
SH 带符号16bit半字
W 无符号32bit字
SW 带符号32bit字
P Pair(一对)
寄存器宽度改变
H 高位(dst gets top half)
N 有限位(dst < src)
L Long (dst > src)
W Wide (dst==src1,src1>src2) ?

常见指令

指令定长32bit,ida里会生成一些8字节的伪代码

mov

MOVK Rn, #imm, #shift:用于将一个 16 位立即数移动到指定的寄存器,左移偏移量shift用于指定将立即数放置在寄存器中的位置,其余位保持不变

MOVZ Rn, #imm, #shif:类似于movk,其余位置零

访存

adrl:和adr一样,是中等范围的地址读取伪指令

ADRP Xd, symbol:(Address of Page) 把symbol向左移动12位 低位补零,移到Xd寄存器,所以就是一个page4k对齐的位置

  • 寻址数据时由于还是四字节定长指令,可以操作立即数太小,一般就addrp xd,sybols把页边界地址载入,再add xd,xd,offset,再加上页偏移来寻址

strb: (store register byte) 将寄存器中的值写入到内存中,只存储一个字节

ldrb: (load register byte) 将内存中的值(只读取一个字节)读取到寄存器中,高位清零(无符号零拓展)

ldrsb: (Load Register Signed Byte)加载一个有符号字节,将有一个字节按符号位拓展到寄存器字长

ldrh:加载半个寄存器字长到寄存器,高位清零

strh:半字存储

swp:交换指令SWP X0,X1,[X2] ;将memory(X2)数据加载到X0,同时将X1中的数据存储到memory(X2)

栈操作

stp: 入栈指令(str 的变种指令,可以同时操作两个寄存器)

  • STP x4, x5, [sp, #-0x20]!:将sp+0x20处依次覆盖为x4,x5,即x4入栈到sp-0x20x5入栈到sp-0x0x20+8,最后sp-=0x20

ldp: 出栈指令(ldr 的变种指令,可以同时操作两个寄存器)

  • LDP x29, x30, [sp], #0x40:将sp弹栈到x29sp+0x8弹栈到x30,最后sp += 0x40

分支跳转

blr Xm:跳转到由Xm目标寄存器指定的地址处,同时将下一条指令地址存放到X30寄存器中

br Xm:跳转到由Xm目标寄存器指定的地址处

**ret {Xm}**:子程序返回到由Xm目标寄存器指定的地址处,Xm不写默认是X30

cbz Xm,label:Xm结果为零(Zero)则跳转label(只能跳到后面的指令)compare and branch if zero

cbnz:不为0时跳转,只能跳到后面的指令

svc #imm:软中断

#include <stdio.h>
#include <unistd.h>
int main() {
int x=0x12345678;
printf("hello,world");
printf("%x",x);
return 0;
}

ida

.text:0000000000000754
.text:0000000000000754 var_20= -0x20
.text:0000000000000754 x= -4
.text:0000000000000754
.text:0000000000000754 ; __unwind {
.text:0000000000000754 FD 7B BE A9 STP X29, X30, [SP,#var_20]!
.text:0000000000000758 FD 03 00 91 MOV X29, SP
.text:000000000000075C 00 CF 8A 52 80 46 A2 72 MOV W0, #0x12345678
.text:0000000000000764 E0 1F 00 B9 STR W0, [SP,#0x20+x]
.text:0000000000000768 00 00 00 90 00 C0 1E 91 ADRL X0, aHelloWorld ; "hello,world"
.text:0000000000000770 B0 FF FF 97 BL .printf
.text:0000000000000770
.text:0000000000000774 E1 1F 40 B9 LDR W1, [SP,#0x20+x]
.text:0000000000000778 00 00 00 90 00 00 1F 91 ADRL X0, aX ; "%x"
.text:0000000000000780 AC FF FF 97 BL .printf
.text:0000000000000780
.text:0000000000000784 00 00 80 52 MOV W0, #0
.text:0000000000000788 FD 7B C2 A8 LDP X29, X30, [SP],#0x20
.text:000000000000078C C0 03 5F D6 RET

objdump

image-20230720143324402

fp和sp都指向栈顶,原来的bp和返回地址存在栈顶,所以通过栈溢出基本修改不到本函数的返回地址,只能修改本函数调用者函数的bp和返回地址

参考链接

https://www.cnblogs.com/lvdongjie/p/6644821.html

https://wiki.cdot.senecacollege.ca/wiki/AArch64_Register_and_Instruction_Quick_Start