1. 레지스터의 역할 (EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP, EIP) 조사
레지스터 : 4바이트만큼의 데이터를 담거나 표현할수있음
EAX : 덧셈 혹은 뺄셈 같은 연산의 결과를 저장
혹은 어떤 함수가 실행이 된 결과 리턴값을 저장하는 역할
ECX : Count 레지스터 루프를 도는 값 즉, 루핑 카운터 레지스터(for문 10번 = ECX 10)
EDX : EAX와 같이 쓰이고 부호 확장 명령 등에 쓰임
큰 수의 곱셈 또는 나눗셈 등의 연산이 이루어질 때, EDX 레지스터가 사용되어 EAX 레지스터와 함께 쓰임
EBX : ESI 레지스터나 EDI 레지스터와 결합 될 수 있으며, 메모리 주소를 저장하기 위한 용도로 사용
ESP : 스택 포인터, 스택 메모리의 최상단을 가르킴
PUSH, POP 명령에 따라 ESP의 값이 4바이트씩 변함.
EBP : 스택 프레임의 시작 지점 주소(스택의 가장 윗 부분, 스택의 처음)가 저장됨.
EBP 레지스터는 현재 사용되는 스택 프레임이 소멸되지 않는 이상 EBP 레지스터의 값은 변하지 않음.
ESI : 데이터를 조작하거나, 복사시에 소스 데이터의 주소가 저장됨.
EDI : ESI 레지스터와 비슷하나, EDI 레지스터에는 복사 시의 목적지의 주소가 저장됨
EIP : Instruction Pointer (명령 포인터) -> 다음에 실행할 명령어의 주소를 담음
맨처음 RUN 하면 Entrypoint로 넘어감 (아직 main함수 실행 안됨)
버퍼 메모리 : 프로그램이 동작중에만 적용되는 메모리들
스택(Stack) 메모리
힙(Heap) 메모리
스택 : 임시메모리이며 바닥에서부터 데이터가 위로 쌓임
힙 : 임시메모리이며 작은 조각 형태로 할당하며 서로가 링크리스트 형식으로 이어져있음
한 개의 실행 프로그램에는 PE구조로 PE헤더와 각 섹션들이 존재하고, 섹션에서 각 dll을 호출한다
커널 메모리 공간 : 운영체제에 신장역할을 한다. PE파일이며 실행파일이다. 커널이미지가 로드됨 ntoskrnl.exe(window7까지)
sys : 하드웨어같은 물리장치들을 통제하기 위해 함수들이 정의된 파일
_EPROCESS : 프로그램에 있는 모든 정보를 담고있는 커널 메모리 영역에 있는 자료구조
.text 섹션 : 컴파일된 기계어 코드
콜러(Caller) : 주체
콜리(Callee) : 피주체
ESP레지스터 : 스택의 꼭대기를 가르킴(포인터) 스택메모리를 가르킴
EIP레지스터 :코드를 포인팅하는 레지스트(.text섹션 어딘가를 가르킴)
둘다 항상 바쁨
call 코드 : 돌아올 주소를 백업하며, 호출할 때 호출하는 코드 바로 아래 코드를 스택에 백업을 하며 호출된 장소로 이동하고 리턴코드를 만나면 스택에 꼭대기(리턴 어드레스)에 있는 값을 참조를 해서 돌아옴
위키백과
ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC
일반 레지스터
32비트 일반 레지스터는 4개가 있다. 이들은 주소 레지스터보다는 더 일반적인 용도로 쓰이지만, 특정 명령에서는 특정한 레지스터만 쓸 수 있는 경우가 있다.
EAX: 누산기에 해당하며 대부분의 연산들이 수행된다. 일반적으로 프로시저의 return 값을 저장한다.
ECX: 개수, 횟수 등을 저장하는 카운터로 주로 사용된다.
EDX: 누산기의 확장으로 누산기와 관련된 연산에서 사용된다. EDX와 EAX를 합쳐 64비트 연산을 하는 경우가 대표적이다.
EBX: 일반적인 데이터 레지스터로, 원래 16비트 모드에서는 포인터로 사용했다.
주소 레지스터
32비트 일반 주소 레지스터는 4개가 있으며, 일반 레지스터에 속하지 않는 주소 레지스터 EIP도 있다.
ESP (stack pointer): 스택의 꼭대기 주소를 담는다.
EBP (base pointer): 현재 스택 프레임의 주소를 담으며, 일반적인 목적으로 쓰기도 한다.
ESI (source index): 문자열 연산에서 사용되는 원본 주소를 담는다.
EDI (destination index): 문자열 연산에서 사용되는 목적 주소를 담는다.
EIP (instruction pointer): 다음에 실행될 명령의 주소를 담는다. 프로그램 카운터와 같은 역할이다.
2. IA32 아키텍처 명령어의 사용 예시
IA-32(Intel Architecture, 32-bit) 또는 x86-32는 인텔의 32비트 마이크로프로세서에서 사용하는 명령 집합 아키텍처이며, 이전에 사용되던 IA-16 아키텍처의 32비트 확장이다. IA-32를 x86이라는 이름으로 부르기도 하지만 엄밀하게는 x86 아키텍처는 IA-16, IA-32 등을 모두 포함하는 일반적인 이름이다.
PUSH EBP : EBP값을 push
MOV EBP, ESP : ESP값에 EBP를 넣는다
SUB ESP,8 : ESP값에 8을 뺀다 (Hex값)
MOV DWORD PTR SS:[EBP-8], 5 : STACK 영역의 EBP-8 주소의 4바이트 공간의 값에 5를 넣는다 (SS 는 STACK 영역을 의미, DS는 DATA 영역을 의미)
MOV DWORD PTR SS:[EBP-4], 7 : STACK 영역의 EBP-4 주소에 7값을 넣는다
MOV EAX, MOV DWROD PTR SS:[EBP-4] : 7값을 EAX에 넣는다.
PUSH EAX : 7값이 들어간 EAX값을 push한다
MOV EAX, DWROD PTR SS:[EBP-8] : 전에 계산한 5값을 EAX 레지스터에 넣는다
PUSH ECX : 루프 카운터를 저장하는 ECX값 push
CALL sample._sum : sample._sum을 실행 (jmp문과는 달리 Return됨)
3. 실습 재현
breakpoint 건 상태
EIP 레지스터를 보면 00401060 실행 직전상태이다.
CALL sample._printf를 실행 시키면 코드 내용인 5 + 7 = 12 값이 cmd창에 나올 것이다.
imagebase
Address Of Entrypoint
Section(.text, .data, .idata ...)
Import Mechanism
IMAGE_IMPORT_DESCRIPTOR, IAT(Import Address Table)
주요 자료구조간의 연관성
Binding (동적, 정적) : 프로그램이 로드에 의해 실행되는 과정에서 실제
호출된 함수들을 메모리에 할당하고 오버라이팅되는 과정
(IAT과 깊은 연관)
가상 주소 공간 (Virtual Address Space)
FFFFFFFF : 4G까지(32bit) 32비트의 주소가 4기가를 넘을수없음 램 8G X
오퍼레이션 : 연산자 push, mov , sub
오퍼랜드 : 피연산자 ebp, esp, eax, ecx -> 영항을 받음
[인덱 아키텍처를 기반으로한 어셈블리 명령의 구조]
OPERATION OPERAND1 [OPERAND2]
PUSH ESP
MOV EAX, ESP
MOV : 데이터 복사
MOV EAX, 0x03 // 3을 EAX 레지스터에 복사 하세요.
MOV EBX, EAX // EAX 레지스터의 값을 EBX 레지스터에 복사 하세요.
MOV EDX, [ESP+0x04] // ESP+0x04 주소에 있는 데이터를 DDX 레지스터에 복사 하세요.
// [] = C언어의 *(asterisk) : 특정 메모리 주소에 있는 값을 참조
ADD/SUB : 덧셈, 뺄셈
MOV EAX, 5 // EAX 레지스터에 5 값을 복사
MOV EBX, 6 // EBX 레지스터에 6 값을 복사
SUB EBX, EAX // EBX 레지스터의 값을 EAX 레지스터 값으로 뺀후 결과를 EBX에 대입. EBX 레지스터의 값이 1이됨
ADD EBX, EAX // EBX 레지스터의 값이 6이 됨
XOR : 배타적 OR 연산
1 XOR 1 = 0, 1 XOR 0 = 1, 0 XOR 1 = 1 , 0 XOR 0 = 0
XOR EAX, EAX // EAX 값이 무엇이 담겨 있든 0 값이 됨. (레지스터 초기화) 대부분이 초기화 용도
LEA : 메모리의 주소 대입
LEA EAX, [EBP+0x04] // LEA는 []를 무시
EAX에는 EBP+0x04 값이 대입됨 *제거됨
JMP : 지정한 주소에 있는 코드로 분기함 (EIP 레지스터의 값을 지정한 주소로 바꿈)
MOV EAX, 0x00401010
JMP EAX // 0x00401010 주소로 분기해라 (EIP 레지스터의 값을 0x00401010으로 바꾸어라)
CALL : 지정한 주소에 있는 코드로 분기함 (EIP 레지스터의 값을 지정한 주소로 바꿈)
단, 분기하기 전에 스택 메모리에 EIP 레지스터의 데이터를 백업함.
CALL 0x00401040 // PUSH EIP, JMP 0x00401040
돌아오기위해 값을 EIP에 저장시켜놈
CALL은 돌아올걸 생각하고 넘어감
JMP는 돌아올걸 생각안하고 넘어감
RETN = POP EIP -> EIP는 다음에 실행될 포인터를 담고 있는데 해당 명령을 실행하면 EIP값이 바뀌면서 RETN됨
PUSH/POP : 스택이라고 부르는 임시 메로리 공간에 데이터를 적재함
PUSH 0x04
MOV EAX, 0x03
PUSH EAX
l l
l l
l l
l 4 l
+------+
POP EBX // 스택의 최상단에 있는 명령을 EBX 레지스터에 이동, 예시에서는 EBX의 값이 3이 대입됨.
l l
l l
l 3 l
l 4 l
+------+
PUSH EAX
PUSH EAX
POP EDX // EDX 레지스터에 스택의 최상단에 있는 값을 이동. 예시에서는 EDX 레지스터의 값은 3이 대입됨
l l
l l
l 3 l
l 4 l
+------+