DLL Injection

안상준·2025년 5월 15일

Reversing

목록 보기
3/16

DLL Injection 이란

DLL Injection은 다른 프로세스 내 DLL을 강제로 삽입하는 것을 의미한다. 주로 코드 후킹을 위해 이를 사용한다.

CreateRemoteThread

DLL Injection을 하기 위해 사용하는 API로, 타 프로세스 메모리에 스레드를 생성할 수 있다. 즉 다른 프로세스에서 나의 코드가 실행되도록 할 수 있다.

Code

실제 코드를 통해 어떻게 DLL Injection을 하는지 살펴보자

#include <windows.h>  
#include <stdio.h>  
#include <string.h>  

int main() {  
   DWORD pid;  
   char dllPath[MAX_PATH] = {0};

   printf("[*] Target PID: ");  
   scanf_s("%d", &pid);  

   printf("[*] Full path to DLL: ");  

   printf("%s\n", dllPath);
   scanf_s("%s", dllPath, (unsigned)_countof(dllPath)); 

   dllPath[MAX_PATH - 1] = '\0';  

   HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);  
   if (!hProcess) {  
       printf("[-] Failed to open process. Error: %lu\n", GetLastError());  
       return 1;  
   }
 
   LPVOID pRemoteMemory = VirtualAllocEx(hProcess, NULL, strlen(dllPath) + 1,  
       MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);  
   if (!pRemoteMemory) {  
       printf("[-] VirtualAllocEx failed. Error: %lu\n", GetLastError());  
       return 1;  
   }  

   WriteProcessMemory(hProcess, pRemoteMemory, dllPath, strlen(dllPath) + 1, NULL);  

   HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");  
   if (!hKernel32) {  
       printf("[-] GetModuleHandleA failed. Error: %lu\n", GetLastError());  
       return 1;  
   }  

   FARPROC pLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");  
   if (!pLoadLibrary) {  
       printf("[-] GetProcAddress failed. Error: %lu\n", GetLastError());  
       return 1;  
   }  
  
   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,  
       (LPTHREAD_START_ROUTINE)pLoadLibrary,  
       pRemoteMemory, 0, NULL);  

   if (!hThread) {  
       printf("[-] CreateRemoteThread failed. Error: %lu\n", GetLastError());  
       return 1;  
   }  

   printf("[+] DLL injected successfully!\n");  

   CloseHandle(hThread);  
   CloseHandle(hProcess);  

   return 0;  
}

DLL Injection을 하기위해 사용한 코드인데 한 부분씩 살펴보자

scanf

pid, dllPath를 입력 받는다. pid는 process id로 어떤 실행 파일이든 실행을 하면 고유 pid가 존재한다. 타겟 프로세스의 pid를 입력하고, 삽입할 dll의 경로를 입력해 준다.

OpenProcess

입력받은 pid를 오픈해 준다. 프로세스를 연다는 의미는 현재 실행 중인 다른 프로세스에 대해 조작 가능한 핸들을 얻는 다는 것을 믜히나다.
메모리에 접근하거나, 쓰레드를 만들거나, 상태를 조회하는 것이 가능하다.

VirtualAllocEx

VirtualAllocEx함수는 프로세스의 가상 메모리 공간에 새로운 메모리 영역을 할당하는 함수다. 각 파라미터를 살펴보면

LPVOID VirtualAllocEx(
  HANDLE hProcess,       // 대상 프로세스 핸들
  LPVOID lpAddress,      // 할당받고 싶은 주소 (NULL이면 자동으로 선택)
  SIZE_T dwSize,         // 할당할 크기
  DWORD flAllocationType,// MEM_COMMIT, MEM_RESERVE 등
  DWORD flProtect        // PAGE_READWRITE 등
);

위 함수를 해석하자면 dllPath+1 길이 만큼 타겟 프로세스의 가상 메모리 공간을 할당하게 된다.

WriteProcessMemory

프로세스 메모리에 쓰는 동작을 하게 된다. 위에서 할당한 메모리 공간에 DLL의 경로를 쓰는 동작을 한다.

GetModuleHandleA

kernel32.dll모듈의 핸들을 현재 프로세스에서 얻는다.

GetProcAddress

위에서 얻은 모듈을 이용하여 LoadLibraryA의 주소를 얻는다.

CreateRemoteThread

스레드를 생성하는 함수로 위에서 얻은 LoadLibraryA의 주소를 이용하여 타겟 프로세스에서 LoadLibraryA(pRemoteMemory)를 호출한다. pRemoteMemory는 위에서 dll경로를 저장한 메모리 공간이다.

DLL


DLL은 간단하게 DllMain만 있는 코드를 작성하였다. 작성한 코드는 빌드를 통해 dll파일을 생성해 주었다.

Result


pid를 찾는 방법은 작업관리자의 세부정보를 보면 pid를 알 수 있다. 대상 프로그램은 위도우의 메모장으로 하였다.

위에서 작성한 코드를 실행하여 pid, dll경로를 입력하면 DLL Injection이 성공했다고 뜬다. 잘 됐는지 확인하기 위하여 Process Explorer 프로그램을 이용하여 확인하였다.

회색 부분을 보면 작성한 TestDll 파일이 존재하는 것을 볼 수 있다.

주의점

모든 프로그램에 대해서 DLL Injection이 되는 것은 아니다. window 프로그램 중에서는 Win32 app은 가능하제만 UWP app의 경우에는 보호기법이 적용되어 프로세스를 여는 것이 안되거나 특정 API를 사용하지 못하게 돼있다고 한다. 예를 들어 윈도우의 메모장 프로그램은 Injection이 가능했지만 계산기의 경우 불가능 하였다.(Window 7 계산기는 가능)
실제 상용 프로그램(kakao, chrome)등 에서는 하지 않는 것이 좋다. 법적 문제 등 위험 소재가 있다.

출처 : 리버스 엔지니어링 바이블(지은이 강병탁, 2012)

0개의 댓글