logo

English

이곳의 프로그래밍관련 정보와 소스는 마음대로 활용하셔도 좋습니다. 다만 쓰시기 전에 통보 정도는 해주시는 것이 예의 일것 같습니다. 질문이나 오류 수정은 siseong@gmail.com 으로 주세요. 감사합니다.

[API Hooking] Dll Injection 하는 방법

by digipine posted Oct 29, 2017
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print

Dll Injection
API Hooking기법에 따라 차이는 있겠으나, API Hooking을 위해서는 대상프로세스의 주소 공간안에서의 메모리 조작이 필요하다.
이를 위해 사용되는 방법이 바로 Dll Injection이다. 즉 타겟 프로세스로 하여금 우리가 작성한 Dll을 로드하도록 하고, 해당 프로세스에 로드된 Dll에서 API를 Hooking하는 방식이다.
많이 사용되는 Dll Injection방법으로는 아래의 세가지 방법이 있다.
( Dll Injection은 API Hooking뿐만 아니라, 소스코드가 없는 프로그램에 대한 패치나 구조분석 등에도 사용될 수 있다. )

 

  1.     AppInit_DLLs 레지스트리 이용
    1.       개요
    2.   User32.dll은(User32.dll에서 Export한 API를 사용하는 모든 프로그램은) DLL_PROCESS_ATTACH 처리 과정에서 LoadLibrary()함수를 이용하여, 아래 키 값의 “AppInit DLLs” 엔트리에 등록된 모든 Dll을 로드한다. 이러한 동작을 이용하여 우리의 Dll을 다른 프로세스에 Injection 시킨다.
      • HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows
        ( AppInit DLLs에는 스페이스(‘ ‘)를 구분자로 하여 여러 개의 Dll을 등록할 수 있다. )
    3.       주의 사항
    4.   하지만 이 방법의 경우, 등록된 dll이 프로세스 생성과정의 전반부에서 로딩되므로, dll 로드과정에서는 kernel32.dll에서 export한 함수만을 안전하게 사용할 수 있다.(하단 URL참조)
    5.   모든 프로세스에 Injection하기 위해서는 시스템 리부팅이 필요하다. 간혹 이 기능이 동작하기 위해서는 무조건 리부팅이 필요하다고 기술한 문서들이 있는데, 리부팅하지 않더라도 해당 레지스트리에 Dll을 등록한 이후에 생성되는 프로세스는 영향을 받는다.
    6.   Dll의 Inject 시점을 임의로 조절할 수 없으며, Injection대상 프로세스를 지정할 수도 없다.
    7.   Dll을 Unload시킬 수 있는 방법이 없다.
    8.   가급적 이 방법 사용하지 않는 것이 좋을 것 같다.
    9.       참고 URL
       http://support.microsoft.com/kb/197571

 

  1.     SetWindowsHook()함수 사용
    1.       개요
      SetWindowsHook() API를 이용하여 특정 HookType에 대해 Hooking을 시도하게 되면, Dll내의 Hook Procedure뿐만 아니라, Dll코드 전체가 대상 프로세스의 메모리공간에 로드 된다. 이러한 특성을 이용하여 다른 프로세스에 Injection한다.
    2.       함수 원형

 

HHOOK SetWindowsHookEx(

  int idHook,        // type of hook to install

  HOOKPROC lpfn,     // address of hook procedure

  HINSTANCE hMod,    // handle to application instance

  DWORD dwThreadId   // identity of thread to install hook for

);

BOOL UnhookWindowsHookEx(

  HHOOK hhk   // handle to hook procedure to remove

);

 

  1.       구현
    •   Hook Handle공유
      •   SetWindowsHook()호출을 통해 리턴되는 HHOOK 타입의 핸들은, Hooking 대상 메시지(?)를 Hook체인으로 전달하기 위해, 모든 Dll 인스턴스들이 공유해야 한다. 이를 위해 shared속성을 갖는 섹션에 선언한다.

 

#pragma data_seg(".hkshared")

HHOOK   g_hHook = NULL;

#pragma data_seg()

#pragma comment(linker, "/SECTION:.hkshared,RWS) //Read|Write|Shared

 

 

  1.     CreateRemoteThread()
    1.       개요
      CreateRemoteThread()를 이용하여 이미 존재하는 프로세스내에 원격스레드를 생성하고, 이 원격스레드의 시작 함수로 Kernel32.dll의 LoadLibrary()의 주소를, 파라미터로 우리가 로드하려하는 hookDll의 파일명(혹은 FullPath)를 전달한다.
      이 방법은 CreateRemoteThread()의 4번째 인자인lpStartAddress와 LoadLibrary()의 함수원형이 같다는 점에서 유효하다.( 엄밀히 말하자면 같지는 않지만, 4byte의 인자와 4byte의 리턴값을 취한다는 점에서 동일하게 취급할 수 있다.)
    2.       함수원형

 

HANDLE CreateRemoteThread(

  HANDLE hProcess,        // handle to process to create thread in

  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes

  DWORD dwStackSize,      // initial thread stack size, in bytes

  LPTHREAD_START_ROUTINE lpStartAddress// pointer to thread function

  LPVOID lpParameter,     // argument for new thread

  DWORD dwCreationFlags,  // creation flags

  LPDWORD lpThreadId      // pointer to returned thread identifier

);

 

  1.       구현
    •   전술한 내용을 이용하여 CreateRemoteThread()를 호출하려면 4번재 파라미터로 , 타겟프로세스 내에서의 LoadLibrary() 함수의 주소를 구하여 넘겨주어야 한다. 하지만 아시다시피 각 프로세스는 별도의 메모리 공간을 가지고 있다.
      •   Kernel32.dll, ntdll.dll, user32.dll등의 시스템 dll들은 중복되지 않는 고유의 Address를 갖으므로, Dll Injection을 시도하는 프로세스에서 구한 Address는 타겟 프로세스에서도 유효하다.( Windows System Dll들은 로딩시 Relocation을 피하기 위해 고유의 BaseAddress를 가지고 있다 )
    •   CreateRemoteThread()의 다섯번째 인자인 lpParameter에는 우리가 로드할 Dll의 이름을 넘겨주어야 한다. 하지만 파라미터로 전달해야하는 hookDll의 파일명을 Dll Injection을 시도하는 프로세스의 주소로 넘겨주어서는 의미가 없다. 각각의 프로세스는 고유의 메모공간을 가지므로, Dll Injection을 시도하는 프로세스의 주소는 타겟 프로세스에서 유효하지 않다.
      •   이를 위해 타겟 프로세스에 메모리 공간을 할당하고, 그 메모리에 우리의 hookDll의 이름을 적어주어야 하는데 다음의 함수들을 사용해서 구현할 수 있다.

 

HANDLE OpenProcess(

  DWORD dwDesiredAccess,

  BOOL bInheritHandle,

  DWORD dwProcessId

);

OpenProcess()는 프로세스ID를 인자로 받아 해당 프로세스의 핸들을 리턴한다.

이 핸들값은 VirtualAllocEx(), WriteProcessMemory()의 첫번째 인자로 사용된다.

LPVOID VirtualAllocEx(

  HANDLE hProcess,

  LPVOID lpAddress,

  SIZE_T dwSize,

  DWORD flAllocationType,

  DWORD flProtect

);

VertualAllocEx()는 첫번째 인자로 주어진 프로세스의 가상메모리내에 메모리를 할당한다.

BOOL WriteProcessMemory(

  HANDLE hProcess,

  LPVOID lpBaseAddress,

  LPCVOID lpBuffer,

  SIZE_T nSize,

  SIZE_T* lpNumberOfBytesWritten

);

VertualAllocEx()는 첫번째 인자로 주어진 프로세스의 가상메모리내에 Write를 지원한다.

 

  1.       기타
    •   CreateRemoteThread()를 이용해 Injection시킨 Dll은 아래와 같은 절차로 Unload시킬 수 도 있다.
      •   Injection 후 GetExitCodeThread()를 통해 LoadLibray()가 리턴한 값(모듈핸들)을 보관
      •   LoadLibrary()를 리모트 프로세스에서 실행시킨 것과 마찬가지 방법으로 FreeLibrary()를 실행(FreeLibrary역시 4바이트의 인자를 가지며, 4바이트의 값을 리턴한다)
    •   Vista이상의 경우 다른 세션에 존재하는 프로세스를 대상으로 CreateRemoteThread()를 호출할 경우, 실패한다( lasterror: NOT_ENOUGH_MEMORY) 세션별로 Injection 프로세스를 띄워주면 되겠지만 용이치 않을 경우, ntdll!NTCreateThreadEx()를 사용하면 된다고 한다.(Vista이상의 OS만 유효함)
TAG •

List of Articles
No. Subject Author Date Views
45 [C#] UI Update from Thread, Thread에서 UI 업데이트 하기 샘플 코드 lizard2019 2019.01.23 1035
44 [C#] 프로그램 종료 방법 lizard2019 2019.01.23 6761
43 [C#] 코드 실행 시간 측정 및 DateTime 스트링으로 변환 포맷 lizard2019 2019.01.23 22947
42 [Win32] HBITMAP Contrast 조절하는 코드 - RGB 이미지 보정 엉뚱도마뱀 2018.05.04 734
41 [Windows] DOS 명령어 실행하고 결과 스트링 가져오는 샘플 코드 digipine 2017.11.02 2687
40 VC++ UTF8 변환 관련 매크로 digipine 2017.11.02 8778
39 C# 으로 구현한 화면 캡춰 클래스 1 digipine 2017.11.02 33962
38 C# - 한글로된 폰트명 처리 방법 개선 (Font Name Localization) digipine 2017.11.02 1388
37 [C#] StreamReader 에서의 한글 Encoding 문제 digipine 2017.10.29 999
» [API Hooking] Dll Injection 하는 방법 digipine 2017.10.29 5210
35 [WIN32] 파일 핸들로 파일 명 구하기 digipine 2017.10.29 1060
34 [WIN32] Process ID로 HWND 구하기 digipine 2017.10.29 5011
33 MS의 Hot Fix API의 유형 연구 digipine 2017.10.29 311
32 [WIN32] 실행 중인 프로세스를 외부에서 강제로 종료, 안전한 TerminateProcess digipine 2017.10.29 3455
31 [WIN32] API Hook 정리 문서 digipine 2017.10.29 1963
30 [WIN32, WINCE] 디스크 용량 구하는 방법 API GetDiskFreeSpaceEx digipine 2017.10.29 1564
29 [WINCE] MulDiv 함수 구현 digipine 2017.10.29 699
28 [DirectShow] 화면 원본 비율유지 digipine 2017.10.29 956
27 [VC++, WInAPI] 폴더를 통채로 지우기, 서브 폴더 포함, DeleteAllFiles digipine 2017.10.29 1761
26 [Win API]프로세스 아이디와 윈도우 핸들을 이용 파일명 구하기 digipine 2017.10.29 1390
Board Pagination Prev 1 2 3 Next
/ 3