728x90
반응형

 

공격자는 비지박스(busybox)라는 리눅스 명령어 패키지를 이용해서 wget 명령으로 악성코드를 다운로드 해 실행

 

x86-64 아키텍처

인텔의 32비트 CPU 아키텍처, 64: CPU가 한번에 처리할 수 있는 데이터의 크기
- 인텔의 x86 아키텍처와 호환되는 64bit 아키텍처 IA-64 발표

Intel 회사에서 개발한 컴퓨터의 중앙처리장치(CPU)
ISA(Instruction Set Architecture)

 

범용 레지스터(General Register)

이름 주용도
rax (accumulator register) 함수의 반환 값
rbx (base register) x64에서는 주된 용도 없음
rcx (counter register) 반복문의 반복 횟수, 각종 연산의 시행 횟수
rdx (data register) x64에서는 주된 용도 없음
rsi (source index) 데이터를 옮길 때 원본을 가리키는 포인터
rdi (destination index) 데이터를 옮길 때 목적지를 가리키는 포인터
rsp (stack pointer) 사용중인 스택의 위치를 가리키는 포인터
rbp (stack base pointer) 스택의 바닥을 가리키는 포인터

세그먼트 레지스터(Segment Register)

x64 아키텍처에는 cs, ss, ds, es, fs, gs 총 6가지 세그먼트 레지스터 존재

arm, mips, mpsl, x86

 

Q1. rax = 0x0123456789abcedf일 때, eax의 값은?

0x89abcdef

 

Q2. rax = 0x0123456789abcdef일 때, al의 값은?

0xef

 

Q3. rax에서 rbx를 뺐을 때, ZF가 설정되었다. rax와 rbx의 대소를 비교하시오.

==

 

Q4. rax = 0x0123456789abcdef일 때, ax의 값은?

0xcdef

 

Q5. rax = 0x0123456789abcdef일 때, ah의 값은?

0xcd

 

프로세스 메모리 구조

섹션

윈도우의 PE 파일은 PE 헤더와 1개 이상의 섹션으로 구성됨

".text" 섹션: PE코드, 실행 가능한 기계 코드가 위치하는 영역

".data" 섹션: PE가 실행중에 참조하는 데이터, 컴파일 시점에 값이 정해진 전역 변수들이 위치, 읽기/쓰기 권한 부여

".rdata" 섹션: 컴파일 시점에 값이 정해진 전역 상수와 참조할 DLL 및 외부 함수들의 정보 저장, 읽기 권한 부여(쓰기 불가능), str_ptr: "readonly" 문자열

섹션이 아닌 메모리

윈도우의 가상 메모리 공간에는 섹션 + 스택/힙 등이 적재됨

스택: 지역 변수나 함수의 리턴 주소가 저장됨, 읽기/쓰기 권한 부여 (기존 주소보다 낮은 주소로 확장됨)

어셈블리어와 x86-64

어셈블리 언어

컴퓨터의 기계어와 치환되는 언어, 명령어 집합구조(Instruction Set Architecture, ISA)

x64 어셈블리 언어

명령어(Operation Code, Opcode)와 목적어에 해당하는 피연산자(Operand)

x86-64 어셈블리어 문법 구조

mov eax, 3

(opcode: 대입해라, operand1: eax에, operand2: 3을)

명령어

인텔의 x64에는 매우 많은 명령어가 존재함, 본 커리큘럼에서는 이 코스와 다음 코스에 걸쳐, 이 중 중요한 21개의 명령어를 자세히 학습할 것.

명령 코드  
데이터 이동(Data Transfer) mov, lea
산술 연산(Arithmetic) inc, dec, add, sub
논리 연산(Logical) and, or, xor, not
비교(Comparison) cmp, test
분기(Branch) jmp, je, jg
스택(Stack) push, pop
프로시져(Procedure) call, ret, leave
시스템 콜(System call) syscall

피연산자

상수(Immediate Value), 레지스터(Register), 메모리(Memory)

크기 지정자(Size Directive) TYPE PTR

여기에 타입에는 BYTE, WORD, DWORD, QWORD가 올 수 있으며, 각각 1바이트, 2바이트, 4바이트, 8바이트의 크기 지정

메모리 피연산자의 예

메모리 피연산자  
QWORD PTR [0x8048000] 0x8048000의 데이터를 8바이트만큼 참조
DWORD PTR [0x8048000] 0x8048000의 데이터를 4바이트만큼 참조
WORD PTR [rax] rax가 가르키는 주소에서 데이터를 2바이트 만큼 참조

자료형 WORD의 크기가 2바이트인 이유

초기에 인텔은 WORD의 크기가 16비트인 IA-16 아키텍처를 개발했음
CPU의 WORD가 16비트였기 때문에, 어셈블리어에서도 WORD를 16비트 자료형으로 정의하는 것이 자연스러웠음

이후에 개발된 IA-32, x86-64 아키텍처는 CPU의 WORD가 32비트, 64비트로 확장됨
이 둘의 아키텍처에서는 WORD 자료형이 32비트, 64비트의 크기를 지정하는 것이 당연할 것

하지만 인텔은 WORD 자료형의 크기를 16비트로 유지함 (새로운 아키텍처 호환 여부)

DWORD(Double Word, 32bit), QWORD(Quad Word, 64bit) 자료형을 추가로 만듦

논리 연산 - and & or

# add
[Register]
eax = 0xffff0000
ebx = 0xcafebabe

[Code]
and eax, ebx

[Result]
eax = 0xcafe0000
# or
[Register]
eax = 0xffff0000
ebx = 0xcafebabe

[Code]
or eax, ebx

[Result]
eax = 0xffffbabe

논리 연산 - xor & not

[Register]
eax = 0xffffffff
ebx = 0xcafebabe

[Code]
xor eax, ebx

[Result]
eax = 0x35014541

xor dst, src: dst와 src의 비트가 서로 다르면 1, 같으면 0

- f0 e1 d2 c3 b4 a5

[Register]
eax = 0xffffffff

[Code]
not eax

[Result]
eax = 0x00000000

 

정리

종류 연산자 의미
데이터 이동 연산자 mov dst, src src의 값을 dst에 대입
데이터 이동 연산자 lea dst, src src의 유효 주소를 dst에 대입
산술 연산 add dst, src src의 값을 dst에 더함
산술 연산 sub dst, src src의 값을 dst에서 뺌
산술 연산 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 op1과 op2에 AND 연산을 하고, 플래그를 설정
분기 jmp addr addf로 rip 이동
분기 je addr 직전 비교에서 두 피연산자의 값이 같을 경우 addr로 rip 이동
분기 jg addr 직전 비교에서 두 피연산자 중 전자의 값이 더 클 경우 addr로 rip 이동

 

728x90
728x90

+ Recent posts