DLL注入原理

1 什么是DLL注入

​ DLL注入指的是向运行中的其他进程强制插入特定的DLL文件;DLL注入与一般DLL加载的区别在于, 加载的目标进程是其自身或其他进程。DLL被加载到进程后会自动运函数DllMain( )。

DLLMain函数模板:参考自MSDoc

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
 switch (ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
   //add your code here
   break;
  case DLL_THREAD_ATTACH:
      //add your code here
   break;
  case DLL_THREAD_DETACH:
   //add your code here
   break;
  case DLL_PROCESS_DETACH:
   //add your code here
   break;
 }
 return TRUE;
}

2 DLL注入方法

  • 创建远程线程:CreateRemoteThreadO API
  • 使用注册表:Applnit_DLLs 值
  • 消息钩取:SetWindowsHookEx()API

2.1 远程线程法注入原理

利用CreateRemoteThrea()函数在目标进程创建LoadLibrary()线程来加载需要注入的DLL。

BOOL InjectDll(DWORD pid, LPCTSTR DllPath)
{
    DWORD dwBufSize = (DWORD)(_tcslen(DllPath) + 1) * sizeof(TCHAR);
    HANDLE hProcess = NULL; 
    HMODULE hMod = NULL;
    HANDLE hThread = NULL;
    LPTHREAD_START_ROUTINE pThreadProc;
    LPVOID pRemoteBuf = NULL;


    //获取目标进程句柄
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hProcess)
    {
        printf("open process failed! pid %d\n", pid);
        return FALSE;
    }

    //在目标进程内存空间分配虚拟内存,存储DLL地址
    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

    //将DLL路径写入目标进程内存
    int ret = WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)DllPath, dwBufSize, NULL);

    //获取LoadLibrary函数地址
    hMod = LoadLibrary("kernel32.dll");
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryA");

    //在目标进程中创建LoadLibrary远程线程
    hThread = CreateRemoteThread(
        hProcess,   //notepad进程句柄
        NULL,
        0,
        pThreadProc,    //LoadLibraryA句柄
        pRemoteBuf, //需要注入的DLL文件路径
        0,
        NULL);

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

2.2 远程线程注入常用 API

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);
//获取指定进程的快照,以及这些进程使用的堆,模块和线程。
//th32ProcessID = 0 则获取所有快照
HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);
//打开本地进程对象
LPVOID VirtualAllocEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);
//在指定进程在内存中分配内存空间
BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);
//将数据写入指定进程的内存区域
HMODULE LoadLibraryA(
  LPCSTR lpLibFileName
);
//将指定的模块加载到调用进程的地址空间中
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);
//创建在另一个进程的虚拟地址空间中运行的线程。
HMODULE GetModuleHandle(
  LPCSTR lpModuleName
);
//检索指定模块的模块句柄。该模块必须已由调用进程加载。
FARPROC GetProcAddress(
  HMODULE hModule,
  LPCSTR  lpProcName
);
//从指定的动态链接库(DLL)中检索导出的函数或变量的地址