RtlCreateUserThread例子

不同于CreateRemoteThread直接调用win api, RtlCreateUserThread是CreateRemoteThread的底层实现,所以使用RtlCreateUserThread的原理是和使用CreateRemoteThread的原理是一样的,这个函数可以实现跨会话创建线程。唯一的问题就是:当我们在Vista 之前的操作系统调用此函数所创建的线程并没有通知给csrss 进程,它没有完整的初始化,在调用一些网络或者其它的系统函数的时候他可能返回失败,而通过CreateRemoteThread 创建的线程没有任何问题,在Vista+的操作系统上调用此函数也没有问题。因此我们需要判断系统版本,当目标系统为Vista-的时候,我们应该通过RtlCreateUserThread创建一个挂起的线程,然后调用CsrClientCallServer通知csrss 这个线程的创建,然后csrss 做相应的记录及初始化工作之后,我们再恢复线程的执行。最后,我们新创建的线程必须自己调用ExitThread退出,否则也会产生崩溃的情况。
LoadLibraryW函数调用原型:

typedef DWORD(WINAPI* pRtlCreateUserThread)(    //函数原型
    IN HANDLE                     ProcessHandle,
    IN PSECURITY_DESCRIPTOR     SecurityDescriptor,
    IN BOOL                     CreateSuspended,
    IN ULONG                    StackZeroBits,
    IN OUT PULONG                StackReserved,
    IN OUT PULONG                StackCommit,
    IN LPVOID                    StartAddress,
    IN LPVOID                    StartParameter,
    OUT HANDLE                     ThreadHandle,
    OUT LPVOID                    ClientID
    );

LoadLibraryW
函数shellcode:

BYTE StaticShellCode[31] = { 0xE8,0,0,0,0,  // call (5字节)           4
        0x5D,           // pop ebp              5
        0x8B,0xC5,  // mov eax,ebp          7
        0x83,0xC0,0x1A, // add eax,1a       10
        0x50,       // push eax             11
        0xB8,0,0,0,0,   // mov eax,LoadLibraryW 16
        0xFF,0xD0,  // call eax             18
        0x6A,0,     // push 0               20
        0xB8,0,0,0,0,   // mov eax,ExitThread   25
        0xFF,0xD0,  // call eax             27
        0xC3,   // ret 4                28
        0};

代码如下:
(整体逻辑一样,就不详细备注)

#include <Windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <iostream>
#include <string>
DWORD findPidByName(const char* pname) //获得pid函数,对上面的查找进行改进
{
    HANDLE h;
    PROCESSENTRY32 procSnapshot;
    h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    procSnapshot.dwSize = sizeof(PROCESSENTRY32);

    do
    {
        if (!_stricmp(procSnapshot.szExeFile, pname))
        {
            DWORD pid = procSnapshot.th32ProcessID;
            CloseHandle(h);
#ifdef _DEBUG
            printf(("[+]进程地址: %ld\n"), pid);
#endif
            return pid;
        }
    } while (Process32Next(h, &procSnapshot));

    CloseHandle(h);
    return 0;
}

typedef DWORD(WINAPI* pRtlCreateUserThread)(    //函数申明
    IN HANDLE                     ProcessHandle,
    IN PSECURITY_DESCRIPTOR     SecurityDescriptor,
    IN BOOL                     CreateSuspended,
    IN ULONG                    StackZeroBits,
    IN OUT PULONG                StackReserved,
    IN OUT PULONG                StackCommit,
    IN LPVOID                    StartAddress,
    IN LPVOID                    StartParameter,
    OUT HANDLE                     ThreadHandle,
    OUT LPVOID                    ClientID
    );

DWORD RtlCreateUserThread(LPCSTR pszLibFile, DWORD dwProcessId)
{
    pRtlCreateUserThread RtlCreateUserThread = NULL;
    HANDLE  hRemoteThread = NULL;

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); //打开目标进程pid
    if (hProcess == NULL)
    {
        printf("[-] Error: Could not open process for PID (%d).\n", dwProcessId);
        exit(1);
    }

    LPVOID LoadLibraryAddress = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");  //load函数地址
    if (LoadLibraryAddress == NULL)
    {
        printf(("[-] Error: Could not find LoadLibraryA function inside kernel32.dll library.\n"));
        exit(1);
    }

    RtlCreateUserThread = (pRtlCreateUserThread)GetProcAddress(GetModuleHandle(("ntdll.dll")), ("RtlCreateUserThread"));//获取Rtl函数地址
    if (RtlCreateUserThread == NULL)
    {
        exit(1);
    }

#ifdef _DEBUG
    printf(("[+]RtlCreateUserThread函数地址: 0x%08x\n"), (UINT)RtlCreateUserThread);
    printf(("[+]LoadLibraryA函数地址: 0x%08x\n"), (UINT)LoadLibraryAddress);
#endif

    DWORD dwSize = (strlen(pszLibFile) + 1) * sizeof(char);

    LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);//开辟一段地址
    if (lpBaseAddress == NULL)
    {
        printf(("[-] Error: Could not allocate memory inside PID (%d).\n"), dwProcessId);
        exit(1);
    }

    BOOL bStatus = WriteProcessMemory(hProcess, lpBaseAddress, pszLibFile, dwSize, NULL);  //目标dll写入
    if (bStatus == 0)
    {
        printf(("[-] Error: Could not write any bytes into the PID (%d) address space.\n"), dwProcessId);
        return(1);
    }

    bStatus = (BOOL)RtlCreateUserThread(
        hProcess,
        NULL,
        0,
        0,
        0,
        0,
        LoadLibraryAddress,  //shellcode
        lpBaseAddress,
        &hRemoteThread,
        NULL);
    if (bStatus < 0)
    {
        printf(("[-]注入失败\n"));
        return(1);
    }
    else
    {
        printf(("[+]注入成功...\n"));
        WaitForSingleObject(hRemoteThread, INFINITE);

        CloseHandle(hProcess);
        VirtualFreeEx(hProcess, lpBaseAddress, dwSize, MEM_RELEASE);
        return(0);
    }

    return(0);
}
int main()
{
    const char* name = ("calc.exe");

    DWORD pId = findPidByName(name);
    LPCSTR location = ("c:\\test.dll");

    RtlCreateUserThread(location, pId);
}
上一篇:内存操作的几个函数


下一篇:windows平台下 c++获取 系统版本 网卡 内存 CPU 硬盘 显卡信息