过NtOpenProcess保护的方法总结


来自:http://blog.csdn.net/jepco1/article/details/5531449

过NtOpenProcess保护的方法总结,搜集了一下网上的方案,自己整理了一下。

一般的保护程序喜欢在NtOpenProcess中设置inline hook,修改返回句柄。调试程序使用该程序附加附加到被保护进程的时候,就得不到正确的进程访问句柄,因而附加失败。

反此类保护可以有这样几种思路

一.恢复
      找到inline hook 的地方,恢复之。
      一般可能在NtOpenProcess的开头几个字节(惯例了)。开始查找jmp ,push xxxxxxxx ret,等等与跳转有关的语句,判断跳转的地址是否到了模块外面。从而判断是否跳转,还有些会在进程内设置一个跳板,通过跳板再跳出去,等等,总之一定会跳出模块的。 具体查看inline hook的原理文章。
二.绕过
     保护程序监视inline hook的地址,如果发现inline hook被恢复,保护程序就会判断有攻击。
     解决办法,
     1.保存ssdt中原NtOpenProcess函数的服务地址。
     2.保存原函数从开始到保护程序inline hook结束的代码。
     3.直接将ssdt中的服务地址改为自定义的hook函数MyNtProcess.
     4.MyNtProcess由两部分组成,第一部分部分为保存的原函数,第二部分为jmp到inline hook的下一条语句。
     (实现可参考附1代码)
三.深入
    绕过了NtOpenProcess不等于就成功了。NtOpenProcess中调用了两个重要的函数
    1.PAGE:004AA813                 call    _PsLookupProcessByProcessId@8 ; PsLookupProcessByProcessId(x,x)       // 得到进程id
    2.PAGE:004AA83D                 call    _ObOpenObjectByPointer@28 ; ObOpenObjectByPointer(x,x,x,x,x,x,x)        // 得到进程访问句柄
    保护程序通常这两个个地方进一步做手脚,比如增加一个inline hook,如果发现有其它进程要访问被保护进程就返回错误的进程id或无效的访问句柄。
    同样如果保护程序没有做校验,可以直接恢复inline hook。如果做了检验,那就只能绕过了。
    绕过的办法和方法二大同小异。
    1.定义MyNtOpenProcess代码体。MyNtOpenProcess由4个部分组成。
    2.将call ObOpenObjectByPointer的代码的前面几条指令保存到MyNtOpenProcess第一部分。
    3.将push xxxx 写入MyNtOpenProcess的第二部分xxxx为call ObOpenObjectByPointer的下一条指令位置。ret返回地址。
    4.将call ObOpenObjectByPointer被inline hook 覆盖的代码保存为第三部分。
    5.将jmp xxxx 写入MyNtOpenProcess的第四部分。
    6.定义完代码体后,就可以修改call ObOpenObjectByPointer函数了,直接将call ObOpenObjectByPointer的前面一段语句替换为jmp xxxx就可以了,xxxx为MyNtOpenProcess的地址。
    原始情况
    NtOpenProcess 函数
          ……
          PAGE:004AA836                 push    eax             ; int
          PAGE:004AA837                 push    [ebp+var_38]    ; int
          PAGE:004AA83A                 push    [ebp+Object]    ; Object
          PAGE:004AA83D                 call    _ObOpenObjectByPointer@28 ; ObOpenObjectByPointer(x,x,x,x,x,x,x)
          PAGE:004AA842                 mov     edi, eax
          ……
    ObOpenObjectByPointer函数
          PAGE:004A0148                 mov     edi, edi
          PAGE:004A014A                 push    ebp
          PAGE:004A014B                 mov     ebp, esp
          PAGE:004A014D                 sub     esp, 94h
          PAGE:004A0153                 push    ebx 
    保护程序修改后
    NtOpenProcess 函数
          ……
          PAGE:004AA836                 push    eax             ; int
          PAGE:004AA837                 push    [ebp+var_38]    ; int
          PAGE:004AA83A                 push    [ebp+Object]    ; Object
          PAGE:004AA83D                 call    _ObOpenObjectByPointer@28 ; ObOpenObjectByPointer(x,x,x,x,x,x,x)
          PAGE:004AA842                 mov     edi, eax
          ……
    ObOpenObjectByPointer函数
          PAGE:004A0148                 jmp      xxxxx
          PAGE:004A014D                 sub     esp, 94h
          PAGE:004A0153                 push    ebx 
    绕过后
    NtOpenProcess 函数
          ……
          PAGE:004AA836                 push    eax             ; int
          PAGE:004AA837                 jmp      0x00600000      // 跳转到自定义代码体
          PAGE:004AA83C                 nop                               // 填充一条空指令

          PAGE:004AA83D                 call    _ObOpenObjectByPointer@28 ; ObOpenObjectByPointer(x,x,x,x,x,x,x)
          PAGE:004AA842                 mov     edi, eax
          ……
    ObOpenObjectByPointer函数           PAGE:004A0148                 jmp      xxxxx 
          PAGE:004A014D                 sub     esp, 94h
          PAGE:004A0153                 push    ebx 
    自定义代码体 
          PAGE:00600000                 push    [ebp+var_38]   // 保存的004AA837 处的代码
          PAGE:006_____                 push    [ebp+Object]         
          PAGE:006_____                 push    ObOpenObjectByPointer+5   // call的返回地址压栈
          PAGE:006_____                 mov     edi, edi             // 保存的004A0148处的代码
          PAGE:006_____                 push    ebp
          PAGE:006_____                 mov     ebp, esp
          PAGE:006_____                 jmp      004A014D        // 跳转回004A014D
         
四.欺骗
     到第三种方法时,保护程序已经被成功的绕过去了,但是NtOpenProcess毕竟是注入的大门,所以保护程序还可以通过调用NtOpenProcess,判断是否被绕过。
     这个时候我们需要先调用一遍原函数,然后调用一遍自己的函数。
     要做到这一步时,我们主要要处理好堆栈。方法比较繁琐,如果试验成功再发出来。先提下原理。
     函数调用前总是一系列的压栈操作,输入参数。
     然后是call,可以把call理解为push 返回地址+jmp被调用函数的的过程。
     然后是平衡堆栈和ret。
     所以可以先调用自定义的NtOpenProcess
     平衡堆栈,还原参数。
     再调用保护程序定义的NtOpenProcess
五.极端的方法
     仅仅是一种设想,如果保护程序,把ssdt base + 0x7A * 4也监视了,甚至IDT,sysentry都监视了,对整个NtOpenProcess和ObOpenObjectByPointer都做了校验,怎么办?
     那就另起炉灶,自己实现一个NtOpenProcess给应用层调用,反正最终目标就是拿到访问被保护进程的句柄而已。
     自定义的NtOpenProcess怎么给Ollydbg之类的调试器?把Od里面做IAT hook或者EAT钩子吧。

附1
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
  PVOID   ServiceTableBase;
  PULONG  ServiceCounterTableBase;
  ULONG   NumberOfService;
  ULONG   ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; 
extern PSERVICE_DESCRIPTOR_TABLE    KeServiceDescriptorTable;    // ssdt表
ULONG JmpAddress;                                                                             // 跳转到NtOpenProcess里的地址
ULONG OldServiceAddress;                                                                  // 原NtOpenProcess函数的服务地址

VOID Hook()
{
  ULONG  Address; 
  Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;    // 0x7A为NtOpenProcess服务ID,Address 为保存的地址
  OldServiceAddress = *(ULONG*)Address;                                                           // 1.保存原NtOpenProcess函数的服务地址
  JmpAddress = (ULONG)NtOpenProcess + 10;                                                      // 2.跳转到NtOpenProcess函数头+10的地方,10根据实际情况取值,注意不要将指令截断 
  __asm{//去掉内存保护
    cli 
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }
  *((ULONG*)Address) = (ULONG)MyNtOpenProcess;                                           // 3.将ssdt中的服务地址改为自定义的hook函数MyNtProcess
  __asm{//恢复内存保护   
    mov  eax,cr0
    or   eax,10000h
    mov  cr0,eax
    sti
  }
}

__declspec(naked) NTSTATUS __stdcall MyNtOpenProcess(PHANDLE ProcessHandle, // hook函数使用__declspec(naked),编译器不处理堆栈 
               ACCESS_MASK DesiredAccess,
               POBJECT_ATTRIBUTES ObjectAttributes,
               PCLIENT_ID ClientId)
{
  DbgPrint("NtOpenProcess() called");
  __asm{
    push    0C4h                                    // 4.MyNtProcess函数第一部分,保存NtOpenProcess原函数代码。此部分也可以从系统获得
    push    804eb560h                          // 共10个字节,根据实际情况
    jmp     [JmpAddress]                        // 4.MyNtProcess函数第一部分,跳转到[JmpAddress],原NtOpenProcess地址 + 10
  }
}

附2:NtOpenProcess 的实现代码,IDA 5.5

805cc43a

PAGE:004AA702 ; Exported entry 764. NtOpenProcess
PAGE:004AA702
PAGE:004AA702 ; =============== S U B R O U T I N E =======================================
PAGE:004AA702
PAGE:004AA702 ; Attributes: bp-based frame
PAGE:004AA702
PAGE:004AA702 ; NTSTATUS __stdcall NtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId)
PAGE:004AA702                 public _NtOpenProcess@16
PAGE:004AA702 _NtOpenProcess@16 proc near             ; DATA XREF: .text:0040DA98o
PAGE:004AA702
PAGE:004AA702 var_D4          = dword ptr -0D4h
PAGE:004AA702 var_B8          = dword ptr -0B8h
PAGE:004AA702 var_A8          = dword ptr -0A8h
PAGE:004AA702 var_A4          = dword ptr -0A4h
PAGE:004AA702 var_38          = dword ptr -38h
PAGE:004AA702 AccessMode      = byte ptr -34h
PAGE:004AA702 var_30          = dword ptr -30h
PAGE:004AA702 var_2C          = dword ptr -2Ch
PAGE:004AA702 var_28          = dword ptr -28h
PAGE:004AA702 Object          = dword ptr -24h
PAGE:004AA702 var_20          = dword ptr -20h
PAGE:004AA702 var_1A          = byte ptr -1Ah
PAGE:004AA702 var_19          = byte ptr -19h
PAGE:004AA702 ms_exc          = CPPEH_RECORD ptr -18h
PAGE:004AA702 ProcessHandle   = dword ptr  8
PAGE:004AA702 AccessMask      = dword ptr  0Ch
PAGE:004AA702 ObjectAttributes= dword ptr  10h
PAGE:004AA702 ClientId        = dword ptr  14h
PAGE:004AA702
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:004C2241 SIZE 0000002F BYTES
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:0050A7D4 SIZE 00000022 BYTES
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:0050B948 SIZE 00000020 BYTES
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:0051085C SIZE 0000002D BYTES
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:0052BE6B SIZE 00000036 BYTES
PAGE:004AA702 ; FUNCTION CHUNK AT PAGE:0052BEC1 SIZE 0000005C BYTES
PAGE:004AA702
PAGE:004AA702                 push    0C4h
PAGE:004AA707                 push    offset stru_41D2E8
PAGE:004AA70C                 call    __SEH_prolog
PAGE:004AA711                 xor     esi, esi
PAGE:004AA713                 mov     [ebp+var_2C], esi
PAGE:004AA716                 xor     eax, eax
PAGE:004AA718                 lea     edi, [ebp+var_28]
PAGE:004AA71B                 stosd
PAGE:004AA71C                 mov     eax, large fs:124h
PAGE:004AA722                 mov     al, [eax+140h]
PAGE:004AA728                 mov     [ebp+AccessMode], al
PAGE:004AA72B                 test    al, al
PAGE:004AA72D                 jz      loc_4C2241
PAGE:004AA733                 mov     [ebp+ms_exc.disabled], esi
PAGE:004AA736                 mov     eax, _MmUserProbeAddress
PAGE:004AA73B                 mov     ecx, [ebp+ProcessHandle]
PAGE:004AA73E                 cmp     ecx, eax
PAGE:004AA740                 jnb     loc_52BE6B
PAGE:004AA746
PAGE:004AA746 loc_4AA746:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+8176Bj
PAGE:004AA746                 mov     eax, [ecx]
PAGE:004AA748                 mov     [ecx], eax
PAGE:004AA74A                 mov     ebx, [ebp+ObjectAttributes]
PAGE:004AA74D                 test    bl, 3
PAGE:004AA750                 jnz     loc_52BE72
PAGE:004AA756
PAGE:004AA756 loc_4AA756:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+81775j
PAGE:004AA756                 mov     eax, _MmUserProbeAddress
PAGE:004AA75B                 cmp     ebx, eax
PAGE:004AA75D                 jnb     loc_52BE7C
PAGE:004AA763
PAGE:004AA763 loc_4AA763:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+81781j
PAGE:004AA763                 cmp     [ebx+8], esi
PAGE:004AA766                 setnz   [ebp+var_1A]
PAGE:004AA76A                 mov     ecx, [ebx+0Ch]
PAGE:004AA76D                 mov     [ebp+var_38], ecx
PAGE:004AA770                 mov     ecx, [ebp+ClientId]
PAGE:004AA773                 cmp     ecx, esi
PAGE:004AA775                 jz      loc_51086D
PAGE:004AA77B                 test    cl, 3
PAGE:004AA77E                 jnz     loc_52BE88
PAGE:004AA784
PAGE:004AA784 loc_4AA784:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+81793j
PAGE:004AA784                 cmp     ecx, eax
PAGE:004AA786                 jnb     loc_52BE9A
PAGE:004AA78C
PAGE:004AA78C loc_4AA78C:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+8179Aj
PAGE:004AA78C                 mov     eax, [ecx]
PAGE:004AA78E                 mov     [ebp+var_2C], eax
PAGE:004AA791                 mov     eax, [ecx+4]
PAGE:004AA794                 mov     [ebp+var_28], eax
PAGE:004AA797                 mov     [ebp+var_19], 1
PAGE:004AA79B
PAGE:004AA79B loc_4AA79B:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+6616Fj
PAGE:004AA79B                 or      [ebp+ms_exc.disabled], 0FFFFFFFFh
PAGE:004AA79F
PAGE:004AA79F loc_4AA79F:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+17B69j
PAGE:004AA79F                                         ; NtOpenProcess(x,x,x,x)+66178j
PAGE:004AA79F                 cmp     [ebp+var_1A], 0
PAGE:004AA7A3                 jnz     loc_52BEC1
PAGE:004AA7A9
PAGE:004AA7A9 loc_4AA7A9:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+817C3j
PAGE:004AA7A9                 mov     eax, _PsProcessType
PAGE:004AA7AE                 add     eax, 68h
PAGE:004AA7B1                 push    eax             ; GenericMapping
PAGE:004AA7B2                 push    [ebp+AccessMask] ; AccessMask
PAGE:004AA7B5                 lea     eax, [ebp+var_D4]
PAGE:004AA7BB                 push    eax             ; int
PAGE:004AA7BC                 lea     eax, [ebp+var_B8]
PAGE:004AA7C2                 push    eax             ; int
PAGE:004AA7C3                 call    _SeCreateAccessState@16 ; SeCreateAccessState(x,x,x,x)
PAGE:004AA7C8                 cmp     eax, esi
PAGE:004AA7CA                 jl      loc_4AA87C
PAGE:004AA7D0                 push    dword ptr [ebp+AccessMode] ; PreviousMode
PAGE:004AA7D3                 push    ds:_SeDebugPrivilege.HighPart
PAGE:004AA7D9                 push    ds:_SeDebugPrivilege.LowPart ; PrivilegeValue
PAGE:004AA7DF                 call    _SeSinglePrivilegeCheck@12 ; SeSinglePrivilegeCheck(x,x,x)
PAGE:004AA7E4                 test    al, al
PAGE:004AA7E6                 jnz     loc_50A7D4
PAGE:004AA7EC
PAGE:004AA7EC loc_4AA7EC:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+600EFj
PAGE:004AA7EC                 cmp     [ebp+var_1A], 0
PAGE:004AA7F0                 jnz     loc_52BEDF
PAGE:004AA7F6                 cmp     [ebp+var_19], 0
PAGE:004AA7FA                 jz      loc_51087F
PAGE:004AA800                 mov     [ebp+var_30], esi
PAGE:004AA803                 cmp     [ebp+var_28], esi
PAGE:004AA806                 jnz     loc_50B948
PAGE:004AA80C                 lea     eax, [ebp+Object]
PAGE:004AA80F                 push    eax
PAGE:004AA810                 push    [ebp+var_2C]
PAGE:004AA813                 call    _PsLookupProcessByProcessId@8 ; PsLookupProcessByProcessId(x,x)
PAGE:004AA818
PAGE:004AA818 loc_4AA818:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+61257j
PAGE:004AA818                                         ; PAGE:0052BF3Fj
PAGE:004AA818                 mov     edi, eax
PAGE:004AA81A                 cmp     edi, esi
PAGE:004AA81C                 jl      loc_51085C
PAGE:004AA822                 lea     eax, [ebp+var_20]
PAGE:004AA825                 push    eax             ; int
PAGE:004AA826                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:004AA829                 push    _PsProcessType  ; ObjectType
PAGE:004AA82F                 push    esi             ; AccessMask
PAGE:004AA830                 lea     eax, [ebp+var_B8]
PAGE:004AA836                 push    eax             ; int
PAGE:004AA837                 push    [ebp+var_38]    ; int
PAGE:004AA83A                 push    [ebp+Object]    ; Object
PAGE:004AA83D                 call    _ObOpenObjectByPointer@28 ; ObOpenObjectByPointer(x,x,x,x,x,x,x)
PAGE:004AA842                 mov     edi, eax
PAGE:004AA844                 lea     eax, [ebp+var_B8]
PAGE:004AA84A                 push    eax
PAGE:004AA84B                 call    _SeDeleteAccessState@4 ; SeDeleteAccessState(x)
PAGE:004AA850                 mov     ecx, [ebp+var_30]
PAGE:004AA853                 cmp     ecx, esi
PAGE:004AA855                 jnz     loc_50B95E
PAGE:004AA85B
PAGE:004AA85B loc_4AA85B:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+61261j
PAGE:004AA85B                 mov     ecx, [ebp+Object]
PAGE:004AA85E                 call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:004AA863                 cmp     edi, esi
PAGE:004AA865                 jl      short loc_4AA87A
PAGE:004AA867                 mov     [ebp+ms_exc.disabled], 2
PAGE:004AA86E
PAGE:004AA86E loc_4AA86E:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+81816j
PAGE:004AA86E                 mov     eax, [ebp+var_20]
PAGE:004AA871                 mov     ecx, [ebp+ProcessHandle]
PAGE:004AA874                 mov     [ecx], eax
PAGE:004AA876                 or      [ebp+ms_exc.disabled], 0FFFFFFFFh
PAGE:004AA87A
PAGE:004AA87A loc_4AA87A:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+163j
PAGE:004AA87A                                         ; NtOpenProcess(x,x,x,x)+66166j ...
PAGE:004AA87A                 mov     eax, edi
PAGE:004AA87C
PAGE:004AA87C loc_4AA87C:                             ; CODE XREF: NtOpenProcess(x,x,x,x)+C8j
PAGE:004AA87C                                         ; NtOpenProcess(x,x,x,x)+66182j ...
PAGE:004AA87C                 call    __SEH_epilog
PAGE:004AA881                 retn    10h
PAGE:004AA881 _NtOpenProcess@16 endp
PAGE:004AA881
PAGE:004AA881 ; ---------------------------------------------------------------------------


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值