본문 바로가기

리버싱/x64dbg 디버거를 활용한 리버싱과 시스템 해킹의 원리

ch07 - 파일 패킹과 언패킹

728x90

01 PE 파일 패킹(packing)

02 PE 파일 언패킹(unpacking)

03 수동 언패킹(manual unpacking)

 

ch07 - 파일 패킹과 언패킹

패커(packer) : PE 파일을 실행 가능한 형태로 파일을 압축시켜주는 프로그램으로 압축과 동시에  보호(anti-debugging, encryption 등) 기능을 포함하고 있으면 프로텍터(protector)라고 부르고 단순히 파일의 사이즈만 줄여준다면 그냥 패커(UPX, Aspack)라고 부른다.

프로텍터는 리버싱으로부터 보호하기 위한 것으로 압축 해제 기능뿐만 아니라 안티 리버싱 기법이 적용된 것을 말하며 기법으로는 안티 디버깅(anti-debugging), 가상 머신 탐지(anti-vm), 코드 난독화(code obfuscating), 다형성 코드(polymorphic code), 더미 코드(garbage code), 디버거 탐지(debugger detection) 등의 기법이 있다.

 

 - 기존에는 용량 때문에 단순 패킹을 했지만 최근 악성코드들은 컴퓨터에서 어떤일을 수행하는지 모르게 활동해야 할 필요가 있어 악성코드들은 분석가들이 자신을 분석하기 어렵게 대부분 패킹 기술이 적용되어 있다.

 

01 - PE 파일 패킹(packing)

 - 윈도우 PE 파일은 그 구조에서 정형화된 형식을 벗어날 수 있도록 허용하고 있는데 다음과 같은 다양한 PE 파일을 생성할 수 있다.

 

 1.1 패커의 주요 기능

 - 실행 압축 기능은 실행하기 전에는 압축된 형태로 존재하고, 실행하는 도중에 이 부분의 압축을 해제하고 실행한다. 패커는 실행 파일의 코드 부분을 압축하고, 이 부분의 압축을 해제하는 코드를 추가한다.

그리고 실행 시작 위치(EP, Entry Point)를 이 추가된 코드로 변경한 파일을 실행 압축 파일이라 한다.

 

 - 프로텍터가 주로 사용되는 곳

  • 온라인 게임을 설치할 때 자동으로 설치되는 프로그램으로 게임 해킹 툴의 실행을 방지
  • 악성코드에서 백신의 분석을 방해할 목적으로 포함
  • 소프트웨어 제품에 대하여 주요 기능의 분석과 인증 과정을 숨긴다.

 

 1.2 패커 종류

 - 인터넷상에 유포된 패커는 굉장히 많은데 가장 잘 알려진 것으로는 UPX, Aspack이 있다.

UPX(Ultimate Packer for Executables)  - 오픈 소스로 압축을 목적으로 만들어짐

https://upx.github.io/

Aspack - 단순 암호화를 제공하는 목적으로 만들어짐

http://aspack.com/

 

 1.3 UPX 패커

 - upx 실행 압축 명령

 upx.exe -o packed_file.exe original_file.exe

original_file을 패킹하여 packed_file.exe로 저장한다. 파일크기도 줄었고 원래 파일과 같은 동작을 수행한다.

 

 

 - UPX 패킹의 구조

코드 섹션(.text)데이터 섹션(. data)이 패킹되고, 섹션 이름이 변경된다. 코드 섹션은 실행 압축되어 UPX0으로 저장되고, 이 섹션을 언패킹하기 위한 루틴은 UPX1 섹션에 작성되어 있다. 그리고 패킹된 파일의 EP는 UPX1 섹션으로 변경된다.

-> 원래 여러 개의 섹션이 존재하던 파일이 패킹 후에 3개의 섹션으로 구성됐다. 그리고 섹션의 권한(characteristics)이 바뀌었다.

 

 1.4 패킹의 증상

 - 실행파일이 다음과 같은 증상이 보일 때 패킹되었을 확률이 높다.

 

#패킹의 증상

  • 섹션 Name이 일반적이지 않거나 패커의 이름을 가진다.
  • 패킹된 데이터가 언패킹 되면서 저장되어야 하는 섹션이 필요하므로, 비어있는 섹션(RawSize == 0)이 있거나, (VIrtualSize - RawSize)가 지나치게 큰 섹션이 존재한다.
  • EP가 가리키는 섹션이 코드 섹션으로 실행 권한(MEM_EXECUTE)을 가지는데, 다른 섹션에 실행 권한이 있다.
  • EP가 가리키는 코드 섹션이 일반적으로 첫 번째 섹션인 경우가 많지만, 첫 번째 섹션이 아니다.
  • 언패킹에 주로 사용되는 API가 많이 사용되었다.
  • 파일 상에 존재하는 문자열(STRING)과 메모리에서 실행 상태의 문자열(string)에 차이가 많이 난다.

 

#EP가 가리키는 섹션이 코드 섹션으로 실행 권한(MEM_EXECUTE)을 가지는데, 다른 섹션에 실행 권한이 있다.

 -> 각각 UPX와 aspack으로 패킹한 것을 볼 수 있다.

 

 - 다음은 실행권한으로 오른쪽 클릭하고 section flags를 들어가면 볼 수 있다.

 

 

#언패킹에 주로 사용되는 API가 많이 사용

 - Import Directory에 kernel32.dll을 보면 패킹에 관련된 API가 나온다.

 

 

 1.5 패커 시그니처 탐지

#패커 시그니처 

- 패커는 특정 알고리즘과 코드가 수행돼서 일정한 시그니처를 가진다. 이를 기반으로 패커를 쉽게 탐지 가능하고 탐지만 되면 언패킹 도구를 사용하여 언패킹을 수행할 수 있다.

http://www.openrce.org/articles/

위의 사이트는 안티 디버깅 여부, 패커 전달 명령 코드, EP에 대한 시그니처 정보, 언패커 정보를 제공한다.

  • UPX 패커 정보

-xdbg에서 OEP(entry point)에 해당

 

 

-xdbg에서 보면 다음 부분에 해당한다.

 

  • ASpack 패커 정보

 

#엔트로피(entropy) 기반 패킹 탐지

 - 시그니처 기반 언패킹은 시그니처가 변경되었을 때 언패킹을 수행할 수없고 기존의 도구로 기존의 시그니처 값을 변조해서 쉽게 우회가 가능하다.

이때 정보 엔트로피 기반으로 패킹 여부를파악할 수 있다.

정보 엔트로피 : 정보의 양을 수치화하여 공식을 만들어 정의한것으로 일반적으로 메시지의 압축에 관한 분야에 대해서 연구할 때 많이 사용한다.

ex) 압축 알고리즘의 압축률을 평가할 때 유용하게 사용, 엔트로피가 높은 데이터일수록 나타날 수 있는 모든 비트들이 골골 존재함을 의미하기 때문에 어떤 압축 파일의 엔트로피 수치가 높을수록 압축률이 높다고 할 수 있다.

 

# 패커 탐지 도구인 DIE(Detect It Easy)로 패커를 탐지

 : 패킹 여부를 판단하는 데 도움을 주는 도구

 

02 - PE 파일 언패킹(unpacking)

언패킹 : 패킹된 실행 파일을 패킹하기 전 상태로 되돌리는 것이다. 실행 압축된 프로그램은 실행되어 언패킹 코드가 먼저 수행된다. 언패킹 과정을 통해서 패킹되기 전의 상태를 복원하고, EP를 실제 실행할 위치 OEP(Original Entry Point)로 옮겨준다.

 

 2.1 언패킹의 목표

 - 언패킹을 수행하기 위해서는 패킹된 실행 파일에서 언패킹을 수행하는 코드를 추출할 필요가 있다. 언패킹 코드는 대부분 반복 작업을 수행하는 루프 형태의 코드가 많다. 그러나 일부만 언패킹하고 실행한 다음 다시 일부 코드를 언패킹하는 과정을 반복하도록 만들 수도 있어 수동 언패킹을 이해할 필요가 있다.

 

 2.2 언패킹 방법

자동 - 도구로 PEiD, PE Explorer등이 있다.

수동 - 디버거나 스크립트를 사용하는 방법

  • 먼저 디버거를 사용하여 OEP를 찾고 해당 영역의 메모리를 덤프 하여 저장한 후에 파일을 재구성
  • 그리고 OEP를 찾기 위해 디버거를 사용하여 언패킹 과정을 분석 후 디버거 스크립트를 작성
  • 수동 언패킹 과정에서는 IAT 복구와 EP 재설정과 같은 작업이 동반된다.

 

#UPX로 패킹된 PE 파일을 언패킹하는 과정

upx.exe -d -o unpacked_file.exe packed_file.exe

 - 패킹된 packed_file 파일을 언패킹하여 unpacked_file로 저장

 - 디버거를 이용하여 실행할 경우 UPX1 섹셔네서 코드가 실행되는 동안에 UPX0 섹션의 코드가 변경되고 있음을 확인

 - 언패킹 루틴이 완료된 후, UPX1 섹션에 저장되어 있는 윈도우 API 문자열을 이용해 IAT를 복구하고 OEP로 이동된다.

 

위 파일 대신 abexcm1.exe와 abexcm1_upx.exe 사용

 - 패킹

 

 - 언패킹

 

 2.3 도구를 이용한 자동 언패킹

  • PE Explorer 활용

상용 도구로서 기본적으로 nsPack, Upack, UPX 패커에 대한 언패킹 플러그인을 제공하고 있다.

 

 -자동으로 언패킹된 것 확인

 

- tools의 plugin manager를 들어가면 언팩 할 수 있는 플러그인이 있다.

 

  • CFF Explorer 활용

-> UPX Utility에서 unpacked 하고 저장해주면 된다.

 

 

03 - 수동 언패킹(manual unpacking)

 - 디버거를 사용하여 OEP를 찾아가는 과정을 수행하는데 옵션에서 소스 디버깅 활성화를 해주면 찾아가기 편하다.

 

 3.1 UPX 패커의 언패킹 과정 디버깅

 - UPX0, UPX1, UPX2 섹션으로 구성되어 있다.

패킹의 증상에서 Virtualsize와 Raw size를 보면 크게 차이가 난다.

  • 패킹된 데이터가 언패킹 되면서 저장되어야 하는 섹션이 필요하므로, 비어있는 섹션(RawSize == 0)이 있거나, (VIrtualSize - RawSize)가 지나치게 큰 섹션이 존재한다.

 -> UPX0 섹션은 Raw_size가 0이지만, Virtual_Size 가 0x6000으로 되어있다. 이것은 파일의 섹션 크기는 0이지만 메모리로 적재하면 0x6000까지 커진다는 말로 이 공간에 언패킹 된 코드가 저장된다.

 

 - Characteristics 값 맨 앞에 E가 있으면 실행 가능한 권한을 가진다.(언패킹 수행섹션에서 언패킹 후에 코드가 저장되는 섹션에는 실행 권한이 필요하기 때문)

  • 읽기(0x4)^쓰기(0x8)^실행(0x2) = 0xE

 - EP는 UPX1에 있으며 UPX1의 코드가 실행되는 동안에 UPX0 섹션에 코드를 저장한다.

 

#언패킹 루틴

언패킹 루틴은 일반적으로 현재 상태의 레지스터 값을 저장한 후에 수행되고 언패킹 과정이 모두 끝나면 저장된 레지스터 값을 복구한다.

이때 나타나는 코드는 PUSHAD와 POPAD이다.

PUSHAD는 모든 레지스터를 스텍에 저장하는 명령, POPAD는 스택에 저장된 레지스터 값을 복원하는 명령으로

이 코드를 찾으면 언패킹 루틴을 찾을 수 있다.

즉, pushad와 popad가 시작과 끝의 명령어니 이 명령어들을 찾으면 쉽게 찾을 수 있다.

 

 - 다음은 UPX의 경우 레지스터 상태 보관 과정과 레지스터 복원 코드다

 

 - 루틴이 수행되면, 빈 섹션에 원본 코드를 복원하거나, 특정 세션의 값을 변경한다. 이러한 언패킹 과정이 완료되면 원본 코드가 복원되고, 이 코드로 EP를 옮기면 원본 코드가 수행될 수 있다.

언패킹 과정이 완료된 코드 섹션을 복사하고, IAT를 복구하면 원본 코드와 같은 동작을 수행시킬 수 있게 된다.

UPX1섹션에 있던 Windows API 문자열을 이용하여 IAT를 재구성할 수 있다. 이과정이 끝나면 새로운 섹션의 oep로 이동할 수 있다.

 

 

 - 디버거 하기전에 윈도우에서 악성코드인 줄 알고 막기 때문에 실시간 보호를 꺼야 원활한 진행이 된다.

 

 

#디버거로 확인하는 과정

 

 - 원래 프로그램을 실행했을 때 메시지 박스

 

 - 원본 프로그램인 abexcm1를 UPX로 패킹했을 때

 

 

 

  •  코드 섹션에 접근하는 상황 확인(pushad, popad)

패킹된 프로그램은 EP에 "pushad" 명령어가 있는데, 이것은 모든 레지스터를 스택에 저장하는 명령이다.

UPX의 경우 진입점(EP)에 바로 pushad코드가 나타나서 언패킹 루틴의 시작 지점이다.

압축 해제하는 부분으로 EP가 있다.

 

 - popad는 현재 모듈 -> 명령어 찾기 -> 현재 모듈 -> popad를 쓰면 찾을 수 있다.

 

 - pushad에서 실행 했을 때 popad로 넘어가지 않는데 값이 어떻게 들어가는지 확인해보자

 

 - 메모리 맵에 보면 00401000이 있는데 메모리 중단점을 정해주면 값들이 하나씩 어떻게 들어오는지 볼 수 있다.

 

 - 오른쪽 레지스트리에서 EDI에 00401000이 들어갔고 EDI는 목적지 주소를 저장하기 때문에 덤프 해서 따라가면 값들이 반복을 통해서 하나씩 들어간다.

 

  • 언패킹(Scylla와 ImportREC 사용)

 - 이제 언패킹을 실행하기 위해서 Scylla를 클릭(플러그인 안에 있다)해서 덤프 및 IAT 테이블 복구를 진행

 

 

 - IAT AutoSearch를 클릭하면 현재까지 값들을 덤프한다.

 

 - 이 값을 dump를 통해서 저장해서 열면 오류가 나오는데 IAT 테이블이 없어서 그렇다.

 

 - ImportREC 프로그램은 현재 실행 중인 액티브 프로세스에 대한 IAT만 복원시켜준다. 

실행중인 프로그램들 카카오, anysign..등등

 

 - dump를 실행시킨 상태(오류가 난 상태)에서 확인을 누르지 않고 import를 돌리면 맨 위에 뜬다.

 

import파일 밑부분에 보면 다음과 같은 파일들이 필요하다.

 

 - scylla의 OEP 값을 import에 RVA값에 넣어주고 IAT Autosearch 클릭

 

 - 주소를 찾았다는 메시지

 

 - 그리고 Getimport를 클릭하면 valid로 됐다고 나온다.

 

 - Fixed dump 버튼을 클릭해서 아까 IAT 테이블이 없어서 실행이 안되었던 프로그램 하위에 실행되는 새로운 파일이 만들어진다.(이제 실행 오류난 메시지 박스는 꺼도 된다)

 

 - 프로그램을 실행해보면 원래대로 메시지 박스가 뜨는 것을 확인[언패킹 완료]