DPC Timer
来源:互联网 发布:办公用品公司软件 编辑:程序博客网 时间:2024/05/12 12:14
呼 回家第三天~睡到下午三点,太爽了。起来无聊看看timer
不知道是我构造关键词太烂还是怎么,好像网上说这个的挺少,internals也没提这个。所以一下内容大多是自己鼓捣的,不一定对。
一。使用
定时器的使用是比较简单的...随便抛点代码上来,自己看WDK就能搞定
1.初始化
每次 settimer 都可以使 5秒后 触发dpc
PS: timer 有分发头 可等待
3.取消定时器
KeCancelTimer(g_pkt);
ExFreePoolWithTag(g_pkt,'RM');
ExFreePoolWithTag(g_pdpc,'RM');
二、枚你个举....
dpc定时器内部实现 好像每一版系统都改动不少,网络上已有人做过一些简单的逆向分析...以下讨论以xp为主,最后会说一点vista。
列一下定时器成员
xp下 ,KeSetTimer 大体工作是把KTIMER 挂入全局数组 KiTimerTableListHead。KiTimerTableListHead是LIST_ENTRY的数组,xp下这个数组有0x100个....插入的机制有点类似于HashTable的方式,以ktimer 的成员 DueTime作为key(wrk是这样的,vista也是,xp下好像还有一个参数,没搞懂是什么) 调用KiComputeTimerTableIndex计算出要把定时器对象挂入的index值,然后把KTIMER挂入这个链表,并且把 KITIMER.Header.Inserted 设置为TRUE。
百度到0GiNr里有一同学纠结于此问题,不过他那个有错误哎,而且方法也不好
他的方法大概是:自己先申请一个定时器,然后在KeSetTimer之后, 判断Inserted(他判断的是SignalState,不过这个跟是否受信没关系啊~)为TRUE时 遍历自己KTIMER 找到链表头 就是 KiTimerTableListHead 的某一项,然后向下搜索0x100次 向上搜索0x100次(他搜索的512次,估计是WRK里TIMER_TABLE_SIZE 是512吧 但xp下似乎是0x100 少了一半)。
这样的方法问题就来了:肯定会搜索到非KiTimerTableListHead的地方,在拿那个地方当做是链表头来遍历,很容易造成死循环
一开始我想自己通过DueTime计算出Index 这样就能定位 KiTimerTableListHead 的地址,后来发现xp的计算方法并不像WRK里面的那么和谐,而是要用到2个未导出变量参与计算,自己实现就比较烦琐了
还是自己太弱智,虽然从 KeSetTimer里面定位 KiTimerTableListHead 不太容易 但是从KeUpdateSystemTime定位就很容易
效果挺和谐....跟xuetr一样
三、Vista下的情况
具体的机理还没看,貌似变化挺大,有涉及到n个函数。
不过KiTimerTableListHead倒是好找了,KeSetTimerEx 开头就有
KiTimerTableListHead变成了KTIMER_TABLE_ENTRY
0: kd> dt _ktimer_table_entry
nt!_KTIMER_TABLE_ENTRY
+0x000 Entry : _LIST_ENTRY
+0x008 Time : _ULARGE_INTEGER
大小也变成了0x200
IDA F5 KiInitSystem( ):
v3 = &KiTimerTableSize; //vista多了一个这个,值似乎一直是0x200 ida里只有这一处引用 搞不懂为什么
v0 = &KiTimerTableListHead;
v1 = 0x200u; //这个数组大小是 0x200 得到验证 下面操作是初始化链表头 和 Time
do
{
*(v0 + 1) = (int)v0;
*v0 = (int)v0;
*(v0 + 3) = -1;
*(v0 + 2) = 0;
v0 += 4;
--v1;
}
while ( v1 );
因此vista下枚举方法跟xp一样了
知道内核把定时器对象放哪,也就可以检测DPC定时器了
参考资料:
1.高手进阶windows内核定时器之二
2.A Performance Issue in Windows Timer Management?
3.WRK/ReactOS 0.3.10
不知道是我构造关键词太烂还是怎么,好像网上说这个的挺少,internals也没提这个。所以一下内容大多是自己鼓捣的,不一定对。
一。使用
定时器的使用是比较简单的...随便抛点代码上来,自己看WDK就能搞定
1.初始化
1 //测试代码 就图方便用全局变量了,实际使用时可以放到设备扩展里 2 //KTIMER要自己分配内存 常驻非分页内存 3 g_pkt = (PKTIMER)ExAllocatePoolWithTag(NonPagedPool,sizeof(KTIMER),'RM'); 4 g_pdpc = (PKDPC)ExAllocatePoolWithTag(NonPagedPool,sizeof(KDPC),'RM'); 5 6 KeInitializeDpc(g_pdpc,(PKDEFERRED_ROUTINE )DpcForTimer,NULL); 7 8 KeInitializeTimerEx(g_pkt,NotificationTimer); 9 10 LARGE_INTEGER li={0}; 11 li.QuadPart =5000000*-10; 12 KeSetTimer(g_pkt,li,g_pdpc); 132.DPC routine 1 VOID 2 DpcForTimer( 3 IN struct _KDPC *Dpc, 4 IN PVOID DeferredContext, 5 IN PVOID SystemArgument1, 6 IN PVOID SystemArgument2 7 ) 8 { 9 DbgPrint("got it\n"); 10 LARGE_INTEGER li={0}; 11 li.QuadPart =5000000*-10; 12 13 KeSetTimer(g_pkt,li,g_pdpc); 14 15 }
每次 settimer 都可以使 5秒后 触发dpc
PS: timer 有分发头 可等待
3.取消定时器
KeCancelTimer(g_pkt);
ExFreePoolWithTag(g_pkt,'RM');
ExFreePoolWithTag(g_pdpc,'RM');
二、枚你个举....
dpc定时器内部实现 好像每一版系统都改动不少,网络上已有人做过一些简单的逆向分析...以下讨论以xp为主,最后会说一点vista。
列一下定时器成员
typedef struct _KTIMER {DISPATCHER_HEADER Header;ULARGE_INTEGER DueTime;LIST_ENTRY TimerListEntry;struct _KDPC *Dpc;LONG Period;} KTIMER, *PKTIMER, *PRKTIMER;
xp下 ,KeSetTimer 大体工作是把KTIMER 挂入全局数组 KiTimerTableListHead。KiTimerTableListHead是LIST_ENTRY的数组,xp下这个数组有0x100个....插入的机制有点类似于HashTable的方式,以ktimer 的成员 DueTime作为key(wrk是这样的,vista也是,xp下好像还有一个参数,没搞懂是什么) 调用KiComputeTimerTableIndex计算出要把定时器对象挂入的index值,然后把KTIMER挂入这个链表,并且把 KITIMER.Header.Inserted 设置为TRUE。
百度到0GiNr里有一同学纠结于此问题,不过他那个有错误哎,而且方法也不好
他的方法大概是:自己先申请一个定时器,然后在KeSetTimer之后, 判断Inserted(他判断的是SignalState,不过这个跟是否受信没关系啊~)为TRUE时 遍历自己KTIMER 找到链表头 就是 KiTimerTableListHead 的某一项,然后向下搜索0x100次 向上搜索0x100次(他搜索的512次,估计是WRK里TIMER_TABLE_SIZE 是512吧 但xp下似乎是0x100 少了一半)。
这样的方法问题就来了:肯定会搜索到非KiTimerTableListHead的地方,在拿那个地方当做是链表头来遍历,很容易造成死循环
一开始我想自己通过DueTime计算出Index 这样就能定位 KiTimerTableListHead 的地址,后来发现xp的计算方法并不像WRK里面的那么和谐,而是要用到2个未导出变量参与计算,自己实现就比较烦琐了
还是自己太弱智,虽然从 KeSetTimer里面定位 KiTimerTableListHead 不太容易 但是从KeUpdateSystemTime定位就很容易
1 ULONG GetKiTimerList(ULONG addr) 2 { 3 /* 4 KeUpdateSystemTime()+95 8D 0C C5 80 57 48 00 lea ecx, _KiTimerTableListHead.anonymous_0[eax*8] ; Load Effective Address 5 KeUpdateSystemTime()+9C 000 mov edx, [ecx] 6 KeUpdateSystemTime()+9E 000 cmp ecx, edx ; Compare Two Operands 7 KeUpdateSystemTime()+A0 000 jz short loc_46E062 ; Jump if Zero (ZF=1) 8 KeUpdateSystemTime()+A2 000 cmp esi, [edx-4] ; Compare Two Operands 9 KeUpdateSystemTime()+A5 000 jb short loc_46E062 ; Jump if Below (CF=1) 10 KeUpdateSystemTime()+A7 000 ja short loc_46E082 ; Jump if Above (CF=0 & ZF=0) 11 KeUpdateSystemTime()+A9 000 cmp edi, [edx-8] ; Compare Two Operands 12 KeUpdateSystemTime()+AC 000 jnb short loc_46E082 ; Jump if Not Below (CF=0)*/ 13 14 15 PBYTE opcode = (PBYTE)addr; 16 for (int i=0;i<0x150;i++) 17 { 18 if (opcode[i] == 0x8d 19 && opcode[i+1] == 0xc 20 && opcode[i+2]== 0xc5) 21 { 22 return *(PULONG)&opcode[i+3]; 23 } 24 } 25 return 0; 26 27 } 28 VOID SearchForDPCTimer(ULONG addr) 29 { 30 PLIST_ENTRY pnode,pnext; 31 ULONG count = 0; 32 KIRQL irql; 33 ULONG routine; 34 35 PMODULES pmodule = GetModuleList(); 36 37 irql = KeRaiseIrqlToDpcLevel(); 38 39 for (int i=0;i<0x100;i++) 40 { 41 pnode = (PLIST_ENTRY)(addr+i*8); 42 pnext = pnode->Blink; 43 while(pnext!=pnode) 44 { 45 PKTIMER ptimer = CONTAINING_RECORD(pnext,KTIMER,TimerListEntry); 46 if (MmIsAddressValid(ptimer) 47 && MmIsAddressValid(ptimer->Dpc) 48 && MmIsAddressValid(ptimer->Dpc->DeferredRoutine)) 49 { 50 routine = (ULONG)ptimer->Dpc->DeferredRoutine; 51 DbgPrint("kitimer:0x%x addr:0x%x ",(ULONG)ptimer,routine); 52 for (int j=0;j<pmodule->dwNumberOfModules;j++) 53 { 54 if (routine>(ULONG)pmodule->smi[j].Base 55 && routine < (ULONG)pmodule->smi[j].Base + pmodule->smi[j].Size) 56 { 57 DbgPrint("path %s\n",pmodule->smi[j].ImageName); 58 } 59 } 60 61 count ++; 62 } 63 pnext = pnext->Blink; 64 } 65 } 66 67 KeLowerIrql(irql); 68 69 FreeModList(pmodule); 70 DbgPrint("count:%d\n",count); 71 72 } 73 74 //入口函数 75 extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath) 76 { 77 NTSTATUS status; 78 79 //注册驱动调用函数入口 80 pDriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload; 81 pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]= DriverIOCtrl ; 82 pDriverObject->MajorFunction[IRP_MJ_CLOSE]= DriverDispatch ; 83 pDriverObject->MajorFunction[IRP_MJ_CREATE]= DriverDispatch ; 84 pDriverObject->MajorFunction[IRP_MJ_READ]= DriverDispatch ; 85 pDriverObject->MajorFunction[IRP_MJ_WRITE]= DriverDispatch ; 86 //创建设备 87 status = CreateDevice(pDriverObject); 88 89 __asm int 3 90 91 UNICODE_STRING ustrFuncName = RTL_CONSTANT_STRING(L"KeUpdateSystemTime"); 92 ULONG addr = (ULONG)MmGetSystemRoutineAddress(&ustrFuncName); 93 addr = GetKiTimerList(addr); 94 SearchForDPCTimer(addr); 95 96 return status; 97 }
效果挺和谐....跟xuetr一样
三、Vista下的情况
具体的机理还没看,貌似变化挺大,有涉及到n个函数。
不过KiTimerTableListHead倒是好找了,KeSetTimerEx 开头就有
KiTimerTableListHead变成了KTIMER_TABLE_ENTRY
0: kd> dt _ktimer_table_entry
nt!_KTIMER_TABLE_ENTRY
+0x000 Entry : _LIST_ENTRY
+0x008 Time : _ULARGE_INTEGER
大小也变成了0x200
IDA F5 KiInitSystem( ):
v3 = &KiTimerTableSize; //vista多了一个这个,值似乎一直是0x200 ida里只有这一处引用 搞不懂为什么
v0 = &KiTimerTableListHead;
v1 = 0x200u; //这个数组大小是 0x200 得到验证 下面操作是初始化链表头 和 Time
do
{
*(v0 + 1) = (int)v0;
*v0 = (int)v0;
*(v0 + 3) = -1;
*(v0 + 2) = 0;
v0 += 4;
--v1;
}
while ( v1 );
因此vista下枚举方法跟xp一样了
知道内核把定时器对象放哪,也就可以检测DPC定时器了
参考资料:
1.高手进阶windows内核定时器之二
2.A Performance Issue in Windows Timer Management?
3.WRK/ReactOS 0.3.10
- DPC Timer
- dpc timer在win7中的改变....
- DPC
- DPC
- DPC函数
- DPC小记
- DPC定时器
- DPC计时器
- DPC定时器
- DPC 延迟过程调用
- DPC 延迟过程调用
- dpc学习笔记
- DPC and APC
- 多核上的DPC
- DPC究竟是什么
- DPC and APC
- DPC延迟过程调用
- 驱动中的DPC函数
- Ubuntu在corporate network下的网络配置问题
- 编译安装基于ifort的MPICH2
- django中url配置
- WebLogic12C+Myeclipse10配置笔记
- C#实现语音识别
- DPC Timer
- 带您走进七周七语言的程序世界
- 华尔街邮报头版文章:致毕业生们
- 新浪微博(二十四)评论、转发、收藏一条微博
- Tutorial 2: Creating a Framework and Window
- java 异步机制与同步机制的区别
- 如何隐藏ProgressDialog后面的最大值进度
- Nocatalog 下的RMAN 增量备份 shell脚本
- Tutorial 3: Initializing DirectX 11