brunch

You can make anything
by writing

C.S.Lewis

by 복지CEO 조정원 Feb 07. 2016

리버스 엔지니어링 방법(제 2부: 링3 디버깅 소개)

보안프로젝트 매거진 - 악성코드 분석 투트리얼



※ 주의사항

아래 공격 코드는 연구 목적으로 작성된 것이며, 허가 받지 않은 공간에서는 테스트를 절대 금지합니다.

악의 적인 목적으로 이용할 시 발생할 수 있는 법적 책임은 자신한테 있습니다. 이는 해당 글을 열람할 때 동의하였다는 것을 의미합니다.


이 문서는 http://fumalwareanalysis.blogspot.kr/p/malware-analysis-tutorials-reverse.html 문서 기반으로 번역을 하며, 실습하면서 다시 정리한 것입니다. 보안프로젝트 풋내기님이 진행하신 프로젝트입니다.


2. 링3 디버깅

 

학습목표

1. 이뮤니티 디버거와 같은 링3 디버거 효율적 습득

2. 프로그램 실행 제어(step in/over, 브레이크포인트)

3. 프로그램 상태 변화/감시(레지스터, 메모리)

4. 이뮤니티 디버거의 주석

 

관련분야

1. 컴퓨터 구조

2. 운영체제

3. 이산 수학

 

1. 개요

악성코드를 분석하려면 좋은 디버거가 필요하다. 디버거의 종류는 두 가지가 있는데, 사용자 수준 디버거(OllyDBG, Immunity Debugger, IDA Pro 등)와커널 수준 디버거(WinDBG, SoftICE, Syser)다. 사용자 수준 디버거와 커널 수준 디버거의 차이점은 커널 수준 디버거는 더 높은 특권을 가지고 실행돼 커널 장치 드라이버와 장치를 디버깅할 수 있지만 사용자 수준 디버거는 제한된다. 윈도우는 보호 도메인 계층 모음을 제공하는 프로세서(예, 인텔 CPU)에 의존하는 운영체제로 알려져 있다. 예를 들어, 인텔 CPU 상에서 프로그램은 4가지 모드(링0(커널 모드)에서 링3(사용자 수준)까지)로 실행된다. 이런 이유로 사용자 수준 디버거를 "링3 디버거"라 부르기도 한다.


 “링3 디버거 보다 링0 디버거가 더 강력한데 왜 링0 디버거를 사용하지 않지?”라는 의문을 가질 수 있다. 하지만 세상엔 항상 공짜는 없다. 링3 디버거는 보통 분석가의 생산성을 매우 개선하는 훌륭한 GUI를 가지고있다. 꼭 필요할 때만 링0 디버거(WinDBG 같은)의 명령어라인을 사용한다. 최근에 예외가 하나 있는데 - IDA Pro는 커널 디버깅에 WinDBG를 이용한 GUI 모듈을 공개했다. 좋은 기능이지만 사용하려면 비용을 지불해야 한다.

이 튜토리얼에서는 오픈 소스나 무료 소프트웨어 도구를 사용한다. 튜토리얼 전반에 걸쳐 이뮤니티디버거와 WinDBG를 조합해서 사용한다.


1.1. 이뮤니티 디버거 간단히 둘러보기

이제 이뮤니티 디버거를 간단히 소개한다. 가상 머신 테스트 환경을 구성하지 않았다면, 첫 튜토리얼 "악성코드 분석 튜토리얼 #1 – 리버스 엔지니어링 방법(강의 1: 가상머신 기반 분석 환경)"을 확인해 실습 환경을 구성하기 바란다.


그림 1. 이뮤니티 디버거 스크린샷


그림 1에 보이는 대로 이뮤니티 디버거는 왼쪽 위에서 시계 방향으로 CPU창(기계어와 사용자 주석이 보이는), 레지스터 창(레지스터의 값을 확인하거나 변경하는), 스택 창 그리고 메모리 덤프가 있다. Max++를 분석하기 전에디버거 단축키를 어떻게 효율적으로 사용하는지 배워두면 유용하다.


디버거를 효율적으로 사용하려면 다음을 기억해야 한다.

1. 실행 흐름은 어떻게 제어하는가?

- F8(Step over),F7(Step in), F9(Run), Shift+F9(continue and intercept exceptions)

2. 데이터는 어떻게 확인하는가?

- 메모리 창 우클릭 → Binary→ Edit, 레지스터 창 우클릭 → Modify

3. 브레이크포인트는 어떻게 설정하는가?

- F2(소프트웨어 브레이크포인트),F4 – 커서까지 실행, 명령어 우 클릭 → Breakpoint→ Hardware, on execution


4. 주석

위에 대부분은 이뮤니티디 디버거 [Debug] 메뉴에서 찾을 수 있지만 항상 단축키를 기억하는 게 좋다. 이제 분석에 유용한 기능을 간단히 설명한다.


2.1 실행 흐름 제어

‘step over’와 ‘step in’의차이점은 다른 모든 디버거들과 같다. ‘step in(F7)’은 CALL명령어의 함수 내부로 진입한다. ‘step over(F8)’은 전체 함수를 실행한 다음 명령어에서 멈춘다. F8은 항상 원하는 결과를 얻을 수는 없다. - 많은 악성코드들은 안티 디버깅을 이용하고 프로그램의 제어 흐름을 변경하는(그리고 실행이 다음 명령어를 절대실행하지 않는) 복귀 기반 프로그래밍(Return-orientedProgramming)을 사용한다. Max++에서 이런 사례들을 보여준다.

F9(Run)는 보통 브레이크 포인트까지 실행하는데 사용한다. 디버거는 사용자를 위해 자동으로 많은 예외를 처리한다. 모든 예외를 가로채려면 ‘SHIFT+F9’를사용해야 한다. 나중에 Max++가 디버거의 존재를 감지하려고 SEH(Structured Exception Handler)를 다시 쓰는 사례를 볼 수 있다. 이런 안티 디버깅 트릭을 피하려면 직접 SEH 코드를 검사하기 위해‘SHIFT+F9’를 사용해야 한다.


2.2 데이터 조작

보통 데이터를 관리하는 세 가지 유형은 레지스터와 스택그리고 세그먼트(코드, 데이터, 그리고 힙)다.

레지스터의 값을 변경하려면 레지스터를 우클릭하고 ‘Edit’를 선택한다.  레지스터가 메모리 포인터(메모리슬롯의 주소)를 가질 때는 레지스터를 우클릭해 'Follow in Dump’ 또는 ‘Follow in Stack’을 선택한다.

이뮤니티 디버거는 레지스터 창에서 EIP 레지스터의 값을 변경할 수 없다. 그러나 "Python ShellWindow"를 이용해 EIP를 변경할 수 있다. EIP 레지스터를 어떻게 변경하는지는 과제로 남긴다.

메모리 덤프 창에서, 아무 데이터나 선택해 우클릭한 다음 "Binary→ Edit"를 선택한다. 편리하게 데이터를 입력할 수 있다(문자열이나 이진 값 중 아무거나).

데이터처럼 코드도 재설정 할 수 있다. CPU 창에서 우클릭하고 "Assemble"을 선택하면 어셈블리 명령어를 입력해 코드 세그먼트를 직접 변경할 수 있다. 이 훌륭한 기능을 이용해 프로그램도 변경할 수 있다. 예를 들어, 코드 세그먼트를 변경한 뒤 다음 방법을사용해 변경된 프로그램을 저장할 수 있다.

(1) CPU창 우클릭

(2) Copy to executable → All modifications

(3) 창 닫기

(4) 파일을 저장할지(save the file) 묻는 팝업 창이 뜨면‘Yes’ 선택, 새로운 이름으로 파일 저장


2.3 브레이크포인트

소프트웨어 브레이크포인트(F2)는 가장 많이 사용하는 브레이크포인트다. 이 브레이크포인트는 고급 언어의 디버거에서 이용 가능한 브레이크포인트와 같다. 소프트웨어 브레이크포인트는 제한이 없고 소프트웨어 브레이크포인트에 조건을 설정할 수도 있다(예를 들어, 브레이크포인트로 레지스터 값이 특정 조건과 같을 때 프로그램이 멈추게 할 수 있다).


소프트웨어 브레이크포인트는 “INT 3” 명령어를 사용해서 실행된다. 기본적으로 한 위치에 브레이크포인트를 설정할 때마다 디버거는 명령어의 첫 1 바이트를 INT 3(1 바이트명령어)로 변경하고 원래 명령어 1 바이트를 저장한다. 프로그램이 그 위치에서 실행될 때마다 인터럽트가 발생하고 그 예외를 처리하는 디버거가 호출된다. 그래서 디버거는 그 브레이크포인트 상태를 확인하고 프로그램을 멈출 수 있다.


하드웨어 브레이크포인트는 CPU 창에서 ‘우클릭 → Breakpoints → Hardware,on execution’으로 설정한다. 두가지 유형의 하드웨어 브레이크포인트가 있다(memoryread, memory access). 이름 그대로하드웨어 브레이크포인트는 하드웨어를 이용한다. 인텔 CPU 상에는 하드웨어 브레이크포인트 위치를 기록하는 4 개의 하드웨어 브레이크포인트 레지스터가 있다. 이는 언제라도 최대 4개의 하드웨어 브레이크포인트를 설정할 수 있다는의미다.


하드웨어 브레이크포인트는 코드의 어느 부분이 변수를 변경하는지 알 필요가 있을 때 매우 유용하다. 변수에 ‘Memory, on access’ 브레이크포인트를 설정하면 그 변수를 변경하는 코드를 찾으려고 전체 소스 코드를 조사할 필요가 없다.


2.4 사용자 주석

사소하게 보이는 사용자 코멘트와 주석은 분석하는 동안 가장 중요한 기능 중 하나다. CPU 창에서 ";" 키를 누르면 기계어에 주석을 추가할 수 있다. 그리고 ":" 키를 누르면 그 위치에 라벨을 설정할 수 있다. 나중에이 위치를 변수나 함수가 참조할 때 해당 라벨로 표시된다. 이 기능은 분석과정을 매우 쉽게 만들어 준다.


3. 오늘의 문제

소매를 걷고 지금까지 배운 모든 걸 실습하자. 오늘의 목표는 0x413BC8부터 0x413BD8까지 코를 분석하는 것이다. 아래 질문에 답하라. 주석에 이 문제들에 대한 해결책이 있다.

 

Q1. 0x413BD5에 EAX의 값은 무엇인가?(INT 2D가 실행되기 전)

Q2. 0X413BD7에 "RET"명령어는 실행되는가?

Q3. EAX의 값을 0으로 변경하면, Q2와 어떤 차이가 있는가?

Q4. 0x413BD5에 EIP의 값을 변경해 INT 2D 명령어를 건너 뛸 수 있는가?

Q5. 0x413BD5에 INT 2D 명령어를 "NOP"로 변경하고 파일을 "max2.exe"로저장해라. max2.exe를 실행한다. 악성코드의 동작의차이점이 있는가? (네트워크 트래픽을 보려면 '튜토리얼 #1'을 참조해라.).

매거진의 이전글 리버스 엔지니어링 방법(제 1부: 가상머신 분석 환경)
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari