발자취

악성코드 01. 악성 윈도우즈 프로그램 분석 본문

3-2/악성코드

악성코드 01. 악성 윈도우즈 프로그램 분석

해린 2023. 9. 18. 16:01

악성 윈도우즈 프로그램이 어떤 식으로 동작하는지에 대해 학습해보았다.

 

1. Windows API

1. 개념

- 마이크로소프트 라이브러리를 액세스할 때 사용함

- 악성코드 역시 API를 이용해 마이크로소프트 라이브러리를 액세스함

- Type, Handle, File System Function, Special File들로 구성됨

 

2. 구성

1. Type

- WORD (w): 16비트 unsigned 값 (2바이트)

- DWORD (dw): 32비트 unsigned (4바이트)

   → WORD, DWORD는 시스템마다 조금 다르게 정의하지만 윈도우즈에서는 2바이트, 4바이트로 정의함

- Handle (H): 객체에 대한 참조 (reference)

   → 객체에 대한 주소 (참조 == 주소). 즉, 핸들은 포인트의 개념임

- Long Pointer (LP): 다른 타입에 대한 포인터

   → 진짜 포인터.

- Callback: Windows API에 의해 호출될 함수

   → 함수 안에서 또 다른 함수를 호출할 때 콜백을 사용함. 탐지 실습할 때 많이 사용

 

2. Handle

- 운영체제에서 생성되거나 열린 아이템을 지칭함

   → 여기서 말하는 아이템: window, process, module, menu, file 등

- 일반적으로 객체나 메모리 위치를 참조하지만 산술 연산(덧셈, 뺄셈 등)에는 사용될 수 없음

   → 이 부분이 진짜 포인터와 다른 점! 포인터에서는 덧셈하면 위치를 바꾸는 개념이었음.

- 또한 항상 객체의 주소를 참조하지는 않으며, handle을 저장하여 추후에 같은 객체를 참조하기 위한 함수 호출에 사용됨

 

3. File System 함수

- CreateFile: 기존 파일, 파이프, 스트림, 그리고 I/O 디바이스를 열거나 새로운 파일을 생성할 때 사용됨.

                     dwCreationDisposition 인자가 새로운 파일을 생성하거나 기존 파일을 여는지에 대한 제어를 수행함.

- ReadFile: 파일을 읽을 때 사용

- WriteFile: 파일에 기록할 때 사용

- CreateFileMapping: 파일을 디스크에서 메모리로 로드하는 함수

   → 파일을 디스크에서 메모리로 로드하는 이유? 하나의 실행 파일들이 프로세스가 돼서 메모리에 할당되는데, 그 할당된 메모리 위치에 가져다놓기 위해!

- MapViewOfFile: 파일 mapping의 base 주소에 대한 포인터를 반환하는 함수

   → mapping: 메모리에 있는 파일을 액세스하는데 사용될 수 있음.

   → base 주소: 메모리의 시작 주소

 

4. Special File

- 공유 파일

- Namespace를 통해 액세스 가능한 파일

- Alternate Data Stream

 

 

2. Windows Registry

1. 개념

- 운영체제와 프로그램 설정 정보를 저장하는데 사용

   → 시스템이 부팅될 때마다 레지스트리에 설정된 내용들이 시스템에 적용됨.

- Malware는 persistence를 위해서 registry를 사용

   → 이런 점을 악용해서 특정 행동을 반복하도록 레지스트리에 설정해두면 맬웨어가 매번 그 행동을 하도록 만들 수 있음

- Registry는 5개의 root key들로 분할됨

 

2. Registry Root Keys

- HKEY_LOCAL_MACHINE (HKLM): local 장치에 global한 설정을 저장

- HKEY_CURRENT_USER (HKCU): 현재 사용자에 맞는 설정을 저장

- HKEY_CLASS_ROOT: 타입을 정의하는 정보를 저장

- HKEY_CURRENT_CONFIG: 현재 하드웨어 구성에 관한 설정을 저장

- HKEY_USERS: 기본 사용자, 새로운 사용자, 현재 사용자를 위한 설정 저장

 

3. 공통적인 Registry 함수

Malware는 registry를 수정하기 위해 registry 함수를 사용할 수 있음

- RegOpenKeyEx: 에디팅과 질의를 위해서 regisrty를 open함

- RegSetValueEx: 새로운 값을 regisrty애 추가하고 해당 데이터를 설정함

- RegGetValue: regisrty에서 특정 entry 데이터를 획득함

 

 

3. DLL (Dynamic Link Libraries)

- 정적 라이브러리: 맨 처음에 프로그램 짤 때부터 같이 들어가는 라이브러리

- 동적 라이브러리: 해당 프로그램이 실행될 때 연결돼서 작업을 함 (저장 방면에서 효율적임. 처음부터 메모리를 차지하는 게 아니니까!)

 

1. 다수의 애플리케이션들이 공유하는 동적 라이브러리

- 독립적으로 실행되지 않고 다른 애플리케이션들에 의해 사용되는 함수를 export하는 실행파일

- DLL에 의해 사용되는 메모리: 동작중인 프로세스들에 의해 공유될 수 있음

- DLL을 사용하면 분배되는 소프트웨어 크기를 줄일 수 있음

- DLL은 유용한 code-reuse (코드 재사용) 기법임

 

위 그림과 같이 프로세스1에 A' DLL이라는 이름의 DLL이 존재한다고 가정.

프로세스 2, 3에서 A' DLL을 사용하고 싶으면, 모든 프로세스에 A' DLL을 넣는 것이 아니라, 그 A' DLL이 존재하는 주소만 넣어서 참조함!

   → 공간을 아낄 수 있고, 코드 재사용이 가능해짐!

 

*DLL의 장단점

- 장점: DLL은 필요할 때만 쓰기 때문에 공간을 효율적으로 쓸 수 있음

- 단점: 악성코드 탐지가 어렵게 만듦.

   → 요즘 악성코드를 만들 때, exe는 작게 만들고 필요할 때마다 DLL을 연결해서 쓰는 방식을 사용하기 때문에.. 탐지가 어려움

 

 

2. Malware가 DLL을 사용하는 방법

- 악성코드 저장: DLL에 악성코드 기능을 넣어서 DLL 자체를 악성코드로 만드는 방법

- Windows DLL 사용: 윈도우즈 시스템이 제공하는 DLL

- Third-party DLL 사용: 윈도우즈 시스템이 제공하는게 아니라 제3자가 만든 DLL

   → 실제로 악성코드 자체가 되진 않지만 악성코드를 만드는 한 기능의 일부로서 사용함

       즉, exe 파일이 악성파일이 되고 부가적인 기능을 DLL로 제공하는 방법

 

3. 기본적인 DLL 구조

- PE 파일 포맷 사용

   → PE 파일: exe 실행파일과 DLL의 포맷

- DllMain: 파일의 entry point로써 PE 헤더에 표기됨. (DLL이 실행될 때 무조건 DllMain부터 실행됨)

- 대부분의 DLL은 per-thread 리소스를 갖지 않음

   → 스레드: 실행중인 프로그램. 리소스를 많이 갖지 않는 가벼운 프로세스.

   → DLL은 리소스를 갖기 보다는 독립적인 모듈로서 실행되게 함.

 

 

4. Process

1. 윈도우 운영체제에 의해 실행되는 프로그램

- 프로세스: CPU에 의해 실행되는 한 개 이상의 스레드를 가짐

- 기존 Malware: 자기 자신의 독립적인 독립적인 프로세스를 가짐 (독립적인 프로세스를 통해 모든 실행이 이루어짐)

- 최신의 Malware: 자신의 코드를 다른 프로세스의 일부로써 실행함 (탐지를 회피하기 위해서 하나의 실행파일에 다 넣지 않고, 다른 프로세스에서 실행되도록 함!)

 

2. 새로운 프로세스 생성

- CreateProcess: malware가 새로운 프로세스를 생성할 때 가장 흔하게 사용하는 함수

 

 

5. Thread

가벼운 프로세스! 꼭 필요한 것만 가지고 있는 프로세스.

 

1. CPU에 의해 실행되는 독립적인 명령어들의 sequence

- 다른 스레드들을 기다리지 않음

 

2. Thread Context

- 하나의 스레드가 동작할 때, 해당 스레드는 CPU나 CPU 코어에 대한 완벽한 제어를 가지며, 다른 스레드들은 CPU나 CPU 코어의 상태에 영향을 주지 못함

- 운영체제가 현재 수행중인 스레드를 새로운 스레드로 교체하기 전에, CPU 상의 모든 값들이 스레드 컨텍스트에 저장됨

운영체제가 새로운 스레드의 스레드 컨텍스트를 CPU에 로드하고 새로운 스레드를 실행함

- CreateThread: 새로운 스레드를 생성하는데 사용되는 함수

 

6. Service

서비스를 설치하면 백그라운드에서 실행됨 (예: 안티 바이러스)

이런 점 때문에 백그라운드에서 돈다는 건 사용자가 들여다보지 않으면 잘 모름.

이런 점을 악용해서 백그라운드에서 돌아가고 있는 애플리케이션이 좋은 기능인지 악성코드인지 사용자가 모르게 할 수 있음.

   → 서비스를 사용하는 것은 악성코드 제작자에게 매력적이다!

 

1. Malware가 추가적인 코드들을 실행하는 방법

- 추가적인 코드들을 service로 설치함

- 태스크가 백그라운드 애플리케이션으로 수행될 수 있게 만듦.

- 사용자 입력 없이 코드가 윈도우즈 서비스 매니저에 의해 스케줄 되고 수행됨

 

2. Malware 작성자에게 Service를 사용하는 장점

- Service는 일반적으로 SYSTEM 또는 다른 특별한 권한이 있는 계정으로 동작함

- Service는 지속성을 유지하는 방법을 제공함

 

3. Service를 설치하고 제어하는데 사용되는 API 함수

- OpenSCManager, CreateService, StartService

 

 

7. Component Object Model (COM)

1. 서로 다른 소프트웨어 컴포넌트들이 서로 호출하는 것을 가능하게 만든 표준 인터페이스

- 다른 소프트웨어 컴포넌트들에 대한 구체적인 지식 없이 가능함

- 어떠한 프로그래밍 언어와도 같이 동작함

- 모든 프로그램에 의해 활용될 수 있는 재사용 가능한 소프트웨어 컴포넌트를 지원하도록 설계됨

 

2. 클라이언트/서버 프레임워크로 구현됨

- 클라이언트: COM 객체를 사용하는 프로그램

- 서버: 재사용 가능한 소프트웨어 컴포넌트 (COM 객체)

 

3. Malware는 COM을 사용할 수 있음

- 클라이언트-악성코드

- 서버-공격자가 운영하는 서버

   → 공격자가 악성코드를 설치해서 서버에서 여러 작업을 할 수 있게 악용할 수 있다