Reversing

[Reversing] 리버싱 입문, 레지스터(Register) ?

psswrd 2020. 4. 10. 16:40

참고문 : 리버싱 핵심원리, 이승원

 

CPU 레지스터란 ?

: 레지스터(Register)란 CPU 내부에 존재하는 다목적 공간입니다. 메모리인 RAM과의 차이점은 CPU가 RAM에 있는 데이터를 액세스하기 위해서는 물리적으로 먼 길을 돌아가 시간이 오래걸린다. 하지만 레지스터는 CPU와 한 몸이기에 고속으로 데이터를 처리할 수 있습니다.


 1) 범용 레지스터

   : 범용 레지스터는 이름처럼 범용적으로 사용되는 레지스터들입니다. IA(Inter Architecture)-32 에서 각각의 범용 레지스터들의 크기는 32비트(4바이트)입니다. EAX, EBX, ECX, EDX는 보통 상수/주소 등을 저장할 때 주로 사용된다. 

  ECX는 반복문 명령어(LOOP)에서 반복 카운트(loop count)로 사용됩니다. (루프를 돌 때마다 ECX를 1씩 감소시킵니다).

  EAX는 일반적으로 함수 리턴 값에 사용됩니다. 모든 Win32 API함수들은 EAX에 저장한 후 리턴합니다.

  EBP, ESI, EDI, ESP는 주로 메모리 주소를 저장하는 포인터로 사용됩니다.

  ESP는 스택 메모리 주소를 가리킵니다. 어떤 명령어들(PUSH, POP, CALL, RET)은 ESP를 직접 조작하기도 합니다. 

  EBP는 함수가 호출되었을 때 그 순간의 ESP를 저장하고 있다가, 함수가 리턴하기 직전에 다시 ESP에 값을 되돌려줘서 스택이 깨지지 않도록 합니다.

  ESI와 EDI는 특정 명령어들(LODS, STOS, REP MOVS 등)과 함께 주로 메모리 복사에 사용됩니다.'

IA-32 메뉴얼에서 발췌

 2) 세그먼트 레지스터

   : 세그먼트(Segment)란 메모리를 조각내어 각 조각마다 시작 주소, 범위, 접근 권한 등을 부여해서 메모리를 보호하는 기법을 말합니다. 세그먼트 메모리는 Segment Descriptor Table(SDT)에 기술되어 있는데, 세그먼트 레지스터는 이 SDT의 index를 가지고 있습니다.

 세그먼트 레지스터는 총 6개(CS, SS, DS, ES, FS, GS)이며 각각의 크기는 16비트(2바이트)입니다. 밑 그림에서 각 세그먼트 레지스터가 가리키는 세그먼트 디스크립터(Segment Descriptor)와 가상 메모리가 조합되어 선형주소(Linear Address)가 되며, 페이징 기법에 의해서 선형주소가 최종적으로 물리주소(Physical Address)로 변환됩니다.

IA-32 메뉴얼에서 발췌

CS는 프로그램의 코드 세그먼트(Code Segment)를 나타내며, SS는 스택 세그먼트, DS는 데이터 세그먼트를 나타냅니다. ES, FS, GS는 추가적인 데이터 세그먼트입니다.

 

  3) 프로그램 상태와 컨트롤 레지스터

    : 플래그 레지스터의 이름은 EFLAGS 이며, 32비트(4바이트) 크기입니다. EFLAGS 레지스터는 그림과 같이 각각의 비트마다 의미를 가지고 있습니다. 각 비트는 1또는 0의 값을 가지는데, 이는 On/Off 혹은 True/False를 의미합니다.

IA-32 메뉴얼에서 발췌

  디버깅에서 필요한 3가지 flag만 보면, 

  • Zero Flag (ZF) : 연산 명령 후에 결과 값이 0이 되면 ZF가 1(True)로 세팅됩니다.
  • Overflow Flag (OF) : 부호 있는 수(signed integer)의 오버플로가 발생했을 때 1로 세팅됩니다. 그릭고 MSB(Most Significant Bit)가 변경되었을 때 1로 세팅됩니다.
  • Carry Flag (CF) : 부호 없는 수(unsigned integer)의 오버플로가 발생했을 때 1로 세팅됩니다.

 

  4) Instruction Pointer

    : EIP (Instruction Pointer) 는 CPU가 처리할 명령어의 주소를 나타내는 레지스터이며, 크기는 32비트(4바이트) 입니다. CPU는 EIP에 저장된 메모리 주소의 명령어를 하나 처리하고 난 후 자동으로 그 명령어 길이만틈 EIP를 증가시킵니다.

  범용 레지스터들과는 다르게 EIP는 그 값을 직접 변경할 수 없도록 되어 있어서 다른 명령어를 통하여 간접적으로 변경해야 합니다. EIP를 변경하고 싶을 때는 특정 명령어(JMP, Jcc, CALL, RET)를 사용하거나 인터럽트, 예외를 발생시켜야 합니다.