어셈블리 언어


기본 구조

  • 명령어 opcode
  • 피연산자 operand
  • mov eax, 3 -> mov(명령어) eax(operand1) 3(operand2)
    • eax에 3을 대입해라
명령코드  
데이터 이동 mov, lea
산술 연산 inc, dec, add, sub
논리 연산 and, or, xor, not
비교 cmp, test
분기 jmp, je, jg
스택 push, pop
프로시저 call, ret, leave
시스템 콜 syscall


피연산자

  • 피연산자에는 3가지 종류가 올 수 있음
    • 상수
    • 레지스터
    • 메모리
  • 메모리 피연산자는 []으로 둘러싸인 것으로 표현되며, 앞에 TYPE PTR이 추가될 수 있음
  • 타입의 종류
    • BYTE, WORD, DWORD, QWORD
    • 1바이트, 2바이트, 4바이트, 8바이트
  • QWORD PTR [0x804800] -> 0x804800의 데이터를 8바이트만큼 참조


어셈블리 명령어

  • mov dst, src => src에 들어있는 값을 dst에 대입
  • lea dst, src => src의 유효 주소(Effective Address, EA)를 dst에 저장
  • add dst, src => dst에 src의 값을 더함
  • sub dst, src => dst에서 src의 값을 뺌
  • inc op => op의 값을 1 증가시킴
  • dec op => op의 값을 1 감소시킴
  • 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의 비트 전부 반전
  • cmp op1,op2 => op1과 op2를 비교 (플래그 레지스터 보고 판단 가능)
  • test op1,op2 => 두 피연산자에 and 연산을 취함
  • jmp addr => addr로 rip를 이동시킴
  • je addr => 직전에 비교한 두 피연산자가 같으면 점프 (jump if equal)
  • jg addr => 직전에 비교한 두 연산자 중 전자가 더 크면 점프 (jump if greater)


스택

  • push val => val을 스택 최상단에 쌓음
    • rsp -= 8
    • [rsp] = val
  • pop reg => 스택 최상단에서 값을 꺼내서 reg에 대입
    • rsp += 8
    • [rsp] = [rsp-8]


프로시저

  • 컴퓨터 과학에서 프로시저(Procedure)는 특정 기능을 수행하는 코드 조각을 말함
  • 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있어 전체 코드의 크기를 줄일 수 있음
  • 기능별로 코드 조각에 이름을 붙일 수 있게 되어 코드의 가독성을 크게 높일 수 있음


  • 프로시저를 부르는 행위를 호출(Call)이라고 하며, 프로시저에서 돌아오는 것을 반환(Return)이라고 부름
  • 프로시저를 호출할 때는 프로시저를 실행하고 나서 원래의 실행 흐름으로 돌아와야 하기 때문에 call 다음의 명령어 주소를 스택에 저장하고 프로시저로 rip를 옮김
    • x64 어셈블리언어에는 프로시저의 호출과 반환을 위한 call, leave, ret 명령어가 존재


  • call addr => addr에 위치한 프로시저 호출
    • push return_address
    • jmp addr
    • 함수를 호출할 때 돌아와야 하기 때문에 스택에 반환 주소를 넣고 함수의 주소로 jmp 해야 함
  • leave => 스택프레임 정리
    • mov rsp, rbp
    • pop rbp
  • ret => return address로 반환
    • pop rip


시스템 콜

  • 운영체제는 커널 모드와 유저 모드가 존재
  • 커널 모드는 파일시스템, 입력/출력, 네트워크 통신, 메모리 관리 등 저수준 작업
  • 유저 모드는 유튜브 시청, 프로그래밍 등
  • 시스템 콜은 유저 모드에서 커널 모드로의 권한이 필요할 때 사용됨 예) cat flag
  • x64 아키텍처는 시스템 콜을 위해 syscall 명령어가 있음
    • 요청: rax
    • 인자 순서: rdi -> rsi -> rdx -> rcx -> r8 -> r9 -> stack
  • 아래 rax를 통해 어떤 요청인지 알 수 있고, rdi rsi rdx를 통해 출력 스트림, 출력 버퍼, 출력 길이 등을 알 수 있음

image-20240403014212281

댓글남기기