x32下PsSetLoadImageNotifyRoutine的逆向

一丶简介

纯属兴趣爱好.特来逆向玩玩.
PsSetLoadImageNotifyRoutine 是内核中用来监控模块加载.操作系统给我们提供的回调. 我们只需要填写对应的回调函数原型即可进行加监控.
既然可以进行监控.那么我们的回调函数存储在哪.这是个问题.所以特来逆向玩玩.

二丶逆向过程

首先我的思路是直接windbg 挂载win7. 然后找到对应的函数进行
uf 反汇编. 来静态查看. 如果那里有疑问则自己进行动态查看.
过程很快.因为逆向过 进程回调监控.所以这个也就很快了.慢慢学习经验.

1.逆向PsSetLoadImageNotifyRoutine


3f809b3 8bff            mov     edi,edi
83f809b5 55              push    ebp
83f809b6 8bec            mov     ebp,esp
83f809b8 53              push    ebx
83f809b9 56              push    esi
83f809ba 57              push    edi
83f809bb 33ff            xor     edi,edi
83f809bd 57              push    edi

83f809be ff7508          push    dword ptr [ebp+8]					参数1压栈: 参数1 = 我们设置的回调函数地址.


83f809c1 e8113d0200      call    nt!ExAllocateCallBack (83fa46d7)	逆向一下ExAllocateCallBack		
83f809c6 8bd8            mov     ebx,eax
83f809c8 3bdf            cmp     ebx,edi
83f809ca 7425            je      nt!PsSetLoadImageNotifyRoutine+0x3e (83f809f1)		//内部会申请一个结构体内存.保存我们的函数指针 以及 参数 结果给eax.

nt!PsSetLoadImageNotifyRoutine+0x19:
83f809cc be802bf583      mov     esi,offset nt!PspLoadImageNotifyRoutine (83f52b80)//得出回调函数数组.

nt!PsSetLoadImageNotifyRoutine+0x1e:
83f809d1 6a00            push    0									0
83f809d3 8bcb            mov     ecx,ebx							ecx = 结构体指针
83f809d5 8bc6            mov     eax,esi							eax = 回调函数数组.
																	ExCompareExchangeCallBack(函数数组,结构体指针,0); 根据函数名可以得知 比较交换回调函数指针. 逆向志之 在下面观看.
83f809d7 e82a3d0200      call    nt!ExCompareExchangeCallBack (83fa4706)
83f809dc 84c0            test    al,al
83f809de 751d            jne     nt!PsSetLoadImageNotifyRoutine+0x4a (83f809fd)

nt!PsSetLoadImageNotifyRoutine+0x2d:
83f809e0 83c704          add     edi,4
83f809e3 83c604          add     esi,4
83f809e6 83ff20          cmp     edi,20h
83f809e9 72e6            jb      nt!PsSetLoadImageNotifyRoutine+0x1e (83f809d1)

nt!PsSetLoadImageNotifyRoutine+0x38:
83f809eb 53              push    ebx
83f809ec e824b71000      call    nt!SepFreeCapturedString (8408c115)

nt!PsSetLoadImageNotifyRoutine+0x3e:
83f809f1 b89a0000c0      mov     eax,0C000009Ah

nt!PsSetLoadImageNotifyRoutine+0x43:
83f809f6 5f              pop     edi
83f809f7 5e              pop     esi
83f809f8 5b              pop     ebx
83f809f9 5d              pop     ebp
83f809fa c20400          ret     4

nt!PsSetLoadImageNotifyRoutine+0x4a:
83f809fd 33c9            xor     ecx,ecx
83f809ff b8a02bf583      mov     eax,offset nt!PspLoadImageNotifyRoutineCount (83f52ba0)
83f80a04 41              inc     ecx
83f80a05 f00fc108        lock xadd dword ptr [eax],ecx
83f80a09 a1782bf583      mov     eax,dword ptr [nt!PspNotifyEnableMask (83f52b78)]
83f80a0e a801            test    al,1
83f80a10 750a            jne     nt!PsSetLoadImageNotifyRoutine+0x69 (83f80a1c)

nt!PsSetLoadImageNotifyRoutine+0x5f:
83f80a12 b8782bf583      mov     eax,offset nt!PspNotifyEnableMask (83f52b78)
83f80a17 f00fba2800      lock bts dword ptr [eax],0

nt!PsSetLoadImageNotifyRoutine+0x69:
83f80a1c 33c0            xor     eax,eax
83f80a1e ebd6            jmp     nt!PsSetLoadImageNotifyRoutine+0x43 (83f809f6)

通过逆向次函数.可以得出我们的回调函数数组. 以及我们申请的回调函数指针.

伪代码

{

    结构体指针 = ExAllocateCallBack(回调函数地址,0);
    ExCompareExchangeCallBack(函数数组,结构体指针,0); 内部进行解密
}

关于上面的函数逆向.如下:

2.逆向 ExAllocateCallBack


3fa46d7 8bff            mov     edi,edi
83fa46d9 55              push    ebp
83fa46da 8bec            mov     ebp,esp
83fa46dc 6843627262      push    62726243h
83fa46e1 6a0c            push    0Ch
83fa46e3 6a01            push    1

83fa46e5 e81bc9f8ff      call    nt!ExAllocatePoolWithTag (83f31005)	申请内存 eax = ExAllocatePoolWithTag(1,0xC,62726243)
83fa46ea 85c0            test    eax,eax

83fa46ec 740f            je      nt!ExAllocateCallBack+0x26 (83fa46fd)

83fa46ee 8b4d08          mov     ecx,dword ptr [ebp+8]					ecx = 参数1
83fa46f1 832000          and     dword ptr [eax],0						struct->one = 0
83fa46f4 894804          mov     dword ptr [eax+4],ecx					struct->two = ecx[ebp + 8] ==> 参数二
83fa46f7 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]				
83fa46fa 894808          mov     dword ptr [eax+8],ecx					struct->Three = [eb[ + c] ==> 参数三
83fa46fd 5d              pop     ebp
83fa46fe c20800          ret     8

汇编代码很简单.通过下面进行赋值可以看做是一个结构体

逆向得知,ExAllocateCallBack其实是申请一块内存.
并且转化为一个结构进行赋值
例如下:

struct 
{
 ULONG UnKnow1;
 ULONG UnKnow2;
 ULONG UnKnow3;
}

但是根据传参得知. UnKnow2 == 我们的回调地址 Unknow3 ==> 我们的参数

然后查看Wrk源码.得出以下结构

typedef struct _EX_CALLBACK_ROUTINE_BLOCK {
    EX_RUNDOWN_REF        RundownProtect;
    PEX_CALLBACK_FUNCTION Function;
    PVOID                 Context;
} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

3.逆向交换 解密函数 ExCompareExchangeCallBack


nt!ExCompareExchangeCallBack:
83fa4706 8bff            mov     edi,edi
83fa4708 55              push    ebp
83fa4709 8bec            mov     ebp,esp

83fa470b 51              push    ecx
83fa470c 51              push    ecx
83fa470d 53              push    ebx
83fa470e 56              push    esi
83fa470f 57              push    edi

83fa4710 8bf0            mov     esi,eax		eax ============> 回调函数数组

83fa4712 85c9            test    ecx,ecx		ecx =  结构体指针

83fa4714 7410            je      nt!ExCompareExchangeCallBack+0x20 (83fa4726)

nt!ExCompareExchangeCallBack+0x10:
83fa4716 6a08            push    8
83fa4718 5a              pop     edx
83fa4719 e87670efff      call    nt!ExAcquireRundownProtectionEx (83e9b794)
83fa471e 84c0            test    al,al

83fa4720 0f84aa000000    je      nt!ExCompareExchangeCallBack+0xca (83fa47d0)

nt!ExCompareExchangeCallBack+0x20:

83fa4726 8b1e            mov     ebx,dword ptr [esi]				ebx = 数组[0]
83fa4728 8bc3            mov     eax,ebx							eax = ebx

83fa472a eb1d            jmp     nt!ExCompareExchangeCallBack+0x43 (83fa4749)

nt!ExCompareExchangeCallBack+0x26:
83fa472c 85c9            test    ecx,ecx
83fa472e 7407            je      nt!ExCompareExchangeCallBack+0x31 (83fa4737)

nt!ExCompareExchangeCallBack+0x2a:
83fa4730 8bc1            mov     eax,ecx
83fa4732 83c807          or      eax,7
83fa4735 eb02            jmp     nt!ExCompareExchangeCallBack+0x33 (83fa4739)

nt!ExCompareExchangeCallBack+0x31:
83fa4737 33c0            xor     eax,eax

nt!ExCompareExchangeCallBack+0x33:
83fa4739 8bd0            mov     edx,eax
83fa473b 8bfe            mov     edi,esi
83fa473d 8bc3            mov     eax,ebx
83fa473f f00fb117        lock cmpxchg dword ptr [edi],edx
83fa4743 3bc3            cmp     eax,ebx
83fa4745 740a            je      nt!ExCompareExchangeCallBack+0x4b (83fa4751)

nt!ExCompareExchangeCallBack+0x41:
83fa4747 8bd8            mov     ebx,eax


=================================>

nt!ExCompareExchangeCallBack+0x43:
83fa4749 334508          xor     eax,dword ptr [ebp+8]					数组[0] ^ 0 = 自己本身
83fa474c 83f807          cmp     eax,7
83fa474f 76db            jbe     nt!ExCompareExchangeCallBack+0x26 (83fa472c) //eax  = 数组[0] 所以不走这个循环.

nt!ExCompareExchangeCallBack+0x4b:
83fa4751 8bfb            mov     edi,ebx								开始解密  edi = ebx = 数组[0]
83fa4753 83e7f8          and     edi,0FFFFFFF8h							edi = 数组[0] & 0xFFFFFFF8 = 结构体指针.  至此已经解析完毕了.
83fa4756 3b7d08          cmp     edi,dword ptr [ebp+8]
83fa4759 7569            jne     nt!ExCompareExchangeCallBack+0xbe (83fa47c4)

nt!ExCompareExchangeCallBack+0x55:
83fa475b 85ff            test    edi,edi
83fa475d 7461            je      nt!ExCompareExchangeCallBack+0xba (83fa47c0)

nt!ExCompareExchangeCallBack+0x59:
83fa475f 648b3524010000  mov     esi,dword ptr fs:[124h]
83fa4766 66ff8e86000000  dec     word ptr [esi+86h]
83fa476d 8745fc          xchg    eax,dword ptr [ebp-4]
83fa4770 8b0dd8c7f483    mov     ecx,dword ptr [nt!ExpCallBackFlush (83f4c7d8)]
83fa4776 83e101          and     ecx,1
83fa4779 8745f8          xchg    eax,dword ptr [ebp-8]
83fa477c 85c9            test    ecx,ecx
83fa477e 7414            je      nt!ExCompareExchangeCallBack+0x8e (83fa4794)

nt!ExCompareExchangeCallBack+0x7a:
83fa4780 b9d8c7f483      mov     ecx,offset nt!ExpCallBackFlush (83f4c7d8)
83fa4785 e803e4efff      call    nt!ExfAcquirePushLockExclusive (83ea2b8d)
83fa478a b9d8c7f483      mov     ecx,offset nt!ExpCallBackFlush (83f4c7d8)
83fa478f e81d10f8ff      call    nt!ExfReleasePushLockExclusive (83f257b1)

nt!ExCompareExchangeCallBack+0x8e:
83fa4794 66ff8686000000  inc     word ptr [esi+86h]
83fa479b 0fb78686000000  movzx   eax,word ptr [esi+86h]
83fa47a2 6685c0          test    ax,ax
83fa47a5 750c            jne     nt!ExCompareExchangeCallBack+0xad (83fa47b3)

nt!ExCompareExchangeCallBack+0xa1:
83fa47a7 8d4640          lea     eax,[esi+40h]
83fa47aa 3900            cmp     dword ptr [eax],eax
83fa47ac 7405            je      nt!ExCompareExchangeCallBack+0xad (83fa47b3)

nt!ExCompareExchangeCallBack+0xa8:
83fa47ae e8e63ce9ff      call    nt!KiCheckForKernelApcDelivery (83e38499)

nt!ExCompareExchangeCallBack+0xad:
83fa47b3 8bd3            mov     edx,ebx
83fa47b5 83e207          and     edx,7
83fa47b8 42              inc     edx
83fa47b9 8bcf            mov     ecx,edi
83fa47bb e81718eaff      call    nt!ExReleaseRundownProtectionEx (83e45fd7)

nt!ExCompareExchangeCallBack+0xba:
83fa47c0 b001            mov     al,1
83fa47c2 eb0e            jmp     nt!ExCompareExchangeCallBack+0xcc (83fa47d2)

nt!ExCompareExchangeCallBack+0xbe:
83fa47c4 85c9            test    ecx,ecx
83fa47c6 7408            je      nt!ExCompareExchangeCallBack+0xca (83fa47d0)

nt!ExCompareExchangeCallBack+0xc2:
83fa47c8 6a08            push    8
83fa47ca 5a              pop     edx
83fa47cb e80718eaff      call    nt!ExReleaseRundownProtectionEx (83e45fd7)

nt!ExCompareExchangeCallBack+0xca:
83fa47d0 32c0            xor     al,al

nt!ExCompareExchangeCallBack+0xcc:
83fa47d2 5f              pop     edi
83fa47d3 5e              pop     esi
83fa47d4 5b              pop     ebx
83fa47d5 c9              leave
83fa47d6 c20400          ret     4

逆向这个函数可以得知.最后我们的数组会与 0xFFFFFFF8 进行and操作.操作之后的结果就是我们上面 逆向ExAllocateCallBack
得出的结构体指针原型.

结构体->two 成员就是记录我们想要的回调函数地址.

三丶总结

1.通过逆向 ExAllocateCallBack 我们得出了结构体原型.以及我们的回调函数如何存储

typedef struct _EX_CALLBACK_ROUTINE_BLOCK {
EX_RUNDOWN_REF RundownProtect;
PEX_CALLBACK_FUNCTION Function;
PVOID Context;
} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

2.通过逆向 ExCompareExchangeCallBack我们得知数组是如何解密的
PEX_CALLBACK_ROUTINE_BLOCK pRoutine = 数组[0] & 0xFFFFFFF8;

pRoutine->Function == 我们要寻找的回调函数

3.简介
从以前的逆向PsSetCreateProcessRoutine得知.他也是通过 & 0xFFFFFFFF8进行解密的.
win64的也有逆向出来. 界面的数值为 & 0xFFFFFFFFFFFFFFF0 进行解密的. 关于64的.后面继续发.

在64位下感觉数组解密应该用的都是 0xFFFFFFFFFFFFFFF0 进行解密的(win7 64)

posted @ 2019-08-03 22:00  iBinary  阅读(833)  评论(0编辑  收藏  举报