김승현

KISA Academy - 리버스 코드 엔지니어링 중급 (13~15강) 본문

교육/KisaGym

KISA Academy - 리버스 코드 엔지니어링 중급 (13~15강)

kshind 2024. 7. 11. 01:03

13강 [이론] CPU의 레지스터와 주요 명령어 - IA32 주요 레지스터 세트

 

레지스터란?

프로세서 레지스터 (혹은 레지스터)는 CPU 내에 존재하는 작은 크기의 저장 공간이다.

CPU 내부에 있기에 HDD나 SSD보다 빠른 접근 가능.

 

레지스터는 목적에 따라 여러 개의 세트 그룹으로 나뉨

 

  • 범용 레지스터
    • 산술/논리 연산에 사용되는 피연산자 정보, 주소, 계산을 위한 피연산자 정보, 메모리 포인터 정보 등을 담고 있음
    • EAX, EBX, ECX, EDX, ESI......
    • 앞에 있는 E는 Extended임. 32비트가 되면서 변경된 이름
    • EAX : Accumulator Register라고 부름 - 어떤 함수의 호출 결과나 연산의 결과를 저장함
      1. 산술/논리 연산 수행 결과값 저장
      2. 윈도우 함수 호출 결과값 저장
    • ECX : Counter Register라고 부름 - for문 등에서 몇 번 Loof한 지를 카운트 할 때 카운트를 저장함
    • ESI, EDI - Source와 Destination을 의미함 - 변수에 다른 변숫값을 넣으려고 할 때 사용
      • 복사할 주소를 ESI 레지스터가 가리키고, 복사될 도착지점을 EDI 레지스터가 가리킴
    • EBP : Base Pointer 할 때 그 B임 
      • 함수 내 고유한 포인트를 할 때 EBP를 사용함 - Base Point를 가리킬 때 사용
    • ESP : Stack Pointer - 스택의 꼭대기를 가리키는 레지스터
      • 스택에 새로운 자료구조가 들어올 때마다 ESP가 변화됨( 꼭대기를 가리키기 때문 )
  • 세그먼트 레지스터
    • GDT(Global Descriptor Table, 메모시 상의 세그먼트 정보를 담은 자료구조)의 인덱스 값을 포함하는 레지스터
    • 실행 파일이 실행되면서 메모리에 올라갈 때 코드의 시작 위치와 코드를 가리키는 포인터들이 있는데 이들이 CS와 DS라고 함
    • CS, DS, SS, ES, FS GS.....
  • EFLAGS 레지스터
    •  명령이 실행되는 과정 중 현재 프로세서의 상대 정보, 제어 정보 등을 보관하며 각 비트가 별도의 의미를 가짐
  • EIP 레지스터
    • Instruction Pointer 혹은 Program Counter라고 불리기도 하며 다음 실행할 명령의 주소 값을 가짐
  • Debug 레지스터
    • 디버깅과 관련하여 주로 브레이크 포인트 지점과 관련된 정보를 가짐

 


14강 [이론] CPU의 레지스터와 주요 명령어 - IA32 주요 명령어

mov eax, ecx가 있으면 mov는 Operation, eax와 ecx는 Operand

Operand에서 [Address] 이렇게 대괄호가 있다면 보통 대괄호 안의 값은 주솟값이며 그 주소가 있는 메모리 공간을 의미

 

MOV

Source 피연산자 값을 Destination 피연산자로 복사함 ( 두 연산자의 사이즈는 반드시 동일해야 함 )

MOV Destination Source    의 형태

 

MOV의 Operand

  1. 메모리 공간
  2. Data
  3. Register

 

LEA

Source 피연산자를 참조하여 계산된 메모리 주소가 Destination 피연산자에 저장 => 주솟값을 저장한다

LEA Destination Source    의 형태

 

ADD

Source 피연산자를 동일한 크기의 Destination 피연산자에 더함

Source 피연산자는 변하지 않으며 덧셈한 결과 값은 Destination 피연산자에 저장

ADD Destination Source    의 형태

 

SUB

Destination 피연산자를 Source 피연산자만큼 감소

CPU의 ALU 내부에서는 실제 덧셈 연산이 수행됨 (2의 보수를 취한 후 덧셈)

SUB Destination Source    의 형태

 

CALL, JMP

분기 명령어

둘 call 100, jmp 100이면 둘 다 100번지로 점프하는 것은 같으나 call은 다음에 실행할 코드를 스택에 저장하나, jmp는 x

즉, call은 돌아오지만 jmp는 이동했다가 돌아오지 않음

 

RET

의미상으론 POP EIP와 동일. 의역하면 함수가 종료된다고 생각 가능

스택에 여러 개의 데이터들이 있는데 예를 들어 call하고 돌아오는 주솟값을 저장하는 용도로 스택을 사용하곤 하는데

돌아올 때 ret을 사용해서 돌아옴 (Opreand에 EIP 값을 저장함)

 

PUSH, POP

PUSH는 피연산자를 스택 메모리 최상단에 입력한 후 ESP를 변화시킴

POP은 스택 메모리의 최상단에 있는 값을 피연산자에 입력한 후 ESP를 변화시킴

 

ex)

PUSH ebp

pop eax면

ebp의 값을 stack에 저장하고 eax에 그 값을 저장함

 

IDA의 표현법 ds: [변수명]라는 형태는 변수명이라는 전역변수를 의미함 (ds는 13강에서 나온 data segment인듯?)

 

cmp가 사용될 때 같이 사용되는 jmp에는  여러 종류가 있음(jl, jg, jnz....)

-> 이때 보통 Operand 중 첫 번째가 기준이 되는 경우가 대부분. jl의 경우 앞이 작으면. jg의 경우 앞이 더 크면.

 


15강 [실습] CPU의 레지스터와 주요 명령어 - IA32 주요 명령어와 레지스터 사용예제 분석 실습

 

사용 툴

IDA, XDBG

 

sub에서 사용된 20h같은 Operand의 경우 0x20과 같음(h는 hex)

 

push ebp 실행 후 모습

사진에서 볼 수 있듯이 EBP의 값을 스택 최상단에 저장됨

 

and esp, FFFFFFF0 실행 전
and esp, FFFFFFF0 실행 후

마지막 비트의 값만 0으로 바꿀 때 사용하는 방식 - and, operand FFFFFFF0

 

 

CALL에는 절대주소, 상대주소로 하는 방식이 있는데 위 사진은 상대주소를 이용해 분기하는 방식

F7과 F8의 차이점

둘 다 한줄 실행이지만 f7은 step into로서 함수가 있다면 함수 내부로 이동,

but f8은 step over로서 그냥 함수를 넘어서 다음으로 이동

 

더블클릭시 해당 지점으로부터 상대적인 주소 확인 가능

loop_count는 bss라는 data segment에 있음 bss는 그 중 전역변수 영역

view - Open subview - Segments를 누르면 세그먼트들을 볼 수 있음

 

xdbg에서 loop를 하는 것을 나타내는 표시loop 탈출 조건  

 

어셈블리어 분석을 할 때 하나하나 직역보단 전체적인 flow를 이해하는 것이 중요

ex) sub esp, 20h라면

단순히 esp에 0x20을 뺀다가 아니라 esp는 이동시키는 그런 것이기에 함수에서 지역 변수를 할당하는 코드구나라는 것을

이해할 수 있도록 해야 함

 

ex) cmp와 jmp가 함께 나왔다면, loop를 하고 있구나라는 걸 알 수 있어야 함

 

ex) xor ebx, ebx가 나와다면, 레지스터를 0으로 초기화하는 구나라는 것을 알아야 함