본문 바로가기

보안

[시스템해킹] Background: x86 Assembly

어셈블리 언어

: 컴퓨터의 기계어와 치환되는 언어

- 명령어 집합구조(ISA)에 따라(IA-32, x86-64, ARM, MIPS ...) 많은 수의 어셈블리어 존재

 

 x86-64 어셈블리 언어
  • 문법 구조: 명령어(Opcde)와 목적어에 해당하는 피연산자(Operand)

  • Opcode 종류

 

기본 어셈블리
  • 데이터 이동: 어떤 값을 레지스터나 메모리에 옮기도록 지시
    • mov dst, src: src에 들어있는 값을 dst에 대입
    • lea dst, src: src의 유효 주소를 dst에 저장
      • lea rsi, [rbx+8*rcx]: rbx+8*rcx를 rsi에 대입
  • 산술 연산: 덧셈, 뺄셈, 곱셈, 나눗셈 연산
    • add dst, src: dst에 src의 값을 더함
    • sub dst, src: dst에서 src의 값을 뺌
    • inc op: op 값 1 증가
    • dec op: op 값 1 감소
  • 논리 연산: and, or, xor, neg 등 비트 연산 
  • 비교: 두 피연산자의 값 비교, 플래그 설정
    • cmp op1, op2: 두 피연산자 빼서 대소 비교
    • test op1, op2: AND 비트연산
  • 분기: rip를 이동시켜 실행 흐름 바꿈
    • jmp addr: addr로 rip 이동
    • je addr: 직전에 비교한 두 피연산자가 같으면 점프
    • jg addr: 직전에 비교한 두 연산자 중 전자가 더 크면 점프
    • ....
스택 관련 어셈블리
  • push val: val을 스택 최상단에 쌓음
    • rsp -= 8
    • [rsp] = val
---- 전 ----
[Register]
rsp = 0x7fffffffc400

[Stack]
0x7fffffffc400 | 0x0  <- rsp
0x7fffffffc408 | 0x0

[Code]
push 0x31337

---- 후 ----
[Register]
rsp = 0x7fffffffc3f8

[Stack]
0x7fffffffc3f8 | 0x31337 <- rsp 
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0
  • pop reg: 스택 최상단의 값을 reg에 대입
    • rsp += 8
    • reg = [rsp-8]
---- 전 ----
[Register]
rax = 0
rsp = 0x7fffffffc3f8

[Stack]
0x7fffffffc3f8 | 0x31337 <- rsp 
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0

[Code]
pop rax

---- 후 ----
[Register]
rax = 0x31337
rsp = 0x7fffffffc400

[Stack]
0x7fffffffc400 | 0x0 <- rsp 
0x7fffffffc408 | 0x0

 

프로시저(Procedure): 특정 기능을 수행하는 코드 조각

- 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있어 전체 코드 크기를 줄일 수 있고, 가독성 증가

- 프로시저를 부르는 행위를 호출(Call)이라 하고, 돌아오는 것을 반환(Return)이라 함

- 프로시저를 호출할 때 프로시저를 실행하고 나서 원래의 실행 흐름으로 돌아와야 하므로 call 다음의 명령어 주소를 스택에 저장하고 프로시저로 rip를 이동시킴

  • call addr: addr에 위치한 프로시저 호출
    • push return_address
    • jmp addr
  • leave: 스택프레임 정리
    • mov rsp, rbp
    • pop rbp
  • ret: return address로 반환
    • pop rip