• 高级远程线程注入NtCreateThreadEx


    高级远程线程注入NtCreateThreadEx

    一丶简介

    在Windows下NtCreateThreadExCreateRemoteThread的底层函数。RtlCreateUserThread 也是对 NtCreateThreadEx的一层包装

    所以着重一下研究NtCreateThreadEx函数

    二丶原型

    2.1 函数原型

    NtCreateThreadEx在32位下和64位下函数原型不一致。

    结构如下:

    #ifdef _AMD64_
    typedef DWORD(WINAPI* PfnZwCreateThreadEx)(
        PHANDLE ThreadHandle,
        ACCESS_MASK DesiredAccess,
        LPVOID ObjectAttributes,
        HANDLE ProcessHandle,
        LPTHREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        ULONG CreateThreadFlags,
        SIZE_T ZeroBits,
        SIZE_T StackSize,
        SIZE_T MaximunStackSize,
        LPVOID pUnkown);
    
    
    #else
    
    typedef DWORD(WINAPI *PfnZwCreateThreadEx)(
        PHANDLE ThreadHandle,
        ACCESS_MASK DesiredAccess,
        LPVOID ObjectAttributes,
        HANDLE ProcessHandle,
        LPTHREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        BOOL CreateThreadFlags,
        DWORD  ZeroBits,
        DWORD  StackSize,
        DWORD  MaximumStackSize,
        LPVOID pUnkown);
    
    #endif // DEBUG
    

    如果要想使用 NtCreateThreadEx函数。那么就需要从NtDll中以动态的方式导出使用。

    2.2 远程线程注入代码

    远程线程代码注入分为如下几个步骤

    • OpenProcess 打开要注入的进程
    • VirtualAllocEx 在被注入的进程中申请读写内存
    • WriteProcessMemory 写入DLL路径到申请的内存中
    • VirtualProtectEx 修改内存保护属性,这一步可以不需要使用。
    • CreateRemoteThread 创建远程线程,高级远程线程注入可以 将此函数 替换为 NtCreateThreadEx
    • WaitForSingleObject 等待过程完成

    完整伪代码如下:

    BOOLEAN RemoteInject(DWORD pid, LPWSTR wszInjectDllPathName,ULONG uDllPathSize)
    {
        HANDLE hProc = NULL;
        LPVOID lpBuffer = NULL;
        SIZE_T dwWriteBytes = 0;
        DWORD dwRetErrorCode = 0;
        HANDLE hThreadHandle = NULL;;
        PVOID pfnLoadLibraryW = NULL;
        HMODULE ntdll = NULL;
        HMODULE k32 = NULL;
        bool bIsOk = FALSE;
    
        do {
            ntdll = LoadLibrary(TEXT("ntdll.dll"));
            if (ntdll == NULL)
            {
                break;
            }
            k32 = LoadLibrary(TEXT("kernel32.dll"));
            if (k32 == NULL)
            {
                break;
            }
            m_ZwCreateThreadEx = reinterpret_cast<PfnZwCreateThreadEx>(GetProcAddress(ntdll, "ZwCreateThreadEx"));
            if (NULL == m_ZwCreateThreadEx)
            {
                break;
            }
            pfnLoadLibraryW = reinterpret_cast<PVOID>(::GetProcAddress(k32, "LoadLibraryW"));
            if (pfnLoadLibraryW == NULL)
            {
                break;
            }
            hProc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
            if (hProc == NULL)
            {
                break;
            }
            lpBuffer = VirtualAllocEx(hProc, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            if (NULL == lpBuffer)
            {
                break;
            }
            dwRetErrorCode = WriteProcessMemory(hProc, lpBuffer, wszInjectDllPathName, uDllPathSize, &dwWriteBytes);
            if (0 == dwRetErrorCode)
            {
                break;
            }
    
            m_ZwCreateThreadEx(&hThreadHandle, PROCESS_ALL_ACCESS, NULL, hProc, (LPTHREAD_START_ROUTINE)pfnLoadLibraryW, lpBuffer, 0, 0, 0, 0, NULL);
            WaitForSingleObject(hProc, 2000);
            if (NULL == hThreadHandle)
            {
                break;
            }
            bIsOk = TRUE;
        } while (FALSE);
    
        if (NULL != lpBuffer)
        {
            VirtualFreeEx(hProc, lpBuffer, 0, MEM_RELEASE);
            lpBuffer = NULL;
        }
        if (NULL != hProc)
        {
            CloseHandle(hProc);
            hProc = NULL;
        }
        if (NULL != hThreadHandle)
        {
            CloseHandle(hThreadHandle);
            hThreadHandle = NULL;
        }
        if (k32 != NULL)
        {
            FreeLibrary(k32);
            k32 = NULL;
        }
        if (ntdll != NULL)
        {
            FreeLibrary(ntdll);
            ntdll = NULL;
        }
        return bIsOk;
    }
    

    注意: uDllPathSize 是DLL全路径的空间长度。 如果是宽字符一定要 wcslen(str) * 2 才可以。

    代码经过验证 32位程序可以注入DLL到32位的进程。 64位进程可以注入dll到64位进程。

    32位进程不可注入DLL到64位进程。需要特殊方式。

  • 相关阅读:
    Log4j的配置
    Linux笔记
    面对一个个路口
    切图布局知识点(四)——不定宽有背景文字块居中
    切图布局知识点(三)——左右布局
    切图布局知识点(二)——高度100%
    切图布局知识点(一)
    window下静默执行python脚本
    mysql 允许远程连接
    linux 防火墙
  • 原文地址:https://www.cnblogs.com/iBinary/p/16026217.html
Copyright © 2020-2023  润新知