下面是分析tessafe.sys对 NtReadVirtualMemory调用的过滤处理方法,以及应对办法。

 一、运行DNF后 打开windbg 定位到 NtReadVirtualMemory 函数位置,内核汇编代码如下:
     nt!NtReadVirtualMemory:
      805b52b8 b808d316b3      mov     eax,0B316D308h  ;TesSafe.sys hook位置
    805b52bd ffe0            jmp     eax
      805b52bf e8dc78f8ff      call    nt!_SEH_prolog (8053cba0)
      805b52c4 64a124010000    mov     eax,dword ptr fs:[00000124h]
      805b52ca 8bf8            mov     edi,eax
      805b52cc 8a8740010000    mov     al,byte ptr [edi+140h]
      805b52d2 8845e0          mov     byte ptr [ebp-20h],al
      805b52d5 8b7514          mov     esi,dword ptr [ebp+14h]
      805b52d8 84c0            test    al,al
      805b52da 7466            je      nt!NtReadVirtualMemory+0x8a (805b5342)
      805b52dc 8b450c          mov     eax,dword ptr [ebp+0Ch]
      805b52df 8d1430          lea     edx,[eax+esi]
      805b52e2 3bd0            cmp     edx,eax

      定位到0B316D308位置,此部分代码就是tessafe.sys的过滤函数。下面是对这些会汇编代码的分析,有点乱


      b316d308 8bff            mov     edi,edi
      b316d30a 55              push    ebp
      b316d30b 8bec            mov     ebp,esp
      b316d30d 81ec00010000    sub     esp,100h
      b316d313 60              pushad
      b316d314 9c              pushfd
      b316d315 b8206f17b3      mov     eax,0B3176F20h                          ;ecx = 0B3176F20h
      b316d31a 33c9            xor     ecx,ecx                                ;ecx =0
      b316d31c 41              inc     ecx                                    ;ecx = 1
      b316d31d f00fc108        lock xadd dword ptr [eax],ecx                  ;[0B3176F20h] += 1
      b316d321 ff154c4017b3    call    dword ptr ds:[0B317404Ch]              ;call nt!PsGetCurrentProcess    
      b316d327 8945f8          mov     dword ptr [ebp-8],eax                  ;[ebp-8]=current EPROCESS
      b316d32a 6a00            push    0                                      ; push 0
      b316d32c 8d45fc          lea     eax,[ebp-4]                            
      b316d32f 50              push    eax                                    ;push ptr[ebp-4]
      b316d330 6a00            push    0                                      ;push 0
      b316d332 a15c4117b3      mov     eax,dword ptr ds:[B317415Ch]            ;eax = [B317415Ch]=805649b8
      b316d337 ff30            push    dword ptr [eax]                        ;push 805649b8
      b316d339 6800040000      push    400h                                    ;push 0x400
      b316d33e ff7508          push    dword ptr [ebp+8]                      ;push 目标进程 ProcessHandle
      b316d341 ff159c4017b3    call    dword ptr ds:[0B317409Ch]              ;call ObReferenceObjectByHandle
      b316d347 8945f4          mov     dword ptr [ebp-0Ch],eax                ;判断函数调用是否成功
      b316d34a 837df400        cmp     dword ptr [ebp-0Ch],0
      b316d34e 7d02            jge     b316d352                                
      b316d350 eb65            jmp     b316d3b7                                ;不成功跳转
      b316d352 8b4dfc          mov     ecx,dword ptr [ebp-4]                  ;ecx = 目标进程句柄信息
      b316d355 ff15584117b3    call    dword ptr ds:[0B3174158h]              ;call ObfDereferenceObject   撤销对象的引用计数
      b316d35b 8b45fc          mov     eax,dword ptr [ebp-4]                  ;eax = 目标的句柄信息
      b316d35e 3b45f8          cmp     eax,dword ptr [ebp-8]                  ;比较目标进程是否是本进程
      b316d361 7502            jne     b316d365                                ;不能,继续判断
      b316d363 eb52            jmp     b316d3b7                                ;相等不进行拦截
      b316d365 6a04            push    4                                      ;push 4
      b316d367 ff75fc          push    dword ptr [ebp-4]                      ;push 目标进程句柄信息
      b316d36a e8c3fdffff      call    b316d132                                ;判断目标进程是否是DNF进程
      b316d36f 0fb6c0          movzx   eax,al                              
      b316d372 85c0            test    eax,eax
      b316d374 7502            jne     b316d378            
      b316d376 eb3f            jmp     b316d3b7                                ;目标进程不是DNF进程,不进行拦截    
      b316d378 6a04            push    4                                      ;push 4
      b316d37a ff75f8          push    dword ptr [ebp-8]                      ;当前进程eprocess
      b316d37d e8f0fcffff      call    b316d072                                ;比较当前进程是否在白名单中
      b316d382 0fb6c0          movzx   eax,al
      b316d385 85c0            test    eax,eax
      b316d387 7402            je      b316d38b                                ;在白名单中,继续判断
      b316d389 eb2c            jmp     b316d3b7                                ;不再则跳转,将屏蔽此次调用
      b316d38b 6a04            push    4                                      ;push 4
      b316d38d ff75f8          push    dword ptr [ebp-8]                      ;push 目标进程结构
      b316d390 e81bfdffff      call    b316d0b0                                ;判断是否在另外一份白名单中  
      b316d395 0fb6c0          movzx   eax,al
      b316d398 85c0            test    eax,eax
      b316d39a 7402            je      b316d39e                                ;在第二份白名单中  
      b316d39c eb19            jmp     b316d3b7                                ;不在第二份白名单中,将屏蔽此次调用
      b316d39e b8206f17b3      mov     eax,0B3176F20h                          ;
      b316d3a3 83c9ff          or      ecx,0FFFFFFFFh
      b316d3a6 f00fc108        lock xadd dword ptr [eax],ecx                  ;[0B3176F20h] += -1
      b316d3aa 9d              popfd
      b316d3ab 61              popad
      b316d3ac 8be5            mov     esp,ebp                               ;
      b316d3ae 5d              pop     ebp
       b316d3af b80d0000c0      mov     eax,0C000000Dh                          ;置返回错误代码
      b316d3b4 c21400          ret     14h                                    ;不在白名单中,调用失败
      b316d3b7 b8206f17b3      mov     eax,0B3176F20h                        ;[0B3176F20h] += -1
      b316d3bc 83c9ff          or      ecx,0FFFFFFFFh
      b316d3bf f00fc108        lock xadd dword ptr [eax],ecx
      b316d3c3 9d              popfd
      b316d3c4 61              popad
      b316d3c5 8be5            mov     esp,ebp
      b316d3c7 5d              pop     ebp
      b316d3c8 6a1c            push    1Ch
      b316d3ca 68f0ae4d80      push    offset nt!MmClaimParameterAdjustDownTime+0x90 (804daef0)
      b316d3cf 90              nop
      b316d3d0 90              nop
      b316d3d1 90              nop
      b316d3d2 90              nop
      b316d3d3 90              nop
      b316d3d4 90              nop
      b316d3d5 90              nop
      b316d3d6 90              nop
      b316d3d7 90              nop
       b316d3d8 ff253c6e17b3    jmp     dword ptr ds:[0B3176E3Ch]          ;跳转到
      b316d3de cc              int     3
      b316d3df cc              int     3
            
  //==============================================================================
  b316d132  如果为DNF进程返回0 否则返回1
 
      b316d132 8bff            mov     edi,edi
      b316d134 55              push    ebp
      b316d135 8bec            mov     ebp,esp
      b316d137 51              push    ecx
      b316d138 53              push    ebx
      b316d139 56              push    esi
      b316d13a c645ff00        mov     byte ptr [ebp-1],0                  ;[ebp-1] = 0;
      b316d13e 32db            xor     bl,bl                              ;bl = 0;
      b316d140 ff15084017b3    call    dword ptr ds:[0B3174008h]          ;call KeGetCurrentIrql 得到IRQ级别
      b316d146 3c02            cmp     al,2                                ;判断是否在 DISPATCH_LEVEL级别
      b316d148 bebc7117b3      mov     esi,0B31771BCh                      ;esi = 0B31771BCh
      b316d14d 8bce            mov     ecx,esi                            ;ecx = 0B31771BCh
      b316d14f 720a            jb      b316d15b                            ;小于DISPATCH_LEVEL级别 跳转
      b316d151 ff15784017b3    call    dword ptr ds:[0B3174078h]          ; call KefAcquireSpinLockAtDpcLevel
      b316d157 fec3            inc     bl                                  ;b1++
      b316d159 eb09            jmp     b316d164                      
      b316d15b ff150c4017b3    call    dword ptr ds:[0B317400Ch]          ;call KfAcquireSpinLock
      b316d161 8845fe          mov     byte ptr [ebp-2],al
      b316d164 a1c07117b3      mov     eax,dword ptr ds:[B31771C0h]       ;eax = [B31771C0h]=88c1dee4 
      b316d169 b9c07117b3      mov     ecx,0B31771C0h                      ;ecx = 0B31771C0h
      b316d16e eb0a            jmp     b316d17a
      b316d170 8b50cc          mov     edx,dword ptr [eax-34h]            ;取得链表节点对应eprocess
      b316d173 3b5508          cmp     edx,dword ptr [ebp+8]              ;与目标进程比较
      b316d176 7408            je      b316d180                            ;相等 跳转
      b316d178 8b00            mov     eax,dword ptr [eax]
      b316d17a 3bc1            cmp     eax,ecx                            ;比较 [B31771C0h] == 0B31771C0h 比较是否到链表尾部
      b316d17c 75f2            jne     b316d170                            ;不等进行进程eprocess 比较
      b316d17e eb0c            jmp     b316d18c                            ;到链表结尾,跳转
      b316d180 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]            ;ECX=4
      b316d183 8548e0          test    dword ptr [eax-20h],ecx            ;0x7ff&0x04 >0    
      b316d186 7404            je      b316d18c
      b316d188 c645ff01        mov     byte ptr [ebp-1],1                  ;[ebp-1]=1
      b316d18c 84db            test    bl,bl                              ;b1 ==0
      b316d18e 8bce            mov     ecx,esi                            ;ecx=0B31771BCh
      b316d190 7408            je      b316d19a                            ;=0 跳转
      b316d192 ff15744017b3    call    dword ptr ds:[0B3174074h]
       b316d198 eb09            jmp     b316d1a3
      b316d19a 8a55fe          mov     dl,byte ptr [ebp-2]                ;dl =irql级别
      b316d19d ff15104017b3    call    dword ptr ds:[0B3174010h]          ;call KfReleaseSpinLock
      b316d1a3 8a45ff          mov     al,byte ptr [ebp-1]                a1 = 1
      b316d1a6 5e              pop     esi
      b316d1a7 5b              pop     ebx
      b316d1a8 c9              leave
      b316d1a9 c20800          ret     8
//=====================================================================
b316d072  判断是否在白名单1中

      b316d072 8bff            mov     edi,edi                        
      b316d074 55              push    ebp
      b316d075 8bec            mov     ebp,esp
      b316d077 8b0da87117b3    mov     ecx,dword ptr [TesSafe+0xd1a8 (b31771a8)]  ;ecx = [b31771a8] = 89a3442c 
      b316d07d baa87117b3      mov     edx,offset TesSafe+0xd1a8 (b31771a8)        ;edx = b31771a8 
      b316d082 32c0            xor     al,al                                      ;a1 = 0
      b316d084 3bca            cmp     ecx,edx                                    ;判断是否是空链表      
      b316d086 741f            je      TesSafe+0x30a7 (b316d0a7)                  ;空链表跳转
      b316d088 56              push    esi                    
      b316d089 8b7508          mov     esi,dword ptr [ebp+8]                      ;esi=当前进程EPROCESS
      b316d08c 3b71dc          cmp     esi,dword ptr [ecx-24h]                    ;比较目标进程是否在白名单中
      b316d08f 7408            je      TesSafe+0x3099 (b316d099)                  ;相等则跳转
      b316d091 8b09            mov     ecx,dword ptr [ecx]                        ;取下一个节点
      b316d093 3bca            cmp     ecx,edx                                    ;判断是否到链表结尾
      b316d095 75f2            jne     TesSafe+0x3089 (b316d089)                  ;不到则继续判断
      b316d097 eb0d            jmp     TesSafe+0x30a6 (b316d0a6)                  ;到链表结尾,而且没有在白名单中匹配
      b316d099 8b550c          mov     edx,dword ptr [ebp+0Ch]                    ;edx =4
      b316d09c ff41fc          inc     dword ptr [ecx-4]                          ;[ecx-4]++
      b316d09f 8551e4          test    dword ptr [ecx-1Ch],edx                    ;[ecx-1ch] 是否等于4 不等于4 则屏蔽
      b316d0a2 7402            je      TesSafe+0x30a6 (b316d0a6)                  
      b316d0a4 b001            mov     al,1
      b316d0a6 5e              pop     esi
      b316d0a7 5d              pop     ebp
      b316d0a8 c20800          ret     8

 在windbg 查看
 
 lkd> dd 89a3442c-24
89a34408  8a5aa288 00000500 000fffff e8710e72
89a34418  74737953 00006d65 00000000 00000000
89a34428  00000000 88afc274 b31771a8 005c003f
89a34438  0a090007 68734c4b 89d5c8f0 89ad8778
89a34448  896ec690 00000000 00000000 897e47a8
89a34458  89d5dbf0 89ad87dc 00010000 00000001
89a34468  0001502b 00000000 e3a67220 00000008
89a34478  00000000 00000000 0a080009 e174754d
lkd> !process 8a5aa288 0
Unable to read selector for PCR for processor 0
PROCESS 8a5aa288  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 0aed8020  ObjectTable: e1002e38  HandleCount: 474.
    Image: System

下面我找到白名单进程
System
smss.exe
csrss.exe
SERVICES.EXE
LSASS.EXE
SVCHOST.EXE


//===========================
判断是否在白名单2中
      b2a510b0 8bff            mov     edi,edi
      b2a510b2 55              push    ebp
      b2a510b3 8bec            mov     ebp,esp
      b2a510b5 51              push    ecx
      b2a510b6 53              push    ebx
      b2a510b7 56              push    esi
      b2a510b8 c645ff00        mov     byte ptr [ebp-1],0                                  ;[ebp-1] = 0
      b2a510bc 32db            xor     bl,bl                                              ;b1 = 0
      b2a510be ff150880a5b2    call    dword ptr [TesSafe+0xa008 (b2a58008)]              call KeGetCurrentIrql
      b2a510c4 3c02            cmp     al,2                                                比较当前IRQL级别是否为DISPATCH_LEVEL级别
      b2a510c6 beb8b1a5b2      mov     esi,offset TesSafe+0xd1b8 (b2a5b1b8)                esi = b2a5b1b8
      b2a510cb 8bce            mov     ecx,esi                                            ecx = b2a5b1b8
      b2a510cd 720a            jb      TesSafe+0x30d9 (b2a510d9)                          ;小于DISPATCH_LEVEL级别 跳转
      b2a510cf ff157880a5b2    call    dword ptr [TesSafe+0xa078 (b2a58078)]              ;call Ke386QueryIoAccessMap
      b2a510d5 fec3            inc     bl                                                  ;b1 = 1
      b2a510d7 eb09            jmp     TesSafe+0x30e2 (b2a510e2)                          
      b2a510d9 ff150c80a5b2    call    dword ptr [TesSafe+0xa00c (b2a5800c)]              ;call KfAcquireSpinLock
      b2a510df 8845fe          mov     byte ptr [ebp-2],al                                [ebp-2] 保存当前IRQL        
      b2a510e2 a1b0b1a5b2      mov     eax,dword ptr [TesSafe+0xd1b0 (b2a5b1b0)]          ;eax = [b2a5b1b0]=8993e02c 
      b2a510e7 b9b0b1a5b2      mov     ecx,offset TesSafe+0xd1b0 (b2a5b1b0)                ;ecx = b2a5b1b0
      b2a510ec eb0a            jmp     TesSafe+0x30f8 (b2a510f8)
      b2a510ee 8b50dc          mov     edx,dword ptr [eax-24h]                            
      b2a510f1 3b5508          cmp     edx,dword ptr [ebp+8]                              ;白名单判断
      b2a510f4 7408            je      TesSafe+0x30fe (b2a510fe)
      b2a510f6 8b00            mov     eax,dword ptr [eax]
      b2a510f8 3bc1            cmp     eax,ecx
      b2a510fa 75f2            jne     TesSafe+0x30ee (b2a510ee)
      b2a510fc eb0f            jmp     TesSafe+0x310d (b2a5110d)
      b2a510fe 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
      b2a51101 ff40fc          inc     dword ptr [eax-4]
      b2a51104 8548e4          test    dword ptr [eax-1Ch],ecx
      b2a51107 7404            je      TesSafe+0x310d (b2a5110d)
      b2a51109 c645ff01        mov     byte ptr [ebp-1],1
      b2a5110d 84db            test    bl,bl
      b2a5110f 8bce            mov     ecx,esi
      b2a51111 7408            je      TesSafe+0x311b (b2a5111b)
      b2a51113 ff157480a5b2    call    dword ptr [TesSafe+0xa074 (b2a58074)]
      b2a51119 eb09            jmp     TesSafe+0x3124 (b2a51124)
      b2a5111b 8a55fe          mov     dl,byte ptr [ebp-2]
      b2a5111e ff151080a5b2    call    dword ptr [TesSafe+0xa010 (b2a58010)]
      b2a51124 8a45ff          mov     al,byte ptr [ebp-1]
      b2a51127 5e              pop     esi
      b2a51128 5b              pop     ebx
      b2a51129 c9              leave
      b2a5112a c20800          ret     8

  
  TXPlatform.exe
  QQ.exe





二 、过滤处理函数的伪代码

int g_globalValue;
 int MyNtReadVirtualMemory(IN HANDLE ProcessHandle,
                                              IN PVOID BaseAddress,
                                              OUT PVOID Buffer,
                                               IN SIZE_T NumberOfBytesToRead,
                                               OUT PSIZE_T NumberOfBytesRead OPTIONAL) 
{
      PEPROCESS AimProcess;
      PEPROCESS curProcess;
      //全局变量计数器加1 具体作用不详
       g_globalValue++;

      //得到当前进程信息
      curProcess = PsGetCurrentProcess();

      //得到目标进程的进程信息
       int status = ObReferenceObjectByHandle(ProcessHandle, ,,,,&AimProcess);
       if(status  < 0)
      {
           //返回失败,跳到不mask标签位置
           goto _ NoMask;       
      }

      //减少引用计数
      ObfDereferenceObject(&AimProcess);

      if(curProcess  == AimProcess)
     {
         //如果当前进程等于目的进程,则不屏蔽
       goto _ NoMask;       
     }

     if(0 == IsDnfProcess(&AimProcess, 4) )
     {
          //如果目的进程不是DNF进程,则不屏蔽
       goto _ NoMask;       
     }
        
    //判断当前进程是否在白名单1中
    if(0 == JudeWhileList1((&curProcess, 4))
   {
          //在白名单1中,则不屏蔽
        goto _ NoMask;   
   }
    
   //判断当前进程是否在白名单2中
  if(0 == JudeWhileList2((&curProcess, 4))
   {
          //在白名单2中,则不屏蔽
        goto _ NoMask;   
   }


   //目的进程时DNF进程,而且既不在白名单1中,也不在白名单2中,所以下面将屏蔽此次调用
   ret = 0C000000Dh;
   return   ret;
    

//不进行屏蔽处理   
_NoMask:
   
   //全局变量计数器-1
   g_globalValue--;
   
   __asm
  {
  
   jmp NtReadVirtualMemory + 7
 
  }
}

   对于白名单1主要为系统常驻进程如下:
System
smss.exe
csrss.exe
SERVICES.EXE
LSASS.EXE
SVCHOST.EXE

   对于白名单2 可能为目前用户打开的信任进程,我这里的是

  TXPlatform.exe
  QQ.exe

三、应对

   1、tessafe.sys 对NtReadVirtualMemory的hook 好像其没有对恢复进行检测
   2、让IsDnfProcess函数返回0
       其实这个函数内部也是有个表,这表中存储的为DNF进程的eprocess结构,如果将
       其清0 ,应该可以,我没有测试过。
    3、将你想要的进程添加到白名单中。


   上面的应对代码我就不写了,有兴趣的可以搜索下论坛。