Programming

[펌] Dll injection

Foolishdevil 2009. 3. 25. 00:20
출처 : http://yuik.tistory.com/83
예전에 복사해 놓은 것인데..
출처가 어디인지 정확히 기억이 안난다;;

dll Injection은?
이미 실행되어 있는 프로세스로 DLL 을 삽입하는 기법
  -특정 함수를 실행 하기 전에 프로세스를 실행 하는 지점에서 제어권을 가로 챈 뒤, 자신의 코드를 주입,   실행 하고 제어권을 다시 돌려주는 방법

dll Injection에 필요한 함수와 코드의 흐름

OpenProcess
        - 프로세스를 열어 핸들을 구한다
LoadLibrary
         - .dll을 로드한다.
GetProcAddres
    - 특정함수의 메모리 주소를 얻어온다.
VirtualAllocEx
- 타 프로세스의 새로운 힙영역을 확보한다.
WriteProcessMemory
    - 타 프로세스의 공간에 데이터를 쓴다.
CreateRemoteThread
      -타 프로세스에 스레드를 생성 시킨다. 


간단한 dll injection 샘플

계산기 프로그램의 주소공간에 DLL을 인젝션하여 숫자 입력시 1씩을 더하도록 하는 인젝션 예..

#include <iostream.h>
#include <windows.h> 
// DLL Inject : 다른 프로세스의 주소 공간에 특정 DLL을 넣는다.
void DllInject(DWORD pid, char* path)
{
 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
 // 내 프로세스에 있는 KERNEL32.DLL의 주소와 LoadLibrary의 주소를 구한다.
 HMODULE hDll = GetModuleHandle("kernel32.dll"); // kernel32.dll 모듈의 핸들값을 GetModuleHandle로 구한다.
 PTHREAD_START_ROUTINE f = (PTHREAD_START_ROUTINE)GetProcAddress(hDll, "LoadLibraryA");
 // PTHREAD_START_ROUTINE은 미리 정의되어 있는 스레드 함수 모양의 함수 포인터 type
 // 계산기의 주소공간에 메모리를 할당하고, DLL의 경로를 복사해준다.
 // VirtualAlloc은 가상 메모리를 할당하는 API이지만, Ex가 붙으면 다른 프로세스의 주소공간을 할당할 수 있다.
 void* p = VirtualAllocEx(hProcess, 0, // 원하는 주소(0은 알아서 해달라)
       strlen(path)+1, // 크기
       MEM_RESERVE | MEM_COMMIT, // 예약과 동시 확정
       PAGE_READWRITE);
 
 // 이제 DLL의 경로를 담을 문자열 복사
 // WriteProcessMemory()는 다른 프로세스 주소 공간에 무언가를 쓸 수 있다.
 DWORD len;
 WriteProcessMemory(hProcess, p, path, strlen(path)+1, &len);
 // 계산기에 새로운 스레드를 만든다.
 // CreateRemoteThread는 다른 프로세스에 스레드를 생성시킨다.
 HANDLE hThread = CreateRemoteThread(hProcess, // 계산기 핸들
          0, 0,
          f, p, // 함수, 파리미터
          0, 0);

 CloseHandle(hThread);
 CloseHandle(hProcess);
}
void main()
{
 HWND hwnd = FindWindow(0, "계산기");
 if(hwnd == 0)
 {
  cout << "계산기를 먼저 실행하시오" << endl;
  return;
 }
 DWORD pid;
 DWORD tid = GetWindowThreadProcessId(hwnd, &pid);
 DllInject(pid, "C:\\spy1.dll");
}


이제부터, DLL 로 작성한다.
#include <windows.h> 
WNDPROC old; // 원래 계산기의 메세지 함수의 주소를 담을 변수
// 계산기의 메세지를 처리할 새로운 함수
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
 switch(msg)
 {
 case WM_COMMAND: // 버튼 또는 메뉴를 선택할 경우
  {
   UINT id = LOWORD(wp);
   if(id >= 0x7c && id <= 0x85)
    return CallWindowProc(old, hwnd, msg, wp+1, lp+1);
   break;
  }
 }
 // 나머지 모든 메세지는 원래의 함수로 보내준다.
 return CallWindowProc(old, hwnd, msg, wp, lp);
}
// 모든 DLL은 Process에 Mapping 되거나 해제될 때 DllMain이 호출됨.
BOOL WINAPI DllMain(HANDLE h, DWORD r, LPVOID p)
{
 if(r == DLL_PROCESS_ATTACH)
 {
  HWND hwnd = FindWindow(0, "계산기");
  old = (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC, (LONG)WndProc);
 }
 return TRUE;
}