本论坛为只读模式,仅供查阅,不能注册新用户,不能发帖/回帖,有问题可发邮件 xikug.xp (^) gmail.com
查看: 8016|回复: 13

仿360的Hook架构的代码,MJ给指教一下 [复制链接]

Rank: 1

发表于 2011-2-20 18:33:45 |显示全部楼层
其实,这个代码主要是逆向加学习的别人的分析搞出来的
MJ给看看,指教一下
#include <ntifs.h>

typedef struct _SERVICE_FILTER_INFO_TABLE{
        ULONG SSDTCnt;
        ULONG SavedSSDTServiceAddress[1024];        //保存被Hook的SSDT函数的地址
        ULONG ProxySSDTServiceAddress[1024];        //保存被Hook的SSDT函数对应的代理函数的地址
        ULONG SavedShadowSSDTServiceAddress[1024];    //保存被Hook的ShadowSSDT函数的地址
        ULONG ProxyShadowSSDTServiceAddress[1024];    //保存被Hook的ShadowSSDT函数对应的代理函数的地址
        ULONG SwitchTableForSSDT[1024];                //保存SSDT Hook开关,决定该函数是否会被Hook
        ULONG SwitchTableForShadowSSDT[1024];        //保存ShadowSSDT Hook开关,决定该函数是否会被Hook
}SERVICE_FILTER_INFO_TABLE,*PSERVICE_FILTER_INFO_TABLE;
PSERVICE_FILTER_INFO_TABLE ServiceFilterInfoTable=NULL;  //记录系统所有SSDT函数hook相关信息


#pragma pack(1) //SSDT Table   
typedef struct ServiceDescriptorEntry
{   
        PULONG ServiceTableBase;   
        PULONG ServiceCounterTableBase;
        ULONG NumberOfServices;   
        PULONG ParamTableBase;   
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
#define FAKE_HANDLE ((HANDLE)0x10100101)
PServiceDescriptorTableEntry_t KeSSDT;
PServiceDescriptorTableEntry_t KeSSDTShadow=NULL;
HANDLE hThread=NULL;

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;


//获得SSDT基址宏   
#define SYSTEMSERVICE(_function)  KeSSDT->ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)]



ULONG hookaddrs=0;//Hook代码填写的地址
ULONG RetAdd=0;//Hook函数执行完后应返回的地址

NTSTATUS (*g_RealZwSetEvent)(HANDLE EventHandle,PLONG PreviousState );
VOID UnHookZwSetEvent();
VOID HookZwEvent();
VOID HookKiFc_By_ZwSetEvent();
__declspec(dllimport) _stdcall KeAddSystemServiceTable(PVOID, PVOID, PVOID, PVOID, PVOID);

PServiceDescriptorTableEntry_t GetKeServiceDescriptorTableShadow(VOID)   
{   
        PServiceDescriptorTableEntry_t ShadowTable = NULL;   
        ULONG   ServiceTableAddress = 0;   
        PUCHAR  cPtr = NULL;   

        for (cPtr = (PUCHAR)KeAddSystemServiceTable;cPtr < (PUCHAR)KeAddSystemServiceTable + PAGE_SIZE;cPtr += 1 )   
        {   
                if (!MmIsAddressValid(cPtr))  continue;   

                ServiceTableAddress = *(PULONG)cPtr;   
                if (!MmIsAddressValid((PVOID)ServiceTableAddress)) continue;   

                if (memcmp((PVOID)ServiceTableAddress, (PVOID)&KeServiceDescriptorTable, 16) == 0)   
                {   
                        if ((PVOID)ServiceTableAddress == &KeServiceDescriptorTable) continue;   
                        ShadowTable = (PServiceDescriptorTableEntry_t)ServiceTableAddress;   
                        ShadowTable ++;   
                        return ShadowTable;   
                }   
        }   
        return NULL;   
}


VOID GetSSDTAndShadowAddress(PVOID ctx)
{
        //遍历线程
        ULONG i;
        NTSTATUS status;
        ULONG thread;
        KeSSDT=&KeServiceDescriptorTable;
        HookKiFc_By_ZwSetEvent();
Tag:
        for( i=8; i<32768; i++)
        {
                status = PsLookupThreadByThreadId( (HANDLE)i,&(PETHREAD)thread);
                if(NT_SUCCESS(status))
                {
                        if( ((PServiceDescriptorTableEntry_t)(*(PULONG)(thread+0x0e0)))->ServiceTableBase != KeServiceDescriptorTable.ServiceTableBase)
                        {
                                KeSSDTShadow=(PServiceDescriptorTableEntry_t)(*(PULONG)(thread+0x0e0));
                        }
                        ObDereferenceObject((PVOID)thread);
                        if (KeSSDTShadow)
                        {
                                break;
                        }
                }
        }
        if (!KeSSDTShadow)
        {
                KeSSDTShadow=GetKeServiceDescriptorTableShadow();
        }
        if (!KeSSDTShadow)
        {
                LARGE_INTEGER timeout={-10000*50};
                KeDelayExecutionThread(KernelMode,FALSE,&timeout);
                i=8;
                goto Tag;
        }
        KdPrint(("SSDT:%X,SSDTShadow:%X\n",KeSSDT,KeSSDTShadow));
        ZwClose(hThread);
        PsTerminateSystemThread(STATUS_SUCCESS);
        return ;
}

//关中断的目的是防止后面的写内存操作过程被中断,所以夹在下面两个函数之间的代码应尽量简短
VOID WPOFF()
{                   \
        __asm
        {
                cli
                push eax   
                mov  eax, cr0
                and  eax, 0FFFEFFFFh
                mov  cr0, eax
                pop  eax
        }   

}

VOID WPON()
{               
        __asm
        {
                push eax
                mov  eax, cr0
                or   eax, NOT 0FFFEFFFFh
                mov  cr0, eax
                pop  eax
                sti
        }            

}
PVOID ReplaceAPI(PVOID TargetAPI,PVOID NewAPI)
{
        PVOID OrignalAPI=NULL;
        //KIRQL OldIrql=0;
        //OldIrql=KeRaiseIrqlToDpcLevel();
    WPOFF();
        OrignalAPI=(PVOID)SYSTEMSERVICE(TargetAPI);
        SYSTEMSERVICE(TargetAPI)=(int)NewAPI;
        WPON();
        //KeLowerIrql(OldIrql);
        return OrignalAPI;
}


ULONG __stdcall MyKiFastCallEntryFilter(ULONG ServiceIndex, ULONG OriginalServiceRoutine, ULONG ServiceTable)
{

        ULONG tmp_ssdt_base=0,tmp_ssdt_shadow_base=0;
        ULONG tmp_ssdt_count=0,tmp_ssdt_shadow_count=0;
        if (KeSSDT )
        {
                tmp_ssdt_base=(ULONG)KeSSDT->ServiceTableBase;
                tmp_ssdt_count=KeSSDT->NumberOfServices;
                //SSDT中的调用
                if ( (ServiceTable == tmp_ssdt_base) && (ServiceIndex<tmp_ssdt_count) )// 参数判断
                {
                        if (ServiceFilterInfoTable->SwitchTableForSSDT[ServiceIndex] && ServiceFilterInfoTable->ProxySSDTServiceAddress[ServiceIndex])
                        {
                                ServiceFilterInfoTable->SavedSSDTServiceAddress[ServiceIndex]=OriginalServiceRoutine;//保存原始例程
                                return ServiceFilterInfoTable->ProxySSDTServiceAddress[ServiceIndex];//返回代理函数的地址,实现hook相应函数
                        }
                }
        }
        if (KeSSDTShadow)
        {
                tmp_ssdt_shadow_base=(ULONG)KeSSDTShadow->ServiceTableBase;
                tmp_ssdt_shadow_count=KeSSDTShadow->NumberOfServices;

                //ShadowSSDT中的调用
                if ( (ServiceTable==tmp_ssdt_shadow_base) && (ServiceIndex <tmp_ssdt_shadow_count))
                {
                        if ( ServiceFilterInfoTable->SwitchTableForShadowSSDT[ServiceIndex] && ServiceFilterInfoTable->ProxyShadowSSDTServiceAddress[ServiceIndex])
                        {
                                ServiceFilterInfoTable->SavedShadowSSDTServiceAddress[ServiceIndex]=OriginalServiceRoutine;
                                return ServiceFilterInfoTable->ProxyShadowSSDTServiceAddress[ServiceIndex];  
                        }                          
                }
        }
        return OriginalServiceRoutine; // 否则,返回原始函数地址,不做任何处理
}



__declspec(naked) JmpStub()
{
        __asm
        {
                mov edi,edi;
                pushfd;
                pushad;
                push edi;
                push ebx;
                push eax;
                call MyKiFastCallEntryFilter;
                mov dword ptr[esp+10h],eax;
                popad;
                popfd;
                sub esp,ecx;//执行被替换的代码
                shr ecx,2;//执行被替换的代码
                push RetAdd;//设置返回地址
                ret;//返回到RetAdd所指地址
        }//此时,ebx的值即为MyKiFastCallEntry_0返回的函数地址,而ebx的值又是将被调用的ssdt函数的地址,因此也就达到了ssdt hook的效果
}


NTSTATUS MyZwSetEvent(HANDLE EventHandle,PLONG PreviousState)
{
        NTSTATUS status;
        char *tmp_byte_ptr0=NULL,*tmp_byte_ptr1=NULL;
        char code[5]={0xe9,0,0,0,0};  
        char feature_code[5]={0x2b,0xe1,0xc1,0xe9,0x02};//被填入hook代码(code[5])处的特征码,用于验证所找位置是否正确
        KIRQL  Irql;

        if (EventHandle!=FAKE_HANDLE||ExGetPreviousMode()==UserMode)   //判断一下是不是自己调用,同时也不处理来自应用层的调用
        {
                if (g_RealZwSetEvent!=NULL)
                {
                        status= g_RealZwSetEvent(EventHandle,PreviousState);
                }else
                {
                        status=STATUS_ACCESS_DENIED;
                }
                 
        }else
        {
                UnHookZwSetEvent();
                __asm
                {
                        mov eax,[ebp+4]
                        mov hookaddrs,eax
                }
        while (hookaddrs)
        {
                        if (memcmp((void*)hookaddrs,feature_code,5)==0)
                        {
                                RetAdd=hookaddrs+5;
                                break;
                        }
                    hookaddrs--;
        }
               
                if(!hookaddrs)
                {
                        KdPrint(("Get Error hookaddrs!\n"));
                        hookaddrs=0;
                        return STATUS_ACCESS_DENIED;
                }
                KdPrint(("RetAdd is %08X\n",RetAdd));
                KdPrint(("hookaddrs is %08X\n",hookaddrs));
                *(PULONG)(code+1)=(ULONG)JmpStub-hookaddrs-5;
                //写入跳转地址,之后code的汇编码为:jmp [JmpStub函数的相对地址],替换掉了原来的
                                                                                                                                                //sub esp,ecx;
                                                                                                                                                //shr ecx,2
                //Irql=KeRaiseIrqlToDpcLevel();
                WPOFF();
                RtlCopyMemory((VOID*)hookaddrs,code,5);//jmp [JmpStub]
                WPON();
                //KeLowerIrql(Irql);
                status=STATUS_SUCCESS;
        }
        return status;
}

VOID UnHookZwSetEvent()
{
        ReplaceAPI(ZwSetEvent,g_RealZwSetEvent);
        g_RealZwSetEvent=NULL;
}

VOID HookZwEvent()
{
        g_RealZwSetEvent=ReplaceAPI(ZwSetEvent,MyZwSetEvent);
        while(1)
        {
                if (ZwSetEvent(FAKE_HANDLE,NULL)>=0)
                {
                        break;
                }else
                {
                        continue;;
                }
        }
}


VOID HookKiFc_By_ZwSetEvent()
{
        HookZwEvent();
}


NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
       
        KdPrint(("Enter " __FUNCTION__ "\n"));
        PsCreateSystemThread(&hThread,THREAD_ALL_ACCESS,NULL,NULL,NULL,(PKSTART_ROUTINE)GetSSDTAndShadowAddress,NULL);
        //KeSSDTShadow=(PServiceDescriptorTableEntry_t)GetSSDTShadowAddress();
        ServiceFilterInfoTable=(PSERVICE_FILTER_INFO_TABLE)ExAllocatePoolWithTag(NonPagedPool,sizeof(SERVICE_FILTER_INFO_TABLE),'GTRZ');
        if (!ServiceFilterInfoTable)
        {
                return STATUS_ACCESS_DENIED;
        }
        RtlZeroMemory(ServiceFilterInfoTable,sizeof(SERVICE_FILTER_INFO_TABLE));
        //HookKiFc_By_ZwSetEvent();
        KdPrint(("Leave " __FUNCTION__ "\n"));
        return STATUS_SUCCESS;
}

Rank: 2

发表于 2011-2-20 19:28:35 |显示全部楼层
LZ系MJ的MJ,鉴定完毕
楼下你说是不是

Rank: 9Rank: 9Rank: 9

发表于 2011-2-21 00:23:45 |显示全部楼层
指教什么?
悟空,退下,为师一个人就够了

Rank: 1

发表于 2011-2-21 02:52:22 |显示全部楼层
[quote=\"xIkUg\"]指教什么?[/quote]
主要我想知道自己的逆向水平有提高没。。。。。。

Rank: 1

发表于 2011-2-21 14:01:15 |显示全部楼层
不管怎样,有代码就是好的

Rank: 1

发表于 2011-3-19 02:46:15 |显示全部楼层
楼主的构架相当好啊~~~超强悍的

Rank: 1

发表于 2011-3-24 20:56:56 |显示全部楼层
编译加载后蓝了。

Rank: 2

发表于 2011-3-28 14:59:37 |显示全部楼层
灰常好的学习资料.

Rank: 1

发表于 2011-3-29 02:06:54 |显示全部楼层
这什么语言啊?楼主?

Rank: 1

发表于 2012-2-18 10:27:41 |显示全部楼层
顶一顶

Rank: 1

发表于 2012-5-10 23:50:37 |显示全部楼层
nbjnh 发表于 2011-3-24 20:56
编译加载后蓝了。

你的机子是多核么?多核蓝的几率90%以上....  顺带问问LZ  你的代码应该只适用于单核吧....虽然我是菜鸟   但是在我之前看的文章中 貌似说过 cil 和sti  无法在多核中防止被打断= =  貌似方法很多 但是我没去深究= =  继续求指教   我乃菜鸟 勿喷...

Rank: 1

发表于 2012-6-12 08:12:46 |显示全部楼层
pandashare 发表于 2012-5-10 23:50
你的机子是多核么?多核蓝的几率90%以上....  顺带问问LZ  你的代码应该只适用于单核吧....虽然我是菜鸟   ...

我的机器是双至强CPU。

Rank: 1

发表于 2013-4-13 23:11:36 |显示全部楼层
学习啦

Rank: 1

发表于 2013-6-17 10:31:02 |显示全部楼层
360的hook框架又不是mj写的
您需要登录后才可以回帖 登录 | 立即加入

Archiver|手机版|第8个男人 - 论坛为只读模式,仅供查阅

GMT+8, 2019-3-20 19:08 , Processed in 0.039098 second(s), 8 queries .

Design by pvo.cn

© 2011 Pvo Inc.

回顶部