能力值:
( LV2,RANK:10 )
2 楼
你要 ANTI-SSDTHOOK ?
能力值:
( LV2,RANK:10 )
3 楼
没有,我要做进程行为分析,需要拦截进程行为,所以。。
能力值:
( LV2,RANK:10 )
4 楼
可能是因为fs的原因
能力值:
( LV2,RANK:10 )
5 楼
中间代码需要屏蔽的问题出在KeQueryTickCount函数上。
先来看看是怎么分析出来的。将注释掉的代码重新启用并编译,加载到IDA中,截取片段如下(注意最后几行加的注释):
PAGE:00010BE7 MyInfoHook proc near ; DATA XREF: GetHookInfo+7F
PAGE:00010BE7 pushf
PAGE:00010BE8 pusha
PAGE:00010BE9 test eax, 3000h
PAGE:00010BEE jnz loc_10CE9
PAGE:00010BF4 mov serviceId, eax
PAGE:00010BF9 mov eax, serviceId
PAGE:00010BFE push eax
PAGE:00010BFF call _PsGetCurrentProcessId@0 ; PsGetCurrentProcessId()
PAGE:00010C04 push eax
PAGE:00010C05 push offset aProcessIdIsLdS ; "process id is : %ld, service id is %x\n"
PAGE:00010C0A call _DbgPrint
PAGE:00010C0F add esp, 0Ch ;到这里,MyInfoHook函数的堆栈是平衡的
PAGE:00010C12 mov ecx, ds:KeTickCount
PAGE:00010C18 mov [ebp-4], ecx ;注意,这里对堆栈进行了操作!!
...skipping
不说后面的,先来看看00010C18处对堆栈的操作会有什么影响。
先来看看MyInfoHook被调用时函数的堆栈情况。
kd> u
nt!KiFastCallEntry+0x41:
8053d751 ff33 push dword ptr [ebx]
8053d753 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh
8053d759 8b6e18 mov ebp,dword ptr [esi+18h]
8053d75c 6a01 push 1
8053d75e 83ec48 sub esp,48h
8053d761 81ed9c020000 sub ebp,29Ch
8053d767 c6864001000001 mov byte ptr [esi+140h],1
8053d76e 3bec cmp ebp,esp ;注意!这里进行的比较操作!
8053d770 759a jne nt!KiFastCallEntry2+0x47 (8053d70c)
8053d772 83652c00 and dword ptr [ebp+2Ch],0
8053d776 f6462cff test byte ptr [esi+2Ch],0FFh
8053d77a 89ae34010000 mov dword ptr [esi+134h],ebp
8053d780 0f854afeffff jne nt!Dr_FastCallDrSave (8053d5d0)
8053d786 8b5d60 mov ebx,dword ptr [ebp+60h]
8053d789 8b7d68 mov edi,dword ptr [ebp+68h]
8053d78c 89550c mov dword ptr [ebp+0Ch],edx
8053d78f c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
8053d796 895d00 mov dword ptr [ebp],ebx
8053d799 897d04 mov dword ptr [ebp+4],edi
8053d79c fb sti
8053d79d 8bf8 mov edi,eax ;检查序号的12、13位来判断是用哪个表
8053d79f c1ef08 shr edi,8
通过你的驱动代码看出,你的函数MyInfoHook是在地址8053d79d处开始执行的。而在地址8053d76e处比较了ebp和esp的值,从地址8053d79d正常执行到8053d76e处,这说明在比较时ebp和esp是相等的!正常执行,中间也不再有push和pop操作,说明一直到MyInfoHook函数的入口处,ebp和esp都是相等的!
我们来构建从调用函数MyInfoHook到函数执行到00010C18处对堆栈进行操作时的堆栈,因为在执行时是直接从KiFastCallEntry中jmp过去的,所以堆栈应该是下面这个样子的:
edi
esi
ebp
esp
ebx
ebx
ecx
eax
eflag
here=esp,ebp
这个时候问题就非常明朗了,00010C18处的"mov [ebp-4], ecx"就已经将pushfd保存的值修改了!
那为什么会这样呢?来看看ntddk.h中对KeQueryTickCount的定义:
#define KeQueryTickCount(CurrentCount ) { \
volatile PKSYSTEM_TIME _TickCount = *((PKSYSTEM_TIME *)(&KeTickCount)); \
while (TRUE) { \
(CurrentCount)->HighPart = _TickCount->High1Time; \
(CurrentCount)->LowPart = _TickCount->LowPart; \
if ((CurrentCount)->HighPart == _TickCount->High2Time) break; \
_asm { rep nop } \
} \
}
这表明了KeQueryTickCount其实是一个宏,而且宏在一开始就定义了一个局部变量_TickCount,我们知道,局部变量是在栈上分配的。本来,编译器有责任对堆栈进行自动平衡,但是这里的MyInfoHook不仅是naked调用方式,更是在整个驱动代码中看不见对MyInfoHook的明显调用,造成编译器不知道怎样去平衡堆栈,所以问题就出现了!
能力值:
( LV2,RANK:10 )
6 楼
先谢谢您。
我也是刚开始接触这些较底层的内容,对很多机制都不了解。但现在又得做一个能得到所有系统调用信息(服务ID,调用进程ID,时间戳)的程序,并将其写到一个log文件中,应该怎么实现?或者,我这个程序有没有更正的方法?
能力值:
( LV2,RANK:10 )
7 楼
之所以没将解决方案实现出来,是想让楼主明白问题的原因之后想办法自己解决,很简单的,相信你能够解决的。多试验几次就可以了,编译之后用IDA分析一下。另外可以参考一下《Undocumented Windows 2000 Secrets》,里面有探测NATIVE API的方法,可以参照。
至于要查找调用进程ID,也是比较非常容易的。先通过fs:124得到CurrentThread,得到的是一个KTHREAD型指针,然后在指针所指位置的20h偏移处得到TEB指针,然后在TEB的20h偏移处得到一个_CLIENT_ID结构,这个结构包含两个成员,一个是当前线程ID,另外一个是当前进程ID。
顺便啰嗦一句,在驱动编程中别用memcpy。驱动编程涉及字符串和内存拷贝的要使用RTL开头的函数,这样会比较安全,比如,这里可以用RtlCopyMemoryNonTemporal替换memcpy。
授人以鱼,不如授人以渔。这是我一向的原则。对了,称呼您我可不敢当,估计我比你大不了多少
能力值:
( LV2,RANK:10 )
8 楼
,好的,我先看看,谢谢你!!
能力值:
( LV2,RANK:10 )
9 楼
我把那个时间宏改了,换成了一个函数,堆栈正确了。但:
用windbg f5(go)执行一段时间(时间长度不定,位置不定)会出现以下信息:
*** An Access Violation occurred in C:\WINDOWS\System32\svchost.exe -k netsvcs:
The instruction at F9013F78 tried to read from an invalid address, F9013F78
再按F5继续运行,过一段时间又会出现以上错误信息。
__declspec(naked)void MyInfoHook()
{ //从kifastcallentry跳到这里,对所需要的信息进行拦截
__asm
{
pushfd;
pushad;
test eax,03000h; //12th\13th bit is 1 =shadow ssdt(in fact 13bit is useless)
jnz goOut;
mov serviceId,eax;
}
DbgPrint("process id is : %ld, service id is %x\n",(ULONG)PsGetCurrentProcessId(),serviceId);
timeTickCount=KeQueryInterruptTime();
.......(代码见附件2 question2)
我想问一下,是不是这个程序思路本来就有问题?
要么,这类程序(patch跳转到的程序)中的操作,有没有要注意的地方?(并发?任务切换?)
谢谢
上传的附件:
能力值:
( LV2,RANK:10 )
10 楼
上面错误好像是在经过几次单步(F10)后就会出现。不是很确定。
RtlCopyMemoryNonTemporal()函数,在DDK帮助里好像没有?
能力值:
( LV2,RANK:10 )
11 楼
看了你的错误日志,里面写的Single step exception - code 80000004 ,我推测十有八九是某个地方将你保存在堆栈中eflags的值修改了,将原来值中的TF值置1了,这说明在堆栈上面的操作还得进行严格的检查,具体如何检查?只能是调试了!软件本来就是调试出来的。
至于说同步的问题,在PATCH的时候肯定是要注意的,如果你的程序在多CPU的环境下运行,出错的可能性是比较大的。所以在PATCH的时候是应该使用interlock开头的函数,直接一次性将4个字节替换掉。用原子操作的好处是你既不需要屏蔽中断,也不需要考虑多CPU带来的同步问题。
至于写驱动,多查资料,internet足以应付你遇见的所有情况。冰冻三尺非一日之寒,在解决问题的同时重点学习解决问题的方法,这才是最主要的!
能力值:
(RANK:210 )
12 楼
把中间的当函数,naked就全部__asm
能力值:
( LV2,RANK:10 )
13 楼
谢谢,有道理。
现在总是遇到一些奇怪的问题。
我一开始问的问题(寄存器值变化),WDSM的分析是对的,我改了改,寄存器没什么问题了。但用windbg时,经过若干次 断点、单步执行,再go(F5)的话,有时候会出现单步错误,很奇怪。错误出现的时间和位置也很不定。
我现在再将原程序改改,过段时间再把改后的情况,跟大家讨论一下。望能给我指点。
能力值:
( LV2,RANK:10 )
14 楼
好的,谢谢你。
麻烦你这么多次,真不好意思。我再改改。