打开 IDA 载入 SDbgMsg.sys 程序, 反汇编代码如下:
; int __stdcall start(PDEVICE_OBJECT DeviceObject)
public start
start proc near
SymbolicLinkName = UNICODE_STRING ptr -18h
DeviceName = UNICODE_STRING ptr -10h
SystemRoutineName = UNICODE_STRING ptr -8
DeviceObject = dword ptr 8
.text:00010850 push ebp
.text:00010851 mov ebp, esp ; 打开栈帧
.text:00010853 sub esp, 18h
.text:00010856 push ebx
.text:00010857 push esi
.text:00010858 mov esi, [ebp+DeviceObject]
.text:0001085B push edi
.text:0001085C push 1Bh
.text:0001085E lea edx, [esi+38h]
.text:00010861 pop ecx ; 给ecx赋值 1Bh
.text:00010862 mov eax, offset loc_10428
.text:00010867 mov edi, edx
.text:00010869 rep stosd
上面的反汇编代码可能有问题, DeviceObject 应该是 DirverObject。如果是 DeviceObject ,那偏移 38H 位置是
DeviceObject->Queue.Blink 或者是 DeviceObject->Queue.Wcb.WaitQueueEntry.Blink 。我想不出 DeviceObject 的这些成员怎么使用。一般情况下程序开始时就是设置 Dispatch 例程, 而 DriverObject 的 Dispatch 例程就是在 38H 偏移位置, 所以我可以认为这里的 DeviceObject 就是 DriverObject。
可见 loc_10428 例程就是通用的派遣例程.
下面是DeviceObject 的偏移为38H 位置的结构图
下面是 DriverObject 偏移为 38H 位置的结构图
.text:0001086B mov edi, ds:RtlInitUnicodeString
.text:00010871 push offset aDeviceSyserdbg ; "//Device//SyserDbgMsg"
.text:00010876 lea eax, [ebp+DeviceName]
.text:00010879 push eax ; DestinationString
; 设置 DirverObject->DriverUnload = sub_10702
.text:0001087A mov dword ptr [esi+34h], offset sub_10702
; 设置 DirverObject->MajorFunction[IRP_MJ_CREATE] = loc_103DC
.text:00010881 mov dword ptr [edx], offset loc_103DC
; 设置 DirverObject->MajorFunction[IRP_MJ_READ] = sub_10646
.text:00010887 mov dword ptr [esi+44h], offset sub_10646
; 设置 DirverObject->MajorFunction[IRP_MJ_CLOSE] = loc_103F8
.text:0001088E mov dword ptr [esi+40h], offset loc_103F8
; 设置 DirverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = loc_10442
.text:00010895 mov dword ptr [esi+70h], offset loc_10442
.text:0001089C call edi ; RtlInitUnicodeString
.text:0001089E lea eax, [ebp+DeviceObject]
.text:000108A1 push eax ; DeviceObject
.text:000108A2 xor ebx, ebx
.text:000108A4 push ebx ; Exclusive
.text:000108A5 push ebx ; DeviceCharacteristics
.text:000108A6 push 22h ; DeviceType
.text:000108A8 lea eax, [ebp+DeviceName]
.text:000108AB push eax ; DeviceName
.text:000108AC push ebx ; DeviceExtensionSize
.text:000108AD push esi ; DriverObject
.text:000108AE call ds:IoCreateDevice
.text:000108B4 test eax, eax
.text:000108B6 jl short loc_108E6
.text:000108B8 mov eax, 2000h
.text:000108BD push eax ; BugCheckParameter1
.text:000108BE mov dword_1221C, eax
.text:000108C3 mov dword_12220, ebx
.text:000108C9 call sub_10FD6
.text:000108CE cmp eax, ebx
.text:000108D0 pop ecx
.text:000108D1 mov dword_12224, eax
.text:000108D6 jnz short loc_108F0
.text:000108D8 push [ebp+DeviceObject] ; DeviceObject
.text:000108DB call ds:IoDeleteDevice
NTSTATUS NtStatus= IoCreateDevice( esi,
0,
"//Device//SyserDbgMsg", // UNICODE_STRING 类型的变量
22h, // FILE_DEVICE_UNKNOWN
0,
0,
DeviceObject );
if (STATUS_SUCCESS != NtStatus)
{
退出;
}
sub_10FD6 ( , 2000h);
.text:000108F0 mov eax, [ebp+DeviceObject]
.text:000108F3 or dword ptr [eax+1Ch], 4
.text:000108F7 mov eax, [ebp+DeviceObject]
.text:000108FA and byte ptr [eax+1Ch], 7Fh
.text:000108FE push offset a??Syserdbgms_0 ; "//??//SyserDbgMsg"
.text:00010903 lea eax, [ebp+SymbolicLinkName]
.text:00010906 push eax ; DestinationString
.text:00010907 call edi ; RtlInitUnicodeString
.text:00010909 lea eax, [ebp+DeviceName]
.text:0001090C push eax ; DeviceName
.text:0001090D lea eax, [ebp+SymbolicLinkName]
.text:00010910 push eax ; SymbolicLinkName
.text:00010911 call ds:IoCreateSymbolicLink
.text:00010917 push offset SpinLock ; SpinLock
.text:0001091C call ds:KeInitializeSpinLock
RtlInitUnicodeString (SymbolicLinkName , L"//??//SyserDbgMsg");
// SymbolicLinkName: "//??//SyserDbgMsg"
// DeviceName: "//Device//SyserDbgMsg"
IoCreateSymbolicLink( SymbolicLinkName , DeviceName) ;
.text:00010938 push offset aDbgsetdebugpri ; "DbgSetDebugPrintCallback"
.text:0001093D lea eax, [ebp+SystemRoutineName]
.text:00010940 push eax ; DestinationString
.text:00010941 call edi ; RtlInitUnicodeString
.text:00010943 mov esi, ds:MmGetSystemRoutineAddress
.text:00010949 lea eax, [ebp+SystemRoutineName]
.text:0001094C push eax ; SystemRoutineName
.text:0001094D call esi ; MmGetSystemRoutineAddress
.text:0001094F cmp eax, ebx
.text:00010951 mov dword_12000, eax
.text:00010956 jz short loc_109A3
.text:00010958 push 1
.text:0001095A push offset sub_10D8A
.text:0001095F call eax
.text:00010961 test eax, eax
.text:00010963 jl short loc_109A3
.text:00010965 push offset aDbgsetdebugfil ; "DbgSetDebugFilterState"
.text:0001096A lea eax, [ebp+SystemRoutineName]
.text:0001096D push eax ; DestinationString
.text:0001096E mov byte_11FFC, 1
.text:00010975 call edi ; RtlInitUnicodeString
.text:00010977 lea eax, [ebp+SystemRoutineName]
.text:0001097A push eax ; SystemRoutineName
.text:0001097B call esi ; MmGetSystemRoutineAddress
.text:0001097D cmp eax, ebx
.text:0001097F mov dword_12004, eax
.text:00010984 jz short loc_109A3
.text:00010986 xor edi, edi
RtlInitUnicodeString (uniSystemRoutineName, L"DbgSetDebugPrintCallback");
dword_12000 = MmGetSystemRoutineAddress(uniSystemRoutineName);
RtlInitUnicodeString (uniSystemRoutineName, L"DbgSetDebugFilterState");
dword_12004 = MmGetSystemRoutineAddress(uniSystemRoutineName);
if ( (dword_12000 == NULL) && (dword_12004 == NULL) )
{
.text:000109AB push ebx ; DeferredContext
.text:000109AC push offset DeferredRoutine ; DeferredRoutine
.text:000109B1 mov edi, offset Dpc
.text:000109B6 push edi ; Dpc
.text:000109B7 call ds:KeInitializeDpc
.text:000109BD mov esi, offset unk_11FB0
.text:000109C2 push esi ; Timer
.text:000109C3 call ds:KeInitializeTimer
.text:000109C9 push edi ; Dpc
.text:000109CA push 3E8h ; Period
.text:000109CF or ecx, 0FFFFFFFFh
.text:000109D2 push ecx
.text:000109D3 mov eax, 0FF676980h
.text:000109D8 push eax ; DueTime
.text:000109D9 push esi ; Timer
.text:000109DA call ds:KeSetTimerEx
.text:000109E0 jmp short loc_109F3
DeferredContext = 0;
KTIMER g_Timer ;
KeInitializeDpc( &g_Dpc , DeferredRoutine, 0);
KeInitializeTimer( &g_Timer );
KeSetTimerEx( &g_Timer, 0FF676980h, 3E8h, &g_Dpc );
.text:000109F3 loc_109F3: ; CODE XREF: start+159j
.text:000109F3 ; start+190j
.text:000109F3 xor eax, eax
.text:000109F5
.text:000109F5 loc_109F5: ; CODE XREF: start+9Bj
.text:000109F5 pop edi
.text:000109F6 pop esi
.text:000109F7 pop ebx
.text:000109F8 leave
.text:000109F9 retn 8
.text:000109F9 start endp
程序结束
}
下面是关于延迟过程调用和Timer的说明:
If the Dpc parameter is specified, a DPC object is associated with the timer object.
When the timer expires, the timer object is removed from the system timer queue and it is set to a signaled state.
If a DPC object was associated with the timer when it was set, the DPC object is inserted in the system DPC queue to be executed as soon as conditions permit after the timer interval expires.
总结:
(1)DeferredRoutine 是一个延迟过程调用, 在该例程中会做些什么呢? 我想可能是先前执行的某段代码由于执行时机的原因而没有成功, 在该例程中会重复执行直至成功为止.
(2)sub_10702: DriverUnload
loc_103DC: SDbgMsgCreate
sub_10646: SDbgMsgRead
loc_103F8: SDbgMsgClose
loc_10442: SDbgMsgDeviceIoControl
在 IDA 中分别选中这些函数名,然后 鼠标右键-->"rename" ,把这些函数替换为上面容易记忆的名字;
(3) 上面的 DirverEntry 例程中通过 MmGetSystemRoutineAddress 来得到 DbgSetDebugPrintCallback和 DbgSetDebugFilterState 系统例程, 并分别存在 dword_12000 和 dword_12004 内存位置.以后的代码中肯定使用这 2 个值(函数的地址), 我们可以在代码中找到 对dword_12000 和 dword_12004 访问的代码并把它改成具体的例程名 "DbgSetDebugPrintCallback" 和 "DbgSetDebugFilterState "
.text:000104D2 ; void __stdcall DeferredRoutine(struct _KDPC *,PVOID,PVOID,PVOID)
.text:000104D2 DeferredRoutine proc near ; DATA XREF: start+15Co
.text:000104D2 xor ecx, ecx
.text:000104D4 cmp dword_12220, ecx
.text:000104DA jz short locret_104EE
.text:000104DC mov eax, Event
.text:000104E1 cmp eax, ecx
.text:000104E3 jz short locret_104EE
.text:000104E5 push ecx ; Wait
.text:000104E6 push ecx ; Increment
.text:000104E7 push eax ; Event
.text:000104E8 call ds:KeSetEvent
.text:000104EE
.text:000104EE locret_104EE: ; CODE XREF: DeferredRoutine+8j
.text:000104EE ; DeferredRoutine+11j
.text:000104EE retn 10h
.text:000104EE DeferredRoutine endp
这是上面 KeInitializeDpc 例程设置延迟调用过程, 第二个参数为NULL, 再该例程中如果 dword_12220 不为 0, 就设置事件,这个event 变量是全局。
if (dword_12220 != 0)
{
if (g_event != NULL)
{
KeSetEvent(g_event, NULL, NULL);
}
}
//--------------------下面是 IRP_MJ_CREATE 对应的例程--------------------------
.text:000103DC SDbgMsgCreate: ; DATA XREF: start+31o
.text:000103DC mov ecx, [esp+8]
.text:000103E0 and dword ptr [ecx+18h], 0
.text:000103E4 xor dl, dl
.text:000103E6 mov dword ptr [ecx+1Ch], 1
.text:000103ED call ds:IofCompleteRequest
.text:000103F3 xor eax, eax
.text:000103F5 retn 8
NTSTATUS SDbgMsgCreate(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 1;
//
// IofCompleteRequest 例程是 _fastcall 调用方式
// 采用 ecx 和 edx 传递参数
//
IoCompleteRequest( ecx , edx );
return Irp->IoStatus.Status ;
}
//--------------------下面是 IRP_MJ_READ 对应的派遣例程-------------------------
下面的代码是由 IDA 自动生成, SDbgMsgRead 是我根据在 DriverObject 例程中的分析得处的该例程对应着 IRP_MJ_READ
; int __stdcall SDbgMsgRead(int,KIRQL NewIrql)
.text:00010646 SDbgMsgRead proc near ; DATA XREF: start+37o
.text:00010646
.text:00010646 NewIrql = byte ptr 18h
.text:00010646
.text:00010646 push ebx
.text:00010647 push ebp
.text:00010648 push esi
.text:00010649 push edi
.text:0001064A mov edi, dword ptr [esp+NewIrql]
.text:0001064E mov ebp, [edi+60h]
.text:00010651 mov ebx, offset SpinLock
.text:00010656 mov ecx, ebx ; SpinLock
.text:00010658 xor esi, esi
.text:0001065A call ds:KfAcquireSpinLock
.text:00010660 mov [esp+NewIrql], al
.text:00010664 mov eax, dword_12220
.text:00010669 test eax, eax
.text:0001066B jz short loc_106BB
.text:0001066D mov esi, [ebp+4]
.text:00010670 inc eax
.text:00010671 cmp esi, eax
.text:00010673 jle short loc_10677
.text:00010675 mov esi, eax
.text:00010677
// 上面的反汇编代码可能又有问题: NewIrql 是从哪来得?
从
MOV edi, dword ptr [esp+NewIrql]
MOV ebp, [edi+60h]
可以猜测出, 第二个参数应该是 Irp 才对, 这样Irp偏移量为 60H是 CurrentStackLocation
ULONG UlLength;
PVOID SystemBuffer = NULL ;
ebp = IoGetCurrentIrpStackLocation(Irp);
KfAcquireSpinLock(&g_SpinLock); // __fastcall 调用方式
UlLength = ebp->Parameters.Read.Length;
if (dword_12220 != 0)
{
if ( ebp->Parameters.Read.Length > dword_12220+1 )
{
UlLength = dword_12220+1; // 应该是和存放读取数据的缓冲区有关, 取小值
}
if (UlLength == 0)
{
; 完成 Irp
; 退出
}
// 取得读取数据的缓冲区
pSystemBuffer = Irp->AssociatedIrp.SystemBuffer ;
.text:00010677 loc_10677: ; CODE XREF: SDbgMsgRead+2Dj
.text:00010677 test esi, esi ; 比较 pSystemBuffer 是否为 NULL
.text:00010679 jz short loc_106BB
.text:0001067B mov eax, [edi+0Ch]
.text:0001067E test eax, eax
.text:00010680 jz short loc_106BB
if ( pSystemBuffer == NULL)
{
; 完成 Irp
; 退出
}
.text:00010682 push esi ; 读取数据的长度
.text:00010683 push dword_12224
.text:00010689 push eax ; 存放数据缓冲区的地址
.text:0001068A call sub_1050E
// 从数据存放的缓冲区中读取指定大小的字节
retValue = sub_1050E( pSystemBuffer, dword_12224, UlLength);
.text:0001068F cmp esi, dword_12220
.text:00010695 jge short loc_106B4
.text:00010697 mov eax, dword_12224
.text:0001069C lea ecx, [eax+esi-1]
.text:000106A0 push ecx
.text:000106A1 push eax
.text:000106A2 call sub_104F2
if (esi < dword_12220)
{
sub104f2_Retvalue = sub_104F2 (dword_12224 , dword_12224+esi-1 );
.text:000106A7 xor eax, eax
.text:000106A9 inc eax
.text:000106AA sub eax, esi
.text:000106AC add dword_12220, eax
.text:000106B2 jmp short loc_106BB
sub104f2_Retvalue = 1;
sub104f2_Retvalue -= UlLength;
dword_12220 += eax;
}else
{
.text:000106B4 loc_106B4: ; CODE XREF: SDbgMsgRead+4Fj
.text:000106B4 and dword_12220, 0
dword_12220 = 0;
}
label :loc_106BB:
.text:000106BB loc_106BB: ; CODE XREF: SDbgMsgRead+25j
.text:000106BB ; SDbgMsgRead+33j ...
.text:000106BB mov dl, [esp+NewIrql] ; NewIrql
.text:000106BF mov ecx, ebx ; SpinLock
.text:000106C1 call ds:KfReleaseSpinLock
KfReleaseSpinLock(g_SpinLock);
.text:000106C7 and dword ptr [edi+18h], 0
.text:000106CB xor dl, dl
.text:000106CD mov ecx, edi ; Irp
.text:000106CF mov [edi+1Ch], esi ; esi 实际读取了多少字节的数据
.text:000106D2 call ds:IofCompleteRequest
.text:000106D8 pop edi
.text:000106D9 pop esi
.text:000106DA pop ebp
.text:000106DB xor eax, eax
.text:000106DD pop ebx
.text:000106DE retn 8
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = esi ; // 实际读取了多少字节的数据
IofCompleteRequest(Irp, 0);
}