[Dreamhack]x86 Assembly

최윤지·2024년 1월 28일

System Hacking

목록 보기
3/9

x64 어셈블리 언어

기본구조 : 명령어 + 피연산자

피연산자(Operand)

  • 상수(Immediate Value)

  • 레지스터(Register)

  • 메모리(Memory)

    • 메모리 피연산자는 [ ]으로 둘러싸인 것으로 표현, 앞에 크기 지정자(Size Directive) TYPE PTR이 추가될 수 있음

    • 타입에는 BYTE(1바이트), WORD(2바이트), DWORD(4바이트), QWORD(8바이트)가 올 수 있음
      ex ) WORD PTR [rax] : rax가 가르키는 주소에서 데이터를 2바이트 만큼 참조

명령어(Operation Code, Opcode)

  • 데이터 이동(Data Transfer) : 어떤 값을 레지스터나 메모리에 옮기도록 지시

    • mov dst, src : src에 들어있는 값을 dst에 대입
    • lea dst, src : src의 유효 주소(Effective Address, EA)를 dst에 저장
  • 산술 연산(Arithmetic) : 덧셈, 뺄셈, 곱셈, 나눗셈 연산 지시

    • add dst, src : dst에 src의 값을 더함
    • sub dst, src : dst에서 src의 값을 뺌
    • inc op : op의 값을 1 증가 시킴
    • dec op : op의 값을 1 감소 시킴
  • 논리 연산(Logical) : 비트 연산 지시(비트 단위)

    • and dst, src : dst와 src의 비트가 모두 1이면 1, 아니면 0
    • or dst, src : dst와 src의 비트 중 하나라도 1이면 1, 아니면 0
    • xor dst, src : dst와 src의 비트가 서로 다르면 1, 같으면 0
    • not op : op의 비트 전부 반전
  • 비교(Comparison) : 두 피연산자의 값을 비교하고, 플래그 설정

    • cmp op1, op2 : op1과 op2를 비교
    • test op1, op2 : op1과 op2를 비교
  • 분기(Branch) : rip를 이동시켜 실행 흐름을 바꿈

    • jmp addr : addr로 rip를 이동시킴(jump)
    • je addr : 직전에 비교한 두 피연산자가 같으면 addr로 rip 이동(jump if equal)
    • jg addr : 직전에 비교한 두 연산자 중 전자가 더 크면 addr로 rip 이동(jump if greater)
  • 스택(Stack)

    • push val : val을 스택 최상단에 쌓음

      연산
      rsp -= 8
      [rsp] = val

    • pop reg : 스택 최상단의 값을 꺼내서 reg에 대입

      연산
      rsp += 8
      reg = [rsp - 8]

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

    호출(Call) : 프로시저를 부르는 행위
    반환(Return) : 프로시저에서 돌아오는 것

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

    • call addr : addr에 위치한 프로시져 호출

      연산
      push return_address
      jmp addr

    • leave : 스택프레임 정리

      연산
      mov rsp, rbp
      pop rbp

    • ret : return address로 반환

      연산
      pop rip

  • 시스템 콜(System call)
    : 유저 모드에서 커널 모드의 시스템 소프트웨어에게 어떤 동작을 요청하기 위해 사용

    커널 모드 : 운영체제가 전체 시스템을 제어하기 위해 시스템 소프트웨어에 부여하는 권한
    유저 모드 : 운영체제가 사용자에게 부여하는 권한

    • syscall : 필요한 기능과 인자에 대한 정보를 레지스터로 전달하면, 커널이 이를 읽어서 요청을 처리

      리눅스에서는 x64 아키텍처에서 rax로 무슨 요청인지 나타내고, 순서대로 필요한 인자를 전달

      요청 : rax
      인자 순서 : rdi -> rsi -> rdx -> rcx -> r8 -> r9 -> stack

    • syscall 테이블

      syscallraxarg0(rdi)arg1(rsi)arg2(rdx)
      read0x00unsigned int fdchar *bufsize_t count
      write0x01unsigned int fdconst char *bufsize_t count
      open0x02const char *filenameint flagsumode_t mode
      close0x03unsigned int fd
      mprotect0x0aunsigned long startsize_t lenunsigned long prot
      connect0x2aint sockfdstruct sockaddr *addrint addrlen
      execve0x3bconst char *filenameconst char *const *argvconst char *const *envp

0개의 댓글