游戏安全实验室 首页 技术入门 查看内容

 阅读目录

远线程注入

发布于:2016-6-27 19:28   |    177598次阅读 作者: 管理员    |   原作者: TP   |   来自: 原创

一. 概述

       远线程注入是指为要注入的目标进程创建一个远程线程,在远程线程里面加载要注入目标dll。Windows操作系统提供了跨进程的内存读写机制,这就为各种注入打下了基础。

二. 用到的Windows API函数

创建远程线程的APICreateRemoteThread,查找msdn其函数原型如下所示:HANDLE WINAPI CreateRemoteThread(

  _In_  HANDLE                 hProcess,//目标进程的句柄

  _In_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,//安全属性

  _In_  SIZE_T                 dwStackSize,//初始堆栈大小

  _In_  LPTHREAD_START_ROUTINE lpStartAddress,//线程要执行的函数

  _In_  LPVOID                 lpParameter,//线程函数传递的参数

  _In_  DWORD                  dwCreationFlags,//线程的一些标志

  _Out_ LPDWORD                lpThreadId//创建好的线程ID

)

三. 远线程注入的原理

,为要注入的目标进程创建远程线程后,线程的执行函数是参数lpStartAddress指向的函数原型为:

 DWORD WINAPI ThreadProc(

   _In_ LPVOID lpParameter

)

一个参数lpParameter就是创建远线程时传入的参数。这个函数原型跟加载dll的API函数LoadLibrary比较发现,二者的形似一样。如下所示

HMODULE WINAPI LoadLibrary(

   _In_ LPCTSTR lpFileName

)

lpStartAddress传入的参数设置为指向LoadLibrary的函数指针,lpParameter为指向要加载dll的路径名称那么就可以把dll注入到目标进程。其中dll的路径名称要写入到目标进程内存空间中,可以使用Windows API函数完成这项工作。首先,需要在目标进程里面分配一块保存dll路径名的内存可以用函数VirtualAllocEx分配,原型如下:

LPVOID WINAPI VirtualAllocEx(

  _In_     HANDLE hProcess,//进程句柄

  _In_opt_ LPVOID lpAddress,//希望分配的内存位置

  _In_     SIZE_T dwSize,//分配的大小

  _In_     DWORD  flAllocationType,//分配类型

  _In_     DWORD  flProtect//保护属性

);调用这个函数,即可在目标进程内分配一块内存,用来保存dll路径名称,函数的返回地址是分配的内存地址。

剩下的就是调用WriteProcessMemory函数把要注入的dll路径名写入到分配的这块内存中,函数原型如下:

BOOL WINAPI WriteProcessMemory(

  _In_  HANDLE  hProcess,//进程句柄

  _In_  LPVOID  lpBaseAddress,//写入的起始地址

  _In_  LPCVOID lpBuffer,//写入的内容

  _In_  SIZE_T  nSize,//要写入的大小

  _Out_ SIZE_T  *lpNumberOfBytesWritten//时机写了多少个字节

)

四. 代码实现

以上的过程串联起来第一步,调用OpenProcess打开目标进程获得句柄第二步调用VirtualAllocEx分配内存第三步,调用LoadLibraryGetProcAddress获得LoadLibraryA函数的地址第四调用WriteProcessMemory把dll路径名称写入到分配的内存中。第五步,创建线程。详细过程如附件的代码所示。关键代码如下所示。

void LoadMyDll(DWORD dwPid, char* pDllName)
{
    HANDLE hProc = NULL;
    HANDLE hRemoteThread = NULL;
    BYTE* pbyDllNameBuf = NULL;

    do
    {
        hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);//获得进程句柄
        if (NULL == hProc)
        {
            printf("[LoadMyDll]OpenProcess Fails\n");
            break;
        }

        DWORD dwDllNameStrLen = strlen(pDllName) + 2;
        pbyDllNameBuf = (BYTE*)VirtualAllocEx(hProc, NULL, dwDllNameStrLen, MEM_COMMIT, PAGE_READWRITE);//目标进程分配内存
        if (!pbyDllNameBuf)
        {
            printf("[LoadMyDll]VirtualAllocEx Fails\n");
            CloseHandle(hProc);
            break;
        }
/*把dll名字写入到目标进程空间*/
        if (!WriteProcessMemory(hProc, pbyDllNameBuf, pDllName, dwDllNameStrLen, NULL))
        {
            printf("[LoadMyDll]WriteProcessMemory Fails\n");
            VirtualFreeEx(hProc, (PVOID)pbyDllNameBuf, 0, MEM_RELEASE);
            break;
        }

        PTHREAD_START_ROUTINE pfnRemoteThreadProc = NULL;
        pfnRemoteThreadProc = (PTHREAD_START_ROUTINE)GetProcAddress((HMODULE)LoadLibraryA("kernel32.dll"), "LoadLibraryA");//得到加载dll的函数地址
        if (!pfnRemoteThreadProc)
        {
            printf("[LoadMyDll]GetProcAddress Fails\n");
            break;
        }

        hRemoteThread = CreateRemoteThread(hProc, NULL, 0, pfnRemoteThreadProc, (PVOID)pbyDllNameBuf, 0, NULL);//创建远程线程
        if (!hRemoteThread)
        {
            printf("[LoadMyDll]CreateRemoteThread Fails\n");
            break;
        }
    } while (0);

    WaitForSingleObject(hRemoteThread, INFINITE);//远程线程退出后的清理工作
    if (hProc)
    {
        CloseHandle(hProc);
    }
    if (hRemoteThread)
    {
        CloseHandle(hRemoteThread);
    }
    if (pbyDllNameBuf)
    {
        VirtualFreeEx(hProc, (PVOID)pbyDllNameBuf, 0, MEM_RELEASE);
    }
}

 

Demo运行结果如下图所示。

五. 思考

    为什么LoadLibraryA函数的地址所有进程都一样?试试在文章后面的Demo基础上添加卸载dll的代码(提示:FreeLibrary)。


*转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩0 赞0

收藏

上一篇:挂起进程注入

下一篇:游戏函数调用及内嵌CALL细节须知

最新评论
B Color Image Link Quote Code Smilies

发表评论