나만의 메모노트

[리버싱 핵심원리] DLL Injection 본문

Security/Reversing

[리버싱 핵심원리] DLL Injection

sp3arm4n 2021. 8. 1. 04:28

DLL Injection

  • 실행 중인 다른 프로세스에 특정 DLL 파일을 강제로 삽입하는 기술
  • 다른 프로세스에서 LoadLibrary() API를 통해 특정 DLL Loading
    • 강제 삽입된 DLL의 DLLMain() 함수 호출
  • 삽입된 DLL은 해당 프로세스의 메모리에 대한 접근권한을 가짐
    • 기능 개선, 버그 패치, 메시지 후킹, API 후킹 등 사용자가 원하는 다양한 일을 수행
  • 현재 악성코드에 의해 악용되고 있음
  • DLL Injection 구현방법
    • 원격 스레드 실행 - CreateRemoteThread() API
    • 레지스트리 이용 - AppInit_DLLs
    • 메시지 후킹 - SetWindowsHookEx() API
    • 그 외 여러 가지 다양한 기법 존재
      notepad.exe DLL Injection

CreateRemoteThread() API를 이용한 DLL Injection

STEP 1.

  • Open Process() API 이용하여 대상 프로세스 핸들 구하기
HANDLE OpenProcess(
  DWORD dwDesiredAccess, 
  BOOL bInheritHandle, 
  DWORD dwProcessId
);

 

// Sample_InjectDLL()

if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
    return FALSE;

 

매개변수 (parameter) 설명
dwDesiredAccess 접근 권한을 의미하며, 대체로 PROCESS_ALL_ACCESS를 사용한다.
bInheritHandle 상속 여부를 나타내는 것으로 해당 프로세스에 의해 생성된 자식 프로세스가 핸들을 상속받기 위해 True를 반환한다.
dwProcessld 0 또는 NULL 입력 시 모든 프로세스에 접근 가능하며, 특정 프로세스에 접근할 경우 해당 프로세스의 PID를 입력한다.

STEP 2.

  • 대상 프로세스 메모리에 Injection할 DLL 경로 작성하기 위해 VirtualAllocEx() API를 이용하여 상대방 프로세스 메모리 공간에 버퍼 할당 후 WriteProcess Memory() API를 이용하여 DLL 경로 문자열을 입력
    • VirtualAllocEx() API
      • 해당 프로세스 가상메모리 공간을 할당 받고자 할 때 사용
    • WriteProcessMemory() API

VirtualAllocEx() API

LPVOID VirtualAllocEx(
  HANDLE hProcess, 
  LPVOID lpAddress, 
  SIZE_T dwSize,
  DWORD flAllocationType,
  DWORD flProtect
);

 

// Sample_InjectDLL()

pRemoteBuf = VirtualAllocEx(
	hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

 

매개변수 (parameter) 설명
hProcess 대상 핸들이며, 대상이 되는 가상메모리 공간을 할당 받을 수 있다.
lpAddress 할당 받을 메모리 주소이며, NULL일 경우 비어 있는 공간에 자동 할당 된다.
dwSize 할당 받을 메모리 크기(Byte)이며, NULL일 경우 Page 크기만큼 할당 받는다
flAllocationType 할당 받은 메모리의 현재 타입을 지정한다.
(MEM_RESERVE,  MEM_COMMIT,  MEM_RESET)
flProtect 할당 받은 메모리에 대한 접근 권한

WriteProcessMemory() API

BOOL WriteProcessMemory(
  HANDLE hProcess, 
  LPVOID lpBaseAddress, 
  LPCVOID lpBuffer,
  SIZE_T nSize,
  SIZE_T *lpNumberOfBytesWritten
);

 

// Sample_InjectDLL()

WriteProcessMemory(
	hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);

 

매개변수 (parameter) 설명
hProcess PROCESS_VM_WRITE PROCESS_VM_OPERATION
접근권한을 가진 대상 프로세스
lpBaseAddress VirtualAllocEx() API로부터 얻은 메모리 시작 주소
lpBuffer InjectionDLL 파일의 경로
nSize DLL 파일 경로 문자열 길이(Terminating NULL 포함)
*lpNumberOfBytesWritten 특정 프로세스로 전송된 바이트 수에 대한 포인터 변수
lpNumberOfBytesWrittenNULL이면 parameter 무시됨

STEP 3.

  • LoadLibrary() API를 호출하기 위한 주소 구하기
    • ASCII 문자열 버전에 따라 LoadLibraryA() 혹은 LoadLibraryW()로 치환
// Sample_InjectDll()

pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(
  GetModuleHandle("kernel32.dll"),
  "LoadLibraryA"
);
    • GetModuleHandle() API를 통해 DLL 핸들값을 가져오고 GetProcAddress() API를 통해 DLL 주소값을 가져옴
    • 대상 프로세스에 로딩된 kernel32.dll과 InjectDll.exe에 의해 로딩된 kernel32.dll의 메모리 시작 위치는 동일
      • Windows OS에서 Kernel32.dll은 프로세스마다 같은 주소에 로딩됨

STEP 4.

  • 대상 프로세스에 원격 스레드 실행
    • 대상 프로세스에 LoadLibrary() API를 호출하기 위해 CreateRemoteThread() API를 사용
HANDLE CreateRemoteThread(
  HANDLE hProcess, 
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  SIZE_T dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId
);

 

// Sample_InjectDLL()

hThread = CreateRemoteThread(
	hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL
);

 

매개변수 (parameter) 설명
hProcess 스레드를 생성할 프로세스의 핸들 (PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_WRITE PROCESS_VM_READ 접근 권한 포함)
lpThreadAttributes 새 스레드에 대한 보안 설명자를 지정하고 하위 프로세스가 반환된 핸들을 상속 할 수 있는지 여부를 결정하는 SECURITY_ATTRIBUTES 구조에 대한 포인터, lpThreadAttributesNULL이면 스레드가 기본 보안 설명자를 가져오고 핸들을 상속할 수 없음. 스레드에 대한 기본 보안 설명자의 ACL(액세스 제어 목록)은 작성자의 기본 토큰에서 가져옴
dwStackSize 스택의 초기 크기(Byte), 시스템은 해당 해당 값을 가장 가까운 page로 반올림,
Parameter0이면 새 스레드는 실행 파일의 기본 크기를 사용
lpStartAddress 스레드에 의해 실행될 LPTHREAD_START_ROUTINE 유형의 application-defined 함수에 대한 포인터로 원격 프로세스에서 스레드의 시작 주소를 나타냄
해당 함수는 원격 프로세스에 존재해야함 (LoadLibrary() 주소)
lpParameter Parameter에 대한 포인터 (InjectionDLL 경로)
dwCreationFlags 스레드 생성을 제어하는 플래그
lpThreadId 대상 스레드의 ID