[此次枚举发生在 32BIT XP sp3 下,别的版本暂时没有试验过]
【前提】
DPC定时器 中描述,KeSetTimerEx中,引用到了 KiInsertTreeTimer ,这个符号是个 FASTCAL L型的函数调用,但是
其并没有使用EDX。 第一个参数 通过 ECX 将 KTIMER的指针传入, 第二个,第三个参数 靠压栈实现,这两个参数就是 LARGE_INTEGER的
数据结构。
可以看见KiInsertTreeTimer 仅仅做了些参数处理,几乎原封不动的传入了下一层去处理
KiInsertTimerTable函数
看来根据DueTime来决定插入的顺序的,该插入链表最后的节点开始
我们看见了_KiTimerTableListHead这个符号
对着这个符号双击一下,跳到定义处
1.找出链表头数组的大小,双击交叉引用的KiInitSystem()+77,进入相关引用处
2.找出数组的地址,双击交叉引用KeUpdateSystemTime+95处,发现确实引用了,用WinDbg看下这个函数
u KeUpdateSystemTime l30 L30表示30行显示,L40则显示40行
直接算偏移 0X804E4267- 0X804E41CF= 0X95 + 3 即是 ULONG 数组地址= * (ULONG*) ((ULONG)KeUpdateSystemTime + 0X98 )
贴一段简码
#include <ntddk.h>
//KTIMER 的结构定义
typedef struct _M_KTIMER{
DISPATCHER_HEADER Header;
ULARGE_INTEGER DueTime;
LIST_ENTRY TimerListEntry;
KDPC* Dpc;
ULONG Period;
}M_KTIMER, *PM_KTIMER;
VOID DriverUnload(PDRIVER_OBJECT pDriverObj){
return;
}
//获取KeUpdateSystemTime函数地址
ULONG GetKeUpdataSystemTimeFuncAddr(){
UNICODE_STRING ustrFunc = { 0 };
RtlInitUnicodeString(&ustrFunc, L"KeUpdateSystemTime");
return (ULONG )MmGetSystemRoutineAddress(&ustrFunc);
}
VOID EnuerateKTIMER(){
/*XP-SP3上,直接硬编码偏移得到
kd> u KeUpdateSystemTime l40
nt!KeUpdateSystemTime:
804e41cf b90000dfff mov ecx,0FFDF0000h
804e41d4 8b7908 mov edi,dword ptr [ecx+8]
804e41d7 8b710c mov esi,dword ptr [ecx+0Ch]
804e41da 03f8 add edi,eax
804e41dc 83d600 adc esi,0
804e41df 897110 mov dword ptr [ecx+10h],esi
804e41e2 897908 mov dword ptr [ecx+8],edi
804e41e5 89710c mov dword ptr [ecx+0Ch],esi
804e41e8 290594305580 sub dword ptr [nt!KiTickOffset (80553094)],eax
804e41ee a180305580 mov eax,dword ptr [nt!KeTickCount (80553080)]
804e41f3 8bd8 mov ebx,eax
804e41f5 0f8f84000000 jg nt!KeUpdateSystemTime+0xb0 (804e427f)
804e41fb bb0000dfff mov ebx,0FFDF0000h
804e4200 8b4b14 mov ecx,dword ptr [ebx+14h]
804e4203 8b5318 mov edx,dword ptr [ebx+18h]
804e4206 030d90305580 add ecx,dword ptr [nt!KeTimeAdjustment (80553090)]
804e420c 83d200 adc edx,0
804e420f 89531c mov dword ptr [ebx+1Ch],edx
804e4212 894b14 mov dword ptr [ebx+14h],ecx
804e4215 895318 mov dword ptr [ebx+18h],edx
804e4218 8bd8 mov ebx,eax
804e421a 8bc8 mov ecx,eax
804e421c 8b1584305580 mov edx,dword ptr [nt!KeTickCount+0x4 (80553084)]
804e4222 83c101 add ecx,1
804e4225 83d200 adc edx,0
804e4228 891588305580 mov dword ptr [nt!KeTickCount+0x8 (80553088)],edx
804e422e 890d80305580 mov dword ptr [nt!KeTickCount (80553080)],ecx
804e4234 891584305580 mov dword ptr [nt!KeTickCount+0x4 (80553084)],edx
804e423a 50 push eax
804e423b a10000dfff mov eax,dword ptr ds:[FFDF0000h]
804e4240 83c001 add eax,1
804e4243 7306 jae nt!KeUpdateSystemTime+0x7c (804e424b)
804e4245 ff051c7e5580 inc dword ptr [nt!ExpTickCountAdjustmentCount (80557e1c)]
804e424b a1187e5580 mov eax,dword ptr [nt!ExpTickCountAdjustment (80557e18)]
804e4250 0faf051c7e5580 imul eax,dword ptr [nt!ExpTickCountAdjustmentCount (80557e1c)]
804e4257 03c1 add eax,ecx
804e4259 a30000dfff mov dword ptr ds:[FFDF0000h],eax
804e425e 58 pop eax
804e425f 25ff000000 and eax,0FFh
804e4264 8d0cc520b35580 lea ecx,nt!KiTimerTableListHead (8055b320)[eax*8]
偏移 804e4264+3-804e41cf=98H
*/
LIST_ENTRY* XPKtimerListArray = (LIST_ENTRY*)(*(ULONG*)(GetKeUpdataSystemTimeFuncAddr() + 0X98) );
static ULONG index = 0;
//XPKtimerListArray是一个100H 大小的数组
//打印 所有链表头
/*
for (ULONG i = 0; i < 0X100; i++, XPKtimerListArray++){
KdPrint(("[0X%08X] 0X%08X - 0X%08X\n", XPKtimerListArray, XPKtimerListArray->Flink, XPKtimerListArray->Blink));
}
*/
// 100h个头部全部都枚举了,PCHunter中只枚举DPC计时器,换句话说和DPC绑定了的KTIMER,但是100H个链表中,是所有的
// KTIMER,而不管有没有绑定KTIMER
for (ULONG i = 0; i < 0X100; i++, XPKtimerListArray++){
if (XPKtimerListArray->Flink == XPKtimerListArray )
continue;//说明此链表头没有被插入节点
else{
LIST_ENTRY* currListHead = XPKtimerListArray->Flink;
do{
PM_KTIMER pTimer = (PM_KTIMER)((ULONG)currListHead - 0X18);
PKDPC dpc = pTimer->Dpc;
ULONG routine;
char importance;
//对有没有绑定DPC进行区分,
if ((ULONG)dpc == 0){
routine = 0;
importance = 0;
}
else{
routine = (ULONG)(dpc->DeferredRoutine);
importance = dpc->Importance;
}
ULONG period = pTimer->Period;
ULARGE_INTEGER li = pTimer->DueTime;
KdPrint(("[KTIMER %d]->0X%08X DPC:0X%08X DPCRoutine:0X%08X Importance:%d Period:0X%08X\n",
index, pTimer,dpc, routine, importance, period));
currListHead = currListHead->Flink;
index++;
} while (currListHead != XPKtimerListArray);
}
}
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath){
pDriverObj->DriverUnload = DriverUnload;
EnuerateKTIMER();
return STATUS_SUCCESS;
}
如果你不相信枚举正确我有一个好办法检测,首先如果是在双击调试下,在DbgView上打印出了结果的话,那么WinDbg上也会打印
,将之复制到记事本,分别就PCHunter中的定时器对象栏下,上,中,下,抽样几个数据去搜索下:这里我就演示一下效果
要记得每次搜索前,将光标重新置位到最前,表示从头开始搜索
OVER 。再次说明下,实验发生在32 BIT XP 下,有可能你做起来并不如意,可能原因:
1.IDA符号原因
2.windbg符号原因
3.双机调试原因
4.windows版本原因
其他的好像没有了。。。3ks for watching。。。。