首页
论坛
课程
招聘
[原创]一种Object hook的思路和实现过程
2008-8-8 20:34 17575

[原创]一种Object hook的思路和实现过程

2008-8-8 20:34
17575
<一种Object hook的思路和实现过程>

作者:sudami [sudami@163.com]
时间:2008/08/08
主题:NtClose相关逆向
关键词:Object/type/hook/OkayToCloseProcedure

------------------------------------------------------
    本来不准备写出来污染眼球的,因为最终没有完全实现.但觉得思路可行,之前也没人具分析过,于是匆匆的写点儿文章,给大家提供些资料参考,也许有兴趣的同学能够进一步的深入...
写的很菜,老鸟飘过 . =.=|

    今天上午在坛子看到一帖,关于"抹掉所有进程中自己的Handle",来防止炉子的LzOpenProcess,防dump等作用.主要思路就是NtClose;其实那个古老的RK--FUTO_enhanced的code中已经实现的更加完善. 抽点儿时间想了想,于是就有了下面的一些分析:

lkd> u NtClose
nt!NtClose:
8056f9e9 8bff mov edi,edi
8056f9eb 55 push ebp
8056f9ec 8bec mov ebp,esp
8056f9ee 64a124010000 mov eax,dword ptr fs:[00000124h]
8056f9f4 0fbe8040010000 movsx eax,byte ptr [eax+140h]
8056f9fb 6a00 push 0 ;比WRK中多一个参数
8056f9fd 50 push eax
8056f9fe ff7508 push dword ptr [ebp+8]
8056fa01 e85bffffff call nt!ObpCloseHandle (8056f961)
;ObpCloseHandle(Handle, KeGetCurrentThread()->PreviousMode, 0);

8056fa06 5d pop ebp
8056fa07 c20400 ret 4
8056fa0a 90 nop
8056fa0b 90 nop
8056fa0c 90 nop
8056fa0d 90 nop
8056fa0e 90 nop
-------------------------------------------------------------------
lkd> u ObpCloseHandle l 20
nt!ObpCloseHandle:
8056f96c c645ff00 mov byte ptr [ebp-1],0
8056f970 64a124010000 mov eax,dword ptr fs:[00000124h]
8056f976 8b4d08 mov ecx,dword ptr [ebp+8] ;ecx = Handle
8056f979 8bf0 mov esi,eax
8056f97b 8b5e44 mov ebx,dword ptr [esi+44h] ;ebx = PsGetCurrentProcess();
8056f97e b800000080 mov eax,80000000h
8056f983 23c8 and ecx,eax
8056f985 3bc8 cmp ecx,eax
;/* Check if we're dealing with a kernel handle */
;#define KERNEL_HANDLE_FLAG (1 << ((sizeof(HANDLE) * 8) - 1))
; return (BOOLEAN)((ULONG_PTR)Handle & KERNEL_HANDLE_FLAG);

8056f987 0f84ccf00000 je nt!ObpCloseHandle+0x28 (8057ea59) ; -->Is a kernel handle
8056f98d 8bbbc4000000 mov edi,dword ptr [ebx+0C4h]
;edi = HandleTable = Process->ObjectTable;
;其他的判断会跳到这里

8056f993 ff7508 push dword ptr [ebp+8] ;
8056f996 ff8ed4000000 dec dword ptr [esi+0D4h];/* Disable Kernel APCs */
;Thread->KernelApcDisable--;
8056f99c 57 push edi
8056f99d e88bf6ffff call nt!ExMapHandleToPointer (8056f02d)
;eax = HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
8056f9a2 85c0 test eax,eax
8056f9a4 0f844e210200 je nt!ObpCloseHandle+0xbc (80591af8) ;-->failed,很多处理...
8056f9aa ff7510 push dword ptr [ebp+10h] ;比WRK中多一个参数
8056f9ad 6a00 push 0
8056f9af ff750c push dword ptr [ebp+0Ch]
8056f9b2 ff7508 push dword ptr [ebp+8]
8056f9b5 50 push eax
8056f9b6 57 push edi
8056f9b7 e853000000 call nt!ObpCloseHandleTableEntry (8056fa0f)
; /* Now close the entry */
;ObpCloseHandleTableEntry( HandleTable,HandleTableEntry,Handle,
; AccessMode,FALSE,0 );
8056f9bc ff86d4000000 inc dword ptr [esi+0D4h];/* Enable Kernel APCs */
;Thread->KernelApcDisable++;

-------------------------------------------------------------------
lkd> u 8057ea59 l 20 ;-->Is a kernel handle
nt!ObpCloseHandle+0x28:
8057ea59 807d0c00 cmp byte ptr [ebp+0Ch],0
8057ea5d 0f852a0fffff jne nt!ObpCloseHandle+0x5c (8056f98d)
8057ea63 837d08fe cmp dword ptr [ebp+8],0FFFFFFFEh
8057ea67 0f84200fffff je nt!ObpCloseHandle+0x5c (8056f98d)
8057ea6d 837d08ff cmp dword ptr [ebp+8],0FFFFFFFFh
8057ea71 0f84160fffff je nt!ObpCloseHandle+0x5c (8056f98d)
8057ea77 314508 xor dword ptr [ebp+8],eax
;#define ObKernelHandleToHandle(Handle) \
; (HANDLE)((ULONG_PTR)(Handle) & ~KERNEL_HANDLE_FLAG)
;Handle = ObKernelHandleToHandle(Handle);

8057ea7a a154965680 mov eax,dword ptr [nt!PsInitialSystemProcess (80569654)]
8057ea7f 3bd8 cmp ebx,eax
;/* Check if we're not in the system process */
8057ea81 8b3d388c5680 mov edi,dword ptr [nt!ObpKernelHandleTable (80568c38)]
8057ea87 0f84060fffff je nt!ObpCloseHandle+0x62 (8056f993)
8057ea8d 8d4de4 lea ecx,[ebp-1Ch]
8057ea90 51 push ecx
8057ea91 50 push eax
8057ea92 e8fe8af7ff call nt!KeStackAttachProcess (804f7595)
8057ea97 c645ff01 mov byte ptr [ebp-1],1
8057ea9b e9f30effff jmp nt!ObpCloseHandle+0x62 (8056f993);attach到system进程后跳回去
--------------------------------------------------------------

;继续进到ObpCloseHandleTableEntry函数中:
nt!ObpCloseHandleTableEntry:
8056fa17 8b7d0c mov edi,dword ptr [ebp+0Ch]
8056fa1a 8b37 mov esi,dword ptr [edi]
8056fa1c 83e6f8 and esi,0FFFFFFF8h
;esi = ObjectHeader = ObpGetHandleObject(HandleEntry);
;#define ObpGetHandleObject(x) \
; ((POBJECT_HEADER)((ULONG_PTR)x->Object & ~OBJ_HANDLE_ATTRIBUTES))

8056fa1f 8b4e08 mov ecx,dword ptr [esi+8]
;nt!_OBJECT_HEADER +0x008 Type : Ptr32 _OBJECT_TYPE
;ecx = ObjectType = ObjectHeader->Type;
8056fa22 83b9a800000000 cmp dword ptr [ecx+0A8h],0
; nt!_OBJECT_TYPE +0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER
; nt!_OBJECT_TYPE_INITIALIZER +0x048 OkayToCloseProcedure
;
8056fa29 8d5618 lea edx,[esi+18h] ; edx=Body=&ObjectHeader->Body;
8056fa2c 894dfc mov dword ptr [ebp-4],ecx
8056fa2f 89550c mov dword ptr [ebp+0Ch],edx
8056fa32 0f85e4ab0100 jne nt!ObpCloseHandleTableEntry+0x25 (8058a61c)
;-->正是跳到我们关心的地方.

------------------------------------------------------------------------
lkd> u 8058a61c
nt!ObpCloseHandleTableEntry+0x25:
8058a61c 64a124010000 mov eax,dword ptr fs:[00000124h]
8058a622 ff7514 push dword ptr [ebp+14h] ;AccessMode
8058a625 ff7510 push dword ptr [ebp+10h] ;Handle
8058a628 52 push edx ;Body
8058a629 ff7044 push dword ptr [eax+44h] ;PsGetCurrentProcess()
8058a62c ff91a8000000 call dword ptr [ecx+0A8h]
; if (!ObjectType->TypeInfo.OkayToCloseProcedure(
; PsGetCurrentProcess(),Body,Handle,AccessMode)) {
; /* 让其返回denny,直接拒绝关我们的句柄 */
; return STATUS_HANDLE_NOT_CLOSABLE;
; }
;
; ---- 要做手脚 ----
;典型的Object hook(MJ0011以前写过一篇文章,即是关于这个的[干涉注册表的hook];
;想必MJ跟踪了这些类似函数的流程,发现了这种隐蔽的hook)
;替换掉这个函数,在我们的fake函数中做处理,是我们自己要保护的handle,就拒绝之
; sudami[sudami@163.com] 2008/08/08
;
8058a632 84c0 test al,al
8058a634 0f85fe53feff jne nt!ObpCloseHandleTableEntry+0x52 (8056fa38)
8058a63a e929490700 jmp nt!ObpCloseHandleTableEntry+0x3f (805fef68) ; --->
8058a63f c3 ret
--------------------------------------------------------------------
lkd> u 805fef68 l 10
nt!ObpCloseHandleTableEntry+0x3f:
805fef68 57 push edi
805fef69 ff7508 push dword ptr [ebp+8]
805fef6c e802d7f6ff call nt!ExUnlockHandleTableEntry (8056c673)
805fef71 b8350200c0 mov eax,0C0000235h
; #define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS)0xC0000235)
805fef76 e9260bf7ff jmp nt!ObpCloseHandleTableEntry+0x158 (8056faa1)

lkd> u 8056faa1 l 10
nt!ObpCloseHandleTableEntry+0x158:
8056faa1 5f pop edi
8056faa2 5e pop esi
8056faa3 c9 leave
8056faa4 c21800 ret 18h

---------------------------------------------------------------------
ps:或者你可以进到ExDestroyHandle函数中,从这里思考其他思路
-->ExpLookupHandleTableEntry-->InterlockedExchangePointer(&HandleTableEntry->Object, NULL);

/////////////////////////////////////////////////////////////////////
继续原来的话题;关键就是patch掉那个函数,看看它的原型:

typedef NTSTATUS
(NTAPI *OB_OKAYTOCLOSE_METHOD)(
IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode
);

在fake函数中:

1. 处理参数2 - Object;若其type是进程/线程,且和我们关心的相匹配,return 0;
2. 处理参数3 - Handle;ObRefenceObjectByHanlde得到EPROCESS,判断之


以上思路具体实现后,便可以防止被其他程序关闭自身句柄.作用如下:
    1. 文件保护 -- 若部分ARK尝试关掉你进程的所有句柄后,删除你的"站炕"文件
[yykingking牛的那种站炕],即使发IRP,也会failed.
    2. 进程相关 -- 可能恶意程序想关掉CSRSS中的自身句柄,来防止被dump;你可以用此种方式保护之
    3. [...]

部分关键code如下:

//安装HOOK
void InstallHook()
{
    NTSTATUS status;
    PVOID CureentProcess;
    CureentProcess = (PVOID)PsGetCurrentProcess();

    __asm
    {
        push eax
        mov eax,CureentProcess
        mov eax,[eax-0x10]
        mov EprocessObjectType,eax
        pop eax
    }

    DbgPrint("Eprocess Object Type :%08x \n" , EprocessObjectType );
    Old_OkayToCloseProcedure = EprocessObjectType->TypeInfo.OkayToCloseProcedure;
    DbgPrint("Eprocess OkayToCloseProcedure routine :%08x \n ", Old_OkayToCloseProcedure );
    DbgPrint("DeleteProcedure routine :%08x \n "
                EprocessObjectType->TypeInfo.DeleteProcedure);
    if (!MmIsAddressValid(Old_OkayToCloseProcedure)) {
        DbgPrint("!MmIsAddressValid");
        return ;
    }
    EprocessObjectType->TypeInfo.OkayToCloseProcedure = fake_OkayToCloseProcedure;
    g_bObjectHook = TRUE;
    return ;
}

NTSTATUS
fake_OkayToCloseProcedure(    
    PEPROCESS Process OPTIONAL,
    PVOID Object,
    HANDLE Handle,
    KPROCESSOR_MODE AccessCheckMode
    )
{
    NTSTATUS stat ;
    PVOID ProcessObject;
    
    stat = ObReferenceObjectByHandle(Handle,
        GENERIC_READ,
        NULL,
        KernelMode,
        &ProcessObject,
        0);
    if (!NT_SUCCESS( stat )) {
        dbg("ObReferenceObjectByHandle failed!\n");
        goto _orig_;
    }
    // 若操作的对象是我们关心的进程,且是其他进程在操作
    // 拒绝之
    if ( (DWORD)g_target_eprocess == (DWORD)ProcessObject &&
        (DWORD)g_target_eprocess != (DWORD)Process ) {
        DbgPrint("%d :denny it \n", (DWORD)Process);
        return 0 ;
    }
    
    ///////////////////////////////////////////////////////////////////
_orig_:
    __asm
    {
        push eax
        movzx eax, AccessCheckMode
        push eax
        push Handle
        push Object
        push Process
        call Old_OkayToCloseProcedure
        mov stat, eax
        pop eax
    } 
    return stat ;
















附件是完整的object type hook的源码 和 调试笔记

第五届安全开发者峰会(SDC 2021)10月23日上海召开!限时2.5折门票(含自助午餐1份)

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (16)
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
lunglungyu 活跃值 1 2008-8-8 20:52
2
0
看着很好看
可惜不懂。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lOOp 活跃值 2008-8-8 23:07
3
0
一直对object hook都不大明白
占位学习
雪    币: 521
活跃值: 活跃值 (134)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
笨笨雄 活跃值 14 2008-8-9 00:02
4
0
他是0,你指定一个给他不行么? 用WRK,搜索对应的变量名,找到赋值得地方,再挂个钩监控,我个人估计,系统会先检测那个位置是不是0,如果已经是非0了,就不赋值了
雪    币: 478
活跃值: 活跃值 (640)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-8-9 00:13
5
0
不行.
可以给它指定一个地址,但此时会进入你的fake函数,要么全部放行,要么全部拒绝.等同于没有效果啊.

用WRK搜了之后,你会发现,系统初始化的时候没有给这个OkayToCloseProcedure安装回调函数.
我想应该是动态赋值....

所以啊...
雪    币: 521
活跃值: 活跃值 (134)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
笨笨雄 活跃值 14 2008-8-9 00:44
6
0
。。。。。。。。。。。。
雪    币: 478
活跃值: 活跃值 (640)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-8-9 09:12
7
0
附酷图一张,某XXer'k牛的



不可当真。。。
上传的附件:
  • 1.jpg (94.76kb,1253次下载)
雪    币: 88
活跃值: 活跃值 (151)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
frozenrain 活跃值 2008-8-9 09:23
8
0
驱动怎么老看不懂, 又那么难学
雪    币: 2362
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zapline 活跃值 2008-8-9 09:24
9
0
很强大··不懂··
雪    币: 308
活跃值: 活跃值 (55)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
zhuwg 活跃值 11 2008-8-9 12:57
10
0
我是进来学习的
雪    币: 302
活跃值: 活跃值 (79)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
SkyJack 活跃值 2008-8-11 22:58
11
0
收藏了,顶一个!
雪    币: 105
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
helyna 活跃值 2008-8-18 23:34
12
0
进来找死的我是
雪    币: 147
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
halfsoul 活跃值 2008-9-3 18:38
13
0
问大米个弱智的问题,你的代码中HOOK那个OkayToCloseProcedure的函数原型是什么得到的?
原来不是为NULL没有给出函数原型吗?,那你怎么知道
NTSTATUS
fake_OkayToCloseProcedure(       
        PEPROCESS Process OPTIONAL,
        PVOID Object,
        HANDLE Handle,
        KPROCESSOR_MODE AccessCheckMode
        )
参数的?
雪    币: 147
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
halfsoul 活跃值 2008-9-3 18:38
14
0
还有这种HOOK怎么检查呢?
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
老是忘 活跃值 2008-11-16 16:15
15
0
无聊1234
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
独舞红尘 活跃值 2009-4-6 22:51
16
0
我也是来学习的,很多看不懂
雪    币: 177
活跃值: 活跃值 (74)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
天堂猪 活跃值 2009-6-1 10:49
17
0
能否直接hook DeleteProcedure 或者SecurityProcedure,这个ok例程只是一个判断把,最终不是要调用别的码
游客
登录 | 注册 方可回帖
返回