1️⃣ X86 Assembly 기초

📜x86 아키텍처

- 데이터 타입 : 어셈블리 기본

- 주소 표기법 : 리틀 엔디안

- 레지스터 : 8개의 범용 레지스터, EIP, EFLAGS

- 호출규약 : cdecl, stdcall, fastcall

- 명령어 세트 : 가변 길이 명령어 형식을 사용

- 피연산자 : 레지스터, 메모리 주소, 주소값, 숫자

- 기본문법 : AT&T(add a,b > b=a+b) 또는 Intel (add a,b > a=a+b)

📜레지스터

- 8개의 범용 레지스터 + EIP(32비트)

- EFLAGS 레지스터(32비트)

- 세그먼트 레지스터(16비트)

![image-20240909093256875](/images/x86 어셈블리 기초/image-20240909093256875.png)

- EAX(Extended Accumulator Register) : 산술 연산에 사용, 함수 리턴값 저장

- EBX(Extended Base Register) : 베이스, 특정 메모리를 가리키는 포인터

- ECX(Extended Count Register) : 카운터 코드에 사용 (흔히 for문 등의 카운터에 사용)

- EDX(Extended Data Register) : 데이터 레지스터 (곱셈, 나눗셈)

- ESI(Extended Source Index) : 문자열 연산의 출발지 포인터

- EDI(Extended Destionation Index) : 문자열 연산의 목적지 포인터 - ESP(Extended Stack Point) : 스택 포인터 - EBP(Extended Base Point) : 스택 프레임 베이스 포인터 .스택의 기준

- EIP(Extended Instruction Point) : 다음 실행할 명령어를 가리키는 포인터

📜EFLAGS 레지스터

- 상태 플래그

- 방향 플래그

- 시스템 & IOPL 플래그

![image-20240909093304256](/images/x86 어셈블리 기초/image-20240909093304256.png)

- CF : Carry

- PF : Parity

- AF : Adjust

- ZF : Zero

- SF : Sign

- OF : Overflow

📜자주쓰는 명령어

명령어 유형의미대표 명령어 세트
데이터 이동src에서 dst로 이동mov, lea, push, pop, les, pushad, popad
산술정수의 산술 연산add, adc, sub, sbb, mul, imul, div, idev, cmp, inc, dec
부동 소수점부동 소수점 산술 연산fadd, fsub, fmul, dic, cmp
논리비트 논리 연산adn, or, xor, not, shl/sal, shr, sar, ror, rol
제어 이동제어 흐름의 이동jmp, jcc, call, ret, int, into
문자열문자열의 비교, 이동movs, stos, sca, outs, rep, repz, repnz, repne
I/O입력과 출력in, out
변환데이터 타입 변환movzx, movsx, cbw, cdq, bswap
기타플래그 조작, 특권 모드 처리clc, stc, cmc, std, cl, sti

📜PUSH, POP

- PUSH : 스택에 데이터를 삽입 > push word/dword

> push 명령어는 자동으로 ESP를 4바이트 감소시킴

- POP : 스택에서 데이터를 꺼냄

> 스택에서 4바이트를 꺼내와 지정한 레지스터에 삽입

> POP 명령어는 자동으로 ESP를 4바이트 증가 시킴

📜MOV

- 레지스터 <-> 레지스터 (가능)

- 메모리 <-> 레지스터 (가능)

- Immediate 값(메모리가 아닌 명령어에 포함된 값) -> 레지스터 또는 메모리 (가능)

- 메모리 <-> 메모리 (불가능)

📜Assembly 프로그래밍 정상적으로 끝내는 방법

- mov eax, 1

mov ebx, 0

int 80h

>exit(0) 의 역할을 함

📜‘r/m32’ 주소형식

- 다음과 같은 형식을 가지는 문법을 의미 • mov eax, ebx ← ebx 에 담긴 내용을 eax 로 복사 • mov eax, [ebx] ← ebx에 담긴 내용이 가리키는 주소의 내용 (포인터 )을 eax 로 복사 • mov eax, [ebx+ecxX] ← ebx에서 ecxX 만큼 떨어진 곳에 위치한 주소의 내용을 eax 로 복사 • mov eax, [ebx + ecxX + Y] ← ebx에서 ecxX + Y 만큼 떨어진 곳에 위치한 주소의 내용을 eax 로 복사

📜ADD, SUB

- 목적지는 r/m32 또는 레지스터

- 출발지는 r/m32 또는 레지스터 또는 상수값

- 출발지와 목적지가 모두 r/m32일 수는 없음

- OF, SF, ZF, AF, PF, CF에 영향

📜LEA (복사, Load Effective Address - 유효주소 로드)

- 출발지는 r/m32

- 목적지는 레지스터

- 레지스터 연살 결과를 레지스터에 저장 (포인터 아님)

- MOV와 다른점

> MOV는 값을 로드함, mov eax, [ebp+esp+4] > [ebp+esp+4]의 주소가 가리키는 값을 로드함

> LEA는 유효 주소를 로드, lea eax, [ebp+esp+4] > [ebp+esp+4]의 주소를 로드함

📜AND

- 목적지는 r/m32 또는 레지스터

- 출발지는 r/m32 또는 레지스터 또는 상수값

- OF, CF, SF, ZF, PF

📜OR

- 목적지는 r/m32 또는 레지스터

- 출발지는 r/m32 또는 레지스터 또는 상수값

- OF, CF, SF, ZF, PF

📜XOR

- 목적지는 r/m32 또는 레지스터

- 출발지는 r/m32 또는 레지스터 또는 상수값

- OF, CF, SF, ZF, PF

📜INC

- 피연산자의 값을 1 증가시킴 > OF, SF, ZF, AF, PF에 영향

📜DEC

- 피연산자의 값을 1 감소시킴 > OF, SF, ZF, AF, PF에 영향

📜CMP(두 값을 비교)

- cmp 레지스터, 상수값

- cmp r/m32, 상수값

- cmp r/m32, 레지스터

- cmp 레지스터, r/m32

- 출발지에서 목적지 값을 뺀 결과를 플래그에 반영

- 결과는버림

📜TEST(논리비교)

- test eax, eax(eax 값이 0인 경우 ZF=1)

- 보통 jcc랑 같이 쓰임

📜제어흐름

- 조건부 제어 : IF, WHILE, SWITCH

- 비조건부 제어 : CALL, GOTO, EXCEPTION, INTERRUPT

📜JMP(jump)

- 피연산자 주소로 EIP를 변경

- Short Jump(OF 85) : 현재 EIP 값에서 -128~127 범위로 이동

- Far Jump(75) : 다른 세그먼트에 위치한 명령어로 이동

📜JCC (Jump if condition is met)

- 특정 조건을 만족할 경우 지정한 주소로 제어 흐름을 이동

- JNE : Jump Not Equal (ZF=0)

- JE : Jump Equal (ZF=1)

- JLE : Jump Less Equal (ZF=1 or SF<>OF)

📜CALL(함수 호출)

- call printf / 0x80480000 / [eax + 4]

- 우선 다음 실행할 명령어 주소를 스택에 삽입한 뒤 EIP에 해당 주소를 옮긴 뒤 이동하는 방식

- 외부 함수를 사용하는 경우 반드시 해당 함수가 포함된 라이브러리를 linker에 함께 전달해야 함

📜x86 함수 호출 규약

- cdecl

> x86 환경에서 대부분 C 컴파일러가 쓰는 규약

> Caller에서 스택을 정리

> 오른쪽에서 왼쪽 순서로 파라미터를 전달

> 항상 스택의 최상위에 함수의 첫 번째 파라미터가 위치

- stdcall

> MS가 자체적으로 만든 호출규약 (Win32 API에서 사용)

> 파라미터 입력 순서는 cdecl과 동일

> Callee가 스택을 정리

> 작고 빠른 프로그램에 용이

- 함수가 시작될 때, Callee가 Stack에 2가지 값을 저장

> EIP : caller의 next instruction (다시 돌아갔을때 실행할 명령어 위치)

> EBP : caller의 base pointer, main함수 시작부분 (다시 돌아갔을때 스택 프레임 기준)