어셈블리어
- 기계어로 1:1 매핑이 가능한 가장 낮은 수준의 언어
- CPU, 레지스터, 메모리 사이에 데이터를 조작함
- CPU에서 지원하는 함수만 사용 가능
- 표기법은 인텔 기반과AT&T 기반
어셈블리 기본
- 기본 문법 : Opcode Operands
- 표기 방식
- 레지스터: EAX, EBP ..
- 값 : 16진수 표현
- 메모리 주소 : [주소값], [레지스터명]
- 오퍼랜드 방식 : 목적지(dst) <- 소스(src) - 메모리 할당 : 값은 스택에 저장(PUSH)
- DWORD : double word(16bit, 2byte) = 32bit
- 함수 호출 시 스택에 순서대로 저장
- RETURN 주소 PUSH
- 기존의 EBP PUSH
- EBP에 현재 ESP 값을 저장, EBP 설정
[데이터 이동]
데이터 이동 방법
- 값을 직접 레지스터로 대입
- 레지스터에서 레지스터로 옮기기
- 값을 직접 메모리로 대입하기
- 레지스터에서 메모리로 또는 그 반대로 옮기기
- 메모리에서 메모리로 옮기기
MOV : 값을 넣어줌, operand1 <- operand2
- MOV EAX, EBX // EBX 레지스터의 값을 EAX 레지스터로 복사
- MOV EBP, ESP // ESP 값을 EBP로 복사
- MOV EAX, 42 // 16진수 42를 EAX 레지스터로 복사
- MOV EAX,[4037C4] // 메모리주소 4037C4에 있는 4바이트 값을 EAX 레지스터로 복사
- MOV EAX, [EBX] // EBX 레지스터가 명시한 메모리 주소의 4바이트 값을 EAX 레지스터로 복사
- MOV EAX, [EBX+ESI*4] // EBX+ESI*4 연산결과가 명시한 메모리 주소의 4바이트 값을 EAX 레지스터로 복사
LEA : Load Effective Address 약자로 MOV와 동일, 주소 값을 저장
- LEA EAX, [EBP+8] // EBP + 8에 저장된 주소를 EAX에 저장
- MOV EAX, [EBP+8] // EBP+8 주소에 저장된 값을 EAX에 복사
PUSH : 스택에 값을 저장, 스택 4byte 증가, ESP 4byte 감소
- PUSH EBP // 스택에 EBP 값을 push
- PUSH 5 // 스택에 5를 push
POP : 스택 끝에 저장된 값을 가져옴, 스택 4byte 감소, ESP 4byte 증가
- POP EBP // 스택의 끝 값을 EBP에 저장
- POP ECX // 스택의 끝 값을 ECX에 저장
[산술연산 명령어]
명령 | 설명 | 사용 예 |
ADD | 덧셈 | ADD ECX, 10 |
SUB | 뺄셈 | SUB ECX, 5 |
INC | 오퍼랜드 내용을 1 증가 | INC ECX |
DEC | 오퍼랜드 내용을1 감소 | DEC ECX |
MUL/IMUL | EAX와 오퍼랜드를 곱셈하여 EAX에 저장 | MUL EDX |
DIV/IDIV | EAX와 오퍼랜드를 나누어 EAX에 저장 | DIV EDX |
NEG | 오퍼랜드의 2의 보수 (부호 반전) | NEG EAX |
INC EAX // EAX 1 증가
DEC EAX // EAX 1 감소
ADD EAX, 1A // EAX에 1A(26) 를 더한 뒤 EAX에 저장
SUB ESP, 10 // ESP에서 10(16) 을 뺀 뒤 ESP에 저장
[비트연산 명령어]
명령 | 설명 |
AND | 두 비트가 모두 1이면 1, 나머지는 0으로 계삱 |
OR | 두 비트 중 하나라도 1이면 1, 아니면 0으로 계산 |
XOR | 각 비트 값을 비교하여 값이 같으면0, 다르면 1로 계산 |
NOT | 비트 값을 반대 값(0->1, 1->0)으로 변경 |
SHL | 왼쪽으로 쉬프트 연산 최하위 비트는 0으로 채워지고 기존 값은 CF 플래그 레지스터에 저장 |
SHR | 오른쪽으로 쉬프트 연산 최상위 비트는 부호비트로 채워지고 CF 플래그 레지스터에 저장 |
ROL/RCL | 왼쪽으로 쉬프트 연산, 최하위 비트는 최상위 비트로 채워짐 |
ROR/RCR | 오른쪽으로 쉬프트 연산, 최상위 비트는 최하위 비트로 채워짐 |
[제어 명령어]
명령 | 설명 | 사용 예 |
CMP | 두 개의 오퍼랜드 비교 (뺄셈 연산 후 플래그 설정) | CMP EAX,0 |
TEST | 두 개의 오퍼랜드 비교 (AND 연산 수행 후 플래그를 설정) | TEST EAX, EAX |
CALL | 해당되는 주소의 함수를 호출하여 수행 코드 위치로 옮김 | CALL 00401990 |
INT | 오퍼랜드로 지정된 예외 처리 수행 중단점으로 디버그용 소프트웨어 트랩 오버플로우 상황시 발생하는 트랩 하드웨어 디버그 트랩 |
INT 3 |
LEAVE | 함수에서 사용한 지역변수 스택을 비움 | LEAVE |
RET | 스택에 저장된 주소로 복귀 | RET |
NOP | 아무 동작도 수행하지 않음 (기계어 코드 0X90) 공격 코드를 삽입할 대 자주 쓰임 |
NOP |
[분기 명령어]
- JMP : 무조건 EIP 주소값으로 점프
- JCC : CC(조건부코드) 값에 따라 해당 EIP 주소값으로 점프
- JE(Jump if equal), JNE(Jump if not equal)
CC | 설명 | 플래그 값 |
E/Z | 같은/0인 | ZF = 1 |
NE/NZ | 다른/0이 아닌 | ZF = 0 |
L/NGE | 작은(부호 있는 연산) | (SF^OF)=1(SF!=OF) |
G/NLE | 큰(부호 있는 연산) | ((SF^OF) | ZF) = 0 |
GE/NL | 크거나 같은(부호 있는 연산) | (SF^OF) = 0 |
LE/NG | 작거나 같은(부호 있는 연산) | ((SF^OF) | ZF) = 1 |
B/ANE | 작은(부호 없는 연산) | CF = 1 |
AE/NB | 크거나 같은(부호 없는 연산) | CF = 0 |
P/PE | PE가 1이면 (짝수) | PF = 1 |
NP/PO | PE가 0이면 (홀수) | PF = 0 |
O | OF가 1이면 | OF = 1 |
S | SF가 1이면 | SF = 1 |
ECXZ | ECX가 0이면 | ECX = 0 |
[반복]
REP : ECX 레지스터 지정횟수만큼 또는 ZF 플래그 조건에 맞을 동안 반복
- REP : ECX가 0이 될 때까지 반복
- REPE,REPZ : ECX가 0이거나 ZF가 0일 때까지 반복
- REPNE, REPNZ : ECX가 0이 아니거나 ZF가 1일 때까지 반복
LOOP : LOOP영역을 ECX 레지스터 지정 값만큼 반복
- LOOP 주소 : ECX 카운터 감소시키고, 카운터가 0이 아니면 주소로 이동함
- LOOPE 주소 : ECX 카운터 감소시키고, 카운터가 0이 아니고 ZF가 1이면 주소로 이동함
- LOOPNE 주소: ECX 카운터 감소시키고, 카운터가 0이 아니고 ZF가 0이면 주소로 이동함
[다형성 코드]
- 컴파일 과정에서 코드의 최적화 수행
- 동일한 결과이나 다른 코드로 생성됨
기계어 | 어셈블리어 | 의미 |
B8 0000000 | MOV EAX, 0 | EAX에 0을 저장함 |
31C0 | XOR EAX, EAX | |
83 E0 00 | AND EAX, 0 | |
6A 00 58 |
PUSH 0 POP EAX |
|
83F8 00 | CMP EAX, 0 | EAX가 0인지 비교함 |
85C0 | TEST EAX, EAX |
[레지스터 종류(32비트)]
구분 | 명칭 | 이름 | Bit | 용도 |
범용 레지스터 (General Register) |
EAX | 누산기(Accumulator) | 32 | 주로 산술 연산에 사용(함수 결과값 저장) |
EBX | 베이스 레지스터 | 32 | 특정 주소 저장 |
|
ECX | 카운터 레지스터 | 32 | 반복적으로 실행되는 특정 명령어 (루프 반복 횟수, 시프트 비트 수) |
|
EDX | 데이터 레지스터 | 32 | 일반 자료 저장(입출력 동작에 사용 | |
세그먼트 레지스터 (Segment Register) |
CS | 코드 세그먼트 레지스터 | 16 | 실행될 기계 명령어가 저장된 메모리 주소 지정 |
DS | 데이터 세그먼트 레지스터 | 16 | 프로그램에 정의된 데이터, 상수, 작업 영역의 메모리 주소 지정 | |
SS | 스택 세그먼트 레지스터 | 16 | 프로그램이 임시로 저장할 필요가 있거나 사용자의 피호출 서브루틴이 사용할 데이터와 주소 포함 | |
ES,FS,GS | 엑스트라 세그먼트 레지스터 | 16 | 문자 연산과 추가 메모리 지정을 위해 사용되는 여분의 레지스터 | |
포인터 레지스터 (Pointer Register) |
EBP | 베이스 포인터 | 32 | ss레지스터와 함께 사용되어 스택 내의 변수 값을 읽는 데 사용 |
ESP | 스택 포인터 | 32 | ss레지스터와 함께 사용되어 스택의 끝 주소를 가리킴 | |
EIP | 명령어(Instruction) 포인터 | 32 | 다음 명령어의 오프셋(상대위치주소)를 저장하며 CS 레지스터와 합쳐져 다음에 수행될 명령의 주소 형성 | |
인덱스 레지스터 (Index Register) |
EDI | 목적지(Destination) 인덱스 | 32 | 목적지 주소에 대한 값 저장 |
ESI | 출발지(Source)인덱스 | 32 | 출발지 주소에 대한 값 저장 | |
플래그 레지스터 (Flag Register) |
EFLAGS | 플래그 인덱스 | 32 | 연산 결과 및 시스템 상태와 관련된 여러 가지 플래그 값 저장 |
[윈도우 메모리 구조]
- 모든 프로그램은 실행하기 전에 메모리로 로드됨
- 취약점 발생도 가능하며 취약점에 대한 공격도 발생
- Buffer overflow, Memory Corruption - 32Bit 윈도우 메모리 구조
- 프로세스 별로 4G로 구성 - 가상메모리
- 여러 개의 프로그램 실행, 4G 이상 활용
- 유저영역 2G + 커널영역 2G = 4G
- 실행되는 프로세서를 할당/적재
PUSH EBP
- 이전 스택 프레임의 EBP를 SFP(Stack Frame Pointer)에 저장
-> 스택 프레임 제거 후 원래 스택 프레임으로 복귀하기 위해서 이전 스택 프레임의 EBP를 저장....