看流星社区

 找回密码
 注册账号
查看: 1755|回复: 0

inline hook

[复制链接]

该用户从未签到

发表于 2017-6-1 13:33:07 | 显示全部楼层 |阅读模式
Inline hook的步骤
1。获得要inline hook的函数在内存中的地址
2。实现T_MyFunc()与MyFunc函数,在该函数中将参数压栈并调用MyFunc函数处理。
3。HOOK。保存函数开头的指令到某个内存中,并在该内存末尾附加JMP指令到开头指令的后面的指令。并将开头的指令替换为JMP T_MyFunc地址。
4。在T_MyFunc执行完MyFunc之后,调用保存的指令,跳回去。



直接的jmp分3种
Short Jump(短跳转)机器码 EB rel8
只能跳转到256字节的范围内
Near Jump(近跳转)机器码 E9 rel16/32
可跳至同一个段的范围内的地址
Far Jump(远跳转)机器码EA ptr 16:16/32
可跳至任意地址,使用48位/32位全指针



例子:
_declspec(naked) T_MyFunc(……)
{
        _asm
        {
                mov edi, edi
                push ebp
                mov ebp ,esp
                //参数压栈,传给MyFunc
                push [ebp+0ch]
                push [ebp+8]
                call MyFunc
                //获得结果,并跳回原来的指令
                cmp eax,1
                jz end
                mov eax,FuncAddress
                add eax,5
                jmp eax
                       
end:
                //恢复栈
                pop ebp
                retn 8
        }
}
[/code]
Naked call
编译器不会给这种函数增加初始化和清理代码,不能用return返回返回值,只能用插入汇编返回结果。

//naked 调用约定。用户自己清理堆栈。不能进行原型声明,否则错误。
__declspec(naked) int add(int a,int b)
{
    __asm push ebp //必须加上两句修改栈帧,否则引用了错误的数据
    __asm mov ebp, esp
    __asm mov eax, a
    __asm add eax, b
    __asm pop ebp
    __asm ret
}

这个修饰是和__stdcall及cdecl结合使用的,前面是它和cdecl结合使用的代码,对于和stdcall结合的代码,则变成:
__declspec(naked) int __stdcall function(int a,int b)
{
    __asm mov eax, a
    __asm add eax, b
    __asm ret 8 //注意后面的8
}
cdecl/fastcall/stdcall/thiscall/nakedcall
扩展阅读(重要):Calling convention: http://gccfeli.cn/tag/naked-call
[/code]
例子:SwapContext inline hook
#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
                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, &#39AWS')))
                {
                        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;r
        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 = 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.
        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);

        // 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);

        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;
       
}
[/code]
两份inline hook NtOpenprocess保护进程的代码:
这份没有使用中间函数:
#include "ntddk.h"

#pragma pack(1)
#define IOCTL_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN,0x801 , METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)  

typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

//global
ULONG   OpenprocessAddress;
ULONG   JmpOldAddress;
UCHAR        OldCode[5];
HANDLE  MyPID;
HANDLE  PID;

int *MyPIDEx;
void IninleHookOpenProcess(int *PID);

NTSTATUS __declspec(naked)(__stdcall MyNtOpenProcess)(
                                                    PHANDLE ProcessHandle,
                                                                                                ACCESS_MASK DesiredAccess,
                                                                                                POBJECT_ATTRIBUTES ObjectAttributes,
                                                                                                PCLIENT_ID ClientId)
{
        __asm
        {
                push eax
                mov eax,[esp+0x14]  //获取ClientId,因为是第四个参数所以【esp+10】,但上面有push eax 所以再加4
                mov eax,[eax]
                mov PID,eax          //不能在naked函数里定义局部变量,会破坏本来的局部变量
                pop eax
        }

        if(PID==MyPID)
                {
                        __asm
                                {
                                        mov [esp+4],0 //返回空句柄
                                        mov eax,0xC0000022L  //返回值STATUS_ACCESS_DENIED 无法发现进程
                                        retn 0x10   //执行保护后的返回
                                }
                }

        /*__asm
        {
                push  0x0C4
                mov edx,RealNtOpenProcess
                add edx,5
                jmp edx
        }*/
       
        __asm
        {
                mov  edi,edi
                push ebp
                mov ebp,esp
                jmp JmpOldAddress
        }

}

void PageProtectOn()
{
        __asm{//恢复内存保护  
                mov  eax,cr0
                or   eax,10000h
                mov  cr0,eax
                sti
        }
}

void PageProtectOff()
{
        __asm{//去掉内存保护
                cli
                mov  eax,cr0
                and  eax,not 10000h
                mov  cr0,eax
        }
}


NTSTATUS IODispatch(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
        Irp->IoStatus.Status = STATUS_SUCCESS;
        IoCompleteRequest(Irp,IO_NO_INCREMENT);
        return STATUS_SUCCESS;
}


NTSTATUS IOManager(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{   
        PIO_STACK_LOCATION StackLocation = IoGetCurrentIrpStackLocation(Irp);
        ULONG IRPcode = StackLocation-&gtarameters.DeviceIoControl.IoControlCode;  
        char outText[]="保护成功";
        ULONG  returnSize;
        UCHAR *oubuffer;
        Irp->IoStatus.Status = STATUS_SUCCESS;

        switch(IRPcode)
        {
        case IOCTL_HOOK:
                KdPrint(("IOCTL_HOOK  \n"));
        MyPIDEx        =(int*)Irp->AssociatedIrp.SystemBuffer;//得到传入数据地址

        oubuffer = (UCHAR*)Irp->AssociatedIrp.SystemBuffer;

        strcpy((char*)oubuffer,outText);

        returnSize=strlen(outText);  

        IninleHookOpenProcess(MyPIDEx);
                break;
        }
       
        Irp->IoStatus.Information=returnSize;
        Irp->IoStatus.Status= STATUS_SUCCESS;
       
        IoCompleteRequest(Irp,IO_NO_INCREMENT);
        return STATUS_SUCCESS;
}

void IninleHookOpenProcess(int *PID)
{
        UCHAR jmpcode[5];
        ULONG jmp_tmp_code;
       
        jmpcode[0]=0xE9;
       
         OpenprocessAddress = KeServiceDescriptorTable.ServiceTableBase[190];

         jmp_tmp_code = (ULONG)MyNtOpenProcess - OpenprocessAddress - 5;

         *(ULONG*)&jmpcode[1]=jmp_tmp_code;

         JmpOldAddress = OpenprocessAddress + 5;
         MyPID = (HANDLE)*PID;
         PageProtectOff();

         RtlCopyMemory(OldCode,(PVOID)OpenprocessAddress,5);
         RtlCopyMemory((PVOID)OpenprocessAddress,jmpcode,5);

         PageProtectOn();

}

void UnHookOpenprocess()
{
         PageProtectOff();

         RtlCopyMemory((PVOID)OpenprocessAddress,OldCode,5);

         PageProtectOn();
}

NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject)
{
        NTSTATUS Status;
        PDEVICE_OBJECT        pDevObj;
        UNICODE_STRING        usDevName;
        UNICODE_STRING        usSymName;

        RtlInitUnicodeString(&usDevName,L"\\Device\\MyDevice");

        Status = IoCreateDevice(pDriverObject,\
                0,\
                &usDevName,\
                FILE_DEVICE_UNKNOWN,\
                0,\
                TRUE,\
                &pDevObj);
        if (!NT_SUCCESS(Status))
        {
                return Status;
        }

        pDevObj->Flags |= DO_BUFFERED_IO;


        RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");

        Status = IoCreateSymbolicLink(&usSymName,&usDevName);
        if (!NT_SUCCESS(Status))
        {
                IoDeleteDevice(pDevObj);
                return Status;
        }

        return STATUS_SUCCESS;
}

void UnloadDriver(PDRIVER_OBJECT pDriverObject)
{
        UNICODE_STRING usSymName;

        RtlInitUnicodeString(&usSymName,L"\\??\\MyDevice");

        if (pDriverObject->DeviceObject!=NULL)
        {
                IoDeleteSymbolicLink(&usSymName);
                IoDeleteDevice(pDriverObject->DeviceObject);
                KdPrint(("删除设备成功."));
        }
        UnHookOpenprocess();
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegString)
{
        NTSTATUS Status;
        Status = CreateDevice(pDriverObject);
        if (!NT_SUCCESS(Status))
        {
                KdPrint(("创建设备失败."));
        }else{
                KdPrint(("创建设备成功."));
        }
       
        pDriverObject->MajorFunction[IRP_MJ_CREATE] = IODispatch;
        pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IOManager;
        pDriverObject->DriverUnload = UnloadDriver;
        return STATUS_SUCCESS;
}[/code]


另外一份使用了中间函数 这才是真正意义上inline hook
//为什么一个是esp+0x34 一个是esp+14 原因是下面这份使用了pushad
pushfd[/code]保护了现场 这将栈提高了0x24字节
#include "ntddk.h"

#pragma pack(1)
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;

NTSTATUS
PsLookupProcessByProcessId(
    IN HANDLE ProcessId,
    OUT PEPROCESS *Process
    );

//global
ULONG        gfn_ntopenprocess;
ULONG        g_jmp_origfunc;
UCHAR        gs_origfunc_code[5];

void PageProtectOn()
{
        __asm{//恢复内存保护  
                mov  eax,cr0
                or   eax,10000h
                mov  cr0,eax
                sti
        }
}

void PageProtectOff()
{
        __asm{//去掉内存保护
                cli
                mov  eax,cr0
                and  eax,not 10000h
                mov  cr0,eax
        }
}

ULONG FilterNtOpenProcess(PCLIENT_ID ClientId)
{
        NTSTATUS        status;
        PEPROCESS        process_obj;
        status = PsLookupProcessByProcessId(ClientId->UniqueProcess,&process_obj);
        if (!NT_SUCCESS(status))
        {
                return 0;
        }

        if (strstr((char*)process_obj+0x16c,"VistaLKD")!=0)
        {
                return 1;
        }

        return 0;
}

__declspec(naked)
NTSTATUS NewNtOpenProcess()
{
        __asm{
                pushad
                pushfd
                push        [esp+0x34]
                call        FilterNtOpenProcess
                test        eax,eax
                je                __Exit
                popfd
                popad
                mov                eax,0
                ret                0x10
__Exit:
                popfd
                popad
                mov                edi,edi
                push        ebp
                mov                ebp,esp
                jmp                g_jmp_origfunc
        }
}

void UnHookNtOpenProcess()
{
        PageProtectOff();

        RtlCopyMemory((PVOID)gfn_ntopenprocess,gs_origfunc_code,5);

        PageProtectOn();
}

void HookNtOpenProcess()
{
        ULONG        u_jmp_address;
        UCHAR        str_jmp_code[5];
       
        gfn_ntopenprocess = KeServiceDescriptorTable.ServiceTableBase[190];
        RtlCopyMemory(gs_origfunc_code,(PVOID)gfn_ntopenprocess,5);
       
        str_jmp_code[0] = 0xE9;

        u_jmp_address = (ULONG)NewNtOpenProcess - gfn_ntopenprocess - 5;
        *(ULONG*)(&str_jmp_code[1]) = u_jmp_address;

        PageProtectOff();

        RtlCopyMemory((PVOID)gfn_ntopenprocess,str_jmp_code,5);

        PageProtectOn();

        g_jmp_origfunc = gfn_ntopenprocess + 5;
}

VOID MyUnload(PDRIVER_OBJECT pDriverObject)
{
        UnHookNtOpenProcess();
}

NTSTATUS DriverEntry(PDRIVER_OBJECT        pDriverObject,PUNICODE_STRING Reg_Path)
{
        HookNtOpenProcess();
        pDriverObject->DriverUnload = MyUnload;
        return STATUS_SUCCESS;
}[/code]

问:为什么一个esp+14 一个是esp+38
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 18:21

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表