• 1855阅读
  • 1回复

DbgkCreateThread [复制链接]

上一主题 下一主题
离线天道酬勤
 

只看楼主 倒序阅读 使用道具 楼主  发表于: 2016-02-02
— 本帖被 天道酬勤 从 驱动保护 移动到本区(2016-05-19) —

首先我们需要替换的是 rdmsr, wrmsr替换掉系统的sysenter跳转地址. 这样整个SSDT表函数都处于被我们的监控当中.


一个新的进程创建线程的时候就会调用到DbgkCreateThread.DbgkCreateThread可以发出两种消息, 一种进程创建,和线程创建消息.


当然, ntdll.dll的消息也在此列.DbgkCreateThread函数内部主要是判断进程是否有PSF_CREATE_REPORTED_BIT标记, 如果有那么就发送进程创建消息, 如果没有那么就发送线程创建消息, 他们都会调用到 DbgkpSendApiMessage 函数.




DbgkpSendApiMessage函数内部做的事情也不多. 主要是挂起线程和恢复线程一类的事情. 然后调用了更底层的DbgkpQueueMessage函数.


DbgkpQueueMessage函数内部大体逻辑就是将消息封装好, 插入队列, 等待R3过来取. 差不多就是这些.下面的代码是ReactOS的代码.


001
VOID
002
NTAPI
003
DbgkCreateThread(IN PETHREAD Thread,
004
                 IN PVOID StartAddress)
005
{
006
    PEPROCESS Process = PsGetCurrentProcess();
007
    ULONG ProcessFlags;
008
    IMAGE_INFO ImageInfo;
009
    PIMAGE_NT_HEADERS NtHeader;
010
    POBJECT_NAME_INFORMATION ModuleName;
011
    UNICODE_STRING NtDllName;
012
    NTSTATUS Status;
013
    PVOID DebugPort;
014
    DBGKM_MSG ApiMessage;
015
    PDBGKM_CREATE_THREAD CreateThread = &ApiMessage.CreateThread;
016
    PDBGKM_CREATE_PROCESS CreateProcess = &ApiMessage.CreateProcess;
017
    PDBGKM_LOAD_DLL LoadDll = &ApiMessage.LoadDll;
018
    OBJECT_ATTRIBUTES ObjectAttributes;
019
    IO_STATUS_BLOCK IoStatusBlock;
020
    PTEB Teb;
021
    PAGED_CODE();
022

023
    /* Sanity check */
024
    ASSERT(Thread == PsGetCurrentThread());
025

026
    //
027
    // 获取是否要调用LoadImageNotifyRoutines标记
028
    //
029
    ProcessFlags = PspSetProcessFlag(Process,
030
                                     PSF_CREATE_REPORTED_BIT |
031
                                     PSF_IMAGE_NOTIFY_DONE_BIT);
032

033
    //
034
    // 如果进程标记中有设置PSF_IMAGE_NOTIFY_DONE_BIT 并且系统中开启了LoadImageNotifyRoutines服务
035
    // 这个if 和调试没有关系, 不管.
036
    //
037
    if (!(ProcessFlags & PSF_IMAGE_NOTIFY_DONE_BIT) && (PsImageNotifyEnabled))
038
    {
039
        /* It hasn't.. set up the image info for the process */
040
        ImageInfo.Properties = 0;
041
        ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
042
        ImageInfo.ImageBase = Process->SectionBaseAddress;
043
        ImageInfo.ImageSize = 0;
044
        ImageInfo.ImageSelector = 0;
045
        ImageInfo.ImageSectionNumber = 0;
046

047
        /* Get the NT Headers */
048
        NtHeader = RtlImageNtHeader(Process->SectionBaseAddress);
049
        if (NtHeader)
050
        {
051
            /* Set image size */
052
            ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage;
053
        }
054

055
        /* Get the image name */
056
        Status = MmGetFileNameForSection(Process->SectionObject, &ModuleName);
057
        if (NT_SUCCESS(Status))
058
        {
059
            /* Call the notify routines and free the name */
060
            PspRunLoadImageNotifyRoutines(&ModuleName->Name,
061
                                          Process->UniqueProcessId,
062
                                          &ImageInfo);
063
            ExFreePool(ModuleName);
064
        }
065
        else
066
        {
067
            /* Call the notify routines */
068
            PspRunLoadImageNotifyRoutines(NULL,
069
                                          Process->UniqueProcessId,
070
                                          &ImageInfo);
071
        }
072

073
        /* Setup the info for ntdll.dll */
074
        ImageInfo.Properties = 0;
075
        ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
076
        ImageInfo.ImageBase = PspSystemDllBase;
077
        ImageInfo.ImageSize = 0;
078
        ImageInfo.ImageSelector = 0;
079
        ImageInfo.ImageSectionNumber = 0;
080

081
        /* Get the NT Headers */
082
        NtHeader = RtlImageNtHeader(PspSystemDllBase);
083
        if (NtHeader)
084
        {
085
            /* Set image size */
086
            ImageInfo.ImageSize = NtHeader->OptionalHeader.SizeOfImage;
087
        }
088

089
        /* Call the notify routines */
090
        RtlInitUnicodeString(&NtDllName,
091
                             L"\\SystemRoot\\System32\\ntdll.dll");
092
        PspRunLoadImageNotifyRoutines(&NtDllName,
093
                                      Process->UniqueProcessId,
094
                                      &ImageInfo);
095
    }
096

097
    //
098
    // 这里才真的关于调试部分的代码
099
    //
100
    DebugPort = Process->DebugPort;
101
    if (!DebugPort) return;
102

103
    //
104
    // 如果调试设置了创建进程通知消息
105
    //
106
    if (!(ProcessFlags & PSF_CREATE_REPORTED_BIT))
107
    {
108
        //
109
        // CreateProcess 是R0这边传递调试消息的主要结构. 既然是创建进程
110
        // 那么线程当然都是空了
111
        //
112
        CreateProcess->InitialThread.SubSystemKey = 0;
113
        CreateProcess->InitialThread.StartAddress = NULL;
114

115
        //
116
        // 填写新进程的句柄
117
        //
118
        CreateProcess->SubSystemKey = 0;
119
        CreateProcess->FileHandle = DbgkpSectionToFileHandle(Process->
120
                                                             SectionObject);
121
        //
122
        // 其他一些信息
123
        //
124
        CreateProcess->BaseOfImage = Process->SectionBaseAddress;
125
        CreateProcess->DebugInfoFileOffset = 0;
126
        CreateProcess->DebugInfoSize = 0;
127

128
        //
129
        // 这些信息其实也不重要, 程序入口, 符号表的地址和数量
130
        //
131
        NtHeader = RtlImageNtHeader(Process->SectionBaseAddress);
132
        if (NtHeader)
133
        {
134
            //
135
            // 根据PE信息获取入口
136
            //
137
            CreateProcess->InitialThread.StartAddress =
138
                (PVOID)((ULONG_PTR)NtHeader->OptionalHeader.ImageBase +
139
                        NtHeader->OptionalHeader.AddressOfEntryPoint);
140

141
            //
142
            // 获取调试信息表地址
143
            //
144
            CreateProcess->DebugInfoFileOffset = NtHeader->FileHeader.
145
                                                 PointerToSymbolTable;
146

147
            //                                  
148
            // 获取调试信息的数量
149
            //
150
            CreateProcess->DebugInfoSize = NtHeader->FileHeader.
151
                                           NumberOfSymbols;
152
        }
153

154
        // 这边开始设置
155
        ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
156
                                 (8 + sizeof(DBGKM_CREATE_PROCESS));
157
        ApiMessage.h.u2.ZeroInit = 0;
158
        ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
159
        ApiMessage.ApiNumber = DbgKmCreateProcessApi;
160

161
        //
162
        // 这个函数是内核里面分发调试消息的主要函数了, 后面一个参数表示
163
        // 是否要冻结进程的所有线程
164
        //
165
        DbgkpSendApiMessage(&ApiMessage, FALSE);
166

167
        //
168
        // 内核这边其实会给R3关闭句柄, 所以R3那边其实不用操心的
169
        //
170
        ObCloseHandle(CreateProcess->FileHandle, KernelMode);
171

172
        //
173
        // 我们看到, 其实创建进程的时候, 默认就会发送nt.dll的LoadDll消息
174
        //
175
        LoadDll->BaseOfDll = PspSystemDllBase;
176
        LoadDll->DebugInfoFileOffset = 0;
177
        LoadDll->DebugInfoSize = 0;
178
        LoadDll->NamePointer = NULL;
179

180
        //
181
        // 获取nt.dll的调试符号偏移和大小. PspSystemDllBase真神奇
182
        //
183
        NtHeader = RtlImageNtHeader(PspSystemDllBase);
184
        if (NtHeader)
185
        {
186
            /* Fill out debug information */
187
            LoadDll->DebugInfoFileOffset = NtHeader->
188
                                           FileHeader.PointerToSymbolTable;
189
            LoadDll->DebugInfoSize = NtHeader->FileHeader.NumberOfSymbols;
190
        }
191

192
        //
193
        // 保存一点nt.dll的信息
194
        //
195
        Teb = Thread->Tcb.Teb;
196
        if (Teb)
197
        {
198
            /* Copy the system library name and link to it */
199
            wcsncpy(Teb->StaticUnicodeBuffer,
200
                    L"ntdll.dll",
201
                    sizeof(Teb->StaticUnicodeBuffer) / sizeof(WCHAR));
202

203
            Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer;
204

205
            /* Return it in the debug event as well */
206
            LoadDll->NamePointer = &Teb->NtTib.ArbitraryUserPointer;
207
        }
208

209
        //
210
        // 获取nt.dll的句柄
211
        //
212
        InitializeObjectAttributes(&ObjectAttributes,
213
                                   &PsNtDllPathName,
214
                                   OBJ_CASE_INSENSITIVE |
215
                                   OBJ_KERNEL_HANDLE |
216
                                   OBJ_FORCE_ACCESS_CHECK,
217
                                   NULL,
218
                                   NULL);
219

220
        Status = ZwOpenFile(&LoadDll->FileHandle,
221
                            GENERIC_READ | SYNCHRONIZE,
222
                            &ObjectAttributes,
223
                            &IoStatusBlock,
224
                            FILE_SHARE_DELETE |
225
                            FILE_SHARE_READ |
226
                            FILE_SHARE_WRITE,
227
                            FILE_SYNCHRONOUS_IO_NONALERT);
228
        if (NT_SUCCESS(Status))
229
        {
230
            //
231
            // 句柄也有了. 有酒有肉了. 可以发送DLL加载消息了
232
            //
233
            ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
234
                                     (8 + sizeof(DBGKM_LOAD_DLL));
235
            ApiMessage.h.u2.ZeroInit = 0;
236
            ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
237
            ApiMessage.ApiNumber = DbgKmLoadDllApi;
238

239
            /* Send the message */
240
            DbgkpSendApiMessage(&ApiMessage, TRUE);
241

242
            //
243
            // 同样的, R3不需要关闭句柄, 以前真是纠结啊.
244
            //
245
            ObCloseHandle(LoadDll->FileHandle, KernelMode);
246
        }
247
    }
248
    else
249
    {
250
        //
251
        // 如果不是首次创建进程, 那么也好办, 直接发送线程创建消息就可以了
252
        //
253
        CreateThread->SubSystemKey = 0;
254
        CreateThread->StartAddress = StartAddress;
255

256
        /* Setup the API Message */
257
        ApiMessage.h.u1.Length = sizeof(DBGKM_MSG) << 16 |
258
                                 (8 + sizeof(DBGKM_CREATE_THREAD));
259
        ApiMessage.h.u2.ZeroInit = 0;
260
        ApiMessage.h.u2.s2.Type = LPC_DEBUG_EVENT;
261
        ApiMessage.ApiNumber = DbgKmCreateThreadApi;
262

263
        /* Send the message */
264
        DbgkpSendApiMessage(&ApiMessage, TRUE);
265
    }
266
}
267

268
NTSTATUS
269
NTAPI
270
DbgkpSendApiMessage(IN OUT PDBGKM_MSG ApiMsg,
271
                    IN BOOLEAN SuspendProcess)
272
{
273
    NTSTATUS Status;
274
    BOOLEAN Suspended = FALSE;
275
    PAGED_CODE();
276

277
    // 看看是否需要挂起整个线程.
278
    if (SuspendProcess)
279
    {
280
        Suspended = DbgkpSuspendProcess();
281
    }
282

283
    //
284
    // 将调试包设置成忙状态
285
    //
286
    ApiMsg->ReturnedStatus = STATUS_PENDING;
287

288
    //
289
    // 设置进程的PSF_CREATE_REPORTED_BIT位
290
    //
291
    PspSetProcessFlag(PsGetCurrentProcess(), PSF_CREATE_REPORTED_BIT);
292

293
    //
294
    // 将调试消息插入队列中
295
    //
296
    Status = DbgkpQueueMessage(PsGetCurrentProcess(),
297
                               PsGetCurrentThread(),
298
                               ApiMsg,
299
                               0,
300
                               NULL);
301

302
    //
303
    // 刷新指令缓存
304
    //
305
    ZwFlushInstructionCache(NtCurrentProcess(), NULL, 0);
306

307
    //
308
    // 如果挂起了线程, 那么还需要重新恢复线程运行
309
    //
310
    if (Suspended)
311
    {
312
        DbgkpResumeProcess();
313
    }
314
    return Status;
315
}
316

317
NTSTATUS
318
NTAPI
319
DbgkpQueueMessage(IN PEPROCESS Process,
320
                  IN PETHREAD Thread,
321
                  IN PDBGKM_MSG Message,
322
                  IN ULONG Flags,
323
                  IN PDEBUG_OBJECT TargetObject OPTIONAL)
324
{
325
    PDEBUG_EVENT DebugEvent;
326
    DEBUG_EVENT LocalDebugEvent;
327
    PDEBUG_OBJECT DebugObject;
328
    NTSTATUS Status;
329
    BOOLEAN NewEvent;
330
    PAGED_CODE();
331

332
    //
333
    // 检测是否需要分配调试事件句柄, 根据调试, 从来就没有进来过. 忽略
334
    //
335
    NewEvent = (Flags & DEBUG_EVENT_NOWAIT) ? TRUE : FALSE;
336
    if (NewEvent)
337
    {
338
        /* Allocate it */
339
        DebugEvent = ExAllocatePoolWithTag(NonPagedPool,
340
                                           sizeof(DEBUG_EVENT),
341
                                           'EgbD');
342
        if (!DebugEvent) return STATUS_INSUFFICIENT_RESOURCES;
343

344
        /* Set flags */
345
        DebugEvent->Flags = Flags | DEBUG_EVENT_INACTIVE;
346

347
        /* Reference the thread and process */
348
        ObReferenceObject(Thread);
349
        ObReferenceObject(Process);
350

351
        /* Set the current thread */
352
        DebugEvent->BackoutThread = PsGetCurrentThread();
353

354
        /* Set the debug object */
355
        DebugObject = TargetObject;
356
    }
357
    else
358
    {
359
        /* Use the debug event on the stack */
360
        DebugEvent = &LocalDebugEvent;
361
        DebugEvent->Flags = Flags;
362

363
        //
364
        // 获取调试消息发送自旋锁
365
        //
366
        ExAcquireFastMutex(&DbgkpProcessDebugPortMutex);
367

368
        // 调试对象
369
        DebugObject = Process->DebugPort;
370

371
        //
372
        // 这里检测是否要跳过某些消息, 显然是没有什么用的.
373
        //
374
        switch (Message->ApiNumber)
375
        {
376
            /* Process or thread creation */
377
            case DbgKmCreateThreadApi:
378
            case DbgKmCreateProcessApi:
379

380
                /* Make sure we're not skipping creation messages */
381
                if (Thread->SkipCreationMsg) DebugObject = NULL;
382
                break;
383

384
            /* Process or thread exit */
385
            case DbgKmExitThreadApi:
386
            case DbgKmExitProcessApi:
387

388
                /* Make sure we're not skipping exit messages */
389
                if (Thread->SkipTerminationMsg) DebugObject = NULL;
390

391
            /* No special handling for other messages */
392
            default:
393
                break;
394
        }
395
    }
396

397
    //
398
    // 初始化调试信息发送完成事件
399
    //
400
    KeInitializeEvent(&DebugEvent->ContinueEvent, SynchronizationEvent, FALSE);
401
    DebugEvent->Process = Process;
402
    DebugEvent->Thread = Thread;
403
    DebugEvent->ApiMsg = *Message;
404
    DebugEvent->ClientId = Thread->Cid;
405

406
    //
407
    // 检测调试端口是否正常
408
    //
409
    if (!DebugObject)
410
    {
411
        /* Fail */
412
        Status = STATUS_PORT_NOT_SET;
413
    }
414
    else
415
    {
416
        //
417
        // 这是进程内调试对象获取的自旋锁
418
        //
419
        ExAcquireFastMutex(&DebugObject->Mutex);
420

421
        //
422
        // 检测调试器目前是否激活
423
        //
424
        if (!DebugObject->DebuggerInactive)
425
        {
426
            //
427
            // 插入进程的调试端口事件链表
428
            //
429
            InsertTailList(&DebugObject->EventList, &DebugEvent->EventList);
430

431
            //
432
            // 事件置位, 这是干什么用的事件呢?
433
            //
434
            if (!NewEvent)
435
            {
436
                /* Signal it */
437
                KeSetEvent(&DebugObject->EventsPresent,
438
                           IO_NO_INCREMENT,
439
                           FALSE);
440
            }
441

442
            /* Set success */
443
            Status = STATUS_SUCCESS;
444
        }
445
        else
446
        {
447
            //
448
            // 没有调试
449
            //
450
            Status = STATUS_DEBUGGER_INACTIVE;
451
        }
452

453
        /* Release the object lock */
454
        ExReleaseFastMutex(&DebugObject->Mutex);
455
    }
456

457
    /* Check if we had acquired the port lock */
458
    if (!NewEvent)
459
    {
460
        //
461
        // 这里释放快速互斥锁
462
        //
463
        ExReleaseFastMutex(&DbgkpProcessDebugPortMutex);
464

465
        /* Check if we got here through success */
466
        if (NT_SUCCESS(Status))
467
        {
468
            //
469
            // 等待R3那边过来取消息
470
            //
471
            KeWaitForSingleObject(&DebugEvent->ContinueEvent,
472
                                  Executive,
473
                                  KernelMode,
474
                                  FALSE,
475
                                  NULL);
476

477
            /* Copy API Message back */
478
            *Message = DebugEvent->ApiMsg;
479

480
            /* Set return status */
481
            Status = DebugEvent->Status;
482
        }
483
    }
484
    else
485
    {
486
        /* Check if we failed */
487
        if (!NT_SUCCESS(Status))
488
        {
489
            /* Dereference the process and thread */
490
            ObDereferenceObject(Thread);
491
            ObDereferenceObject(Process);
492

493
            /* Free the debug event */
494
            ExFreePool(DebugEvent);
495
        }
496
    }
497

498
    return Status;
499
}
离线v2680267313

只看该作者 沙发  发表于: 2016-04-30
用户被禁言,该主题自动屏蔽!
快速回复
限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个