어셈블리어란?
어셈블리어(assembly language)는 기계어와 일대일 대응이 되는 컴퓨터 프로그래밍의 저급 언어이다.
0과 1의 이진수로 프로그램을 하는 기계어는 인간의 관점에서는 컴퓨터가 바로 읽을 수 있다는 점만 빼면 장점이 없는 언어이기 때문에 이를 보완하기 위해 나온 언어가 어셈블리어이다. 기계어와 명령어가 1:1로 대응되는 단어들로 구성되어 있으며 저급 언어는 컴퓨터와 가까운 언어이기 때문에 컴파일을 해도 간단한 명령으로 실행돼서 실행 속도가 굉장히 빠르다. 하지만 배우기가 어렵고 유지보수가 힘들다는 이유로 특수한 경우를 제외하고는 사용되지 않고 있다.
컴파일 vs 어셈블
고급언어로 작성한 원시 프로그램을 컴파일러가 기계어로 번역하는 작업을 컴파일(Complie)한다고 하고, 어셈블리어로 작성한 원시 프로그램을 어셈블러가 번역하는 작업을 어셈블(Assemble)한다고 한다.
어셈블리어의 명령어 형식
어셈블리어의 명령어 형식은 Label, OP, Operand로 구성된다.
Label : 데이터를 기억할 기억장소, 또는 분기할 위치, 기호 상수 등에 대한 기호를 기술하는 부분이다. (생략 가능)
OP : 명령어(OP-Code)를 기술하는 부분이다.
Operand : OP-code가 연산을 수행하기 위한 연산의 대상이 되는 Literal(상수,데이터)나 주소, Register 번호 등을 기술하는 부분이다.
어셈블리에서 사용되는 레지스터 종류
레지스터란?
레지스터는 CPU의 요청을 처리하는 데이터의 임시공간이다. 레지스터는 공간이 작고 가격은 비싸지만 CPU에 직접 연결되어 있어서 연산 속도가 매우 빠르다는 장점이 있다. 32비트의 경우 레지스터의 처음이 E로 시작하고, 64비트의 경우 R로 시작한다.
범용 레지스터
EAX : 사칙연산 등 산술 연산에 자동으로 사용되며, 함수의 반환 값을 처리할 때도 사용된다.
EBX : 간접 번지 지정에 사용된다. 산수, 변수를 저장한다.
ECX : 반복(Loop)에서 반복 Count 역할을 수행한다.
EDX : EAX를 보조하는 역할을 한다. 예를 들어, 나누기를 진행할 경우 몫은 EAX에 나머지는 EDX에 저장된다.
인덱스 레지스터
ESI : 복사나 비교를 할 경우 출발지 주소를 저장하는 레지스터이다.
EDI : 복사나 비교를 할 경우 목적지 주소를 저장하는 레지스터이다.
포인터 레지스터
EIP : 다음에 실행할 명령어의 주소를 가지고 있는 레지스터이다. 현재 실행하고 있는 명령어가 종료되면 이 레지스터에 있는 명령어를 실행한다.
ESP : Stack Pointer의 가장 최근에 저장된 공간의 주소를 저장하는 레지스터이다.
EBP : Stack Pointer의 기준점(바닥 부분)을 저장하는 레지스터이다.
어셈블리어 - 자주 사용하는 명령어
명령어 | 예제 | 설명 | 분류 |
push | push eax | eax의 값을 스택에 저장 | 스택 조작 |
pop | pop eax | 스택 가장 상위에 있는 값을 꺼내서 eax에 저장 | 스택 조작 |
mov | mov eax, ebx | 메모리나 레지스터의 값을 옮길때 사용 | 데이터 이동 |
inc | lnc eax | eax의 값을 1증가시킨다 (++) | 데이터 조작 |
dec | dec eax | eax의 값을 1감소시킨다 (--) | 데이터 조작 |
add | add eax, ebx | 레지스터나 메모리의 값을 덧셈할때 쓰인다. | 논리, 연산 |
sub | sub eax, ebx | 레지스터나 메모리의 값을 뺄셈할때 쓰인다. | 논리, 연산 |
call | call proc | 프로시저를 호출한다. | 프로시저 |
ret | ret | 호출했던 바로 다음 지점으로 이동 | 프로시저 |
cmp | cmp eax, ebx | 레지스터와 레지스터의 값을 비교 | 비교 |
jmp | jmp proc | 특정한 곳으로 분기 | 분기 |
int | int $0x80 | OS에 할당된 인터럽트 영역을 system call | 인터럽트 |
nop | nop | 아무 동작도 하지 않는다. (No Operation) |
어셈블리어 예제 ( C언어 → 어셈블리어 )
#include<stdio.h>
int main() {
int a = 1;
int b = 2;
int c = a + b;
printf("%d", c);
}
C언어로 작성되어 있는 위의 코드를 어셈블리어로 번역하면 다음과 같다.
push ebp
mov ebp,esp
sub esp,0E4h
push ebx
push esi
push edi
lea edi,[ebp+FFFFFF1Ch]
mov ecx,39h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
mov ecx,9AC003h
call 009A1316
mov dword ptr [ebp-8],1
mov dword ptr [ebp-14h],2
mov eax,dword ptr [ebp-8]
add eax,dword ptr [ebp-14h]
mov dword ptr [ebp-20h],eax
mov eax,dword ptr [ebp-20h]
push eax
push 9A7D08h
call 009A10CD
add esp,8
xor eax,eax
pop edi
pop esi
pop ebx
add esp,0E4h
cmp ebp,esp
call 009A123F
mov esp,ebp
pop ebp
ret
참고 자료
https://coding-factory.tistory.com/651
https://coding-factory.tistory.com/304
'2. Reversing (리버싱) > 2) 개념 정리' 카테고리의 다른 글
[2021.11.13] 패킹과 언패킹, UPX, 매뉴얼 언패킹, 코드 인젝션 (0) | 2021.11.15 |
---|---|
[2021.09.18] abex crackme 1&2, 어셈블러 (0) | 2021.09.18 |
[2021.09.11] 리버싱을 위한 준비, codeengn basic 01 (0) | 2021.09.12 |
[2021.09.11] 코드 분석, PE FILE FORMAT (0) | 2021.09.11 |
[ 2021.09.04 ] 01. 리버싱을 위한 기초 지식 (0) | 2021.09.07 |