zoukankan      html  css  js  c++  java
  • 栈回溯法的一个例子

    看了几个例子,一般都是在ExAllocatePoolWithTag这里挂钩啊,根据MemoryTag来判断,以后再发现发现有没有更精准的挂钩位置

    #include <ntddk.h>
    #include <windef.h>
    #include <stdio.h>
    #include <string.h>
    #include "MmLoadSystemImage.h"
    
    
    #define pwszModuleName L"ntoskrnl.exe" //这里只考虑单核的情况
    
    #define ObjectNameInformation  1
    
    UCHAR oldcode[5]={0};
    UCHAR jmpcode[5]={0xE9,0x00,0x00,0x00,0x00};
    
    ULONG g_ntoskrnl_addr=0;
    
    ULONG g_ntoskrnl_size=0;
    
    ULONG oldExAllocatePoolWithTagaddr=0;
    
    ULONG Address_MmLoadSystemImage=0;//通过栈回溯(技术难点)得到MmLoadSystemImage函数的地址
    
    /*
    这里说明一下原先通过东方微点的Mp110003的驱动是通过Hook KeWaitForSingleObject,
    然后通过栈回溯来找到MmLoadSystemImage的地址,但是通过我跟踪堆栈调用,
    发现要经过很多次KeWaitForSingleObject调用,才会进入到
        KeWaitForSingleObject
        MmLoadSystemImage
        NtSetSystemInformation
        nt!KiFastCallEntry
        nt!ZwSetSystemInformation
    反正是猥琐,我就更猥琐,大米兄就是这么干的,调用流程中来找到MmLoadSystemImage地址,调用过程如下:
        ExAllocatePoolWithTag
        MmLoadSystemImage
        NtSetSystemInformation
        nt!KiFastCallEntry
        nt!ZwSetSystemInformation
    因此我直接HOOK ExAllocatePoolWithTag来进行栈回溯
    */
    __declspec(naked) PVOID fake_ExAllocatePoolWithTag(
        IN POOL_TYPE  PoolType,
        IN SIZE_T  NumberOfBytes,
        IN ULONG  Tag)
    {
        ULONG *PEBP;
    
        _asm{
            mov  edi,edi
            push ebp    
            mov  ebp,esp
            mov eax,[ebp+0xc] //参数是NumberOfBytes
            cmp eax,0x100
            jnz end
            mov eax,[ebp+0x10] //第三个参数Tag
            cmp eax,0x6E4C6D4D //标志为"nLmM",也就是MmLoadSystemImage装载的镜像标志
            jnz end 
    
            mov eax,[ebp]  //堆栈回溯的原理
            mov eax,[eax+4]
            push eax        //上一个函数的地址
            call StackTrace_for_ExAllocatePoolWithTag    
    end:
            mov  eax,oldExAllocatePoolWithTagaddr
            add  eax,5
            jmp  eax
        }
    }
    
    //通过栈回溯找到 
    ULONG StackTrace_for_ExAllocatePoolWithTag(ULONG RetAddress)
    {
        ULONG CallAddress=0;
        ULONG JmpOffset=0;
    
        if (RetAddress)
        {
            CallAddress=(ULONG)RetAddress-  5 ;//Ret --->call Address
            //跳转的偏移量
            JmpOffset=*(ULONG*)((PUCHAR)CallAddress+1); //(PUCHAR)CallAddress+1--->指针CallAddress往后走一位,(PULONG)CallAddress+1,指针CallAddress往后走(sizeof(ULONG)=4)字节
            //MmLoadSystemImage函数的地址
            Address_MmLoadSystemImage=(ULONG)CallAddress + 5 +JmpOffset;
            KdPrint(("MmLoadSystemImage Address=0x%x/n",Address_MmLoadSystemImage));
            //加入判定如果ntoskrnl.Base<Address_MmLoadSystemImage<ntoskrnl.Base+size,则说明可以进行inlineHook_MmLoadSystemImage()
            if (Address_MmLoadSystemImage>g_ntoskrnl_addr&&Address_MmLoadSystemImage<(g_ntoskrnl_addr+g_ntoskrnl_size))
            {
                unlineHook_ExAllocatePoolWithTag(); 
                inlineHook_MmLoadSystemImage(); 
                KdPrint(("inlineHook MmLoadSystemImage Success!")); 
            }   
        }
        return 0;    
    }
    
    
    
    __declspec(naked) NTSTATUS OrigiMmLoadSystemImage(
        IN PUNICODE_STRING ImageFileName,
        IN PUNICODE_STRING NamePrefix OPTIONAL,
        IN PUNICODE_STRING LoadedBaseName OPTIONAL,
        IN ULONG LoadFlags,
        OUT PVOID *ImageHandle,
        OUT PVOID *ImageBaseAddress)
    {
        __asm{
            push 174h 
            mov eax,Address_MmLoadSystemImage
            add eax,5
            jmp eax 
        }
    }
    
    
    
    //拦截驱动的过程
    NTSTATUS fake_MmLoadSystemImage(
                                    IN PUNICODE_STRING ImageFileName,
                                    IN PUNICODE_STRING NamePrefix OPTIONAL,
                                    IN PUNICODE_STRING LoadedBaseName OPTIONAL,
                                    IN ULONG LoadFlags,
                                    OUT PVOID *ImageHandle,
                                    OUT PVOID *ImageBaseAddress)
    {
        ANSI_STRING ImageName;
    
        RtlUnicodeStringToAnsiString(&ImageName,ImageFileName,TRUE);
    
        KdPrint(("MmLoadSystemImage LoadDriver :%s/n",ImageName.Buffer));
    
        return OrigiMmLoadSystemImage(ImageFileName,
            NamePrefix,
            LoadFlags,
            LoadFlags,
            ImageHandle,
            ImageBaseAddress);
    
    }
    
    
    
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PIRP Irp)
    {
        NTSTATUS status;
    
        PEPROCESS crsEProc; 
        ANSI_STRING TestSysName;
        SYSTEM_LOAD_AND_CALL_IMAGE sysImage;
    
        DriverObject->DriverUnload=DriverUnload;
        status=PsLookupProcessByProcessId((ULONG)GetCsrPid(),&crsEProc); 
        if (!NT_SUCCESS(status))
        {
            KdPrint(("PsLookupProcessByProcessId() error/n"));
            return status;
        }   
    
        //通过DriverObject->DriverSection获得加载驱动的模块
        if (GetBase((ULONG)DriverObject)&&inlineHook_ExAllocatePoolWithTag())
        {
            //下面是调用ZwSetSystemInformation来加载驱动,从而引发跳转到fake_ExAllocatePoolWithTag中,先依附进csrss.exe,再加载测试驱动
            KeAttachProcess(crsEProc);
            //加载测试驱动; 
            RtlInitAnsiString(&TestSysName,"//??//c://Hooksys.sys");
            RtlAnsiStringToUnicodeString(&(sysImage.ModuleName),&TestSysName,TRUE);
            status= ZwSetSystemInformation(SystemExtendServiceTableInformation,&sysImage,sizeof(sysImage));
            if (!NT_SUCCESS(status))
            {         
                KdPrint(("Driver STATUS=0X%x/n",status));
            }
    
            KeDetachProcess();  
        }
    
        return STATUS_SUCCESS;
    }
    
    NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject )
    {
    
        unlineHook_MmLoadSystemImage();
        KdPrint(("DriverUnload!/n"));
        return   STATUS_SUCCESS;
    
    }
    
    
    //得到模块的基址和映像大小
    int GetBase(IN ULONG  EntryAddress)
    {
        ULONG  listHead;
        ULONG  currentList;
        ULONG  NameAddress;
        int reault=0;
    
        listHead=*(ULONG*)(EntryAddress+0x14);
        currentList=*(ULONG*)(listHead+0x4); //Blink
    
    
        if (currentList!=listHead)
        {
            while (1)
            {      
                NameAddress=*(ULONG*)(currentList+0x030); 
                if ((PCWSTR)NameAddress!=NULL)
                {
                    KdPrint(("ModuleName=%ws/n",(PCWSTR)NameAddress));
                }
    
                if(!_wcsicmp((PCWSTR)NameAddress,pwszModuleName))
                {
                    g_ntoskrnl_addr=*(ULONG*)(currentList+0x18);
                    g_ntoskrnl_size=*(ULONG*)(currentList+0x20);
                    KdPrint(("ntoskrnl.exe [base]=0x%X,[size]=0x%X/n",g_ntoskrnl_addr,g_ntoskrnl_size));
                    reault=1;
                    break;
                }
    
                currentList=*(DWORD*)(currentList + 0x4);//下一个Blink 
                if (currentList == listHead)
                {
                    KdPrint(("链表查询结束!/n"));
                    break;
                }
    
            }      
        }
    
        return reault;
    
    }
    
    PVOID GetInfoTable(ULONG ATableType)
    {
        ULONG mSize=0x4000;
        PVOID mPtr=NULL;
        NTSTATUS status;
    
        do 
        {
            mPtr=ExAllocatePool(PagedPool,mSize);
            memset(mPtr, 0, mSize);
            if (mPtr)
            {
                status = ZwQuerySystemInformation(ATableType,mPtr,mSize,NULL);
            }else
                return NULL;
            if (status == STATUS_INFO_LENGTH_MISMATCH)
            {
                ExFreePool(mPtr);
                mSize *=2;
            }  
        } while(status == STATUS_INFO_LENGTH_MISMATCH);
    
        if (status == STATUS_SUCCESS)
            return mPtr;
    
        ExFreePool(mPtr);
        return NULL;  
    }
    
    
    //得到csrss.exe的PID
    HANDLE GetCsrPid()
    {
        HANDLE Process,hObject;
        HANDLE CsrssId=(HANDLE)0;
        OBJECT_ATTRIBUTES obj;
        CLIENT_ID cid;
        UCHAR buff[0x100];
        POBJECT_NAME_INFORMATION objName=(PVOID)&buff;
        PSYSTEM_HANDLE_INFORMATION_EX Handles;
        ULONG i;
    
    
        Handles=GetInfoTable(SystemHandleInformation);
        if (!Handles) return CsrssId;
    
        for (i=0;i<Handles->NumberOfHandles;i++)
        {
            if (Handles->Information[i].ObjectTypeNumber == 21)
            {
                InitializeObjectAttributes(&obj,NULL,OBJ_KERNEL_HANDLE,NULL,NULL);
                cid.UniqueProcess=(HANDLE)Handles->Information[i].ProcessId;
                cid.UniqueThread = 0;
    
                if (NT_SUCCESS(NtOpenProcess(&Process,PROCESS_DUP_HANDLE,&obj,&cid)))
                {
                    if (NT_SUCCESS(ZwDuplicateObject(Process,(HANDLE)Handles->Information[i].Handle,NtCurrentProcess(),&hObject,0,0,DUPLICATE_SAME_ACCESS)))
                    {
                        if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, objName, 0x100, NULL)))
                        {
                            if (objName->Name.Buffer&& !wcsncmp(L"//Windows//ApiPort",objName->Name.Buffer,20))
                            {
    
                                CsrssId=(HANDLE)Handles->Information[i].ProcessId;
    
                            }
    
                        }     
                        ZwClose(hObject); 
                    }
    
                    ZwClose(Process);
                }    
    
            }
    
        }
    
        ExFreePool(Handles);
    
        return CsrssId;
    }
    
    
    //inline Hook ExAllocatePoolWithTag
    BOOLEAN inlineHook_ExAllocatePoolWithTag()
    {
        KIRQL  oldIrql;
        DWORD distance; 
        UNICODE_STRING unamestr;
        BOOLEAN result;
    
        RtlInitUnicodeString(&unamestr,L"ExAllocatePoolWithTag");
        oldExAllocatePoolWithTagaddr=(ULONG)MmGetSystemRoutineAddress(&unamestr);
        if (oldExAllocatePoolWithTagaddr)
        {
            //保存原来开始的5个字节
            RtlCopyMemory(oldcode,(BYTE*)oldExAllocatePoolWithTagaddr,5); 
            distance=(BYTE*)fake_ExAllocatePoolWithTag - (BYTE*)oldExAllocatePoolWithTagaddr -5;
            RtlCopyMemory(jmpcode+1,&distance,4);
            WPOff();
            oldIrql=KeRaiseIrqlToDpcLevel();
            RtlCopyMemory((BYTE*)oldExAllocatePoolWithTagaddr,jmpcode,5);
            KeLowerIrql(oldIrql);
            WPOn();
            result=TRUE;  
        } else
            result=FALSE;
    
        return result;
    }
    
    
    VOID unlineHook_ExAllocatePoolWithTag()
    {
        KIRQL  oldIrql;
    
        WPOff();
        oldIrql=KeRaiseIrqlToDpcLevel();
        RtlCopyMemory((BYTE*)oldExAllocatePoolWithTagaddr,oldcode,5);
        KeLowerIrql(oldIrql);
        WPOn();
    
        return;
    }
    
    
    BOOLEAN inlineHook_MmLoadSystemImage()
    {
        KIRQL  oldIrql;
        DWORD distance;  
        BOOLEAN result;
    
        if (Address_MmLoadSystemImage)
        {
            //保存原来开始的5个字节
            RtlCopyMemory(oldcode,(BYTE*)Address_MmLoadSystemImage,5);
            distance=(BYTE*)fake_MmLoadSystemImage - Address_MmLoadSystemImage -5;
            RtlCopyMemory(jmpcode+1,&distance,4);
            WPOff();
            oldIrql=KeRaiseIrqlToDpcLevel();
            RtlCopyMemory((BYTE*)Address_MmLoadSystemImage,jmpcode,5);
            KeLowerIrql(oldIrql);
            WPOn();
            result=TRUE;
    
        }else
            result=FALSE;
    
        return result;
    }
    
    VOID unlineHook_MmLoadSystemImage()
    {
        KIRQL  oldIrql;
    
        WPOff();
        oldIrql=KeRaiseIrqlToDpcLevel();
        RtlCopyMemory((BYTE*)Address_MmLoadSystemImage,oldcode,5);
        KeLowerIrql(oldIrql);
        WPOn();
    
        return;
    
    
    
    
    }
    
    
    
    
    VOID WPOn()
    {
        __asm {
            mov eax,cr0
            or eax,0x10000
            mov cr0,eax
            STI
        }
    
    }
    
    VOID WPOff()
    {
        __asm{
            cli  
            mov eax, cr0
            and eax,not 0x10000
            mov cr0,eax
        }
    
    }
    -------------------------------------------------------

    kedebug

    Department of Computer Science and Engineering,

    Shanghai Jiao Tong University

    E-mail: kedebug0@gmail.com

    GitHub: http://github.com/kedebug

    -------------------------------------------------------

  • 相关阅读:
    Could A New Linux Base For Tablets/Smartphones Succeed In 2017?
    使用libhybris,glibc和bionic共存时的TLS冲突的问题
    6 Open Source Mobile OS Alternatives To Android in 2018
    Using MultiROM
    GPU drivers are written by the GPU IP vendors and they only provide Android drivers
    Jolla Brings Wayland Atop Android GPU Drivers
    How to Use Libhybris and Android GPU Libraries with Mer (Linux) on the Cubieboard
    闲聊Libhybris
    【ARM-Linux开发】wayland和weston的介绍
    Wayland and X.org problem : Why not following the Android Solution ?
  • 原文地址:https://www.cnblogs.com/kedebug/p/2791748.html
Copyright © 2011-2022 走看看