首页
论坛
课程
招聘
[求助][求助]请高手赐教patch kifastcallentry()
2009-4-18 17:48 6735

[求助][求助]请高手赐教patch kifastcallentry()

2009-4-18 17:48
6735
我想patch kifastcallentry,在该函数中间某处放置一个jmp 跳到自己的处理函数
__declspec(naked)void MyInfoHook()里去,在此函数中取得系统调用信息:(调用服务的进程ID、服务ID、时间戳)。
程序结构类似于 www.rootkit.com中例子klog
在系统中维护一个列表,每次截获的系统调用信息,做为一个数据块存入列表中。用信号量进行同步。
另有一个worker线程,从该列表中取得所获信息,存入log.txt文件里。
现处理函数有问题:
__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);
  //KeQueryTickCount(&timeTickCount);
  //pListDataEntry=(PLIST_DATA)ExAllocateFromNPagedLookasideList(&NPagedList);
        //pListDataEntry->timeCount=timeTickCount;
        //pListDataEntry->processId=(ULONG)PsGetCurrentProcessId();
        //pListDataEntry->serviceId=serviceId;
        //ExInterlockedInsertTailList(&queueListHead,&pListDataEntry->listEntry,&lockQueue);
        //ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
        //KeReleaseSemaphore(&semQueue,0,1,false);
        __asm
        {
goOut:       
        popad;         
        popfd;         
        mov edi,eax; //jmp patch is 5 bytes,so 5 bytes in factcallentry should
        shr edi,8;         //be restored here then jmp to patch address+5         
        jmp [bkToFastCallEntryAddr];
        }
}

若将中间部分代码(如图中所示)屏蔽,则patch工作正常,若将注释取掉,则popad、popfd弹出的寄存器值与入口时不同。
请高手帮忙分析。
是不是线程切换的问题?
naked 中再调用其它函数有没有什么要求?
望高手赐教,感激不尽。。
谢谢..(代码如附件)
或者说,拦截kifastcallentry的方法本来就不对,那有没有别的方法获取进程对系统服务的调用情况?

[培训] 优秀毕业生寄语:恭喜id咸鱼炒白菜拿到远超3W月薪的offer,《安卓高级研修班》火热招生!!!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 419
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fixfix 活跃值 2009-4-18 18:50
2
0
你要 ANTI-SSDTHOOK ?
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-18 18:51
3
0
没有,我要做进程行为分析,需要拦截进程行为,所以。。
雪    币: 1099
活跃值: 活跃值 (323)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
loqich 活跃值 2009-4-18 21:25
4
0
可能是因为fs的原因
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wdsm 活跃值 2009-4-18 21:54
5
0
中间代码需要屏蔽的问题出在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的明显调用,造成编译器不知道怎样去平衡堆栈,所以问题就出现了!
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-18 22:23
6
0
先谢谢您。
我也是刚开始接触这些较底层的内容,对很多机制都不了解。但现在又得做一个能得到所有系统调用信息(服务ID,调用进程ID,时间戳)的程序,并将其写到一个log文件中,应该怎么实现?或者,我这个程序有没有更正的方法?
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wdsm 活跃值 2009-4-18 23:01
7
0
之所以没将解决方案实现出来,是想让楼主明白问题的原因之后想办法自己解决,很简单的,相信你能够解决的。多试验几次就可以了,编译之后用IDA分析一下。另外可以参考一下《Undocumented Windows 2000 Secrets》,里面有探测NATIVE API的方法,可以参照。

至于要查找调用进程ID,也是比较非常容易的。先通过fs:124得到CurrentThread,得到的是一个KTHREAD型指针,然后在指针所指位置的20h偏移处得到TEB指针,然后在TEB的20h偏移处得到一个_CLIENT_ID结构,这个结构包含两个成员,一个是当前线程ID,另外一个是当前进程ID。

顺便啰嗦一句,在驱动编程中别用memcpy。驱动编程涉及字符串和内存拷贝的要使用RTL开头的函数,这样会比较安全,比如,这里可以用RtlCopyMemoryNonTemporal替换memcpy。

授人以鱼,不如授人以渔。这是我一向的原则。对了,称呼您我可不敢当,估计我比你大不了多少
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-19 13:07
8
0
,好的,我先看看,谢谢你!!
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-19 14:55
9
0

我把那个时间宏改了,换成了一个函数,堆栈正确了。但:
用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跳转到的程序)中的操作,有没有要注意的地方?(并发?任务切换?)
谢谢
上传的附件:
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-19 20:50
10
0
上面错误好像是在经过几次单步(F10)后就会出现。不是很确定。

RtlCopyMemoryNonTemporal()函数,在DDK帮助里好像没有?
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wdsm 活跃值 2009-4-19 21:43
11
0
看了你的错误日志,里面写的Single step exception - code 80000004 ,我推测十有八九是某个地方将你保存在堆栈中eflags的值修改了,将原来值中的TF值置1了,这说明在堆栈上面的操作还得进行严格的检查,具体如何检查?只能是调试了!软件本来就是调试出来的。

至于说同步的问题,在PATCH的时候肯定是要注意的,如果你的程序在多CPU的环境下运行,出错的可能性是比较大的。所以在PATCH的时候是应该使用interlock开头的函数,直接一次性将4个字节替换掉。用原子操作的好处是你既不需要屏蔽中断,也不需要考虑多CPU带来的同步问题。

至于写驱动,多查资料,internet足以应付你遇见的所有情况。冰冻三尺非一日之寒,在解决问题的同时重点学习解决问题的方法,这才是最主要的!
雪    币: 12
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
Nooby 活跃值 5 2009-4-19 22:02
12
0
把中间的当函数,naked就全部__asm
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-19 22:07
13
0
谢谢,有道理。
现在总是遇到一些奇怪的问题。
我一开始问的问题(寄存器值变化),WDSM的分析是对的,我改了改,寄存器没什么问题了。但用windbg时,经过若干次 断点、单步执行,再go(F5)的话,有时候会出现单步错误,很奇怪。错误出现的时间和位置也很不定。
我现在再将原程序改改,过段时间再把改后的情况,跟大家讨论一下。望能给我指点。
雪    币: 238
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lovebubble 活跃值 2009-4-19 22:14
14
0
好的,谢谢你。
麻烦你这么多次,真不好意思。我再改改。
游客
登录 | 注册 方可回帖
返回