zoukankan      html  css  js  c++  java
  • 逆向工程核心原理——第二十三章

    第二十三章 DLL注入

    DLL注入,是指向运行中的其他进程强制插入特定的DLL文件。常用于渗透其他进程,DLL注入可以实现API钩取、改写程序、修复BUG等。


    可以看到,notepad.exe进程本来是会加载myhack.dll的,但由于我们强制注入了myhack.dll,所以现在他会加载myhack.dll。

    DLL注入实验

    接下来书本上进行了一个DLL注入的实例:

    首先我们准备一个notepad文件(记事本),这将是我们进行注入的文件:

    和一个DLL文件(此DLL的作用是下载一个.html)已经将DLL注入进notepad的EXE文件:

    首先我们打开notepad文件,利用process explorer查看notepad文件的PID:

    打开cmd,输入指令:'''InjectDLL.exe 1580 c:workmyhack.dll'''

    cmd显示我们注册成功,然后我们在process explorer上查看dll是否被注入成功,在View菜单中,选择Show Lower PaneLower Pane Views - DLLs项。就可以看到:

    可以看到myhack.dll已经被成功加载进去了。然后我们打开dll所在文件夹,查看url是否被成功下载。

    这样,就说明我们DLL注入成功了。

    接下来我们来看看dll文件和exe文件的代码:

    // 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)
    {
        TCHAR szPath[_MAX_PATH] = { 0, };
    
    if (!GetModuleFileName(g_hMod, szPath, MAX_PATH))
        return FALSE;
    
    TCHAR* p = _tcsrchr(szPath, '\');
    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)
    {
        HANDLE hThread = NULL;
    
    g_hMod = (HMODULE)hinstDLL;
    
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        OutputDebugString(L"<myhack.dll> Injection!!!");
    
    ​    //创建远程线程进行download
    ​    hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    
    ​    // 需要注意,切记随手关闭句柄,保持好习惯
    ​    CloseHandle(hThread);
    ​    break;
    }
    
    return TRUE;
    
    }
    

    我是使用vs2019进行编译的,在创建新项目的时候,我选择的是“动态链接库(DLL)”

    vs不知道从哪个本开始,会加入一个预编译头,例如这里的“pch.h”的头文件:

    这个头文件,会存放一些使用者预设的一些代码。

    这里如果我们删除这个头文件,则会报错提示你加入头文件:

    但如果加入了这个头文件,则会报错提示很多变量找不到标识符:

    解决方案就是在项目——>属性中进行更改:

    在属性的预编译头中选择不使用预编译头,就可以了

    然后是exe文件:

    // InjectDll.cpp
    #include "windows.h"
    #include "tchar.h"
    
    BOOL InjectDll(DWORD dwPID, LPCTSTR szDllPath)
    {
        HANDLE hProcess = NULL, hThread = NULL;
        HMODULE hMod = NULL;
        LPVOID pRemoteBuf = NULL;
    
        //确定路径需要占用的缓冲区大小
        DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
        LPTHREAD_START_ROUTINE pThreadProc;
        
        // #1. 使用OpenProcess函数获取目标进程句柄(PROCESS_ALL_ACCESS权限)
        if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)))
        {
            _tprintf(L"OpenProcess(%d) failed!!! [%d]
    ", dwPID, GetLastError());
            return FALSE;
        }
        
        // #2. 使用VirtualAllocEx函数在目标进程中分配内存,大小为szDllName
              // 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的加载地址还是一样的。
        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);
        WaitForSingleObject(hThread, INFINITE);
        
        //同样,记得关闭句柄
        CloseHandle(hThread);
        CloseHandle(hProcess);
        
        return TRUE;
    
    }
    
    int _tmain(int argc, TCHAR* argv[])
    {
        if (argc != 3)
        {
            _tprintf(L"USAGE : %s <pid> <dll_path>
    ", argv[0]);
            return 1;
        }
    
        // inject dll
        if (InjectDll((DWORD)_tstol(argv[1]), argv[2]))
            _tprintf(L"InjectDll("%s") success!!!
    ", argv[2]);
        else
            _tprintf(L"InjectDll("%s") failed!!!
    ", argv[2]);
        
        return 0;
    
    }
    

    这一部分代码,我在编译时并没有遇到问题,编译平台也是VS2019

    接下来是利用OD调试myhack.dll:

    首先我们打开一个未注入myhack.dll的notepad:

    然后利用OD的attach功能,将notepad(附加)加载进OD(注意,OD只能加载32的程序,我这里是64位系统,所以使用Xdbg进行调试)。

    notepad加载进来后,会首先暂停,这里我们在选项中进行设置:

    打开DLL加载,这样程序在加载DLL时,OD(Xdbg,虽然使用的是Xdbg,但在后面我都会用OD记录)就会自动断下来。

    接着我们打开InjectDLL.exe,将myhack.dll加载进notepad,回车的瞬间,OD断了下来。

    这里OD断下来的,不是myhack.dll,因为在加载myhack.dll之前,会先加载其他的dll,所以我们只需要F9运行到myhack.dll就行:

  • 相关阅读:
    判断IE浏览器的版本号
    解决下拉框第一行出现空格的问题
    Springboot整合log4j2日志全解
    Java NIO之Selector(选择器)
    ZooKeeper客户端 zkCli.sh 节点的增删改查
    Java API操作ZooKeeper
    ReentrantLock(重入锁)功能详解和应用演示
    MySQL高可用集群方案
    Redis高可用之集群配置(六)
    linux free命令详解
  • 原文地址:https://www.cnblogs.com/lex-shoukaku/p/13718319.html
Copyright © 2011-2022 走看看