본문 바로가기

2. Reversing (리버싱)/2) 개념 정리

[26.03.27] 개구리버싱 1주차 활동

<1강 리버싱 OT 및 분석 방법론>

1. 리버싱이란? 역공학

RE(Reverse Engineering) : 역공학의 총칭

= RCE(Reverse Code Engineering) : 소프트웨어 실행 파일 분석에 특화된 역공학

 

2. 리버싱 분석 방법

  1. 정적 분석

-파일을 실행하지 않고 분석하는 방법

-파일의 겉모습(Header, String, Import Table)을 분석 / 전체 구조 파악에 용이함. (ex. IDA, DIE)

  1. 동적 분석 

-(디버거로) 파일을 실행하고 분석하는 방법 / 메모리, 레지스터의 실시간 변화를 관찰

-내부 파일까지 깊이 들어가서 분석, 관찰 (ex. Cheat Engine, Ollydbg, x64dbg)

 

3. 데이터 표현 단계

  1. 소스코드: 개발자가 작성한 고수준 언어 

>> printf(“Hello, World!”)

  1. Hex code : 기계어를 16진수로 표현한 형태

>> 45 46 44 43

  1. assembly code : 기계어와 1:1 대응되는 최하위 수준의 인간 가독형 언어

>> mov eax, ebx / add1

 

4. 패치(Patch)와 크랙(Crack)

패치란? 프로그램의 동작 수정을 위해 프로세스의 메모리나 파일의 코드를 변경하는 것

크랙이란? 불법적인 메모리 수정, 비도덕적인 목적으로 행해지는 패치

 

<2강 Hello World 분석 및 디버거 활용>

1. 프로그램 빌드 과정

전처리(Preprocessing) → 컴파일(Compile) → 어셈블(Assemble) → 링킹(Linking)

 

2. 디버깅 목적

Hello World 실행 파일을 디버깅하여 어셈블리 언어로 변환 >  main 함수 탐색

이 과정을 통해 기본적인 디버거의 사용법과 어셈블리 명령어 체계를 알아 보는 것

 

3. 디버거 핵심 개념 (x64dbg 사용)

  1. 엔트리 포인트 (EP) : 운영체제(OS)가 프로그램을 메모리에 올린 후 제어권을 넘겨주는 공식적 시작 주소
  2. 브레이크 포인트 (BP) : 특정 코드의 동작을 확인하거나 변수값을 조사하기 위해 실행  흐름을 멈추게 하여 상태를 조사하는 도구

 

4. 실습 및 기능 활용

-문자열 변조 :  메모리 상의 문자열 주소를 찾아 데이터를 수정함으로써 실행 결과 변경 가능

-주요 단축키 : Ctrl+G (특정 주소 이동), Space바 (어셈블리 코드 직접 수정)

 

<3강 바이트 오더링(Byte Ordering)> 

1. 바이트 오더링이란? 

데이터를 메모리에 저장할 때 바이트(8 bits) 단위의 배치 순서를 결정하는 규칙

 

2. 빅 엔디안(Big-Endian) vs. 리틀 엔디안(Little-Endian) -> MSB(가장 큰 자릿수)를 어디에 두느냐

  1. 빅 엔디안

-저장 방식 : MSB(가장 큰 수)를 낮은 주소부터 저장, 사람이 읽는 순서와 동일.

-특징 : 데이터의 순서가 직관적이라 디버깅 시 사람이 읽기 용이.

-주요 사용 : 네트워크 프로토콜(TCP/IP), 대형 메인 프레임 등

  1. 리틀 엔디안

-저장 방식 : LSB(가장 작은 수)를 낮은 주소부터 저장, 바이트 단위로 역순 배치됨

-특징 : Intel x86/x64 CPU의 기본 방식. 산술 연산 시 하위 바이트부터 계산하므로 물리적 회로 설계상 효율적임. 

 

3. 리버싱 실습 포인트!

  1. 메모리 덤프 확인 : 디버거에서 보이는 메모리와 실제 값, 즉시 치환 가능해야함.
  2. 문자열 예외 : 숫자는 엔디안의 영향을 받아 뒤집히지만, 문자열은 배열 형태이므로 엔디안의 영향을 받지 않고 정방향으로 저장됨
  3. 주소값 분석 : 점프문이나 포인터가 가리키는 주소 역시 리틀 엔디안으로 기록됨을 인지해야 함. 
  4. 수치 데이터: 리틀 엔디안 방식에 따라 메모리 덤프를 역순으로 조합해야 실제 값을 얻을 수 있음. 

 

4. 리버싱 중요성 강조 !!

1) 값의 변조: 특정 변수값을 찾으려 할 때, 리틀 엔디안 방식을 모르면 메모리에서 해당 값을 찾을 수 없음 

2) 포인터 분석: 점프할 대상 주소(Adress) 역시 리틀 엔디안으로 저장됨

 

<4강 레지스터(Register)>

1. 레지스터의 역할 

: CPU 내부에 위치한 초고속 임시 저장소. 명령어 실행에 따라 가장 빈번하게 값이 변하는 지점

★ 리버싱 포인트 : 디버거로 프로그램을 한 줄씩 실행 시, 가장 먼저 변함

 

2. 범용 레지스터

: 가장 자주 쓰이는 8개 레지스터 (32비트 기준)

  1. 범용 레지스터의 종류

-EAX: 산술 연산 수행 및 함수의 리턴값 저장

-ECX: 반복문(Loop)을 돌 때 횟수 카운트

-EDX: EAX를 보조하여 큰 숫자의 곱셈/나눗셈을 도움

-ESP: 현재 스택의 가장 윗부분 주소

-EBP: 함수의 시작 지점 주소를 고정해서 가리킴 (스택 프레임의 기준점) 

-ESI / EDI: 주로 데이터를 복사할 때 각각 ‘출발지’와 ‘목적지’ 주소를 저장

 

3. 플래그 레지스터 (EFLAGS) 

: 숫자가 아니라 ‘상태’ 저장 / 비트(0 또는 1) 단위로 기록되며 조건문을 분석할 때의 핵심

  • ZF(Zero Flag) : 연산 결과가 0일 때, 1(True)이 됨 / 두 값을 비교(CMP)했을 때 일치하면 결과가 0이 되므로 ZF가 세팅
  • CF (Carry Flag): 연산 중 자릿수 올림/내림이 발생할 때 세팅
  • SF (Sign Flag): 연산 결과가 음수일 때 세팅

★ 리버싱 포인트 :  JZ(Jump if Zero) 같은 명령어는 ZF 플래그를 보고 점프할지 말지(실행여부)를 결정함. 크랙을 할 때 이 플래그를 강제로 조작하기도 함.(리버싱의 핵심 기법)

 

4. 세그먼트 레지스터(Segment Register) 

: 메모리를 용도별로 구획화하여 효율적으로 관리하기 위한 특수 포인터

  • CS (Code Segment): 현재 실행 중인 기계어 코드가 저장된 메모리 영역을 가리킴. 
  • DS (Data Segment): 프로그램의 전역 변수나 정적 데이터가 위치한 영역을 가리킴. 
  • SS (Stack Segment): 함수 호출 시 사용하는 스택 메모리 영역의 시작 주소를 가리킴. 
  • ES/FS/GS: 추가적인 데이터 저장이나 운영체제별 특수 목적(예: 윈도우의 TEB/PEB 정보 접근)을 위해 사용됨.

 

5. 실습의 핵심 : 변화 관찰(Tracing)

1) 명령어 실행: MOV EAX, 1 실행하면? 

2) 레지스터 확인: 디버거 창의 EAX 값이 즉각적으로 00000001로 갱신되는 것을 디버거의 Register 창에서 실시간 확인 

3) 프로그램 흐름(Control Flow) 파악: 

-비교 연산 : CMP EAX, EBX 명령 실행 시, 두 값의 차이에 따라 변하는 EFLAGS(특히 ZF,SF)의 상태를 분석.

-분기 판단 : 현재 플래그 상태를 바탕으로 다음에 올 JMP, JZ, JNZ 등의 분기문이 실행될지 여부를 예측하여 프로그램의 전체적인 로직 파악.

-메모리 덤프 활용 : 특정 주소의 값이 의도한 대로 변경되었는지 메모리 맵을 통해 검증하고, 코드 패치(Patch)의 성공 여부를 판단.