리버스 엔지니어링

HW·2024년 11월 7일
  1. 리버스 엔지니어링의 기본 개념
    리버스 엔지니어링(Reverse Engineering)은 제품이나 시스템의 구조와 동작 방식을 분석하여 그 원리를 이해하는 과정이다. 주로 소프트웨어의 경우, 바이너리 파일을 분석해 원래의 소스코드를 유추하거나, 프로그램의 기능과 알고리즘을 역으로 추적하여 시스템을 분석한다.

리버스 엔지니어링은 해킹, 보안 분석, 악성 코드 분석 등 다양한 분야에서 중요하게 활용된다.

  1. 프로그램의 구조: 컴파일 과정
    리버스 엔지니어링을 이해하려면 먼저 프로그램이 어떻게 만들어지는지에 대해 이해할 필요가 있다. 프로그램은 고급 언어로 작성된 소스코드를 컴퓨터가 이해할 수 있는 기계어로 변환하는 여러 단계를 거친다.

프로그램의 기본 구조
소스 코드 (Source Code): 사람이 읽을 수 있는 고급 언어로 작성된 코드다. 예를 들어 C, C++, Java 등으로 작성된다.
컴파일(Compile): 소스 코드를 컴파일러를 이용해 기계어(바이너리 코드)로 변환하는 과정이다.
링크(Linking): 여러 개의 컴파일된 object file을 결합하여 실행 파일(EXE)을 만든다.

컴파일 과정
1) 전처리(Preprocess)
컴파일러가 소스코드를 어셈블리어로 컴파일하기 전에 필요한 형식으로 가공하는 과정
주요 작업 - 주석 제거, 매크로 치환, 파일 병합 등
2) 컴파일(Compile)
C나 다른 고급 언어로 작성된 소스코드를 어셈블리어로 번역하는 과정
문법 오류가 발생하면 에러 출력
3) 어셈블(Assemble)
컴파일된 어셈블리어 코드를 기계어(바이너리 코드)로 변환하는 과정
ELF 형식의 객체 파일(Object File) 생성됨
4) 링크(Link)
여러 개의 목적 파일을 결합하여 실행 가능한 바이너리 파일(EXE 파일) 생성

  1. 디스어셈블과 디컴파일
    리버스 엔지니어링에서 핵심적인 과정은 디스어셈블링(Disassembling)디컴파일링(Decompiling)이다. 이는 바이너리 파일을 분석하여 원래의 소스코드를 추론하는 과정이다.
  • 디스어셈블링(Disassembling)
    바이너리 파일을 어셈블리 코드로 변환하는 작업이다. 기계어로 작성된 프로그램을 사람이 읽을 수 있는 어셈블리어로 변환하여 분석한다.
  • 디컴파일링(Decompiling)
    바이너리 파일을 고급 언어로 변환하는 과정이다. 이는 디스어셈블링보다 더 높은 수준에서 원본 소스 코드에 가까운 형태로 복원하려는 시도이다.

디스어셈블 후 분석 방법

  • 정적 분석(Static Analysis)
    프로그램을 실행하지 않고 코드만을 분석하는 방법이다. 주로 바이너리 파일에서 직접 정보나 패턴을 찾아내어 프로그램의 동작 원리를 이해한다.
  • 동적 분석(Dynamic Analysis)
    실제로 프로그램을 실행하면서 프로그램의 동작을 분석한다. 프로그램이 실행될 때 일어나는 행동을 추적하여 프로그램의 기능을 파악한다.

  1. 컴퓨터 아키텍처와 리버스 엔지니어링
    리버스 엔지니어링을 제대로 수행하려면, 컴퓨터 아키텍처에 대한 기본적인 이해가 필요하다. 컴퓨터 아키텍처는 하드웨어와 소프트웨어의 상호작용을 다루며, 프로그램이 어떻게 실행되는지, CPU가 어떻게 명령을 처리하는지를 이해하는 데 중요한 역할을 한다.
    CPU와 레지스터
  • 범용 레지스터: CPU에서 데이터를 저장하거나 연산을 수행하는 데 사용하는 레지스터들이다. 예를 들어 eax, ebx, ecx, edx 등이 있다.
  • 명령어 포인터: 현재 실행 중인 명령의 주소를 저장하는 레지스터이다. 보통 rip(x64)라는 이름으로 불린다.
  • 플래그 레지스터: 연산 결과에 따라 설정되는 플래그들(Carry Flag, Zero Flag, Sign Flag 등)이 저장되는 곳이다.

어셈블리어의 명령어들

  • 데이터 이동 명령어 (mov)
    데이터를 레지스터나 메모리 간에 이동한다.
  • 산술 연산 명령어 (ADD, SUB, MUL, DIV)
    데이터 간의 덧셈, 뺄셈, 곱셈, 나눗셈을 수행한다.
  • 비교 연산 (CMP)
    두 피연산자를 비교하여 플래그를 설정한다.
  • 분기 연산 (jmp, je, jne)
    프로그램 흐름을 제어하는 명령어들로, 조건에 따라 점프한다.
  • 함수 호출 (CALL)
    함수를 호출하고, 호출된 함수가 끝난 후 return 주소로 돌아간다.

0개의 댓글