TL;DR

  • Windows는 AArch64 함수에도 패치 지점을 두며, 고정 길이 명령어 덕분에 x86보다 단순한 핫패칭 방식을 사용함.
  • AArch64의 명령어 포인터는 항상 4의 배수 위치에 있어 명령어 중간에 놓이지 않음.
  • 함수 첫 명령어에 별도 제약이 없으며, 모든 명령어는 명령어 포인터가 내부에 있는 위험 없이 원자적으로 갱신할 수 있음.
  • 각 함수 앞의 12바이트 패치 공간은 대체 함수로 분기하는 세 명령어 트램펄린에 사용됨.
  • 함수 진입점의 첫 명령어는 대개 반환 주소에 서명하는 포인터 인증 명령어인 pacibsp임.

AArch64의 패치 지점

  • x86-32와 x86-64용 Windows는 각 함수 시작 부분에 패치 지점을 두는 것으로 알려져 있으며, AArch64(Windows에서 arm64로 부름)도 함수에 패치 지점을 둠.
  • AArch64는 명령어 길이가 고정되어 있어 명령어 포인터가 바이트 시퀀스 중간에 있을 때 명령어를 패치하는 상황을 고려할 필요가 없음. 명령어 포인터는 항상 4의 배수 위치에 있음.
  • 따라서 함수의 첫 명령어에는 특별한 제한이 없으며, 모든 명령어를 명령어 포인터가 명령어 내부에 놓일 위험 없이 원자적으로 갱신할 수 있음.

트램펄린과 레지스터 사용

  • 각 함수 앞에는 12바이트의 패치 공간이 있으며, 대체 함수 주소를 구성해 그곳으로 분기하는 세 명령어 트램펄린을 수용함.
  • 트램펄린은 adrp로 대체 함수의 페이지 주소를 구하고, add로 페이지 내 오프셋을 더한 뒤, br로 해당 주소에 분기하는 방식임.
  • 함수 진입점의 한 명령어는 패치 공간으로 되돌아가는 분기 명령어로 덮어씀.
  • xip0는 프로시저 내부 호출용 임시 레지스터 두 개 중 하나이며, 모든 분기 명령어가 이 레지스터를 변경할 수 있다는 규약이 적용됨.
  • 호출자는 원래 분기 명령어를 사용해 함수 진입점에 도달하므로 xip0를 다른 용도로 사용할 수 없음. 따라서 트램펄린에서 xip0를 변경해도 문제가 없음.

함수 진입점의 포인터 인증

  • 함수 진입점의 첫 명령어는 거의 확실히 pacibsp임.
  • pacibsp는 반환 주소에 서명하는 포인터 인증(pointer authentication) 명령어로, 반환 주소를 덮어쓰는 공격과 ROP 공격에 대한 코드의 저항성을 높임.