您的位置:首页 > 运维架构

过NtOpenProcess保护的方法总结

2010-04-26 21:06 260 查看
过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 ; ---------------------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: