栈回溯法的一个例子

看了几个例子,一般都是在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
    }

}

 

转载于:https://www.cnblogs.com/kedebug/archive/2010/12/22/2791748.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值