본문 바로가기

2. Reversing (리버싱)/1) Write UP

[2022.11.26]R4 활동보고

일시: 2022.11.26

팀원: 엄설인, 유예지, 이유빈, 정현수

 

내용: 리버싱 입문 05. 리버싱의 어려운 문제들 개념 정리

 

1. 패킹과 언패킹

1.1 패킹과 언패킹의 개요

- 패킹(Packing)이란?

프로그램 코드 크기를 줄이려고 압축하거나 프로그램 분석을 어렵게 만들려고 암호화하는 것. 단순 압축하는 것은 컴프레싱(Compressing), 암호화하는 것은 프로텍팅(Protecting)

- 컴프레싱은 초기에 프로그램을 만들었을 때 메모리와 하드디스크 용량이 작았기에 프로그램 크기를 줄여야하는 상황에 등장한 기술이다. 실행 코드를 압축해서 PE 파일의 특정 섹션에 저장하고 프로그램이 실행될 때 공간에 압축을 풀어 실행하는 구조이다.

- 프로텍팅은 실행 파일을 암호화해서 분석을 어렵게 만드는 기술이다. 실행 코드는 암호화된 상태로 배포되고, 실행 시점에 복호화되어 동작을 수행한다. 약간의 속도 저하가 발생하지만, 비밀 보호가 중요한 프로그램이나 악성코드 같은 경우는 다양한 방식의 프로텍팅 기술이 적용된다.

 

패킹된 실행 파일을 살펴보자. 대표적인 오픈소스 패킹 도구인 UPX 기반으로 살펴본다.

UPX로 패킹된 파일은 데이터 영역, 언패킹된 데이터가 저장될 빈 공간으로 구성된다.

     1) 운영체제의 로더(Loader)가 실행 파일을 메모리에 로딩하고 나면

     2) 진입점(엔트리 포인트)로부터 프로그램이 실행된다. 패킹된 파일의 진입점은 언패킹 코드 영역에 들어가 있다.

     3) 언패킹 코드는 패킹된 데이터를 하나씩 읽어 압축을 풀고 공간에 원본 데이터를 저장한다.

모든 코드가 언패킹되면 원 진입점(Original Entry Point)에서부터 프로그램이 다시 시작된다.

 

1.2 패킹 도구

UPX(Ultimate Packer for Executables): 현재 가장 많이 사용하는 실행 압축 프로그램. 여러 운영체제에서 다양한 파일 형식을 지원하도록 오픈 소스 형태로 제공된다. 특히, OllyDbgUPX 언패킹 도구나 내장되어 있어 쉽게 MUP(Manual Unpacking)할 수 있다.

ASPack: 상용 프로그램으로ㅆ 지속적인 프로그램 개발이 이루어지는 고성능 컴프레서이다. 빠른 복호화 루틴을 통해 높은 성능을 제공하고 있다. 32비트 윈도우 프로그램에서는 70% 이상의 압축 효율을 보여준다.

Themida: 상용 프로텍터, 적용된 옵션마다 언패킹 방법이 다르기 때문에 풀기가 어려운 강력한 프로텍터 중 하나. 많은 악성코드가 Themida를 사용해서 프로텍팅되어 있으며, 국내에서 사용되는 많은 보안 프로그램과 게임들이 실행 파일을 리버싱으로부터 보호하기 위해 사용한다.

ASProtect: UPX와 유사하게 패킹된 코드를 특정 영역에 집어넣고 실행 시간에 언패킹해서 사용하는 방식이다. 가상 머신을 제공하는 Themida에 비해 상대적으로 수동으로 언패킹(MUP,Manual Unpacking)하기 쉬운 단점이 있다.

 

2. 대표적인 패커 UPX

2.1 UPX 개요

UPX(Ultimate Packer for Exetable)는 오픈 소스 실행 압축 파일이다. 압축과 해제에 효율적인 알고리즘을 제공하고 있으며 압축 효율도 높다. UPX로 압축된 파일을 실행하면 원본 코드를 읽기 전에 먼저 압축을 해제해야 하는데, 이러한 과정을 매우 효율적으로 처리하여 메모리 부하가 매우 낮은 편이다.

홈페이지(http://upx.sourceforge.net/)에 접속해서 UPX를 내려받는다. Windows일 경우 upx-4.0.1-win64.zip을 내려받아야 한다.

2.4 언패킹과 OEP

  엔트리 포인트(Entry Point)는 프로그램에 대한 제어권이 운영체제에서 사용자 코드로 넘어가는 지점이다. 다시 말해, 프로세서(Processor)가 메모리에 있는 코드 섹션으로 처음으로 들어가는 지점. C 언어에서 main() 함수라고 생각하면 이해하기 쉽다. 엔트리 포인트의 위치는 PE 헤더에 있는 AdressOfEntryPoint에 저장되어 있다. 이 위치는 상대 주소이기 때문에 역시 PE 헤더에 있는 ImageBase 값과 합산된 메모리 주소가 프로세서가 인식하는 진짜 엔트리 포인트의 주소이다.

  힘들게 프로그램 코드를 분석하면서 언패킹하는 이유는 메모리 덤프(메모리에 저장된 상태를 그대로 파일을 저장)를 떠서 실행 파일로 저장하면 언패킹된게 아닌가 하지만, 중요한 건 패킹되기 이전 프로그램의 실제 엔트리 포인트를 찾아야한다는 것이다. 메모리 덤프를 파일로 저장했을 때 PE 헤어데 있는 엔트리 포인트 값을 실제 엔트리 포인트 주소로 수정해줘야 프로그램이 정상적으로 동작한다.

  리버싱할 때 자주 언급되는 OEP(Original Entry Point)가 바로 패킹되기 이전 프로그램의 실제 엔트리 포인트다. 언패킹할 때 가장 중요한 것 중 하나가 바로 정확한 OEP를 어떻게 찾느냐이다.

2.6 IAT 복구

윈도우 응용 프로그램은 DLL 형태의 시스템 라이브러리를 사용하는데, 프로그램이 실행되면서 필요할 때 DLL을 불러와서 사용한다. 어떤 DLL에서 어떤 함수를 참조하는지에 대한 정보가 PE 헤더의 IAT에 저장되어 있다. 메모리 덤프하는 과정에서 IAT 테이블은 쉽게 손상되기에 복구 과정이 필요하다.

원래의 실행 파일에 저장된 IAT(Import Address Table) 정보를 새로운 파일에 알맞게 갱신해줘야 한다.

 

3. 매뉴얼 언패킹 사례

3.1 ESP 레지스터를 활용한 OEP 찾기

매뉴얼 언패킹(MUP:Manual Unpacking)의 핵심은 OEP(Original Entry Point)를 찾는 것이다. OEP를 찾는 데에는 정답은 없다. 다양한 패킹 도구와 기술이 있으며 어떤 기술을 사용해서 패킹 되었는가에 따라 OEP를 찾는 방법도 다양해진다. OEP를 찾는 대표적인 방법 중 하나에는 ESP 레지스터를 이용하는 방법이 있다.

 EBP 레지스터 값을 복구하는 방법은 원래 EBP 레지스터 값(원본)을 스택에 넣어두고 사용될 EBP 레지스터에 스택에 저장된 원본을 가리키는 주소를 저장하는 것이다. 이 과정에 사용되는 것이 ESP 레지스터이다.

 서브루틴이 언패킹하는 로직이라고 생각해보자. 서브루틴에 들어가기 전 ESP 레지스터에 저장된 주소가 가리키는 값은 현재 루틴의 EBP 레지스터의 값이며, 언패킹 로직이 종료되고 현재 루틴으로 복귀될 때 다시 ESP 레지스터가 가리키는 값을 읽는다. 따라서 이 값을 읽는 동작에 브레이크 포인트를 성정하면 언패킹 로직이 종료되는 시점을 파악할 수 있다.

3.2 하드웨어 브레이크포인트

OllyDbg에서 많이 사용하는 브레이크포인트에는 소프트웨어 브레이크포인트와 하드웨어 브레이크포인트가 있다. 소프트웨어 브레이크포인트는 OllyDbg에서 <F2> 키를 눌러 설정하는 가장 일반적인 브레이크포인트로서, 개수에 제한 없이 필요한 만큼 만들어서 쓸 수 있다. 하드웨어 브레이크포인트는 프로세서(Processor)에서 제공하는 특정 영역에 브레이크포인트에 대한 주소를 기록하는 방식이다. 하드웨어 브레이크포인트의 장점은 명령어뿐만 아니라 메모리에도 브레이크포인트 설정이 가능하다는 것이다. , 프로세스에 의해 직접 실행되는 명령어 뿐만 아니라, 실행되지 않는 메모리에 저장된 데이터에 브레이크포인트를 설정할 수 있다.

 

4. 코드 인젝션

4.1 코드 인젝션의 개요

코드 인젝션 기술은 PE 파일의 빈 공간에 셸코드를 입력해서 실행하게 만드는 해킹 기술이다. 셸코드(Shellcode)란 기계어로 만들어진 크기가 작은 코드로, 운영체제의 명령 셸을 이용해서 공격자가 원하는 동작을 수행하기 위해 사용된다.

코드 인젝션의 동작 방법은 다음과 같다.

인젝션할 코드는 크기가 보통 100바이트를 넘어가기 때문에 하나의 명령어를 대체해서는 프로그램에 입력할 수 없다. 따라서 사용하지 않는 공간에 셸코드를 입력하고

1) 하나의 명령어를 선택해서 셸코드가 있는 영역을 점프하는 코드로 바꿔치기한다. 그리고 원래 명령어는 셸코드 영역의 맨 위에 넣어준다. 그리고 프로그램을 실행하면 Instruction A->InstructionB->Jump code A->Instruction C->Shell code->Jump code B->Instruction D 순서대로 명령이 실행된다. Shell 코드 영역에 해킹 코드를 입력하면 해커가 의도하는 동작을 수행할 수 있다. 셸코드는 실행 가능한 메모리 영역에 집어넣어야 한다. 코드를 어디에 넣으면 실행할 수 있는지는 메모리 맵 메뉴에서 확인 가능하다.

코드 인젝션 기술은 쉽게 구현할 수 있기 때문에 많이 활용되는 해킹 기술이다. 인터넷에서 프로그램을 내려받을 때 설치되는 바로 가기 아이콘이나 브라우저에 설치되는 툴바와 같은 것들이 이런 해킹 기술을 응용해서 개발된다.