• 【windows核心编程】使用远程线程注入DLL


     

    前言

    该技术是指通过在【目标进程】中创建一个【远程线程】来达到注入的目的。

    创建的【远程线程】函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写。

     

     示意图如下:

     

     

     

     相关API

    1、创建远程线程

    //该函数除了第一个参数为目标进程句柄外
    //其他参数均和CreateThread一样
    HANDLE hThread = CreateRemoteThread( 
                    __in HANDLE  hProcess,  //目标进程句柄
                    __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 
                    __in SIZE_T dwStackSize,     //线程栈初始预定空间=Max(/STACK, dwStackSize, 初始调拨大小=(dwStackSize == 0?  /STACK, dwStackSize)
                    __in LPTHREAD_START_ROUTINE lpStartAddress, //线程函数
                    __in_opt LPVOID lpParameter,    //线程函数参数
                    __in DWORD dwCreationFlags,     //标志
                    __out_opt LPDWORD lpThreadId    //线程ID
                   )

     

     失败返回NULL

    2、根据进程ID获取进程句柄,并且传入相应权限标志,自定义函数

    //根据进程ID获取进程句柄
    HANDLE GetProcessHandle(DWORD deProcessID)
    {
        HANDLE hProcess = OpenProcess(
            PROCESS_QUERY_INFORMATION  //查询进程句柄
            | PROCESS_VM_OPERATION     //PROCESS_VM_WRITE + PROCESS_VM_READ + x 
            | PROCESS_CREATE_THREAD    //创建线程
            | PROCESS_VM_WRITE,        //WriteProcessMemory
            FALSE,                     //不继承
            deProcessID                //进程句柄
            ); 
    
        return hProcess;
    }

     

     

    3、获得LoadLibrary函数地址

    由于LoadLibrary是个宏,而非实际的函数,因此需要使用GetProcAddress并传入LoadLibraryW 或 LoadLibraryA来获取真实地址

     

     4、从目标进程申请内存

    当把Dll名字作为线程函数LoadLibraryW(A)的参数传给他时,由于此时的线程是运行在其他进程地址空间中的,因此当把本地进程中的字符串指针传给CreateRemoteThread函数时会引起访问违例,因此需要从目标进程地址空间中申请内存,并将本地Dll名字符串写入远程进程,然后使用远程进程中的地址作为CreateRemoteThread函数的参数。

    //该函数除了第一个参数为进程句柄外
    //其他参数和VirtualAlloc一样
    LPVOID WINAPI VirtualAllocEx(
      __in      HANDLE hProcess,       //进程句柄
      __in_opt  LPVOID lpAddress,   //地址,为NULL自动找一个合适的地址
      __in      SIZE_T dwSize,           //内存块大小,单位为字节
      __in      DWORD flAllocationType, //分配类型,预定或调拨
      __in      DWORD flProtect             //保护属性
    );

    5、往远程进程中写输入, 即把本地DLL名字字符串 写入 远程进程地址空间中

    BOOL WINAPI WriteProcessMemory(
      __in   HANDLE hProcess,         //进程句柄
      __in   LPVOID lpBaseAddress, //写入地址
      __in   LPCVOID lpBuffer,          //源缓冲区
      __in   SIZE_T nSize,                 //缓冲区大小,单位为字节
      __out  SIZE_T *lpNumberOfBytesWritten  //实际写入的字节数
    );

     

     

    No code you say a XX

    本demo的作用是将一个DLL注入一个窗口标题为"Endl"的目标进程,该DLL的作用是在DLL_PROCESS_ATTACHExitProcess,即强制退出目标进程。

    开发进程代码

    //根据进程ID获取进程句柄
    HANDLE GetProcessHandle(DWORD deProcessID)
    {
        HANDLE hProcess = OpenProcess(
            PROCESS_QUERY_INFORMATION  //查询进程句柄
            | PROCESS_VM_OPERATION     //PROCESS_VM_WRITE + PROCESS_VM_READ + x 
            | PROCESS_CREATE_THREAD    //创建线程
            | PROCESS_VM_WRITE,        //WriteProcessMemory
            FALSE,                     //不继承
            deProcessID                //进程句柄
            ); 
    
        return hProcess;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        DWORD dwErrCode = 0;
    
        //获取进程ID
        //HWND hWnd = FindWindow(NULL, _T("计算器"));
        HWND hWnd = FindWindow(NULL, _T("Endl"));
    
        DWORD dwProcessID = 0;
        GetWindowThreadProcessId(hWnd, &dwProcessID);
        HANDLE hDestProcess = GetProcessHandle(dwProcessID);
        if(NULL == hDestProcess) 
        {
            cerr<<"打开进程句柄失败"<<endl;
            return 0;
        }
    
    
        //获取KERNER32.DLL 模块句柄
        HMODULE hModule = GetModuleHandle(_T("kernel32.dll")); 
        if(NULL == hModule) 
        {
            cerr<<"获取kernel32.dll句柄失败"<<endl;
            return -1;
        }
    
        //线程函数,kernerl32.dll被映射到所有进程内相同的地址
        LPTHREAD_START_ROUTINE lpThreadStartRoutine = 
    (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryW");
    if(NULL == lpThreadStartRoutine) { cerr<<"获取LoadLibraryW地址失败"<<endl; return -2; } //从目标进程内申请堆内存 LPVOID lpMemory = VirtualAllocEx(
    hDestProcess, NULL, MAX_PATH, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if(NULL == lpMemory) { cerr<<"申请目标进程内存失败"<<endl; return -3; } //注入DLL LPCTSTR lpDLLName = _T("DLLForRemoteThread.dll"); //把DLL名字写入目标进程 BOOL bWriteMemory = WriteProcessMemory( hDestProcess, lpMemory, lpDLLName, (_tcslen(lpDLLName) + 1) * sizeof(lpDLLName[0]), NULL); if(FALSE == bWriteMemory) { cerr<<"WriteProcessMemory失败"<<endl; dwErrCode = GetLastError(); VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT); return -4; } //创建远程线程 HANDLE hThread = CreateRemoteThread( hDestProcess, NULL, 0, lpThreadStartRoutine, lpMemory, 0, NULL); if (NULL == hThread || INVALID_HANDLE_VALUE == hThread) { cerr<<"创建远程线程CreateRomoteThread失败"<<endl; VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT); return -5; } VirtualFreeEx(hModule, lpMemory, 0, MEM_RELEASE | MEM_DECOMMIT); return 0; }

     

     

     

     待注入DLL代码

    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch(ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
    #if defined _DEBUG
            OutputDebugString(TEXT("
    *************DLL_PROCESS_ATTACH*************"));
    #endif
            ExitProcess(1);
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
        }
    
        return TRUE;
    }

     

      

      

  • 相关阅读:
    表示数值的字符串(C++描述)
    单链表是否有环及环入口点
    医院信息运维系统-信息科专用运维系统
    c# List 按类的指定字段排序
    运维系统说明
    更新库下载
    mysql数据库备份
    网络编程基础
    面向对象和过程,一样的价格,不一样的口味
    模块的导入顺序细节
  • 原文地址:https://www.cnblogs.com/cuish/p/3804990.html
Copyright © 2020-2023  润新知