1. register란
간단히 요약하자면, 프로그램이 실행되면 기본적으로 ram에 필요한 데이터들이 적재되는데, 연산을 포함한 실행은 register가 담당하게 된다.
즉, 프로그램이 실행되면
- 특정 동작을 위한 명령어들을 ram에 적재,
- 적재된 순서대로 register가 값을 가져가 연산.
- 그 결과를 다시 ram에 적재.
하는 식으로 프로그램은 작동한다.
2. register 종류와 역할
각 register는 사실 각각의 역할이 있다.
기억하면 좋겠지만 사실 분석 시 조금 더 도움이 되는 수준이라 기억하지 않아도 전혀 문제 없다.
아래는 hello 문자열을 출력하는 간단한 프로그램을 gdb로 열어 start 명령어 직후 레지스터에 들어간 값 들이다.
$rax : 0x00555555556004 → 0x00006f6c6c6568 ("hello"?)
$rbx : 0x0
$rcx : 0x00555555557df0 → 0x005555555550f0 → <__do_global_dtors_aux+0> endbr64
$rdx : 0x007fffffffe058 → 0x007fffffffe3ad → "COLORFGBG=15;0"
$rsp : 0x007fffffffdf30 → 0x0000000000000001
$rbp : 0x007fffffffdf30 → 0x0000000000000001
$rsi : 0x007fffffffe048 → 0x007fffffffe396 → "/home/kali/Downloads/a"
$rdi : 0x1
$rip : 0x00555555555144 → <main+11> mov %rax, %rdi
$r8 : 0x007ffff7fa3ef0 → 0x0000000000000004
$r9 : 0x007ffff7fceaa0 → <_dl_fini+0> push %rbp
$r10 : 0x007ffff7fcb518 → 0x000b00120000000e
$r11 : 0x007ffff7fe0fa0 → <_dl_audit_preinit+0> mov 0x1beba(%rip), %eax # 0x7ffff7ffce60 <_rtld_global_ro+896>
$r12 : 0x007fffffffe048 → 0x007fffffffe396 → "/home/kali/Downloads/a"
$r13 : 0x00555555555139 → <main+0> push %rbp
$r14 : 0x00555555557df0 → 0x005555555550f0 → <__do_global_dtors_aux+0> endbr64
$r15 : 0x007ffff7ffd020 → 0x007ffff7ffe240 → 0x00555555554000 → jg 0x555555554047
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
2.1 범용 레지스터
X로 끝나는 레지스터 들으로 AX, BX, CX, DX가 있으며, ABCD 차례로 이름을 지은 것 같지만, 사실 줄인 것이다.
범용 레지스터들은 "데이터"를 저장한다.
- AX(Accumulator) : 산술 / 논리 연산 수행. 함수의 return 값 저장.
- BX(Base) : 메모리 주소를 저장. ESI 및 EDI와 함께 인덱스로 사용됨.
- CX(Counter) : 반복 명령에서 반복 카운터(for 문의 i)로 사용. 반복 최대값 저장 후 1씩 줄어듦.
- DX(Data) : 여분의 레지스터이며 주로 큰 수의 곱셈이나 나눗셈 등을 위해 EAX와 함께 사용.
2.2 인덱스 레지스터
우리가 첫번째로 관심있어해야할 레지스터이며, "주소"를 저장한다.
- SI (Source Index) : 복사 및 비교 할 때 복사할 / 비교 기준이 되는 "데이터의 주소"를 저장한다.
- DI (Destination Index) : 복사 및 비교할 때 붙여넣을 / 비교 대상이 되는 "데이터의 주소"를 저장한다.
2.3 포인터 레지스터
인덱스 레지스터와 더불어 꼭 기억해야할 레지스터이며, 현재 스택에서 사용되고 있는 위치들을 저장한다.
- SP (Stack Pointer) : 스택의 끝 지점을 저장한다.
- BP (Base Pointer) : 스택의 시작 지점을 저장한다.
스택에 데이터가 쌓이는 방식으로 인해 SP가 스택의 시작지점, BP를 스택의 끝 지점을 나타낸다고 오해할 수 있으나 스택은 first in, last out 방식으로 데이터를 저장하기 때문에 위의 설명이 맞다.
2.4 확장된 명령 지시자
우리가 가장 관심있어해야할 레지스터로 이 위치의 주소를 변경하는 것이 system hacking의 주된 목적이다.
- IP (Instruction Pointer) : 프로그램의 다음 명령이 실행될 주소를 저장한다.
2.5 플래그 레지스터
가장 머릿속에 안들어오는 레지스터다.
CPU의 상태나 동작을 제어하며, 우선은 이런게 있다 정도만 기억하고 넘어가면 충분하다.
- FLAGS :
- [제어 플레그]
- DF(Direction) : 문자열을 처리할 때, 플래그가 0이면 데이터 이동 주소 증가, 1이면 자동 감소.
- IF(Interrupt) : 플래그가 0일 때 외부 인터럽트(일시정지) 요구 무시, 1일 때는 외부 인터럽트 요구 수용.
- TF(Trap) : 플래그가 0일 때 기존의 명령 실행, 1일 때는 내부 인터럽트 발생.
- [상태 플레그]
- CF(Carry) : 산술 연산에서 빌림수 발생시 1로 설정.
- AF(Adjust) : 16(8)bit 연산에서 빌림수 발생 시 1로 설정.
- PF(Parity) : 연산의 결과가 짝수면 1, 홀수면 0으로 설정/ 패리티를 체크.
- OF(Overflow) : 부호 "있는" 산술 연산의 결과가 오버플로가 발생했을 때 플래그를 1로 설정.
- SF(Sign) : 산술 논리 연산의 결과가 음수일 때 플래그를 1로 설정.
- ZF(Zero) : 산수 논리 연산의 결과가 0일 때 플래그를 1로 설정
3. 반드시 알아야될 것.
아래 테이블은 꼭 기억해야 한다.
많은 문서들이 bit 기준으로 위의 테이블을 명기하고 있기에 사실 조금 헷갈릴 수 있어 byte를 추가로 명기하였다.
(오히려 이게 더 헷갈릴 수도 있겠지만...)
기본적으로 16 bit 환경에서는 아무것도 붙이지 않고 AX, BX, CX 등과 같이 2 byte 단위로 데이터를 처리하였다.
이후 32 bit가 개발되면서 E를 붙여 EAX, EBX, ESP 등과 같이 이름을 붙여 4 byte 씩 값을 처리하였고,
64 bit에서는 R을 붙여 RCX, RDI 등과 같이 이름을 붙여 8 byte 씩 값을 처리한다.
당연히 최대 크기 이하의 데이터 또한 다룰 수 있지만, 1,2,4 byte로 끊어서 처리할 수 있다.
* 함께 보면 좋은 글.
'Tips & theory' 카테고리의 다른 글
one gadget 사용법 (0) | 2022.09.05 |
---|---|
함수 호출 규약. (0) | 2022.09.05 |
_IO_FILE_plus의 모든 것. (0) | 2022.08.21 |
FSOP - _IO_flush_all_lockp () (0) | 2022.08.18 |
Bypass IO_validate_vtable (0) | 2022.08.17 |