继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

InlineHookSwapContext

holdtom
关注TA
已关注
手记 1885
粉丝 240
获赞 992


作用:

枚举进程, 获取隐藏进程的EPROCESS

源码地址:

https://github.com/haidragon/HookSwapContext

#include <ntddk.h>

#include <ntimage.h>

#include <ntdef.h>

#include "hash.h"

#include "xde.h"

#include "main.h"

typedef struct _BYTECODE

{

    BYTE *pAddress;

    SIZE_T size;

} BYTECODE, *PBYTECODE;

typedef struct _OFFSETS

{

    BYTE threadsProcess;

    BYTE CID;

    BYTE imageFilename;

    BYTE crossThreadFlags;

    unsigned  PID;

    unsigned PPID;

    unsigned pecreatetimeoff;

    unsigned peexittimeoff;

} OFFSETS, *POFFSETS;

#define JMP_SIZE 5

#define SIG_SIZE 20

#define HASHTABLE_SIZE 256

#define MAINTAG1 'NIAM'

// NOTICE: WinDbg gives offsets in BYTEs, we use DWORDS.

OFFSETS offsets;

// The beginning of the SwapContext function is stored here.

BYTE *pSwapContext = NULL;

// The trampoline function which executes the replaced code and

// passes control to the hooked function.

BYTECODE trampoline;

// Inline assembler does not support structures, so this points

// directly to the pCode of the _BYTECODE structure.

BYTE *pTrampoline = NULL;

// The hashtable where we store the data.

PHASHTABLE pHashTable = NULL;

DWORD num = 0;

extern  USHORT  *NtBuildNumber;

const WCHAR deviceLinkBuffer[]  = L"\\DosDevices\\SwapContextDrv";

const WCHAR deviceNameBuffer[]  = L"\\Device\\SwapContextDrv";

PDEVICE_OBJECT g_HookDevice;

ULONG gNameOffset = 0x174;

PsLookupThreadByThreadId(

        IN PVOID UniqueThreadId,

        OUT PETHREAD *ppEthread

);

KIRQL           OldIrql;

KSPIN_LOCK      DpcSpinLock;

ULONG GetLocationOfProcessName(PEPROCESS CurrentProc)

{

    ULONG ul_offset;

    for(ul_offset = 0; ul_offset < PAGE_SIZE; ul_offset++) // This will fail if EPROCESS

                                                           // grows bigger than PAGE_SIZE

    {

        if( !strncmp( "System", (PCHAR) CurrentProc + ul_offset, strlen("System")))

        {

            return ul_offset;

        }

    }

    return (ULONG) 0;

}

// This function returns an MDL to an nonpaged virtual memory area.

// 

// IN pVirtualAddress Virtual address to the start of the memory area.

// IN length Length of the memory area in bytes.

//

// OUT PMDL Mdl to the nonpaged virtual memory area.

//

PMDL GetMdlForNonPagedMemory(PVOID pVirtualAddress, SIZE_T length)

{

    PMDL pMdl;

    if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))

    {

        DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");

        return NULL;

    }

    pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);

    if (NULL == pMdl)

    {

        DbgPrint("IoAllocateMdl returned NULL!\n");

        return NULL;

    }

    MmBuildMdlForNonPagedPool(pMdl);

    return pMdl;

}

// This function returns an MDL to a paged virtual memory area while

// making sure the pages are not paged out to the disk.

// 

// IN pVirtualAddress Virtual address to the start of the memory area.

// IN length Length of the memory area in bytes.

// IN operation Desired mode of operation.

//

// OUT PMDL Mdl to the locked and nonpaged memory area.

//

PMDL GetMdlForPagedMemory(PVOID pVirtualAddress, SIZE_T length, LOCK_OPERATION operation)

{

    PMDL pMdl;

    if (length >= (PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)))

    {

        DbgPrint("Size parameter passed to IoAllocateMdl is too big!\n");

        return NULL;

    }

    pMdl = IoAllocateMdl((PVOID)pVirtualAddress, length, FALSE, FALSE, NULL);

    if (NULL == pMdl)

    {

        DbgPrint("IoAllocateMdl returned NULL!\n");

        return NULL;

    }

    // Make sure the memory is not paged on the disk.

    try

    {

        MmProbeAndLockPages(pMdl, KernelMode, operation);

    }

    except (EXCEPTION_EXECUTE_HANDLER)

    {

        DbgPrint("MmProbeAndLockPages caused an exception!\n");

        IoFreeMdl(pMdl);

        return NULL;

    }

    return pMdl;

}

// This function writes the given data to the given non-paged kernel memory location.

// It makes sure that no other instance can access it in any way until we have finished

// our job.

//

// IN pDestination Pointer to the kernel memory where we want to write.

// IN pSource Pointer to the data we want to write.

// IN length Length of data we want to write in bytes.

//

// OUT NTSTATUS return code.

//

NTSTATUS WriteKernelMemory(BYTE *pDestination, BYTE *pSource, SIZE_T length)

{

    KSPIN_LOCK spinLock;

    KLOCK_QUEUE_HANDLE lockHandle;

    PMDL pMdl;

    PVOID pAddress;

    pMdl = GetMdlForNonPagedMemory(pDestination, length);

    if (NULL == pMdl)

    {

        DbgPrint("GetMdlForSafeKernelMemoryArea returned NULL!\n");

        return STATUS_UNSUCCESSFUL;

    }

    pAddress = MmGetSystemAddressForMdlSafe(pMdl, HighPagePriority);

    if (pAddress == NULL)

    {

        IoFreeMdl(pMdl);

        DbgPrint("MmGetSystemAddressForMdlSafe returned NULL!\n");

        return STATUS_UNSUCCESSFUL;

    }

    KeInitializeSpinLock(&spinLock);

    // Only supported on XP and later. For Windows 2000 compatibility you can

    // use the older, less efficient and less reliable KeAcquireSpinLock function.

    KeAcquireInStackQueuedSpinLock (&spinLock, &lockHandle);

    // We have the spinlock, so we can safely overwrite the kernel memory.

    RtlCopyMemory(pAddress, pSource, length);

    KeReleaseInStackQueuedSpinLock(&lockHandle);

    IoFreeMdl(pMdl);

    return STATUS_SUCCESS;

}

void __stdcall ProcessData(DWORD *pEthread)

{

    DWORD   *pEprocess  = (DWORD *)*(pEthread + offsets.threadsProcess);

    DWORD   *pCid       = (DWORD *)(pEthread+offsets.CID);

    DWORD   key         = 0;

    DATA    data        = {0};

    data.processID = 0x0;

    data.threadID = 0x0;

    data.imageName = "NONE";

    key = (DWORD)pEthread;

    if (pCid != NULL)

    {

        data.processID = *pCid;

        data.threadID = *(pCid + 0x1);

    }

    if (pEprocess != NULL)

    {

        data.imageName = (BYTE *)(pEprocess+offsets.imageFilename);

        data.xlow = *(DWORD *)(pEprocess+offsets.peexittimeoff);

        data.xhigh = *(DWORD *)(pEprocess+offsets.peexittimeoff+4);

    }

    if (*(pEthread + offsets.crossThreadFlags) & 1)

    {

        KeAcquireSpinLock(&DpcSpinLock,&OldIrql);

        Remove(key, pHashTable);

        KeReleaseSpinLock(&DpcSpinLock,OldIrql);

    }

    else

    {

        KeAcquireSpinLock(&DpcSpinLock,&OldIrql);

        Insert(key, &data, pHashTable);

        KeReleaseSpinLock(&DpcSpinLock,OldIrql);

    }

}

void __declspec(naked) DetourFunction()

{

    __asm 

    {

        // Save parameters we will overwrite. We save all data to play it safe.

        pushad

        pushfd

        // Disable interrupts. Assume single processor machine.

        // cli

        // EDI holds the thread whose context we will switch out.

        push edi//edi寄存器中存放的是要切换出去的线程

        call ProcessData

        // ESI holds the thread whose context we will switch in.

        push esi

        call ProcessData

        // Enable interrupts.

        // sti

        // Restore the saved state.

        popfd

        popad

        // Jump to the trampoline function.

        jmp dword ptr pTrampoline//弹簧床

    }

}

BYTE * GetSwapAddr()

{

    BYTE        *res = 0;

    NTSTATUS    Status;

    PETHREAD    Thread;

    if (*NtBuildNumber <= 2195)

        Status = PsLookupThreadByThreadId((PVOID)4, &Thread);

    else

        Status = PsLookupThreadByThreadId((PVOID)8, &Thread);

    if (NT_SUCCESS(Status))

    {

        if (MmIsAddressValid(Thread))

            res = (BYTE *)(*(ULONG *)((BYTE *)(Thread)+0x28));

        if (MmIsAddressValid(res+8))

            res = (BYTE *)(*(ULONG *)(res+8));

        else

            res = 0;

    }

    return res;

}

ULONG GetFunctionAddr( IN PCWSTR FunctionName)

{

        UNICODE_STRING UniCodeFunctionName;

        RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );

        return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );    

}

VOID DoFindSwap(IN PVOID pContext)

    {

        NTSTATUS ret;

        PSYSTEM_MODULE_INFORMATION  module = NULL;

        ULONG n=0;

        void  *buf    = NULL;

        ULONG ntosknlBase;

        ULONG ntosknlEndAddr;

        ULONG curAddr;

        ULONG code1_sp1=0xc626c90a,code2_sp1=0x9c022d46,code3_sp1=0xbb830b8b,code4_sp1=0x00000994;

        ULONG code1,code2,code3,code4;

        ULONG i;

        NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)GetFunctionAddr(L"NtQuerySystemInformation");

        if (!NtQuerySystemInformation) 

        {

            DbgPrint("Find NtQuerySystemInformation faild!");

            goto Ret;

        }

        ret=NtQuerySystemInformation(SystemModuleInformation,&n,0,&n);

        if (NULL==( buf=ExAllocatePoolWithTag(NonPagedPool, n, 'PAWS')))

        {

            DbgPrint("ExAllocatePool() failed\n" );

            goto Ret;

        }

        ret=NtQuerySystemInformation(SystemModuleInformation,buf,n,NULL);

        if (!NT_SUCCESS(ret))   {

            DbgPrint("NtQuerySystemInformation faild!");

            goto Ret;

        } 

        module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1);

        ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;

        ntosknlBase=(ULONG)module->Base;

        curAddr=ntosknlBase;

        ExFreePool(buf);

        code1 = code1_sp1;

        code2 = code2_sp1;

        code3 = code3_sp1;

        code4 = code4_sp1;

        for (i=curAddr;i<=ntosknlEndAddr;i++)

        {

            if (*((ULONG *)i)==code1) 

            {

                if (*((ULONG *)(i+4))==code2) 

                {

                    if (*((ULONG *)(i+8))==code3) 

                    {

                        if (*((ULONG *)(i+12))==code4) 

                        {

                                pSwapContext=(BYTE *)i;

                                break;

                        }

                    }

                }

            }

        }

Ret:

    PsTerminateSystemThread(STATUS_SUCCESS);

    }

void FindSwapAddr()

{

        HANDLE  hThread     = NULL;

        PVOID   objtowait   = 0;

        NTSTATUS dwStatus = 

            PsCreateSystemThread(

            &hThread,

                  0,

               NULL,

            (HANDLE)0,

                  NULL,

               DoFindSwap,

            NULL

            );

        if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)

        {

            KfRaiseIrql(PASSIVE_LEVEL);

        }

        if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)

        {

            return;

        }

        ObReferenceObjectByHandle(

            hThread,

            THREAD_ALL_ACCESS,

            NULL,

            KernelMode,

            &objtowait,

            NULL

            ); 

        KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL); //NULL表示无限期等待.

        return;

}

NTSTATUS InstallSwapContextHook()

{

    NTSTATUS rc;

    int length = 0;

    int totalLength = 0;

    struct xde_instr instr;

    BYTE *pJmpCode = NULL;

    long displacement = 0;

    __asm

    {

            push    eax

            mov        eax, CR0

            and        eax, 0FFFEFFFFh

            mov        CR0, eax

            pop        eax

    }

    // Disassemble the code to get how many bytes we have to replace.

    // We use XDE v1.01 by Z0MBie (http://z0mbie.host.sk/).

    while (totalLength < 5)

    {

        length = xde_disasm(pSwapContext + totalLength, &instr);

        if (length == 0)

        {

            DbgPrint("xde_disasm returned 0!\n");

            return STATUS_UNSUCCESSFUL;

        }

        totalLength += length;

    }

    DbgPrint("Hook will replace the first %d bytes.\n", totalLength);

    // Allocate the required bytes for the trampoline function.

    //pTrampoline:是保存原来的被替换的指令+JMP指令

    pTrampoline = trampoline.pAddress = ExAllocatePoolWithTag(NonPagedPool, totalLength + 5, MAINTAG1);

    if (trampoline.pAddress == NULL)

    {

        DbgPrint("ExAllocatePoolWithTag returned NULL!\n");

        return STATUS_UNSUCCESSFUL;

    } 

    DbgPrint("Trampoline is at 0x%x\n", pTrampoline);

    // This tells how many bytes we replaced from the original function.

    //备份原来的指令

    trampoline.size = totalLength;

    RtlCopyMemory(trampoline.pAddress, pSwapContext, totalLength);

    // We are using JMP rel32 instruction to jump to the rest of the

    // swapcontext function, so we first calculate the 32bit displacement

    // and then create the five byte JMP instruction.

    //在备份完原来的指令后,在后面构造一个跳回去的jmp指令

    //displacement是跳回去的偏移

    displacement = (pSwapContext + totalLength) - (trampoline.pAddress + totalLength + JMP_SIZE);

    pJmpCode = trampoline.pAddress + totalLength;

    //直接的jmp分3种 

    //Short Jump(短跳转)机器码 EB rel8 

    //只能跳转到256字节的范围内 

    //Near Jump(近跳转)机器码 E9 rel16/32 

    //可跳至同一个段的范围内的地址 

    //Far Jump(远跳转)机器码EA ptr 16:16/32 

    //可跳至任意地址,使用48位/32位全指针 

    *pJmpCode = 0xe9;

    RtlCopyMemory(pJmpCode+1, &displacement, 4);

    //执行这个时候,被替换的指令备份就已经完成

    //接下来,就应该生成一个jmp指令,覆盖原来的指令

    // Allocate the required bytes for the jmp code to the detour function.

    pJmpCode = ExAllocatePoolWithTag(NonPagedPool, totalLength, MAINTAG1);

    if (pJmpCode == NULL)

    {

        DbgPrint("ExAllocatePoolWithTag returned NULL!\n");

        return STATUS_UNSUCCESSFUL;

    }

    // Initialize the jmp-code with NOPs.

    RtlFillMemory(pJmpCode, totalLength, 0x90);

    // We are using JMP rel32 instruction to jump to our hook function,

    // so we first calculate the 32bit displacement and then create the

    // five byte JMP instruction.

    displacement = ((BYTE *)&DetourFunction) - (pSwapContext + JMP_SIZE);

    *pJmpCode = 0xe9;

    RtlCopyMemory(pJmpCode+1, &displacement, 4);

    //inline hook完成

    rc = WriteKernelMemory(pSwapContext, pJmpCode, totalLength);

    ExFreePoolWithTag(pJmpCode, MAINTAG1);

    __asm

    {

        push    eax

            mov        eax, CR0

            or        eax, NOT 0FFFEFFFFh

            mov        CR0, eax

            pop        eax

    }

    return rc;

}

// This function removes our hook by restoring the bytes we have replaced

// from the original SwapContext function.

//

// OUT NTSTATUS return value.

//

NTSTATUS UninstallSwapContextHook()

{

    return WriteKernelMemory(pSwapContext, trampoline.pAddress, trampoline.size);

}

NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)

{

    NTSTATUS rc;

    UNICODE_STRING          deviceLinkUnicodeString;

    PDEVICE_OBJECT          p_NextObj;

    PPROCLIST pTemp = NULL, pt = NULL;

    PThreadData pTempT = NULL, pp = NULL;

    PDriverData pTempD = NULL, pd = NULL;

    PFileList pTempF = NULL, pf = NULL;

    DbgPrint("OnUnload called\n");

    rc = UninstallSwapContextHook();

    if (STATUS_SUCCESS == rc)

    {

        DbgPrint("UninstallSwapContextHook succeeded.\n");

    }

    else

    {

        DbgPrint("UninstallSwapContextHook failed!\n");

    }

    // Show the collected data and release all resources.

    //DumpTable(pHashTable);

    KeAcquireSpinLock(&DpcSpinLock,&OldIrql);

    DestroyTable(pHashTable);

    KeReleaseSpinLock(&DpcSpinLock,OldIrql);

    //num = 0;

    ExFreePoolWithTag(pTrampoline, MAINTAG1);

    // Delete the symbolic link for our device

    //

    RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );

    IoDeleteSymbolicLink( &deviceLinkUnicodeString );

    // Delete the device object

    //

    IoDeleteDevice( DriverObject->DeviceObject );

    //return STATUS_SUCCESS;

    return rc;

}

NTSTATUS DispatchCreate (

        IN PDEVICE_OBJECT   pDevObj,

        IN PIRP             pIrp            )

{

    pIrp->IoStatus.Status = STATUS_SUCCESS;

    pIrp->IoStatus.Information = 0; // no bytes xfered

    IoCompleteRequest( pIrp, IO_NO_INCREMENT );

    return STATUS_SUCCESS;

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

{

    RTL_OSVERSIONINFOW      osvi;

    NTSTATUS                ntStatus;

    UNICODE_STRING          deviceNameUnicodeString;

    UNICODE_STRING          deviceLinkUnicodeString;   

    RTL_OSVERSIONINFOEXW    VersionInfo;

    ULONGLONG               ConditionMask = 0;

    memset(&VersionInfo,0,sizeof(VersionInfo));

    VER_SET_CONDITION (

           ConditionMask,

            VER_SERVICEPACKMAJOR,

            VER_EQUAL

            );

    DbgPrint("DriverEntry called.\n");

    RtlZeroMemory(&osvi, sizeof(RTL_OSVERSIONINFOW));

    osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);

    // Initialize the OS specific data.

//  gNameOffset = GetLocationOfProcessName(PsGetCurrentProcess());

//  if (!gNameOffset)

//      return STATUS_UNSUCCESSFUL;

    if (STATUS_SUCCESS == RtlGetVersion(&osvi))

    {

        if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) //Windows XP

        {

            offsets.pecreatetimeoff = 0x070;

            offsets.peexittimeoff = 0x078;

            offsets.CID = 0x7b;

            offsets.threadsProcess = 0x88;

            offsets.crossThreadFlags = 0x92;

            offsets.imageFilename = 0x5d;

        }

        //VersionInfo.wServicePackMajor = 3;

        //if( STATUS_SUCCESS==RtlVerifyVersionInfo(&VersionInfo,VER_SERVICEPACKMAJOR,ConditionMask))//sp3

        //{

        //

        //}

        else

        {

            //更多的调试

            DbgPrint("Unsupported OS version!\n");

            return STATUS_UNSUCCESSFUL;

        }

    }

    else

    {

        DbgPrint("RtlGetVersion failed!\n");

        return STATUS_UNSUCCESSFUL;

    }

    RtlInitUnicodeString (&deviceNameUnicodeString,

                              deviceNameBuffer );

    RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer);

    ntStatus = IoCreateDevice ( DriverObject,

                                    0, // For driver extension

                                    &deviceNameUnicodeString,

                                    FILE_DEVICE_UNKNOWN,

                                    0,

                                    TRUE,

                                    &g_HookDevice );

    if(! NT_SUCCESS(ntStatus))

    {

            DbgPrint(("Failed to create device!\n"));

            return ntStatus;

    }

    ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,

                                            &deviceNameUnicodeString );

    if(! NT_SUCCESS(ntStatus)) 

    {

         IoDeleteDevice(DriverObject->DeviceObject);

            DbgPrint("Failed to create symbolic link!\n");

            return ntStatus;

    }

    DriverObject->DriverUnload  = OnUnload;

    pHashTable = InitializeTable(HASHTABLE_SIZE);

    if (pHashTable == NULL)

    {

        DbgPrint("InitializeTable failed!\n");

        return STATUS_UNSUCCESSFUL;

    }

    //pSwapContext = GetSwapAddr();

    FindSwapAddr();

    if(NULL==pSwapContext)

    {

        DbgPrint("SwapContext addr not found!\n");

        return STATUS_UNSUCCESSFUL;

    }

    else

    {

        DbgPrint("SwapContext found at 0x%x\n", pSwapContext);

        ntStatus = InstallSwapContextHook();

    }

    if (STATUS_SUCCESS == ntStatus)

    {

        DbgPrint("InstallSwapContextHook succeeded.\n");

        DbgPrint("DetourFunction is at 0x%x\n", DetourFunction);

    }

    else

    {

        DbgPrint("InstallSwapContextHook failed!\n");

        return STATUS_UNSUCCESSFUL;

    }

    return STATUS_SUCCESS;

}

©著作权归作者所有:来自51CTO博客作者土匪猿的原创作品,如需转载,请注明出处,否则将追究法律责任


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP