欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DLL注入系列之远程线程注入

程序员文章站 2024-03-02 11:56:52
...

最近打算复习一下,把注入的东西理一理,网上代码很多,就不啰嗦了

0x01 前言

DLL注入指的是向运行中的其他进程强制插入特定的DLL文件。从技术细节来说, DLL注人,命令其他进程自行调用LoadLibrary API,加载( Loading)用户指定的DLL文件。
使用LoadLibrary()API加载某个DLL时,该DLL中的DIIMain()函数就会被调用执行。DLL注人的工作原理就是从外部促使目标进程调用LoadLibrary()API (与一般DLL加载相同),所以会强制调用执行DLL的DIIMain()函数。并且,被注入的DLL拥有目标进程内存的访问权限,用户可以随意操作(修复Bug、添加功能等)。
注入的DLL成为EXE文件中的一部分,这样做的方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EXE文件中的API),或以被注入EXE的身份去执行一些操作等等。

0x02 写一个dll

我这里使用的是VS2019,先建一个新项目。然后选择项目模板,我这选择的是动态链接库(DLL),然后点击下一步。
DLL注入系列之远程线程注入
输入项目名称,点击创建
DLL注入系列之远程线程注入
建好以后,在dllmain.cpp里面输入你想执行的操作,我简单弹个窗,证明注入成功,然后编译,就会生成一个dll。
DLL注入系列之远程线程注入
TestDll.dll写好了,使用x32dbg来调试一下是否会弹窗,成功弹窗。
DLL注入系列之远程线程注入

0x03

下面开始写注入的代码,第一步先获取要注入进程的PID,作为参数传给InjectDll。

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <tlhelp32.h>

int main(int argc, CHAR* argv[])
{
    DWORD pid = GetProcessId((PTCHAR)L"notepad.exe");
    if (InjectDll(pid, (PCHAR)argv[1])!= -1)
    {
        printf("InjectDll(\"%s\") success!!!\n", argv[1]);
    }
    else
    {
        printf("InjectDll(\"%s\") failed!!!\n", argv[1]);
    }  
    return 0;
}

获取指定进程PID

DWORD GetProcessId(PTCHAR pszProcessName)
{
    HANDLE hProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (INVALID_HANDLE_VALUE == hProcess)
    {
        return 0;
    }

    DWORD dwProcessId = 0;

    PROCESSENTRY32 process32 = { 0 };
    process32.dwSize = sizeof(PROCESSENTRY32);

    BOOL bRetProcess = FALSE;
    bRetProcess = Process32First(hProcess, &process32);

    do
    {
        if (_tcscmp(pszProcessName, process32.szExeFile) == 0)
        {
            dwProcessId = process32.th32ProcessID;
            break;
        }

        bRetProcess = Process32Next(hProcess, &process32);
    } while (bRetProcess);
    CloseHandle(hProcess);

    return dwProcessId;
}

然后准备开始注入,首先得提升自己进程的权限,要不然后被拒绝访问,导致注入失败

int EnablePrivilege(bool isStart)
{
    //1. 得到令牌句柄  
    HANDLE  hToken = NULL;      //令牌句柄    
    if (!OpenProcessToken(GetCurrentProcess(),//GetCurrentProcess 检索当前进程的伪句柄 OpenProcessToken得到进程的令牌句柄
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,
        &hToken))
    {
        return FALSE;
    }

    //2. 得到特权值  
    LUID    luid = { 0 };         //特权值  
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
    {
        return FALSE;
    }
    //3. 提升令牌句柄权限  
    TOKEN_PRIVILEGES tp = { 0 };  //令牌新权限  
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = isStart ? SE_PRIVILEGE_ENABLED : 0;
    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
    {
        return FALSE;
    }
    //4. 关闭令牌句柄  
    CloseHandle(hToken);
    return 0;
}

远线程注入原理是利用Windows 系统中CreateRemoteThread()这个API,其中第4个参数是准备运行的线程,我们可以将LoadLibrary()填入其中,这样就可以执行远程进程中的LoadLibrary()函数,进而将我们自己准备的DLL加载到远程进程空间中执行。

int InjectDll(DWORD dwProcessId, PCHAR szDllName)
{
    if (szDllName[0] == NULL)
        return -1;
    //提高权限相关操作  
    EnablePrivilege(TRUE);
    //1. 打开进程  
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,   //打开进程权限  
        FALSE,                                              //是否可继承   
        dwProcessId);                                       //进程ID  

    if (hProcess == INVALID_HANDLE_VALUE)
        return -1;

    //2. 在远程进程中申请空间  
    LPVOID pszDllName = VirtualAllocEx(hProcess, //远程进程句柄  
        NULL,                                  //建议开始地址  
        4096,                                  //分配空间大小  
        MEM_COMMIT,                            //空间初始化全0  
        PAGE_EXECUTE_READWRITE);               //空间权限  

    if (NULL == pszDllName)
    {
        return -1;
    }

    //3. 向远程进程中写入数据  
    BOOL bRet = WriteProcessMemory(hProcess, pszDllName,
        szDllName, MAX_PATH, NULL);

    if (NULL == bRet)
    {
        return -1;
    }

    //4. 在远程进程中创建远程线程  
    HANDLE m_hInjecthread = CreateRemoteThread(hProcess,      //远程进程句柄  
        NULL,                                            //安全属性  
        0,                                               //栈大小  
        (LPTHREAD_START_ROUTINE)LoadLibraryA,             //进程处理函数      
        pszDllName,                                      //传入参数  
        NULL,                                            //默认创建后的状态  
        NULL);                                           //线程ID  

    if (NULL == m_hInjecthread)
    {
        DWORD dwErr = GetLastError();
        return -1;
    }

    //5. 等待线程结束返回  
    DWORD dw = WaitForSingleObject(m_hInjecthread, -1);
    //6. 获取线程退出码,即LoadLibrary的返回值,即dll的首地址  
    DWORD dwExitCode;
    GetExitCodeThread(m_hInjecthread, &dwExitCode);
    HMODULE m_hMod = (HMODULE)dwExitCode;

    //7. 释放空间  
    BOOL bReturn = VirtualFreeEx(hProcess, pszDllName,
        4096, MEM_DECOMMIT);

    if (NULL == bReturn)
    {
        return -1;
    }

    CloseHandle(hProcess);
    hProcess = NULL;
    //恢复权限相关操作  
    EnablePrivilege(FALSE);

    return 0;
}

0x04 几个小坑

1、首先是编译程序的权限,选择requireAdministrator (/level=‘requireAdministrator’),但是貌似没什么用
DLL注入系列之远程线程注入
2、静态编译,选多线程(/MT)
DLL注入系列之远程线程注入
3、调试时别使用Release版本,不然编译器自动优化很难调,平台使用Win32
DLL注入系列之远程线程注入

0x05 效果

DLL注入系列之远程线程注入

相关标签: 学习笔记