728x90

 

mov dst, src : src의 값을 dst로 넘긴다. ex) mov eax, 100 -> 100을 eax에 저장한다.

 

LEA dst, src : LEA는 특정 배열에 접근할려고 할때 많이 사용한다. 연산을 포함하여 복사가능하다. ex) LEA EAX, EAX+1000 -> eax에 1000을 더한값을 다시 eax에 삽입한다.

ex) LEA EAX, [EAX+1000] -> [ ]대괄호는 어셈블리에서 주소가 가리키는 값을 의미한다. 즉 EAX에서 1000을 더한 주소가 가리키는 값을 EAX에 넣어라 라는 의미의 명령어가 된다.

 

JMP : 특정 위치로 건너뛰어 코드를 실행시킨다.

 

CALL : 함수 호출을 위해 사용된다. JMP를 통해 해당 함수로 이동하여 명령어 실행후 함수종료후 RET을 통해 돌아온다.

CALL은 JMP와 다르게 다시 돌아오는 RET이 포함되어있다.

 

NOP : 아무작업도 하지않는 명령어이다. 1Byte 공간을 차지한다.

 

RET : 현재 함수가 끝난 뒤에 돌아갈 주소를 지정하기 위해 사용한다.

 

PUSH : 스택에 해당값을 저장할때 사용된다.

 

POP : 스택에 있는 값을 가져올때 사용된다.

 

LEAVE : 현재까지의 메모리 스택을 비우고 EBP를 자신이 호출한 메모리 주소로 채운다.

 

nasm은 문자와 문자열을 구분하지 않는다.

 

db 'hello' 와 db 'h','e','l','l','o'는 같다.

 

msg db 'Hello World!!!',10,00

은 Hello World!!! 개행 문자열 종료 와 같다.(10은 \n , 00은 NULL이다.)

 

위에서 msg는 변수명이아니라 레이블이다. 레이블은 주소를 가리키는 주소의 표현이라고 생각하면 된다.

 

 

 

 

 

 

 

 

 

 

 

어셈블리 컴파일

 

 

목적파일 생성

nasm -f elf64 -o abc.o abc.s

 

실행 파일

ld -o abc abc.o

 

어셈블리 소스코드 마지막에

mov rax, 60

syscall

을 넣어주지 않으면 세그멘테이션 오류 발생 

 

728x90

'Programming > assembly' 카테고리의 다른 글

nasm x64 assembly strlen 구현  (0) 2020.03.10
loop  (0) 2020.03.01
echo  (0) 2020.03.01
sum.c 스택 프레임  (0) 2020.03.01
메모리 구조  (0) 2020.03.01
728x90

 

echo.s

xor rax, rax를 통해 rax를 0으로 설정해주고 rdx, rcx, rdx 또한 0으로 설정해준다.

rsp를 64만큼 확장하여 문자열 저장공간을 확보한다.

 

rax, 0 sys_call number 0번은 sys_read이다. 파일을 읽어들이는 함수인다. rdi 0을 통해 fd를 0으로 설정해주어 stdin이 가능하다. 즉 키보드 입력이 가능한 것이다. 이후 rsi에는 저장될 공간 rsp를 넣어주고 rdx에는 저장가능한 문자열 공간 63을 넣어준다. 64를 확장해주고 NULL이 들어갈 공간을 위해 rdx에는 63을 넣어준 것이다.

 

이후 rax, 1을 통해 syscall sys_write를 호출할 준비를 하고 rdi에 1을 넣음으로써 fd를 1로 설정하여 stdout이 가능하게 한다. 저장되어있는 문자열 주소인 rsp를 인자로 넣어주고 출력 크기인 63을 넣어준다.

syscall을 통해 화면에 문자열을 출력해준다.

 

60번 syscall 인 sys_exit을 통해 프로그램을 종료시켜준다.

echo 실행화면

입출력은 sys_read 와 sys_write로 가능하다.

rsp의 값 확장은 sub rsp, 확장할 크기 로 가능하다.

스택은 주소상 위에서 아래로 자라기 때문이다. sub로 값을 빼준만큼 스택공간이 확장된다.

728x90

'Programming > assembly' 카테고리의 다른 글

loop  (0) 2020.03.01
어셈블리 문법  (0) 2020.03.01
sum.c 스택 프레임  (0) 2020.03.01
메모리 구조  (0) 2020.03.01
Hello World (x64)  (0) 2020.03.01
728x90

sum.c

위 코드의 스택프레임을 정리할려고 한다.

RET이 스택의 가장 아래쪽이다.(스택이 위로 쌓인다고 가정할때) (스택은 주소값상에서는 위에서부터 아래로 쌓인다.)

RET(return address)은 함수종료후 돌아갈 주소를 가리킨다.

main함수 실행 전 _start가 실행되고 _start에서 main을 호출하는데 main함수가 종료되면 다시 _start로 돌아온다. 이때 돌아가는 주소가 RET에 저장되어 있다.

 

함수의 BASE포인터가 RET 바로위에 저장되고 RBP 이후로 지역변수들이 차례로 저장된다. 변수 C가 RBP바로 위에 저장된 모습이다.

 

sum 호출 후 스택프레임

함수를 호출할 때 그함수의 매개변수는 그함수의 RET 아래에 저장된다.

sum을 호출할때 매개변수 x, y가 sum의 ret 아래에 저장된 모습이다.

 

sum 함수가 종료되면 변수 X ~ RBP, 버퍼 까지 모든 스택들이 사라진다. 그리고 변수 C에는 3이 들어간다.

 

sum 함수 종료 후 스택 프레임

sum의 반환을 통해 변수 C에 3이 저장된 형태이다. 메인함수가 종료되면 3도 main함수가 호출된 곳으로 반환한다.,

 

RET의 경우 함수 종료 후 돌아가는 메모리 주소가 저장되어있다. bufferover flow를 통해 ret을 조정하여 임의로 원하는 주소로 이동이 가능하다.

 

728x90

'Programming > assembly' 카테고리의 다른 글

어셈블리 문법  (0) 2020.03.01
echo  (0) 2020.03.01
메모리 구조  (0) 2020.03.01
Hello World (x64)  (0) 2020.03.01
어셈블리 기초(x86)  (0) 2020.03.01
728x90

위 그림은 프로세스가 메인메모리에 올라갔을때 각 세그먼트를 나타낸 것이다.

 

stack : 함수가 호출될 때마다 스택이 사용된다. 함수에 관련 정보를 저장하는 용도를 사용된다. 함수를 호출할 때마다 함수의 지역변수들이 스택에 쌓인다.

 

Heap : 동적으로 할당되는 공간 ex)malloc(), alloc()

 

BSS : 프로그램에서 사용되는 변수들이 실제로 존재하는 곳, 초기화가 되지않은 변수들이 존재한다.

 

Data : 실제로 초기화가 이루어진 변수들이 존재한다.

 

Text : 실제로 작성한 소스코드가 들어간다. TEXT 영역의 어셈블리 코드들이 한줄씩 실행된다.

728x90

'Programming > assembly' 카테고리의 다른 글

어셈블리 문법  (0) 2020.03.01
echo  (0) 2020.03.01
sum.c 스택 프레임  (0) 2020.03.01
Hello World (x64)  (0) 2020.03.01
어셈블리 기초(x86)  (0) 2020.03.01
728x90

Hello_World.s

section .data

data섹션은 초기화된 데이터 또는 상수를 선언하는데 사용된다. 위에서는 문자열 변수 msg에 'Hello World'을 넣어준 것이다. .data섹션은 읽기/ 쓰기가 가능한 섹션이다. 일반적으로 정적변수와 전역변수가 저장된다.

 

section .text

text섹션은 실제 코드를 작성하는 section이다. 이섹션은 global _start로 시작하며 _start: 부터 코드가 실행된다.

 

 

_start: 이후부터 코드가 실행되는데 위 소스코드는 sys_write시스템콜을 하여 Hello World를 실행시키고 sys_exit(0)를 호출하여 프로그램을 끝내는 소스코드이다.

 

rax에 sys_call number가 들어가고, 해당 sys함수에 따라 인자들이 들어가는 것이다.

64bit syscall table 검색하면 sys_call number와 함수들 인자 레지스터 까지 리스트가 나온다.

 

위 소스코드에서는 mov rax,1을 통해 syscall 1번 syswrite 호출

mov rdi, 1을 통해 파일 디스크립터(fd) 1번을 넣어 stdout을 의미하게 한다.

mov rsi, msg 를 통해 rsi에 msg 포인터 변수를 넣어 해당 위치를 넣어준다.

mov rdx, 12를 통해 'Hello World' 문자열 길이를 rdㅌ에 넣어준다.

syscall -> rax시스템콜 번호와 인자들 설정 후 시스템 콜을 시켜주는 명령어이다.

 

rax, 60은 sys_exit 의 sys_call number이다.

rdi, 0은 sys_exit의 인자로 들어가면서 error code가 들어가야 하지만 0은 에러가 없다는 의미이다.

 

 

 

728x90

'Programming > assembly' 카테고리의 다른 글

어셈블리 문법  (0) 2020.03.01
echo  (0) 2020.03.01
sum.c 스택 프레임  (0) 2020.03.01
메모리 구조  (0) 2020.03.01
어셈블리 기초(x86)  (0) 2020.03.01
728x90

레지스터 : CPU 내부에 존재하는 다목적 임시 저장 공간 CPU 내부에 있으며 고속으로 데이터 처리가 가능하다.

 

레지스터의 종류

1. 범용 레지스터 : 범용적 즉 다양한 용도로 사용되는 레지스터이다. 범용 레지스터는 8개가 있으며, 각 32bit 크기이다.(64bit 운영체제에서는 레지스터 각 64bit크기) 주로 상수(연산 처리, 연산 결과), 주소(주소 지정, 복구 주소)등을 저장할 때 사용된다.

 

2. 세그먼트 레지스터 : 세그먼트란 메모리를 조각내어 각 조각마다 시작 주소, 범위, 접근 권한 등을 부여하여 메모리를 보호하는 기법이다. 또한 페이징(paging)기법과 함께 가상 메모리를 실제 물리 메모리로 변경할 때 사용된다. 16bit 크기로 6개가 있으며 메모리 영역에 대한 주소 지정을 제공한다.

 

3.EFLAGS(Extended FLAGS) 레지스터 : EFLAGS의 크기는 32bit이며 각 레지스터 bit마다 의미를 가지고 있다. 1 또는 0의 값을 가지며 On/Off 혹은 True/False 를 표시한다. 동작을 제어하거나 상태를 나타내는데 사용된다.

 

4.EIF(Instruction Pointer) : CPU가 다음으로 실행해야할 명령어가 존재하는 주소가 저장된다. CPU는 현재 명령어를 실행완료한 후에 EIP 레지스터에 존재하는 주소에 위치한 명령어를 실행하게 된다.

 

위의 4가지 외에도 다양한 레지스터 종류가 있다.

 

범용 레지스터 목록

1.EAX(Extended Accumulater Register) : 산술 연산을 수행하기 위해 사용되거나 함수의 리턴값을 전달하기 위해 사용된다. 즉, 더하기, 빼기, 비교 연산, 곱셈, 나눗셈 등을 위해 사용된다. EAX에 저장된 값을 조사하면 호출한 함수가 성공했는지, 실패했는지 여부를 판단할 수 있으며 리턴값을 알 수 있다.

 

2.EBP(Extended Base Pointer) : 스택 프레임의 시작지점 주소(함수 호출시 형성되는 스택 프레임의 시작주소를 가리킴), 스택 프레임이 소멸되지 않는다면 EBP의 값은 변하지 않는다.

 

3.EDX(Extended Data Register) : 기본적으로 EAX레지스터의 확장 개념으로 사용된다. 큰수이 곱셈과 나눗셈 연산에서 EAX레지스터와 함께 사용되고 부호 확장 명령 등에도 사용된다.

 

4.EBX(Exteneded Base Register) : ESI 레지스터, EDI 레지스터와 결합될 수 있으며, 이 EBX레지스터는 메모리 주소를 저장하는 용도로 사용된다.

 

5.ECX(Extended Counter Register) : 반복연산에서 주로 사용된다. 반복 명령어 사용시 반복 카운터로 사용된다. ECX레지스터에 반복할 횟수를 지정하고, 반복 작업을 수행한다.

 

6.ESI(Extended Source Index) : 데이터 조작, 복사시 Source Data의 주소가 지정된다. 일반적으로 문자열 전송 및 비교에서 사용되며 소스 문자열의 주소를 가리킨ㄴ다.

 

7.EDI(Extended Destination Index) : 데이터 복사시 목적지 주소 저장. 주로  ESI레지스터가 가리키는 주소의 데이터가 저장된다.

 

8.ESP(Extenede Stack Pointer) : 스택의 가장 높은 위치를 가리킨다. PUSH 명령어의 경우 현재 가리키는 ESP 주소에 데이터를 저장하고 ESP를 4byte증가 시킨다. POP명령어시 현재 가리키는 ESP의 값을 꺼내고 ESP를 4byte감소 시킨다.(PUSH, POP, CALL, RET 등의 명령어들은 ESP를 직접 조작한다.)

 

세그먼트 레지스터

CS (Code Segment) : 명령어 코드들이 저장되어 있는 부분을 코드 세그먼트라고 하며 CS레지스터는 이곳의 시작 주소를 가지고 있다. CS주소에 명령어 포인터(Instruction pointer,EIP)레지스터의 오프셋 값을 더하면, 실행하기 위해 메모리로부터 가져와야할 명령어 주소가 된다.

 

DS(Data Segment) : 주로 전역, 정적(static)변수 데이터가 들어있는 데이터 세그먼트의 시작 위치를 가리키는 레지스터이다. 명령어들은 DS를 사용하여 데이터의 위치를 알아낸다.

 

SS(Stack Segment) : 프로그램은 주소, 데이터의 임시저장을 위해 스택을 사용한다. 스택 세그먼트의 시작 주소를 SS에 저장한다. SS에 스택 포인터(ESP)레지스터의 오프셋 값을 더하면 실제 메모리 주소가 나온다.

 

ES(Extra(Data) Segment) : 일반적으로 문자열 연산에서 사용된다. 이 경우 EDI레지스터와 연관된다.

 

FS : 유저모드에서 FS레지스터는 TEB(Thread Environment Block, 현재 실행중인 스레드에 대한 정보를 저장하고 있는 구조체)을 지칭한다. 커널 모드에서는 일반적으로 KPCR(Kernel Process Control Region)을 가리킨다.

 

GS : 여분의 데이터 세그먼트로 주로 스택 스매싱이 일어났는지 확인할 때 사용한다.

 

Flag Register

Carry Flag(CF) : 부호없는 산술 연산 수행결과로 자리 올림이나 내림이 발생할 때 set(1) 된다. 어셈블리어 STC, CLC, CMC 명령어를 이용하여 직접적인 플래그 값 수정이 가능하다.

 

Parity Flag(PF) : 연산 결과의 bit중 1인 bit의 개수가 짝수개이면 1, 홀수개이면 0으로 세팅된다.

 

Auxiliary Carry Flag(AF) : 보조 캐리플래그이다. 산술연산 8비트연산자에서 비트 3에서 비트4로 캐리가 발생할 경우 1로 set된다.

 

Zero Flag(ZF) : 산술 연산 또는 논리 연산의 결과가 0이되면 플래그 값이 1로 set된다. 결과가 0이 아니라면 플래그 값은 0으로 리셋된다. 두값의 산술연산이나 루프 내부의 카운터를 점차적으로 빼서 0을 만들어 플래그를 Set시켜 루프를 빠져나가는 등 여러방식으로 사용된다.

 

Sign Flag(SF) : 최상위 bit(MSB)의 결과가 같은 값으로 저장된다. SF=1일 경우 음수이고, SF = 0일 경우 양수이다.

 

Overflow Flag(OF) : 부호 있는 산술연산의 결과가 sign-bit(MSB)를 제외한 최대 허용 정수값보다 크거나 최소 정수값보다 작으면 1로 Set 된다.

 

제어플래그

Direction Flag(DF) : 문자열 데이터 복사에서 방향을 결정하는 Flag이다. set(1)되어있으면 높은 주소 -> 낮은 주소로 Clear(0)으로 되어있으면 낮은 주소 -> 높은 주소로 처리한다. 어셈블리어 STD로 set, CLD로 Clear 가능하다.

 

시스템 플래그

Trap Flag(TF) : 플래그가 0일때 CPU는 평소처럼 명령어를 실행시킨다. 플래그가 1일 때에는 CPU가 하나의 명령을 시행하고 Interrupt가 발생한다. Interrupt가 발생하면 디버거가 해당 프로세스를 attach할 수 있는 상태가 된다.

 

Interrupt Flag(IF) : 프로세스에 인터럽트가 발생했을 때 인터럽트처리를 할것인지 제어한다. 플래그 값이 1로 Set 되어있으면 외부로부터 인터럽트 신호가 들어왔을 때 인터럽트를 처리하고, 0으로 Clear되어있으면 인터럽트 신호가 들어오더라도 반응하지 않는다.

 

 

명령어 지시자 레지스터

EIP(Extended Instruction Pointer) : 다음에 실행할 명령어 들어 이는 메모리 주소를 가리킨다. CS세그먼트 레지스터를 참조하여 실행번지를 참조한다. CPU는 EIP의 주소를 보고, 다음에 처리할 명령어를 가져온다. 직접적인 조작이 불가능 하다. 그러나 call, jmp, loop, interrupt와 같은 프로그램 흐름제어 명령을 통해 EIP를 자동으로 변경할 수 있다.

728x90

'Programming > assembly' 카테고리의 다른 글

어셈블리 문법  (0) 2020.03.01
echo  (0) 2020.03.01
sum.c 스택 프레임  (0) 2020.03.01
메모리 구조  (0) 2020.03.01
Hello World (x64)  (0) 2020.03.01

+ Recent posts