최근 수정 시각 : 2023-12-13 20:57:33

프로세스 인젝션


1. 개요2. 상세3. 기법
3.1. DLL 로드3.2. PE 삽입3.3. 프로세스 교체
4. 예방법

1. 개요

Process Injection

한 프로세스가 타켓 프로세스에 코드를 삽입하여 타켓 프로세스 내에서 실행시키도록 하는 기법. 랜섬웨어 등의 악성코드부터 게임 해킹 프로그램, 모드 로더, 한국어 자동 번역[1] 등, 여러 부분에서 많이 사용되는 기법이기도 하다.

2. 상세

타켓 프로세스의 메모리를 조작하여 원하는 코드를 주입한 다음 해당 코드를 실행시킬 스레드를 생성하는 것이다. 물론 메모리를 직접 조작하는 것이다보니 잘못했다간 타켓 프로세스가 뻗어버리기도 한다. 프로세스마다 자신만의 가상 메모리 영역을 가지고 있으며 프로세스가 다른 프로세스의 메모리를 보거나 수정할 수 없다. 하지만 다른 프로세스의 메모리를 직접 읽어내거나 메모리에 쓸 수 있는 API가 있으므로 이를 이용하여 다른 프로세스의 메모리를 쓰거나 읽을 수 있다. 윈도우의 경우 WriteProcessMemory, ReadProcessMemory가 있다. 심지어는 다른 프로세스에 스레드를 만들어주는 API가 있다. (CreateRemoteThread)

윈도우에서는 DEP(Data Execution Prevention, 데이터 실행 방지)라는 보안 기능이 있으므로 아무 메모리 주소에서 코드를 실행시킬 수 없고 실행 권한이 부여되어 있어야 한다. 실행 권한이 없는 메모리에서 코드 실행을 시도하면 예외가 발생하여 프로세스가 종료된다.

3. 기법

많지만 이들 중에서 가장 쓰여지는 프로세스 인젝션 기법은 다음과 같다. 아래의 기법들은 윈도우 기준으로 설명한다. 기법 목록

3.1. DLL 로드

DLL 파일을 디스크에 드랍시킨 뒤 타켓 프로세스의 메모리에서 새 페이지 영역을 할당하고 새 영역에 드랍시킨 DLL 파일의 경로를 기록한 후 CreateRemoteThread로 타켓 프로세스에 스레드를 생성하여 DLL 파일을 로드시키는 방법이다.

이 기법의 순서는 다음과 같다.
  • DLL 파일을 디스크에 드랍시킨다.
  • OpenProcess로 타켓 프로세스를 연다. 이 때 액세스 권한은 PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, PROCESS_VM_READ 이어야 한다.
  • 타켓 프로세스를 여는데 성공하면 VirtualAllocEx로 타켓 프로세스의 메모리 영역에서 새 페이지 영역을 할당시킨다. 할당시킬 크기(dwSize)는 드랍된 DLL 파일이 있는 전체 경로의 길이로 설정해야 한다. 보호 플래그(flProtect)는 PAGE_EXECUTE_READWRITE로 설정해야 한다.
  • 그런 다음에 WriteProcessMemory로 아까 할당시킨 타켓 프로세스의 메모리에 드랍된 DLL 파일의 전체 경로를 기록시킨다.
  • (선택 사항) 메모리에 DLL 파일의 경로를 기록한 후 VirtualProtectEx로 해당 메모리의 보호 플래그를 수정하여 PAGE_EXECUTE_READ로 설정할 수 있다.
  • GetModuleHandle로 로드된 Kernel32.dll의 주소를 가져온다. 그런 다음에 GetProcAddress로 Kernel32.dll의 LoadLibrary의 주소를 얻어온다. (주의 : GetModuleHandle와 LoadLibrary는 유니코드 버전과 ANSI 버전이 존재한다. 메모리에 기록한 DLL 파일의 경로 문자열이 ANSI인지 유니코드인지에 따라 맨 뒤에 A(ANSI 버전, 예: LoadLibraryA)이나 W(유니코드 버전, 예: LoadLibraryW)를 붙여야 한다.)
  • CreateRemoteThread로 타켓 프로세스에 스레드를 생성시킨다. 이때 CreateRemoteThread의 인수 중 lpStartAddress는 아까 가져온 LoadLibrary의 주소를 넣고 lpParameter에는 아까 할당시킨 DLL 파일의 경로가 있는 메모리 주소를 넣는다.
  • 그러면 타켓 프로세스는 해당 DLL 파일을 로드시키게 된다. 드랍된 DLL 파일의 DllMain가 실행되어 우리가 원하는 코드를 타켓 프로세스 내에서 실행시킬 수 있게 된다.

다른 기법들에 비해 쉽고 GetModuleHandle, GetProcAddress, VirtualAllocEx, WriteProcessMemory, CreateRemoteThread 함수의 사용법만 알면 되는 간단한 방법이라 한국어 자동 번역, 게임 패치 등에서 많이 쓰인다. 다만 DLL 파일이 디스크에 드랍되어 있어야 하기에 안티바이러스 소프트웨어가 막을 수 있다는 단점이 있다. 안티바이러스 측에서 드랍된 DLL 파일이 악성코드라면 그냥 날려버리면 되기 때문이다. 또한 시스템 프로세스이나 높은 권한으로 실행되는 프로세스(서비스 등) 등에 사용할 수 없다. OpenProcess부터 액세스 거부로 실패해서 인젝션을 수행할 수 없다.

DLL 로드를 사용하는 예시 프로그램으로는 wLauncher가 있다. 이 프로그램의 경우 wDetector.dll를 스타크래프트 프로세스에 인젝션시키는 방식으로 동작한다.

3.2. PE 삽입

타켓 프로세스의 메모리에 자신 또는 다른 EXE 파일의 전체 내용을 기록시킨 뒤 CreateRemoteThread로 실행하고 싶은 함수를 실행시키는 기법이다. 이 기법의 경우 디스크에 DLL 파일을 드랍하지 않기에 안티바이러스의 탐지를 회피할 수 있다는 특징이 있다.

흔히 악성코드 등지에서 탐지를 피하기 위해 이런 기법을 많이 사용한다. 특히 마이크로소프트 프로그램, 즉 마이크로소프트 디지털서명으로 된 프로세스에 코드를 삽입시킨다. 시스템 프로세스에 삽입하기도 하지만 주로 관리자 권한이 필요 없는 explorer.exe 프로세스에 코드를 삽입시킨다. 물론 다른 마이크로소프트 프로세스에 삽입시키기도 한다. 어느 프로세스에 삽입시킬 지는 악성코드 개발자 마음대로다.

3.3. 프로세스 교체

타켓 프로세스를 일시 정지 상태로 생성시킨 뒤 타켓 프로세스의 메모리에서 본래 프로세스 이미지의 매핑을 해제시킨 뒤 다른 프로세스 이미지로 새로 매핑시키고 주 스레드의 진입점을 수정한 후 재개시키는 방법이다.

CreateProcess로 타켓 프로세스를 만들 때 인수 중 dwCreationFlags에 CREATE_SUSPENDED를 포함시키면 타켓 프로세스의 주 스레드가 일시 정지 싱태(Suspended)로 만들어지며 ResumeThread를 호출할 때까지 실행되지 않는다. 이후 NtUnmapViewOfSection로 타켓 프로세스의 메모리에서 기존의 영역의 매핑을 해제시킨다. 그런 다음에 VirtualAllocEx로 새 영역을 할당시켜주고 WriteProcessMemory로 코드를 새 영역에 기록한 후 SetThreadContext를 사용하여 주 스레드의 시작 지점을 새 영역으로 가리키도록 수정한다. 이후 ResumeThread를 호출하여 주 스레드의 일시 정지 상태를 풀어주면 우리가 삽입한 코드가 실행하게 된다.

이것도 역시 악성코드에서 많이 쓰여지는 기법이다. 그 외에도 타셋 프로세스의 기존 스레드의 실행 영역을 수정하는 기법도 있다.

4. 예방법

커널 모드 드라이버로 다른 프로세스가 자신의 프로세스의 메모리에 접근하지 못하도록 막아버리면 된다. 한 예시로 게임의 경우 안티 치트가 다른 프로세스가 게임 프로세스의 메모리를 수정하거나 읽는 것을 막는다.
[1] 특히 미연시 게임에서 사용된다.