Jiyong's STUDY

[기초] 레지스터 본문

보안/리버싱, 어셈블리

[기초] 레지스터

Kingjiyong 2020. 7. 16. 12:17

IA-32 레지스터는 범용 레지스터가 8개 있다. 

레지스터를 '변수'로 이해하면 이해하기 쉽다.

 

정확하게 "변수는 변수인데, CPU가 사용하는 변수다."

 

레지스터는 EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP로 총 8개다.

 

EAX부터 EDX까지는 ABCD순인데 정확히는

EAX, EDX, ECX, EBX의 순으로 외우는게 맞다.

 

 

EAX (Extended Accumulator Register)

 

Accumulator. 이 레지스터의 역할을 요약하면 산술 계산을 하며, 리턴값을 전달한다.

쉽게 생각하면 단지 "변수"이며, 구체적으로는 "가장 많이 쓰는 변수"이다.

계산식에 사용되며 사칙연산 등에 자주 등장한다.

함수의 리턴값이나 return 100, return FALSE 등의 코드를 사용할 떄 return 뒤의 값이 EAX에 기록된다고 보면 된다.

 

EDX (Extended Data Register)

 

Data. 이 레지스터도 변수의 일종이다. EAX와 역할은 같되, 리턴값의 용도로는 사용되지 않는다.

각종 연산에 쓰이며 더하고 뺴고 곱하는 용도로 이용된다.

곱하거나 나눌 때, 좀 더 복잡한 연산이 필요할 때 덤으로 쓰이기도 한다.

 

ECX (Extended Count Register)

 

Count. 카운팅의 역할을 한다. 

루프문을 수행할 때, 카운팅하는 역할을 한다.

for(int i=0; ... ) 와 같은 루프문에서 int i에서 i의 역할을 한다.

C/C++에서는 보통 0부터 특정 조건까지 루프를 돌리는데,

반대로 ECX는 미리 루프를 돌 값을 넣어놓고 0까지 i--; 연산 같은걸 한다.

카운팅할 필요가 없을 떄엔 변수로 사용해도 무방하다.

 

EBX (Extended Base Register)

 

Base. 하지만 Base보단 별거 없다고 외우면 된다.

어떤 목적을 가지고 만들어진 레지스터가 아니다. 레지스터가 하나쯤 더 필요하거나

공간이 필요할떄 등 적당한 용도를 알아서 만들어서 사용하고 있다.

EAX, EDX, ECX가 부족할 떄 사용하기도 한다.

 

ESI, EDI (Extended Source Index, Extended Destination Index)

 

Source Index, Destination Index. 시작지 인덱스, 목적지 인덱스.

문자열이나 각종 반복 데이터를 처리 또는 메모리를 옮기는 데 사용된다.

 

ESP, EBP (Extended Stack Pointer, Extended Base Pointer)

 

현재 스택의 가장 높은 위치에 있는 데이터를 가리키는 포인터,

현재 스택의 가장 낮은 위치에 있는 데이터를 가리키는 포인터다.  

 

 

 

하지만 꼭 지켜야 프로그램이 돌아가는 것은 아니다. 

 

 

#include <stdio.h>
#include <windows.h>

int Plus(int a, int b) {
return a + b;
}

_declspec(naked) PlusAsm(int a, int b) {
_asm {
mov eax, dword ptr ss:[esp+8]
mov ecx, dword ptr ss:[esp+4]
add eax, ecx
retn
}
}

int main() {
int num = Plus(3, 4);
int num2 = PlusAsm(3, 4);

printf("%d, %d\n", num, num2);
return 0;
}

 

정상코드

 

#include <stdio.h>
#include <windows.h>

int Plus(int a, int b) {
return a + b;
}

_declspec(naked) PlusAsm(int a, int b) {
_asm {
mov ebx, dword ptr ss:[esp+8]
mov edx, dword ptr ss:[esp+4]
add edx, ebx
mov eax, edx
retn
}
}

int main() {
int num = Plus(3, 4);
int num2 = PlusAsm(3, 4);

printf("%d, %d\n", num, num2);
return 0;
}

 

비정상코드

 

두 소스코드의 결과는 같다. 하지만 레지스터의 목적에 맞지 않게 컴파일러는 변환하지는 않는다.

하지만 책에서는 레지스터는 단순하게 어떻게 하든 작동은 한다는 것을 보여주는 것이다.

 

p.s. _declspec(naked)에서 _declspec은 클래스의 정보를 알려주는 것이며

그 안의 naked는 간단하게 말하면 컴파일러에게 건들지 말라는 의미다.