Reverse-Study: 2주차

KangDroid·2021년 3월 29일
0

ReverseEngineering

목록 보기
2/2

Instruction

Instruction Cycle

  • Fetch / Decode / Execute 형태
    • Fetch: Program / Object로부터 명령어를 가지고 오는 단계
    • Decode: 해당 명령어가 무슨 명령어인지 알아오는 단계
      • 주로 OPCode / Addr로 알아냄
    • Execute: OPCode에 해당하는 연산을 실행
      • 연산 방식과 Branch 계산법은 주소 비트 수[주소 계산 방식]에 따라 달라짐

Register with Instruction

  • 항상 프로그램이 돌아가기 위해서는 변수/상수 선언은 필수적이고[없을 수가 없음]
  • 메모리에 이를 저장해서 계산을 진행한다.
  • 그러면 명령어 그 자체는?
    • '레지스터' 를 이용해서 연산을 진행함.
    • 레지스터 = [어떻게 보면] 시스템[Low-Level operation]을 위한 메모리라고 할 수 있음!

X86 Instruction

General Purpose Register

  • 말 그대로 여러 목적으로 막 쓸 수 있는 레지스터
  • 여러 GPR 중에 rax는 Return-Address를 의미합니다.
    • 다만, 함수의 리턴 값이 들어갈 '수' 있다는 것
  • 종류
rax
rcx
rdx
r8
r9
r10
r11
rbx
rsi
rdi
rbp
r12
r13
r14
r15
rsp

Calling Convention

  • Reference: https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160
  • Refernce2: System V Application Binary Interface AMD64 Architecture Processor Supplement
  • 흔히 함수 호출을 어떻게 진행할 것인지 -> 즉 인자를 스택에 넣을 것인지 아니면 레지스터에 넣을 것인지 결전하는 것이 바로 Calling Convention이라고 한다.
  • 전체적으로 Parameter Passing 부분에서
    • 윈도우는 레지스터[인자] 4개까지 지원하고
    • System V 아키텍쳐는 총 6개까지 지원하고
    • 나머지는 스택에 저장한다.

Windows Calling Convention[Int 기준]

  • RCX/RDX/R8/R9 순으로 레지스터 지원, 그 후로는 Stack 활용

Windows Calling Convention[Double 기준]

  • XMM0/XMM1/XMM2/MXX3 순으로 레지스터 지원, 그 후로는 Stack 활용

System V[Linux/macOS] Calling Convention[Int 기준]

  • RDI/RSI/RDX/RCX/R8/R9 순으로 레지스터를 지원하고, 그 후로는 Stack 활용
    ###3 System V[Linux/macOS] Calling Convention[Double 기준]
  • XMM0 ~ XMM7까지 모두 사용, 그 후로는 Stack 활용

RSP -> Stack Pointer

  • RSP는 함수 파라미터 혹은 변수를 넣고 뺄때 사용 하는 것으로 알고 있다

RIP -> Instruction Pointer

  • RIP는 현재 명령어 그 다음 명령어 주소를 저장하고 있다.
  • 꼭 '현재 그 다음' 이 아니라, Decode/Execute 단계에서 Branch 계산이 완료된 경우, RIP를 업데이트 한다.

Flag Register

CF

  • Carry Flag
    • 2진수 덧셈/뺼샘 시 Carry가 발생한 경우 1, 아니면 0

ZF

  • Zero Flag
    • 어떠한 계산 결과가 0이면 1, 아니면 0

SF

  • Sign Flag
    • 어떠한 계산 중에, 양수이면 0, 음수이면 1

OF

  • Overflow Flag
    • 어떠한 계산에서 Overflow가 발생 했을때 1, 아니면 0

Data Size

Word, Dword, Qword

  • Byte: 8비트
  • Word: 16비트
    • ax/cx/dx/bx
  • DWord: 32비트
    • eax/ecx/edx/ebx
  • QWord: 64비트
    • rax/rcx/rdx/rbx

하위 레지스터 접근[R**기준]

  • R -> E = 하위 32비트
    • i.e rax -> eax
  • R -> x[없음] = 하위 16비트
    • i.e rax -> ax

하위 레지스터 접근[R8~R15 기준]

  • *d -> 하위 32비트
  • *w -> 하위 16비트
  • *b -> 하위 8비트

Instruction Format

OPCode

  • 무엇을 건지[어떠한 Operation인지] 알려주는 코드
    • operation = 실제 명령어
  • 주로 2진/16진수로 이루어져 있음

Assembly Code

  • OP코드는 결국에 하나의 명령어 파이프라인 디코딩 단계 중 한 곳에서 쓰임
    • 즉, OP코드 = 명령어 전체 가 아님
    • OP코드는 결국 어떠한 명령어인지 '식별'만 하는 존재
  • 어찌 되었던 이러한 OP코드를 가지고 어떤 연산인지 확인할 수 있는데 그 연산을 문자로 나타낸 것이
    • 바로 어셈블리 코드

Operand

  • OP코드에 따라 정의가 달라짐
    • 즉, 64비트 명령어 구조에서 항상 피연산자가 고정된 위치에 담겨있는 것이 아님
    • 레지스터가 될 수도, 주소가 될 수도, 어떠한 상수가 될 수도 있음
  • 명령어의 인자에 속하는 부분

상수값

mov rcx, 0x0 // rcx = 0x0
mov r8, 0x1 // r8 = 0x1

레지스터

mov rcx, rbx // rcx = rbx
sub rcx, rax // rcx = rcx - rax // -= rax

Addressing Mode

  • [reg]
    • reg에다가 값을 쓰는게 아니라, reg이 가리키는 주소에다가 값을 쓰기!
    • *reg = val -> mov의 경우
  • [reg + d]
    • 배열 포인터 접근 방식과 유사
    • 레지스터의 값에 d를 더해서 그 주소에 접근
  • [reg + reg]
    • 레지스터 값들을 더한 값을 포인터로 쓰는 예
  • [reg + reg * 4 + 3]
    • 계산 순서 = 일반 사칙연산과 동일
    • 약간 2차원 배열 혹은 구조체와 비슷..?

Instructions

MOV

mov destination, source
equals to
destination = source

LEA[Load Effective Address]

lea destination, addr
equals to
destination = addr

  • mov랑 다른 점
    • mov는 데이터 이동이고, lea는 주소를 저장하는 방식

INC/DEC

  • i++ / i--와 동일
    inc dst, dec dst

Neg

  • i = -i와 동일[부호 반전]
    neg dst

NOT

  • 비트 반전[dst = ~dst]
    not dst

Add

  • i = i + n과 동일
    add dst, src

SUB

  • i = i - n과 동일
    sub dst, src

imul

  • i = i * n과 동일
    imul dst, src

and

  • [Bitwise] i = i & n과 동일
    and dst, src

or

  • [Bitwise] i = i | n 과 동일
    or dst, src

xor

  • [Bitwise] i = i ^ n과 동일
    xor dst, src

shl/shr[Logical]

  • Shift Left, Shift Right
    shl dst, k == dst << k
    shr dst, k == dst >> k

sal, sar[Arith]

  • 수적인 내용을 다루므로 MSB유지
  • 내용은 SHL/SHR과 동일

Test

  • and 연산을 하지만, 피연산자들에게 영향을 끼치지 않음
  • 대신 연산 결과가 음수이면 SF = 1을, 연산 결과가 영이면 ZF를. 1로

CMP

  • sub과 거의 동일, 그러나 이 역시 TEST처럼 피연산자 들에게 영향을 미치치 않고
  • DST/SRC 관계에 따라 ZF/CF가 바뀜

Jump Family

JMPMeaningCondition
jmpJump straight to locationN/A
jeJump when ZF is 1ZF = 1
jneJump when ZF is 0ZF != 1[ZF = 0]
jgjump if greaterone's cmp results greater
jgejump if greater or equalone's cmp results greater or equal
jljump if lessone's cmp results less
jlejump if less or equalone's cmp results less or equal

Function Prologue/Epilogue

Pro/Epilogue

  • 스택을 준비하고, 정리하는 부분

The RSP

  • 낮은 주소로 이동[밑으로 증가]

Push/Pop

CMDMeaningRSP
pushPush data to stackDecrease[Sub]
PopGet latest stack dataIncrease[Add

Procedure Call Instructions

Call

  • Jump and link?
  • 현재 위치[돌아올 주소]를 스택에 푸쉬 하고
  • 특정 장소에 푸쉬

Ret

  • 모든 과정을 마친 후, 이 전 함수로 돌아갈때 쓰는 명령어
  • 이 때는 함수 에필로그까지 마친 상태이므로 rsp는 Return Address를 가지고 있음
profile
Student Platform[Backend] Developer

0개의 댓글