-
-
[原创]拦截,弹窗
-
发表于: 2023-2-7 08:23 7502
-
本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正
拦截,弹窗
- 驱动截获攻击操作,进行数据收集
- 驱动为了拿到应用处理完弹窗的返回的结果,建立一个
WaitList
(等待链表,结点包括一个标识ID(用来区分攻击事件),一个event,一个等待结果的域),通过WaitList
上等待应用层处理弹窗的结果。 - 驱动为了把收集数据传给应用层,建立一个
OperList
(操作链表,进程Pid,进程全路径,目标对象等), 建立一个PendingIrpList
来应对OperList
为空情况。把收集数据存为一个结构体放在OperList
,传给应用。或者优先满足PendingIrpList
的Irp。- 如果此时
有
内容可读(链表不为空),则该独立线程向驱动发出一个读Irp
来读取OperList
一个结点的数据,弹出一个弹窗提示用户(比如某某进程正在往system32释放DLL文件)并倒计时等待用户操作,对弹窗处理的结果通过DeviceIoControl
返回给驱动,把结果存放在WaitList
里面,结点上的事件就会通知驱动来拿数据,驱动从WaitList
拿到结果做出相应操作(阻止/执行某个进程的操作) - 如果此时
没有
内容可读(链表为空,系统比较健康,攻击事件比较少),则该独立线程向驱动发出的读Irp
会被挂起,放在PendingIrpList
中,当下次驱动截获到攻击操作的时候,不会把收集数据存为一个结构体放在OperList
,而是会直接把收集的数据直接给PendingIrpList
的Irp(此时PendingIrpList
不为空,优先满足挂起的Irp请求),弹出一个弹窗提示用户(比如某某进程正在往system32释放DLL文件)并倒计时等待用户操作,对弹窗处理的结果通过DeviceIoControl
返回给驱动,把结果存放在WaitList
里面,结点上的事件就会通知驱动来拿数据,驱动从WaitList
拿到结果做出相应操作(阻止/运行某个进程的操作)
- 如果此时
- 驱动拿到用户操作结果做出相应的动作。
- 流程:
- 1.驱动截获到攻击(在驱动IOCTL分发函数中(IOCTL_XXX_ATTACK)),生成一个WaitList结点插入等待队列,等待R3下发结果,收集信息放到一个结构体中,查看是否有未完成的pendingIRP,如果有,直接将该OperInfo传给R3;否则插入OperList,等待R3来读取
- 2.应用层通过DipatchRead()读取R0的数据,如果为空,就把当前读Irp放到PendingIrpList中去,并注册一个CommonIrpCancel函数;不为空,直接读取数据
- 3.在驱动IOCTL分发函数中(IOCTL_SEND_RESULT_TO_R0),将用户结果放入链表WaitList中同WaitID的结构体中,设置EVENT事件,唤醒内核层GetResultFromUser()里的等待事件
- 4.驱动拿到用户操作结果,摘掉链表中的结点,并获取操作中的结果
- 5.驱动根据操作结果判断是否允许或者阻止,下发结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | #include <ntddk.h> #include "Ioctlcmd.h" #include "main.h" #define DEVICE_NAME L"\\device\\PopupDrv" #define LINK_NAME L"\\dosDevices\\PopupDrv" LIST_ENTRY g_OperList; / / / < 操作链表 ERESOURCE g_OperListLock; / / / < 保护全局资源的读写锁共享锁,允许多人读,一个人写 LIST_ENTRY g_WaitList; / / / < 等待链表 ERESOURCE g_WaitListLock; / / / < 保护全局资源的读写锁共享锁,允许多人读,一个人写 LIST_ENTRY g_PendingIrpList; / / / < Irp挂起链表 ERESOURCE g_PendingIrpListLock; / / / < 保护全局资源的读写锁共享锁,允许多人读,一个人写 ERESOURCE g_GetResultFromUserLock; / / / < 保护全局资源的读写锁共享锁,允许多人读,一个人写 ULONG g_ulCurrentWaitID = 0 ; / / / < Student 当前攻击事件的 ID / / / __stdcall表示 1. 参数从右向左压入堆栈 2. 函数被调用者负责栈平衡 / / / 拿写锁 VOID __stdcall LockWrite(ERESOURCE * lpLock) { KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(lpLock, TRUE); } / / / 释放写锁 VOID __stdcall UnLockWrite(ERESOURCE * lpLock) { ExReleaseResourceLite(lpLock); KeLeaveCriticalRegion(); } / / / 拿读锁 VOID __stdcall LockRead(ERESOURCE * lpLock) { KeEnterCriticalRegion(); ExAcquireResourceSharedLite(lpLock, TRUE); } / / / 以让等待读优先的方式去拿写锁,StarveWriter,使写进程饥饿 VOID __stdcall LockReadStarveWriter(ERESOURCE * lpLock) { KeEnterCriticalRegion(); ExAcquireSharedStarveExclusive(lpLock, TRUE); } / / / 释放读锁 VOID __stdcall UnLockRead(ERESOURCE * lpLock) { ExReleaseResourceLite(lpLock); KeLeaveCriticalRegion(); } / / / 初始化锁 VOID __stdcall InitLock(ERESOURCE * lpLock) { ExInitializeResourceLite(lpLock); } / / / 删除锁 VOID __stdcall DeleteLock(ERESOURCE * lpLock) { ExDeleteResourceLite(lpLock); } / / / 初始化链表 VOID __stdcall InitList(LIST_ENTRY * list ) { InitializeListHead( list ); } / / / 用来取消Irp的例程 VOID CommonIrpCancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { KIRQL CancelOldIrql = Irp - >CancelIrql; IoReleaseCancelSpinLock(DISPATCH_LEVEL); KeLowerIrql(CancelOldIrql); LockWrite(&g_PendingIrpListLock); RemoveEntryList(&Irp - >Tail.Overlay.ListEntry); UnLockWrite(&g_PendingIrpListLock); Irp - >IoStatus.Status = STATUS_CANCELLED; / / 把Irp的执行状态设置成STATUS_CANCELLED Irp - >IoStatus.Information = 0 ; IoCompleteRequest(Irp, IO_NO_INCREMENT); } / / / 将Irp挂起,并为Irp注册一个CommonIrpCancel VOID PendingIrpToList(PIRP pIrp, PLIST_ENTRY pIrpList, PDRIVER_CANCEL pfnCancelRoutine) { InsertTailList(pIrpList, &pIrp - >Tail.Overlay.ListEntry); / / 把Irp插入到PendingIrpToList IoMarkIrpPending(pIrp); / / 把Irp标记成pending状态 / / / / / 为Irp设置一个CancelRoutine回调函数,R3调用CancelIo(handle)会触发CancelRoutine例程(假设Irp一直没有得到满足,直到客户端退出或者系统关机了还没有拿到数据,这时候只能把Irp取消掉,不然系统可能会蓝屏) / / CancelIo from r3 or IoCancelIrp to call IoSetCancelRoutine(pIrp, pfnCancelRoutine); } / / 处理应用层的read()函数 NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDevObj, IN PIRP lpIrp) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulLength = 0 ; PIO_STACK_LOCATION lpIrpStack = IoGetCurrentIrpStackLocation(lpIrp); OP_INFO * lpOpInfoEntry = NULL; LIST_ENTRY * lpOpInfoList = NULL; / / / 做一个简单的参数判断,读的数据长度 if (lpIrpStack - >Parameters.Read.Length < sizeof(RING3_OP_INFO)) { ntStatus = STATUS_INVALID_PARAMETER; ulLength = 0 ; goto Completed; } LockWrite(&g_OperListLock); / / / 如果为空,就把当前读Irp放到PendingIrpList中去,并注册一个CommonIrpCancel函数, if (IsListEmpty(&g_OperList) = = TRUE) { UnLockWrite(&g_OperListLock); LockWrite(&g_PendingIrpListLock); PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel); / / 将Irp挂起,并为Irp注册一个CommonIrpCancel UnLockWrite(&g_PendingIrpListLock); goto Pended; } / / / 不为空,直接读取数据 lpOpInfoList = g_OperList.Flink; lpOpInfoEntry = CONTAINING_RECORD(lpOpInfoList, OP_INFO, m_List); / / 拿到一个结点 RemoveEntryList(lpOpInfoList); UnLockWrite(&g_OperListLock); RtlCopyMemory(lpIrp - >AssociatedIrp.SystemBuffer, lpOpInfoEntry, sizeof(RING3_OP_INFO)); ntStatus = STATUS_SUCCESS; ulLength = sizeof(RING3_OP_INFO); ExFreePool(lpOpInfoEntry); Completed: lpIrp - >IoStatus.Status = ntStatus; lpIrp - >IoStatus.Information = ulLength; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); return ntStatus; Pended: return STATUS_PENDING; } WAIT_LIST_ENTRY * FindWaitEntryByID(PLIST_ENTRY pListHead, ULONG ulWaitID) { PLIST_ENTRY pList = NULL; WAIT_LIST_ENTRY * pEntry = NULL; for (pList = pListHead - >Flink; pList ! = pListHead; pList = pList - >Flink) { pEntry = CONTAINING_RECORD(pList, WAIT_LIST_ENTRY, m_List); if (pEntry - >m_ulWaitID = = ulWaitID) { return pEntry; } } return NULL; } / / / @brief MakeWaitID 用来创建一个WaitID,用来区分攻击事件; / / / @ return ULONG 返回WaitID, 4 个字节 ULONG MakeWaitID() { InterlockedIncrement(&g_ulCurrentWaitID); / / 原子操作,对全局变量 + 1 。 return g_ulCurrentWaitID; } BOOLEAN CompletePendingIrp(LIST_ENTRY * pIrpListHead, OP_INFO * pOpInfo) { LIST_ENTRY * lpIrpList = NULL; PIRP lpIrp = NULL; BOOLEAN bFound = FALSE; BOOLEAN bReturn = FALSE; / / / 如果PendingIrpList为空,即当前没有读Irp在等待 if (IsListEmpty(pIrpListHead) = = TRUE) { return bReturn; } / / / 找到Irp for (lpIrpList = pIrpListHead - >Flink; lpIrpList ! = pIrpListHead; lpIrpList = lpIrpList - >Flink) { lpIrp = CONTAINING_RECORD(lpIrpList, IRP, Tail.Overlay.ListEntry); / / 拿到一个结点 if (IoSetCancelRoutine(lpIrp, NULL)) / / 把当前Irp设置成NULL并且returns the previous value of Irp - >CancelRoutine(在Irp被取消的时候被调用(程序退出,系统重启等),如果注册了CancelRoutine则是之前被挂起Irp). no Cancel routine, or cancellation in progress, returns NULL. { RemoveEntryList(lpIrpList); bFound = TRUE; break ; } } if (bFound = = FALSE) { return bReturn; } / / / 把OperList结点的数据copy到pIrp - >AssociatedIrp.SystemBuffer,进程就可以拿到数据了 RtlCopyMemory(lpIrp - >AssociatedIrp.SystemBuffer, pOpInfo, sizeof(RING3_OP_INFO)); / / 只拷贝进程全路径,进程PID,攻击事件 ID , lpIrp - >IoStatus.Information = sizeof(RING3_OP_INFO); lpIrp - >IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(lpIrp, IO_NO_INCREMENT); bReturn = TRUE; return bReturn; } R3_RESULT __stdcall GetResultFromUser() { R3_RESULT NotifyResult = R3Result_Pass; BOOLEAN bSuccess = FALSE; NTSTATUS Status = STATUS_SUCCESS; LARGE_INTEGER WaitTimeOut = { 0 }; OP_INFO * lpNewOpInfo = NULL; WAIT_LIST_ENTRY * lpNewWaitEntry = NULL; ULONG_PTR ulPtr = 0 ; LockWrite(&g_GetResultFromUserLock); / / / 生成一个结点,是个OP_INFO结构体,存放进程的名字,进程的PID,攻击事件的 ID ,前面三个数据放在LIST_ENTRY之前是为了方便拷贝数据 lpNewOpInfo = (OP_INFO * )ExAllocatePool(PagedPool, sizeof(OP_INFO)); / / / memset(lpNewOpInfo, 0 , sizeof(OP_INFO)); if (lpNewOpInfo = = NULL) { UnLockWrite(&g_GetResultFromUserLock); return NotifyResult; } / / / 设置事件相关的数据,发送给R3,比如进程 ID ,名字,路径,以及具体操作(创建,修改,删除)等等 / / / 这里只是简单的捕捉了进程的 ID 或者名字 ulPtr = (ULONG_PTR)PsGetCurrentProcessId(); lpNewOpInfo - >m_ulProcessID = (ULONG_PTR)ulPtr; / / / @todo 通过进程pid拿到进程路径,需要完善 lpNewOpInfo - >m_ulWaitID = MakeWaitID(); / / 生成WatitID,用来区别不同事件的 ID / / / 生成Wait结点,WaitID,WaitEvent(用来同步,当应用层把弹窗结果放在Blocked之后,设置成有信号状态,驱动就通过这个信号,知道应用层已经发结果下来了,就去WaitList上拿结果) lpNewWaitEntry = (WAIT_LIST_ENTRY * )ExAllocatePool(NonPagedPool, sizeof(WAIT_LIST_ENTRY)); if (lpNewWaitEntry = = NULL) { goto End; } lpNewWaitEntry - >m_ulWaitID = lpNewOpInfo - >m_ulWaitID; KeInitializeEvent(&lpNewWaitEntry - >m_ulWaitEvent, SynchronizationEvent, FALSE); / / 插入等待队列,等待R3下发结果 LockWrite(&g_WaitListLock); InsertTailList(&g_WaitList, &lpNewWaitEntry - >m_List); UnLockWrite(&g_WaitListLock); LockWrite(&g_PendingIrpListLock); bSuccess = CompletePendingIrp(&g_PendingIrpList, lpNewOpInfo); / / 查看是否有未完成的pendingIRP,直接将该OperInfo传给R3 UnLockWrite(&g_PendingIrpListLock); if (bSuccess = = FALSE) / / 完成pending irp失败(当前没有读Irp在等待),将lpNewOpInfo插入Operlist { LockWrite(&g_OperListLock); InsertTailList(&g_OperList, &lpNewOpInfo - >m_List); / / 插入OperList,等待R3来读取 UnLockWrite(&g_OperListLock); lpNewOpInfo = NULL; } / / 等 40 秒,环 3 是 30 秒超时 WaitTimeOut.QuadPart = - 40 * 10000000 ; Status = KeWaitForSingleObject(&lpNewWaitEntry - >m_ulWaitEvent, Executive, KernelMode, FALSE, &WaitTimeOut); / / 等待R3下发允许或阻止操作 LockWrite(&g_WaitListLock); RemoveEntryList(&lpNewWaitEntry - >m_List); / / 把当前WaitList结点摘除 UnLockWrite(&g_WaitListLock); if (Status ! = STATUS_TIMEOUT) { if (lpNewWaitEntry - >m_bBlocked = = TRUE) { NotifyResult = R3Result_Block; / / / < 阻止 } else { NotifyResult = R3Result_Pass; / / / < 放行 } } else { NotifyResult = R3Result_DefaultNon; } End: if (lpNewWaitEntry ! = NULL) { ExFreePool(lpNewWaitEntry); } if (lpNewOpInfo ! = NULL) { ExFreePool(lpNewOpInfo); } UnLockWrite(&g_GetResultFromUserLock); return NotifyResult; } / / 处理应用层的DeviceIoControl() NTSTATUS DispatchControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PIO_STACK_LOCATION lpIrpStack = NULL; PVOID inputBuffer = NULL; PVOID outputBuffer = NULL; ULONG inputBufferLength = 0 ; ULONG outputBufferLength = 0 ; ULONG ioControlCode = 0 ; NTSTATUS ntStatus = STATUS_SUCCESS; ntStatus = Irp - >IoStatus.Status = STATUS_SUCCESS; Irp - >IoStatus.Information = 0 ; / / 获取当前IRP堆栈位置 lpIrpStack = IoGetCurrentIrpStackLocation(Irp); / / 获得输入缓冲和长度 inputBuffer = Irp - >AssociatedIrp.SystemBuffer; inputBufferLength = lpIrpStack - >Parameters.DeviceIoControl.InputBufferLength; / / 获得输出缓冲和长度 outputBuffer = Irp - >AssociatedIrp.SystemBuffer; outputBufferLength = lpIrpStack - >Parameters.DeviceIoControl.OutputBufferLength; / / 获取控制码 ioControlCode = lpIrpStack - >Parameters.DeviceIoControl.IoControlCode; switch (ioControlCode) { case IOCTL_SEND_RESULT_TO_R0: / / R3向内核传递弹窗结果,将对应的WaitID事件设置成用户选择结果 { RING3_REPLY * lpReply = NULL; WAIT_LIST_ENTRY * lpWaitEntry = NULL; if (lpIrpStack - >Parameters.DeviceIoControl.InputBufferLength < sizeof(RING3_REPLY)) { Irp - >IoStatus.Information = 0 ; Irp - >IoStatus.Status = STATUS_INVALID_PARAMETER; break ; } / / / RING3_REPLY结构体包含WaitID和Blocked这两个成员 lpReply = (RING3_REPLY * )Irp - >AssociatedIrp.SystemBuffer; LockWrite(&g_WaitListLock); lpWaitEntry = FindWaitEntryByID(&g_WaitList, lpReply - >m_ulWaitID); / / 根据WaitID,找到对应的拦截事件 if (lpWaitEntry ! = NULL) { lpWaitEntry - >m_bBlocked = lpReply - >m_ulBlocked; / / 将对应的WaitList结点设置成用户选择结果 KeSetEvent(&lpWaitEntry - >m_ulWaitEvent, 0 , FALSE); / / 设置EVENT事件,唤醒内核层GetResultFromUser()里的等待事件 } UnLockWrite(&g_WaitListLock); Irp - >IoStatus.Information = 0 ; ntStatus = Irp - >IoStatus.Status = STATUS_SUCCESS; } break ; case IOCTL_XXX_ATTACK: / / 攻击拦截模仿 { R3_RESULT notifyResult = R3Result_DefaultNon; / / LockWrite(&g_GetResultFromUserLock); / / 最好是在函数内部。除非你在任何调用这个函数的地方都加锁 / / KeEnterCriticalRegion(); / / 改成串行 notifyResult = GetResultFromUser(); / / 这里最长会等待 40s ,收集数据封装成一个结构体结点,放在OperList或者满足PendingIrpList中等待的Irp,从R3获得弹框结果,是阻止还是放过 / / KeLeaveCriticalRegion(); / / UnLockWrite(&g_GetResultFromUserLock); if (notifyResult = = R3Result_Block) { DbgPrint( "阻止\n" ); * (ULONG * )outputBuffer = 0 ; ntStatus = STATUS_SUCCESS; } else if (notifyResult = = R3Result_Pass) { DbgPrint( "允许\n" ); * (ULONG * )outputBuffer = 1 ; ntStatus = STATUS_SUCCESS; } else { DbgPrint( "超时允许\n" ); * (ULONG * )outputBuffer = 1 ; ntStatus = STATUS_SUCCESS; } } Irp - >IoStatus.Information = sizeof(ULONG); Irp - >IoStatus.Status = ntStatus; break ; default: break ; } IoCompleteRequest(Irp, IO_NO_INCREMENT); return ntStatus; } / / 驱动Unload()函数 VOID DriverUnload( IN PDRIVER_OBJECT pDriverObject) { UNICODE_STRING deviceLink = { 0 }; RtlInitUnicodeString(&deviceLink, LINK_NAME); IoDeleteSymbolicLink(&deviceLink); IoDeleteDevice(pDriverObject - >DeviceObject); DeleteLock(&g_GetResultFromUserLock); DeleteLock(&g_OperListLock); DeleteLock(&g_WaitListLock); DeleteLock(&g_PendingIrpListLock); return ; } / / 处理应用层的create()函数 NTSTATUS DispatchCreate( IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { / / 设置IO状态信息 pIrp - >IoStatus.Status = STATUS_SUCCESS; pIrp - >IoStatus.Information = 0 ; / / 完成IRP操作,不向下层驱动发送 IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } / / 处理应用层的close()函数 NTSTATUS DispatchClose( IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { pIrp - >IoStatus.Status = STATUS_SUCCESS; pIrp - >IoStatus.Information = 0 ; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } / / 驱动程序入口,完成各种初始化工作,创建设备对象 NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_OBJECT pDevObj = NULL; UNICODE_STRING uDevName = { 0 }; UNICODE_STRING uLinkName = { 0 }; DbgPrint( "Driver Load begin!\n" ); / / / 初始化锁 InitLock(&g_OperListLock); InitLock(&g_WaitListLock); InitLock(&g_PendingIrpListLock); InitLock(&g_GetResultFromUserLock); / / / 初始化链表 InitList(&g_OperList); InitList(&g_WaitList); InitList(&g_PendingIrpList); / / 初始化各个例程 pDriverObject - >MajorFunction[IRP_MJ_CREATE] = DispatchCreate; pDriverObject - >MajorFunction[IRP_MJ_CLOSE] = DispatchClose; pDriverObject - >MajorFunction[IRP_MJ_READ] = DispatchRead; / / read operlist data pDriverObject - >MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl; / / get r3 result&attack pDriverObject - >DriverUnload = DriverUnload; RtlInitUnicodeString(&uDevName, DEVICE_NAME); / / 创建驱动设备 status = IoCreateDevice(pDriverObject, 0 , / / sizeof(DEVICE_EXTENSION) &uDevName, FILE_DEVICE_UNKNOWN, 0 , FALSE, &pDevObj); if (!NT_SUCCESS(status)) { DbgPrint( "IoCreateDevice Failed:%x\n" , status); return status; } pDevObj - >Flags | = DO_BUFFERED_IO; RtlInitUnicodeString(&uLinkName, LINK_NAME); / / 创建符号链接 status = IoCreateSymbolicLink(&uLinkName, &uDevName); if (!NT_SUCCESS(status)) { / / STATUS_INSUFFICIENT_RESOURCES 资源不足 / / STATUS_OBJECT_NAME_EXISTS 指定对象名存在 / / STATUS_OBJECT_NAME_COLLISION 对象名有冲突 DbgPrint( "IoCreateSymbolicLink Failed:%x\n" , status); IoDeleteDevice(pDevObj); return status; } DbgPrint( "Driver Load success!\n" ); return status; } |
应用
- 流程
- 1.加载驱动
- 2.打开设备
- 3.新建一个读线程,如果有数据读出来弹窗,如果没有数据可读则等待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 | / / PopupClientDlg.cpp : implementation file / / #include "stdafx.h" #include "PopupClient.h" #include "PopupClientDlg.h" #include "ioctlcmd.h" #include <shlwapi.h> #include "PopupDlg.h" #pragma comment(lib, "shlwapi.lib") #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define DRIVER_NAME _T("PopupDrv") #define DRIVER_PATH _T(".\\PopupDrv.sys") HANDLE gh_Device = INVALID_HANDLE_VALUE; CWinThread * g_hReadThread = NULL; BOOL g_bToExitThread = FALSE; HANDLE g_hOverlappedEvent = NULL; BOOL LoadDriver(TCHAR * lpszDriverName, TCHAR * lpszDriverPath) { TCHAR szDriverImagePath[ 256 ] = { 0 }; / / 得到完整的驱动路径 GetFullPathName(lpszDriverPath, 256 , szDriverImagePath, NULL); BOOL bRet = FALSE; SC_HANDLE hServiceMgr = NULL; / / SCM管理器的句柄 SC_HANDLE hServiceDDK = NULL; / / NT驱动程序的服务句柄 / / 打开服务控制管理器 hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hServiceMgr = = NULL) { / / OpenSCManager失败 / / printf( "OpenSCManager() Failed %d ! \n" , GetLastError() ); bRet = FALSE; goto BeforeLeave; } else { / / / / OpenSCManager成功 printf( "OpenSCManager() ok ! \n" ); } / / 创建驱动所对应的服务 hServiceDDK = CreateService(hServiceMgr, lpszDriverName, / / 驱动程序的在注册表中的名字 lpszDriverName, / / 注册表驱动程序的 DisplayName 值 SERVICE_ALL_ACCESS, / / 加载驱动程序的访问权限 SERVICE_KERNEL_DRIVER, / / 表示加载的服务是驱动程序 SERVICE_DEMAND_START, / / 注册表驱动程序的 Start 值 SERVICE_ERROR_IGNORE, / / 注册表驱动程序的 ErrorControl 值 szDriverImagePath, / / 注册表驱动程序的 ImagePath 值 NULL, / / GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList NULL, NULL, NULL, NULL); DWORD dwRtn; / / 判断服务是否失败 if (hServiceDDK = = NULL) { dwRtn = GetLastError(); if (dwRtn ! = ERROR_IO_PENDING && dwRtn ! = ERROR_SERVICE_EXISTS) { / / 由于其他原因创建服务失败 / / printf( "CrateService() Failed %d ! \n" , dwRtn ); bRet = FALSE; goto BeforeLeave; } else { / / 服务创建失败,是由于服务已经创立过 printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" ); } / / 驱动程序已经加载,只需要打开 hServiceDDK = OpenService(hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS); if (hServiceDDK = = NULL) { / / 如果打开服务也失败,则意味错误 dwRtn = GetLastError(); / / printf( "OpenService() Failed %d ! \n" , dwRtn ); bRet = FALSE; goto BeforeLeave; } else { / / printf( "OpenService() ok ! \n" ); } } else { / / printf( "CrateService() ok ! \n" ); } / / 开启此项服务 bRet = StartService(hServiceDDK, NULL, NULL); if (!bRet) { DWORD dwRtn = GetLastError(); if (dwRtn ! = ERROR_IO_PENDING && dwRtn ! = ERROR_SERVICE_ALREADY_RUNNING) { / / printf( "StartService() Failed %d ! \n" , dwRtn ); bRet = FALSE; goto BeforeLeave; } else { if (dwRtn = = ERROR_IO_PENDING) { / / 设备被挂住 / / printf( "StartService() Failed ERROR_IO_PENDING ! \n" ); bRet = FALSE; goto BeforeLeave; } else { / / 服务已经开启 / / printf( "StartService() Failed ERROR_SERVICE_ALREADY_RUNNING ! \n" ); bRet = TRUE; goto BeforeLeave; } } } bRet = TRUE; / / 离开前关闭句柄 BeforeLeave: if (hServiceDDK) { CloseServiceHandle(hServiceDDK); } if (hServiceMgr) { CloseServiceHandle(hServiceMgr); } return bRet; } / / 卸载驱动程序 BOOL UnloadDriver(TCHAR * szSvrName) { BOOL bRet = FALSE; SC_HANDLE hServiceMgr = NULL; / / SCM管理器的句柄 SC_HANDLE hServiceDDK = NULL; / / NT驱动程序的服务句柄 SERVICE_STATUS SvrSta; / / 打开SCM管理器 hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hServiceMgr = = NULL) { / / 带开SCM管理器失败 printf( "OpenSCManager() Failed %d ! \n" , GetLastError()); bRet = FALSE; goto BeforeLeave; } else { / / 带开SCM管理器失败成功 printf( "OpenSCManager() ok ! \n" ); } / / 打开驱动所对应的服务 hServiceDDK = OpenService(hServiceMgr, szSvrName, SERVICE_ALL_ACCESS); if (hServiceDDK = = NULL) { / / 打开驱动所对应的服务失败 printf( "OpenService() Failed %d ! \n" , GetLastError()); bRet = FALSE; goto BeforeLeave; } else { printf( "OpenService() ok ! \n" ); } / / 停止驱动程序,如果停止失败,只有重新启动才能,再动态加载. if (!ControlService(hServiceDDK, SERVICE_CONTROL_STOP, &SvrSta)) { printf( "ControlService() Failed %d !\n" , GetLastError()); } else { / / 打开驱动所对应的失败 printf( "ControlService() ok !\n" ); } / / 动态卸载驱动程序. if (!DeleteService(hServiceDDK)) { / / 卸载失败 printf( "DeleteSrevice() Failed %d !\n" , GetLastError()); } else { / / 卸载成功 printf( "DelServer:eleteSrevice() ok !\n" ); } bRet = TRUE; BeforeLeave: / / 离开前关闭打开的句柄 if (hServiceDDK) { CloseServiceHandle(hServiceDDK); } if (hServiceMgr) { CloseServiceHandle(hServiceMgr); } return bRet; } HANDLE OpenDevice() { / / 测试驱动程序 HANDLE hDevice = CreateFile(_T( "\\\\.\\PopupDrv" ), GENERIC_WRITE | GENERIC_READ, 0 , NULL, OPEN_EXISTING, 0 , / / 这里要传入FILE_FLAG_OVERAPPED才是真正异步读 NULL); if (hDevice ! = INVALID_HANDLE_VALUE) { printf( "Create Device ok ! \n" ); } else { printf( "Create Device faild %d ! \n" , GetLastError()); return NULL; } return hDevice; } typedef struct _R3_REPLY { ULONG m_ulWaitID; ULONG m_ulBlocked; } R3_REPLY; typedef struct _OP_INFO { WCHAR m_ProcessName[MAX_PATH]; DWORD m_ulProcessID; ULONG m_ulWaitID; } OP_INFO, * POP_INFO; VOID SendResultToR0(ULONG ulWaitID, BOOL bBlocked) { if (gh_Device = = INVALID_HANDLE_VALUE) { return ; } R3_REPLY R3Reply; R3Reply.m_ulWaitID = ulWaitID; R3Reply.m_ulBlocked = bBlocked; ULONG ulRet = 0 ; ::DeviceIoControl(gh_Device, IOCTL_SEND_RESULT_TO_R0, &R3Reply, sizeof(R3_REPLY), NULL, 0 , &ulRet, NULL); / / 把R3弹窗处理的结果返回给R0 return ; } BOOL HandleData(OP_INFO * pOpInfoData) { CPopupDlg dlg; dlg.SetProcess(pOpInfoData - >m_ProcessName); / / 进程名字 dlg.SetDetail(_T( "有进程正在非法攻击" )); / / 弹窗 dlg.DoModal(); / / 倒计时 30s if (dlg.m_bAllow = = 0 ) / / 允许还是阻止 { return FALSE; } return TRUE; } void PopupInfoToUser(OP_INFO * pOpInfo, int Num) { OP_INFO * currData = pOpInfo; CString szNum; for ( int i = 0 ; i < Num; i + + ) { BOOL bResult = HandleData(currData); / / 此处可以弹框获得用户的结果 if (bResult) { SendResultToR0(pOpInfo - >m_ulWaitID, TRUE); / / 把弹窗结果返回给Ro0 } else { SendResultToR0(pOpInfo - >m_ulWaitID, FALSE); } currData + + ; } } UINT ReadThreadProc(LPVOID lpContext) { OVERLAPPED Overlapped; g_hOverlappedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (g_hOverlappedEvent = = NULL || gh_Device = = INVALID_HANDLE_VALUE) { return - 1 ; } memset(&Overlapped, 0 , sizeof(OVERLAPPED)); ULONG ulReturn = 0 ; ULONG ulBytesReturn = 0 ; OP_INFO OpInfo; Overlapped.hEvent = g_hOverlappedEvent; ::SleepEx( 1 , TRUE); while (TRUE) { ulReturn = ReadFile(gh_Device, &OpInfo, sizeof(OP_INFO), &ulBytesReturn, &Overlapped); / / 异步读.该函数会立即返回 if (g_bToExitThread = = TRUE) { break ; } if (ulReturn = = 0 ) / / 没有读到数据 { if (GetLastError() = = ERROR_IO_PENDING) { ULONG ulApiReturn = WaitForSingleObject(Overlapped.hEvent, INFINITE); / / 在这个事件上进行等待 if (ulApiReturn = = WAIT_FAILED) { break ; } if (g_bToExitThread = = TRUE) { break ; } } else { continue ; } } if (ulBytesReturn = = sizeof(OP_INFO)) { PopupInfoToUser(&OpInfo, 1 ); / / 弹窗 } } return 0 ; } / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); / / Dialog Data / / {{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; / / }}AFX_DATA / / ClassWizard generated virtual function overrides / / {{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange * pDX); / / DDX / DDV support / / }}AFX_VIRTUAL / / Implementation protected: / / {{AFX_MSG(CAboutDlg) / / }}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { / / {{AFX_DATA_INIT(CAboutDlg) / / }}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange * pDX) { CDialog::DoDataExchange(pDX); / / {{AFX_DATA_MAP(CAboutDlg) / / }}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) / / {{AFX_MSG_MAP(CAboutDlg) / / No message handlers / / }}AFX_MSG_MAP END_MESSAGE_MAP() / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / CPopupClientDlg dialog CPopupClientDlg::CPopupClientDlg(CWnd * pParent / * = NULL * / ) : CDialog(CPopupClientDlg::IDD, pParent) { / / {{AFX_DATA_INIT(CPopupClientDlg) / / NOTE: the ClassWizard will add member initialization here / / }}AFX_DATA_INIT / / Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp() - >LoadIcon(IDR_MAINFRAME); } void CPopupClientDlg::DoDataExchange(CDataExchange * pDX) { CDialog::DoDataExchange(pDX); / / {{AFX_DATA_MAP(CPopupClientDlg) / / NOTE: the ClassWizard will add DDX and DDV calls here / / }}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CPopupClientDlg, CDialog) / / {{AFX_MSG_MAP(CPopupClientDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop) ON_WM_CLOSE() ON_COMMAND(ID_MENU_EXIT, OnMenuExit) ON_COMMAND(ID_MENU_RESTORE, OnMenuRestore) ON_WM_DESTROY() / / }}AFX_MSG_MAP ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification) ON_BN_CLICKED(IDOK, &CPopupClientDlg::OnBnClickedOk) END_MESSAGE_MAP() / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / CPopupClientDlg message handlers BOOL CPopupClientDlg::OnInitDialog() { CDialog::OnInitDialog(); ::BringWindowToTop(m_hWnd); ::SetWindowPos( m_hWnd, HWND_TOPMOST, 0 , 0 , 0 , 0 , SWP_NOMOVE | SWP_NOSIZE); / / Add "About..." menu item to system menu. / / IDM_ABOUTBOX must be in the system command range . ASSERT((IDM_ABOUTBOX & 0xFFF0 ) = = IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000 ); CMenu * pSysMenu = GetSystemMenu(FALSE); if (pSysMenu ! = NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu - >AppendMenu(MF_SEPARATOR); pSysMenu - >AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } / / Set the icon for this dialog. The framework does this automatically / / when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); / / Set big icon SetIcon(m_hIcon, FALSE); / / Set small icon / / TODO: Add extra initialization here NOTIFYICONDATA m_tnid; m_tnid.cbSize = sizeof(NOTIFYICONDATA); / / 设置结构大小 / / m_tnid.hWnd = this - >m_hWnd; / / 设置图标对应的窗口 m_tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; / / 图标属性 m_tnid.uCallbackMessage = WM_ICON_NOTIFY; / / 应用程序定义的回调消息 ID CString szToolTip; szToolTip = _T( "HIPS -- 客户端程序" ); _tcscpy(m_tnid.szTip, szToolTip); / / 帮助信息 m_tnid.uID = IDR_MAINFRAME; / / 应用程序图标 m_tnid.hIcon = m_hIcon; / / 图标句柄 PNOTIFYICONDATA m_ptnid = &m_tnid; ::Shell_NotifyIcon(NIM_ADD, m_ptnid); / / 增加图标到系统盘 GetDlgItem(IDOK) - >EnableWindow(TRUE); GetDlgItem(IDC_BUTTON_STOP) - >EnableWindow(FALSE); return TRUE; / / return TRUE unless you set the focus to a control } void CPopupClientDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0 ) = = IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } if (nID = = SC_MINIMIZE) { ShowWindow(FALSE); / / 隐藏窗口 } } / / If you add a minimize button to your dialog, you will need the code below / / to draw the icon. For MFC applications using the document / view model, / / this is automatically done for you by the framework. void CPopupClientDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); / / device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM)dc.GetSafeHdc(), 0 ); / / Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1 ) / 2 ; int y = (rect.Height() - cyIcon + 1 ) / 2 ; / / Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } / / The system calls this to obtain the cursor to display while the user drags / / the minimized window. HCURSOR CPopupClientDlg::OnQueryDragIcon() { return (HCURSOR)m_hIcon; } void CPopupClientDlg::OnButtonStop() { / / TODO: Add your control notification handler code here g_bToExitThread = TRUE; if (g_hOverlappedEvent ! = NULL) { ResetEvent(g_hOverlappedEvent); if (g_hReadThread ! = NULL) { if (WaitForSingleObject(g_hReadThread - >m_hThread, 3000 ) = = WAIT_TIMEOUT) { TerminateThread(g_hReadThread - >m_hThread, 0 ); } delete g_hReadThread; g_hReadThread = NULL; } CloseHandle(g_hOverlappedEvent); g_hOverlappedEvent = NULL; } if (gh_Device ! = INVALID_HANDLE_VALUE) { CloseHandle(gh_Device); gh_Device = INVALID_HANDLE_VALUE; } / / UnloadDriver(DRIVER_NAME); GetDlgItem(IDOK) - >EnableWindow(TRUE); GetDlgItem(IDC_BUTTON_STOP) - >EnableWindow(FALSE); } void CPopupClientDlg::OnOK() { / / TODO: Add extra validation here DWORD dwThreadID = 0 ; g_bToExitThread = FALSE; / / 加载驱动 BOOL bRet = LoadDriver(DRIVER_NAME, DRIVER_PATH); if (!bRet) { MessageBox(_T( "加载驱动失败" ), _T( "Error" ), MB_OK); return ; } gh_Device = OpenDevice(); if (gh_Device = = NULL) { MessageBox(_T( "打开设备失败" ), _T( "Error" ), MB_OK); return ; } g_hReadThread = AfxBeginThread(ReadThreadProc, this); / / 创建一个读线程 g_hReadThread - >SuspendThread(); g_hReadThread - >m_bAutoDelete = FALSE; g_hReadThread - >ResumeThread(); if (g_hReadThread = = NULL) { CloseHandle(gh_Device); gh_Device = INVALID_HANDLE_VALUE; UnloadDriver(DRIVER_NAME); return ; } GetDlgItem(IDOK) - >EnableWindow(FALSE); GetDlgItem(IDC_BUTTON_STOP) - >EnableWindow(TRUE); } LRESULT CPopupClientDlg::OnTrayNotification(WPARAM wParam, LPARAM lParam) { switch (lParam) { case WM_LBUTTONDOWN: { AfxGetApp() - >m_pMainWnd - >ShowWindow(SW_SHOWNORMAL); SetForegroundWindow(); break ; } case WM_RBUTTONUP: { POINT point; HMENU hMenu, hSubMenu; GetCursorPos(&point); / / 鼠标位置 hMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MENU_TRAY)); / / 加载菜单 hSubMenu = GetSubMenu(hMenu, 0 ); / / 得到子菜单(因为弹出式菜单是子菜单) SetMenuDefaultItem(hSubMenu, - 1 , FALSE); / / 设置缺省菜单项, - 1 为无缺省项 SetForegroundWindow(); / / 激活窗口并置前 TrackPopupMenu(hSubMenu, 0 , point.x, point.y, 0 , m_hWnd, NULL); } } return 1 ; } void CPopupClientDlg::OnClose() { NOTIFYICONDATA nd = { 0 }; nd.cbSize = sizeof(NOTIFYICONDATA); nd.hWnd = m_hWnd; nd.uID = IDR_MAINFRAME; nd.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; nd.uCallbackMessage = WM_ICON_NOTIFY; nd.hIcon = m_hIcon; Shell_NotifyIcon(NIM_DELETE, &nd); CDialog::OnCancel(); } void CPopupClientDlg::OnMenuExit() { OnClose(); } void CPopupClientDlg::OnMenuRestore() { ShowWindow(SW_SHOWNORMAL); SetForegroundWindow(); } void CPopupClientDlg::OnDestroy() { CDialog::OnDestroy(); } void CPopupClientDlg::OnBnClickedOk() { / / TODO: Add your control notification handler code here OnOK(); } |
模拟攻击者
- 向驱动发送一个IOCTL_XXX_ATTACK控制码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | / / attacker.cpp : Defines the entry point for the console application. / / #include "StdAfx.h" #include <windows.h> #include <winsvc.h> #include <conio.h> #include <stdio.h> #include <winioctl.h> #define DRIVER_NAME "PopupDrv" #define DRIVER_PATH ".\\PopupDrv.sys" #define IOCTL_BASE 0x800 #define MY_CTL_CODE(i) \ CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_XXX_ATTACK MY_CTL_CODE(2) / / 装载NT驱动程序 BOOL LoadDriver(char * lpszDriverName, char * lpszDriverPath) { char szDriverImagePath[ 256 ] = { 0 }; / / 得到完整的驱动路径 GetFullPathName(lpszDriverPath, 256 , szDriverImagePath, NULL); BOOL bRet = FALSE; SC_HANDLE hServiceMgr = NULL; / / SCM管理器的句柄 SC_HANDLE hServiceDDK = NULL; / / NT驱动程序的服务句柄 / / 打开服务控制管理器 hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hServiceMgr = = NULL) { / / OpenSCManager失败 printf( "OpenSCManager() Failed %d ! \n" , GetLastError()); bRet = FALSE; goto BeforeLeave; } else { / / / / OpenSCManager成功 printf( "OpenSCManager() ok ! \n" ); } / / 创建驱动所对应的服务 hServiceDDK = CreateService(hServiceMgr, lpszDriverName, / / 驱动程序的在注册表中的名字 lpszDriverName, / / 注册表驱动程序的 DisplayName 值 SERVICE_ALL_ACCESS, / / 加载驱动程序的访问权限 SERVICE_KERNEL_DRIVER, / / 表示加载的服务是驱动程序 SERVICE_DEMAND_START, / / 注册表驱动程序的 Start 值 SERVICE_ERROR_IGNORE, / / 注册表驱动程序的 ErrorControl 值 szDriverImagePath, / / 注册表驱动程序的 ImagePath 值 NULL, / / GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList NULL, NULL, NULL, NULL); DWORD dwRtn; / / 判断服务是否失败 if (hServiceDDK = = NULL) { dwRtn = GetLastError(); if (dwRtn ! = ERROR_IO_PENDING && dwRtn ! = ERROR_SERVICE_EXISTS) { / / 由于其他原因创建服务失败 printf( "CrateService() Failed %d ! \n" , dwRtn); bRet = FALSE; goto BeforeLeave; } else { / / 服务创建失败,是由于服务已经创立过 printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" ); } / / 驱动程序已经加载,只需要打开 hServiceDDK = OpenService(hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS); if (hServiceDDK = = NULL) { / / 如果打开服务也失败,则意味错误 dwRtn = GetLastError(); printf( "OpenService() Failed %d ! \n" , dwRtn); bRet = FALSE; goto BeforeLeave; } else { printf( "OpenService() ok ! \n" ); } } else { printf( "CrateService() ok ! \n" ); } / / 开启此项服务 bRet = StartService(hServiceDDK, NULL, NULL); if (!bRet) { DWORD dwRtn = GetLastError(); if (dwRtn ! = ERROR_IO_PENDING && dwRtn ! = ERROR_SERVICE_ALREADY_RUNNING) { printf( "StartService() Failed %d ! \n" , dwRtn); bRet = FALSE; goto BeforeLeave; } else { if (dwRtn = = ERROR_IO_PENDING) { / / 设备被挂住 printf( "StartService() Failed ERROR_IO_PENDING ! \n" ); bRet = FALSE; goto BeforeLeave; } else { / / 服务已经开启 printf( "StartService() Failed ERROR_SERVICE_ALREADY_RUNNING ! \n" ); bRet = TRUE; goto BeforeLeave; } } } bRet = TRUE; / / 离开前关闭句柄 BeforeLeave: if (hServiceDDK) { CloseServiceHandle(hServiceDDK); } if (hServiceMgr) { CloseServiceHandle(hServiceMgr); } return bRet; } / / 卸载驱动程序 BOOL UnloadDriver(char * szSvrName) { BOOL bRet = FALSE; SC_HANDLE hServiceMgr = NULL; / / SCM管理器的句柄 SC_HANDLE hServiceDDK = NULL; / / NT驱动程序的服务句柄 SERVICE_STATUS SvrSta; / / 打开SCM管理器 hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hServiceMgr = = NULL) { / / 带开SCM管理器失败 printf( "OpenSCManager() Failed %d ! \n" , GetLastError()); bRet = FALSE; goto BeforeLeave; } else { / / 带开SCM管理器失败成功 printf( "OpenSCManager() ok ! \n" ); } / / 打开驱动所对应的服务 hServiceDDK = OpenService(hServiceMgr, szSvrName, SERVICE_ALL_ACCESS); if (hServiceDDK = = NULL) { / / 打开驱动所对应的服务失败 printf( "OpenService() Failed %d ! \n" , GetLastError()); bRet = FALSE; goto BeforeLeave; } else { printf( "OpenService() ok ! \n" ); } / / 停止驱动程序,如果停止失败,只有重新启动才能,再动态加载. if (!ControlService(hServiceDDK, SERVICE_CONTROL_STOP, &SvrSta)) { printf( "ControlService() Failed %d !\n" , GetLastError()); } else { / / 打开驱动所对应的失败 printf( "ControlService() ok !\n" ); } / / 动态卸载驱动程序. if (!DeleteService(hServiceDDK)) { / / 卸载失败 printf( "DeleteSrevice() Failed %d !\n" , GetLastError()); } else { / / 卸载成功 printf( "DelServer:DeleteSrevice() ok !\n" ); } bRet = TRUE; BeforeLeave: / / 离开前关闭打开的句柄 if (hServiceDDK) { CloseServiceHandle(hServiceDDK); } if (hServiceMgr) { CloseServiceHandle(hServiceMgr); } return bRet; } void TestDriver() { / / 测试驱动程序 HANDLE hDevice = CreateFile( "\\\\.\\PopupDrv" , GENERIC_WRITE | GENERIC_READ, 0 , NULL, OPEN_EXISTING, 0 , NULL); if (hDevice ! = INVALID_HANDLE_VALUE) { printf( "Create Device ok ! \n" ); } else { printf( "Create Device failed %d ! \n" , GetLastError()); return ; } CHAR bufInput[ 1024 ] = "Hello, world" ; DWORD dwAttackRes = 0 ; DWORD dwRet = 0 ; printf( "Begin to attack\n" ); / / / 得到的设备对象,通过DeviceIoControl发送一个控制码,模拟攻击 DeviceIoControl(hDevice, IOCTL_XXX_ATTACK, bufInput, sizeof(bufInput), &dwAttackRes, sizeof(dwAttackRes), &dwRet, NULL); if (dwAttackRes = = 0 ) { printf( "Attack denied\n" ); } else { printf( "Attack OK\n" ); } CloseHandle(hDevice); } int main( int argc, char * argv[]) { / / 加载驱动 BOOL bRet = LoadDriver(DRIVER_NAME, DRIVER_PATH); if (!bRet) { printf( "LoadNTDriver error\n" ); return 0 ; } / / 加载成功 / / printf( "press any to create device!\n" ); / / getch(); TestDriver(); / / 这时候你可以通过注册表,或其他查看符号连接的软件验证. / / printf( "press any to unload the driver!\n" ); / / getch(); / / 卸载驱动 / / bRet = UnloadDriver(DRIVER_NAME); / / if (!bRet) / / { / / printf( "UnloadNTDriver error\n" ); / / return 0 ; / / } return 0 ; } |
弹窗程序待完善的问题
1.超时问题
- 同时模拟两个攻击(几乎同时运行两个attcker.exe),对GetResultFromUserLock()加了锁后,驱动中调用GetResultFromUser()应该是串行的,第一个弹窗倒计时30s后,自动关闭,attcker.exe退出,第二弹窗开始倒计时也需要倒计时满30s后,atccker.exe才退出
原因
- 内核层程序是支持
多线程并发
的(可以同时(并发不是并行)拦截多个攻击事件) - 应用层程序只有一个线程处理
- 假设内核层同时监测到3个攻击,发给应用层,每个攻击同时等待40s,应用层只有一个线程,只能依次把攻击事件弹窗,倒计时30s。这时候用户可能在第一个30s内只处理完第一弹窗的话,
30s过后
第2、3个攻击事件可能来不及弹窗,因为超时
都消失了,用户来不及处理。解决方法
- 方法1:
应用层改为多线程
,当内核层在很短时间间隔内截获较多攻击事件,应用层为每个攻击事件单独开一个线程来弹窗处理,但这样会导致短时间内较多弹窗,用户体验不佳
- 方法2:将内核层发送攻击事件改为串行的
- 方式1:把攻击事件加到队列
- 方式2:把GetResultFromUser()设为临界区,这样一次只能有一个线程调用GetResultFromUser()
1 2 3 4 5 6 | / / / 加放锁放入函数内部 / / LockWrite(&g_GetResultFromUserLock); / / 最好是在函数内部。除非你在任何调用这个函数的地方都加锁 / / KeEnterCriticalRegion(); / / 改成串行 notifyResult = GetResultFromUser(); / / 这里最长会等待 40s ,收集数据封装成一个结构体结点,放在OperList或者满足PendingIrpList中等待的Irp,从R3获得弹框结果,是阻止还是放过 / / KeLeaveCriticalRegion(); / / UnLockWrite(&g_GetResultFromUserLock); |
@todo 共享资源锁并没有生效,还需要用windbg R3-R0联调一下
2.不是真正异步读
原因
CreateFile()倒数第二个参数是0
异步编程
:线程在调用函数的时候,不管这个函数有没有拿到数据,会立即返回,后面通过回调函数
或者是事件机制
来拿到函数执行的结果。异步比同步效率要高
。同步编程
:线程在调用函数的时候,只要这个函数没有拿到数据,就一直在哪里等待,不会立即返回,直到拿到数据才会返回。- eg:A在微信上向女盆友B发消息之后,A去做其他事情了,B给A回消息,会有消息声音提醒A,A打开微信拿到B回复的消息
- eg1:完成端口模型
同步阻塞编程
(Block)- 基于锁的(lock-based)
- 阻塞的意思是,会睡眠让出CPU,有结果的时候就会被唤醒,一般用于读之前不确定有没有结果数据,使用阻塞比较好。
- eg:A在微信上向女盆友B发消息之后,A抱着手机睡着了,直到B给A回消息,会有消息声音吵醒A,A醒来打开微信拿到B回复的消息
同步非阻塞编程
(Non-blocking Synchronization) :根据粒度不同分为以下几类- CreateFile()倒数第二个参数设置成
FILE_FLAG_OVERAPPED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | HANDLE OpenDevice() { / / 测试驱动程序 HANDLE hDevice = CreateFile(_T( "\\\\.\\PopupDrv" ), GENERIC_WRITE | GENERIC_READ, 0 , NULL, OPEN_EXISTING, 0 , / / 这里要传入FILE_FLAG_OVERAPPED才是真正异步读 NULL); if (hDevice ! = INVALID_HANDLE_VALUE) { printf( "Create Device ok ! \n" ); } else { printf( "Create Device faild %d ! \n" , GetLastError()); return NULL; } return hDevice; } |
3.获取攻击进程的全路径还没完成
根据PID获得进程全路径思路
- 根据PID获得进程全路径
- PID→exprocess→KeStackAttachProcess→ZwQuerylnformationProcess->ProcesslmageFileName→ZwCreateFile
- 设备对象名转换成符号链接名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | / * * * @brief GetProcessFullNameByPid 获取进程的全路径; * @param[ in ] nPid 进程pid; * @param[out] FullPath 进程的全路径; * @ return ntStatus 成功返回 0 ,否则为非 0 ,如果例程成功,则它必须返回 STATUS_SUCCESS。 * 否则,它必须返回在 ntstatus中定义的错误状态值之一; * / NTSTATUS GetProcessFullNameByPid(HANDLE nPid, PUNICODE_STRING FullPath) { HANDLE hFile = NULL; ULONG nNeedSize = 0 ; NTSTATUS nStatus = STATUS_SUCCESS; NTSTATUS nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST; PEPROCESS Process = NULL; KAPC_STATE ApcState = { 0 }; PVOID lpBuffer = NULL; OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; IO_STATUS_BLOCK IoStatus = { 0 }; PFILE_OBJECT FileObject = NULL; PFILE_NAME_INFORMATION FileName = NULL; WCHAR FileBuffer[MAX_PATH] = { 0 }; DECLARE_UNICODE_STRING_SIZE(ProcessPath, MAX_PATH); DECLARE_UNICODE_STRING_SIZE(DosDeviceName, MAX_PATH); PAGED_CODE(); / / / 通过pid拿到进程的eprocess结构 nStatus = PsLookupProcessByProcessId(nPid, &Process); if (NT_ERROR(nStatus)) { KdPrint(( "%s error PsLookupProcessByProcessId.\n" , __FUNCTION__)); return nStatus; } __try { / / / 切换到当前进程的上下文 KeStackAttachProcess(Process, &ApcState); nStatus = ZwQueryInformationProcess( NtCurrentProcess(), ProcessImageFileName, NULL, NULL, / / 第一次传NULL是为了获取进程路径的大小 &nNeedSize); if (STATUS_INFO_LENGTH_MISMATCH ! = nStatus) { KdPrint(( "%s NtQueryInformationProcess error.\n" , __FUNCTION__)); nStatus = STATUS_MEMORY_NOT_ALLOCATED; __leave; } / / / 分配一个内存来存放进程的全路径 lpBuffer = ExAllocatePoolWithTag(NonPagedPool, nNeedSize, 'GetP' ); if (lpBuffer = = NULL) { KdPrint(( "%s ExAllocatePoolWithTag error.\n" , __FUNCTION__)); nStatus = STATUS_MEMORY_NOT_ALLOCATED; __leave; } nStatus = ZwQueryInformationProcess( NtCurrentProcess(), ProcessImageFileName, lpBuffer, / / 在查询一遍就获得进程的全路径了 nNeedSize, &nNeedSize); if (NT_ERROR(nStatus)) { KdPrint(( "%s NtQueryInformationProcess error2.\n" , __FUNCTION__)); __leave; } / / 获得的路径是\device\harddiskvolume3\program files\qq.exe这种格式,需要转化成用户熟悉的盘符 / / \??\c:\program files\qq.exe RtlCopyUnicodeString(&ProcessPath, (PUNICODE_STRING)lpBuffer); InitializeObjectAttributes( &ObjectAttributes, &ProcessPath, OBJ_CASE_INSENSITIVE, NULL, NULL); / / / 打开路径得到handle nStatus = ZwCreateFile( &hFile, FILE_READ_ATTRIBUTES, &ObjectAttributes, &IoStatus, NULL, FILE_ATTRIBUTE_NORMAL, 0 , FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0 ); if (NT_ERROR(nStatus)) { hFile = NULL; __leave; } nStatus = ObReferenceObjectByHandle( hFile, NULL, * IoFileObjectType, KernelMode, (PVOID * )&FileObject, / / 得到handle对应的FileObject NULL); if (NT_ERROR(nStatus)) { FileObject = NULL; __leave; } FileName = (PFILE_NAME_INFORMATION)FileBuffer; nStatus = ZwQueryInformationFile( hFile, &IoStatus, FileName, sizeof(WCHAR) * MAX_PATH, FileNameInformation); if (NT_ERROR(nStatus)) { __leave; } if (FileObject - >DeviceObject = = NULL) / / 通过FileObject得到DeviceObject { nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST; __leave; } / / / 求出进程文件所在盘符的符号链接 nDeviceStatus = RtlVolumeDeviceToDosName(FileObject - >DeviceObject, &DosDeviceName); } __finally { if (NULL ! = FileObject) { ObDereferenceObject(FileObject); } if (NULL ! = hFile) { ZwClose(hFile); } if (NULL ! = lpBuffer) { ExFreePool(lpBuffer); } KeUnstackDetachProcess(&ApcState); } if (NT_SUCCESS(nStatus)) { RtlInitUnicodeString(&ProcessPath, FileName - >FileName); if (NT_SUCCESS(nDeviceStatus)) { / / / 拼接DosDeviceName + ProcessPath RtlCopyUnicodeString(FullPath, &DosDeviceName); RtlUnicodeStringCat(FullPath, &ProcessPath); } else { RtlCopyUnicodeString(FullPath, &ProcessPath); } } return nStatus; } |
4.也可以在内核层弹窗
不仅可以应用层弹窗。内核层也调用ExRaiseHardError()
来弹窗(但可定制性不高,没有计时功能,比如在反截屏中,可以弹窗提示用户)
主防的几个经典问题
弹窗弹的是什么?
A把B怎么了?
A
:R3某进程。- 忽略内核操作,互不干涉,内核和内核对战是没必要的,主要是
阻止进程进入内核
。比如五大常任理事国都有核武器,五大常任理事国一旦打架,地球重启。共同阻止其他非常任理事国突破核武器。朝鲜。
- 忽略内核操作,互不干涉,内核和内核对战是没必要的,主要是
B
:文件/注册表/驱动/进程怎么了
:创建/删除/修改/重命名/启动允许还是阻止
弹框的不同颜色警示危险等级
- 做得太弱智,老弹窗,用户会厌烦,用户也可能误判
- 拦截到攻击自己判断处理
最好
,也防止用户误判,但太智能也不行,一次都没有弹窗,用户会怀疑你行不行
,所以还是偶尔弹一下绿框告诉用户,拦截到某个攻击事件已经自动处理,一闪而过刷一下存在感
。模式匹配
正则匹配
- 为了性能和安全的平衡,不可能监控所有文件,监控重要的文件比较合理,比如sytem32文件夹等。这时候就需要使用模式匹配了
*
表示零次或者任意次字符?
表示零次或下一次字符- eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | BOOLEAN IsPatternMatch(PUNICODE STRING Expression, PUNICODE_STRING Name, BOOLEAN IgnoreCase) { / / / 如果匹配成功 return True ,但也有局限性,只支持文件路径的正则匹配,比如注册表就不支持了 return FsRtllsNamelnExpression( Expression, / / 正则式 Name, / / 具体某个文件的路径, IgnoreCase, / / 如果这里设置为TRUE,那么Expression必须是大写的 NULL ); } / / / 比如现在有两条规则:假设忽略大小写 L'C:\\WINDOWS\\SYSTEM32\\ * .SYS" L "C:\\WINDOWS\\SYSTEM32\\*\\*.SYS" / / / 有路径: L "C:\\Window\\system32\\122222\\2.sys" / / / 就会匹配第一、第二条规则 / / / 如果区分分文件夹,只想命中第二条规则,可以把第一条规则改成 L'C:\\WINDOWS\\SYSTEM32 / * .SYS" |
实战:支持任何字符串的正则匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | #include <Ntifs.h> #include <ntddk.h> #include <windef.h> VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { DbgPrint( "Goodbye!\n" ); } BOOLEAN IsPatternMatch(PUNICODE_STRING Expression, PUNICODE_STRING Name, BOOLEAN IgnoreCase) { return FsRtlIsNameInExpression( Expression, Name, IgnoreCase, / / 如果这里设置为TRUE,那么Expression必须是大写的 NULL ); } BOOL PatternMatch(WCHAR * pat, WCHAR * str ) { register WCHAR * s; register WCHAR * p; BOOL star = FALSE; loopStart: for (s = str , p = pat; * s; + + s, + + p) { switch ( * p) { case L '?' : if ( * s = = L '.' ) goto starCheck; break ; case L '*' : star = TRUE; str = s, pat = p; if (! * + + pat) return TRUE; goto loopStart; default: / / if (Lower( * s) ! = Lower( * p)) goto starCheck; break ; } } if ( * p = = L '*' ) + + p; return (! * p); starCheck: if (!star) return FALSE; str + + ; goto loopStart; } BOOL PatternNMatch(WCHAR * pat, WCHAR * str , DWORD count) { register WCHAR * s; register WCHAR * p; BOOL star = FALSE; DWORD dwCount = count; loopStart: for (s = str , p = pat; dwCount> 0 ; - - dwCount, + + s, + + p) { switch ( * p) { case L '?' : if ( * s = = L '.' ) goto starCheck; break ; case L '*' : star = TRUE; str = s, pat = p; if (! * + + pat) return TRUE; goto loopStart; default: / / if (Lower( * s) ! = Lower( * p)) goto starCheck; break ; } } if ( * p = = L '*' ) + + p; return (! * p); starCheck: if (!star) return FALSE; str + + ; dwCount - - ; goto loopStart; } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) { UNICODE_STRING uExpression = { 0 }; UNICODE_STRING uName = { 0 }; RtlInitUnicodeString(&uExpression, L "C:\\WINDOWS\\SYSTEM32\\*.SYS" ); RtlInitUnicodeString(&uName, L "c:\\Windows\\system32\\122222\\2.sys" ); if (IsPatternMatch(&uExpression, &uName, TRUE)) { DbgPrint( "Matched\n" ); } else { DbgPrint( "Not Matched\n" ); } pDriverObject - >DriverUnload = DriverUnload; return STATUS_SUCCESS; } |
格式转换
获得目标对象的全路径
- 内核中有多种对象,对象不同获取全路径的方式不同
- Handle
- ObReferenceObjectByHandle→ loQueryFileDosDeviceName
- ObReferenceObjectBylHandle→ ObQueryNameString(强删文件例子里)
- IRP查询(FILEMON4.34中FilemonQueryFile函数)
- FltGetName(minifilter)
获得文件短名的长名
- windows用
dir /x
查看短名- dos环境下的83格式(文件名总数<=8,扩展名<=3,太长的文件名中间部分会被
~
替换)
- dos环境下的83格式(文件名总数<=8,扩展名<=3,太长的文件名中间部分会被
- 统一使用长名来做规则匹配
- 所以需要短名转化成长名
- 思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | #include <ntifs.h> #include <ntstrsafe.h> #include <ntddk.h> #include <windef.h> BOOL IsRootDirecotry(WCHAR * wszDir) { SIZE_T length = wcslen(wszDir); / / c: if ((length = = 2 ) && (wszDir[ 1 ] = = L ':' )) return TRUE; / / \\??\\c: if ((length = = 6 ) && (_wcsnicmp(wszDir, L "\\??\\" , 4 ) = = 0 ) && (wszDir[ 5 ] = = L ':' )) return TRUE; / / \\DosDevices\\c: if ((length = = 14 ) && (_wcsnicmp(wszDir, L "\\DosDevices\\" , 12 ) = = 0 ) && (wszDir[ 13 ] = = L ':' )) return TRUE; / / \\Device\\HarddiskVolume1 if ((length = = 23 ) && (_wcsnicmp(wszDir, L "\\Device\\HarddiskVolume" , 22 ) = = 0 )) return TRUE; return FALSE; } BOOL IsDirectorySep(WCHAR ch) { return (ch = = L '\\' || ch == L' / '); } / / C:\\Program\\ 123456 ~ 1 / / wszRootdir为:c:\\Program / / wszShortName为: 123456 ~ 1 BOOL QueryDirectoryForLongName( WCHAR * wszRootDir, WCHAR * wszShortName, WCHAR * wszLongName, ULONG ulSize) { UNICODE_STRING ustrRootDir = { 0 }; UNICODE_STRING ustrShortName = { 0 }; UNICODE_STRING ustrLongName = { 0 }; OBJECT_ATTRIBUTES oa = { 0 }; IO_STATUS_BLOCK Iosb = { 0 }; NTSTATUS ntStatus = 0 ; HANDLE hDirHandle = 0 ; BYTE * Buffer = NULL; WCHAR * wszRoot = NULL; PFILE_BOTH_DIR_INFORMATION pInfo = NULL; RtlZeroMemory(&Iosb, sizeof(IO_STATUS_BLOCK)); Iosb.Status = STATUS_NO_SUCH_FILE; wszRoot = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), 'L2S' ); if (wszRoot = = NULL) { return FALSE; } RtlZeroMemory(wszRoot, MAX_PATH * sizeof(WCHAR)); wcsncpy(wszRoot, wszRootDir, MAX_PATH); RtlInitUnicodeString(&ustrRootDir, wszRoot); RtlInitUnicodeString(&ustrShortName, wszShortName); if (IsRootDirecotry(wszRoot)) RtlAppendUnicodeToString(&ustrRootDir, L "\\" ); InitializeObjectAttributes(&oa, &ustrRootDir, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0 , 0 ); ntStatus = ZwCreateFile(&hDirHandle, GENERIC_READ | SYNCHRONIZE, &oa, &Iosb, 0 , FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT , 0 , 0 ); if (!NT_SUCCESS(ntStatus)) { ExFreePool(wszRoot); return FALSE; } ExFreePool(wszRoot); Buffer = ExAllocatePoolWithTag(PagedPool, 1024 , 'L2S' ); if ( Buffer = = NULL) { ZwClose(hDirHandle); return FALSE; } RtlZeroMemory( Buffer , 1024 ); ntStatus = ZwQueryDirectoryFile(hDirHandle, NULL, 0 , 0 , &Iosb, Buffer , 1024 , FileBothDirectoryInformation, TRUE, &ustrShortName, / / 传回与 ustrShortName Match的项 TRUE); if (!NT_SUCCESS(ntStatus)) { ExFreePool( Buffer ); ZwClose(hDirHandle); return FALSE; } ZwClose(hDirHandle); pInfo = (PFILE_BOTH_DIR_INFORMATION) Buffer ; if (pInfo - >FileNameLength = = 0 ) { ExFreePool( Buffer ); return FALSE; } ustrShortName.Length = (USHORT)pInfo - >FileNameLength; ustrShortName.MaximumLength = (USHORT)pInfo - >FileNameLength; ustrShortName. Buffer = pInfo - >FileName; / / 长名 if (ulSize < ustrShortName.Length) { ExFreePool( Buffer ); return FALSE; } ustrLongName.Length = 0 ; ustrLongName.MaximumLength = (USHORT)ulSize; ustrLongName. Buffer = wszLongName; RtlCopyUnicodeString(&ustrLongName, &ustrShortName); ExFreePool( Buffer ); return TRUE; } BOOL QueryLongName(WCHAR * wszFullPath, WCHAR * wszLongName, ULONG size) { BOOL rtn = FALSE; WCHAR * pchStart = wszFullPath; WCHAR * pchEnd = NULL; WCHAR * wszShortName = NULL; / / c:\\Program\\Files1~ 1 - - >获得Files1~ 1 的长名 while ( * pchStart) { if (IsDirectorySep( * pchStart)) pchEnd = pchStart; pchStart + + ; } / / wszFullPath = c:\\Program / / pchEnd = Files~ 1 if (pchEnd) { * pchEnd + + = L '\0' ; / / c:\\Program\\Files1~ 1 / / wszFullPath:c:\\Program / / pchEnd:Files1~ 1 wszShortName = pchEnd; rtn = QueryDirectoryForLongName(wszFullPath, wszShortName, wszLongName, size); * ( - - pchEnd) = L '\\' ; / / wszFullPath = c:\\Program\\Files1~ 1 } return rtn; } / / 先把根目录拷贝到目标目录中,剩下的找到下一级目录是否含有~,如果有,则开始转化. / / 如:c:\\Progam\\a~ 1 \\b~ 1 \hi~ 1.txt / / pchStart指向目录中前一个\\,pchEnd扫描并指向目录的下一个\\,其中如果发现了~,则是短名,需要转换. / / 传c:\\Program\\a~ 1 - - >c:\\Progam\\ax / / 传c:\\Program\\ax\\b~ 1 - - >c:\\Program\\ax\\by / / 传c:\\Program\\ax\by\\hi~ 1.txt - - >c:\\Program\\ax\by\\hiz.txt BOOL ConverShortToLongName(WCHAR * wszLongName, WCHAR * wszShortName, ULONG size) { WCHAR * szResult = NULL; WCHAR * pchResult = NULL; WCHAR * pchStart = wszShortName; INT Offset = 0 ; szResult = ExAllocatePoolWithTag(PagedPool, sizeof(WCHAR) * (MAX_PATH * 2 + 1 ), 'L2S' ); if (szResult = = NULL) { return FALSE; } RtlZeroMemory(szResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1 )); pchResult = szResult; / / C:\\x\\ - - >\\??\\c: if (pchStart[ 0 ] && pchStart[ 1 ] = = L ':' ) { * pchResult + + = L '\\' ; * pchResult + + = L '?' ; * pchResult + + = L '?' ; * pchResult + + = L '\\' ; * pchResult + + = * pchStart + + ; * pchResult + + = * pchStart + + ; Offset = 4 ; } / / \\DosDevices\\c:\\xx - - >\\??\\c: else if (_wcsnicmp(pchStart, L "\\DosDevices\\" , 12 ) = = 0 ) { RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1 ), L "\\??\\" ); pchResult + = 4 ; pchStart + = 12 ; while ( * pchStart && !IsDirectorySep( * pchStart)) * pchResult + + = * pchStart + + ; Offset = 4 ; } / / \\Device\\HarddiskVolume1\\xx - - >\\Device\\HarddiskVolume1 else if (_wcsnicmp(pchStart, L "\\Device\\HardDiskVolume" , 22 ) = = 0 ) { RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1 ),L "\\Device\\HardDiskVolume" ); pchResult + = 22 ; pchStart + = 22 ; while ( * pchStart && !IsDirectorySep( * pchStart)) * pchResult + + = * pchStart + + ; } / / \\??\\c:\\xx - - >\\??\\c: else if (_wcsnicmp(pchStart, L "\\??\\" , 4 ) = = 0 ) { RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1 ), L "\\??\\" ); pchResult + = 4 ; pchStart + = 4 ; while ( * pchStart && !IsDirectorySep( * pchStart)) * pchResult + + = * pchStart + + ; } else { ExFreePool(szResult); return FALSE; } while (IsDirectorySep( * pchStart)) { BOOL bShortName = FALSE; WCHAR * pchEnd = NULL; WCHAR * pchReplacePos = NULL; * pchResult + + = * pchStart + + ; pchEnd = pchStart; pchReplacePos = pchResult; while ( * pchEnd && !IsDirectorySep( * pchEnd)) { if ( * pchEnd = = L '~' ) { bShortName = TRUE; } * pchResult + + = * pchEnd + + ; } * pchResult = L '\0' ; if (bShortName) { WCHAR * szLong = NULL; szLong = ExAllocatePoolWithTag(PagedPool, sizeof(WCHAR) * MAX_PATH, 'L2S' ); if (szLong) { RtlZeroMemory(szLong, sizeof(WCHAR) * MAX_PATH); if (QueryLongName(szResult, szLong, sizeof(WCHAR) * MAX_PATH)) { RtlStringCbCopyW(pchReplacePos, sizeof(WCHAR) * (MAX_PATH * 2 + 1 ), szLong); pchResult = pchReplacePos + wcslen(pchReplacePos); } ExFreePool(szLong); } } pchStart = pchEnd; } wcsncpy(wszLongName, szResult + Offset, size / sizeof(WCHAR)); ExFreePool(szResult); return TRUE; } BOOL IsShortNamePath(WCHAR * wszFileName) { WCHAR * p = wszFileName; while ( * p ! = L '\0' ) { if ( * p = = L '~' ) { return TRUE; } p + + ; } return FALSE; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { DbgPrint( "Goodbye!\n" ); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) { / / dir / x看短名 WCHAR wszShortName[MAX_PATH] = L "\\??\\C:\\PROGRA~1\\COMMON~1\\MICROS~1\\VC\\1.txt" ; WCHAR wszLongName[MAX_PATH] = { 0 }; if (ConverShortToLongName(wszLongName, wszShortName, sizeof(wszLongName))) { DbgPrint( "%ws\n" , wszLongName); } pDriverObject - >DriverUnload = DriverUnload; return STATUS_SUCCESS; } |
设备名与符号链接名的转化
- 设备名-> 符号链接名
- 有指定的API可以调用
- ZwOpenSymbolicLinkObject()得到符号链接名
- ZwQuerySymbolicLinkObject()得到设备名
- 设备名<-符号链接名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | #include <ntddk.h> #include <windef.h> #include <ntstrsafe.h> / / 输入\\??\\c: - - >\\device\\\harddiskvolume1 / / LinkTarget. Buffer 注意要释放 NTSTATUS QuerySymbolicLink( IN PUNICODE_STRING SymbolicLinkName, OUT PUNICODE_STRING LinkTarget ) { OBJECT_ATTRIBUTES oa = { 0 }; NTSTATUS status = 0 ; HANDLE handle = NULL; InitializeObjectAttributes( &oa, SymbolicLinkName, OBJ_CASE_INSENSITIVE, 0 , 0 ); status = ZwOpenSymbolicLinkObject(&handle, GENERIC_READ, &oa); if (!NT_SUCCESS(status)) { return status; } LinkTarget - >MaximumLength = MAX_PATH * sizeof(WCHAR); LinkTarget - >Length = 0 ; LinkTarget - > Buffer = ExAllocatePoolWithTag(PagedPool, LinkTarget - >MaximumLength, 'SOD' ); if (!LinkTarget - > Buffer ) { ZwClose(handle); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(LinkTarget - > Buffer , LinkTarget - >MaximumLength); status = ZwQuerySymbolicLinkObject(handle, LinkTarget, NULL); ZwClose(handle); if (!NT_SUCCESS(status)) { ExFreePool(LinkTarget - > Buffer ); } return status; } / / 输入\\Device\\harddiskvolume1 / / 输出C: / / DosName. Buffer 的内存记得释放 NTSTATUS MyRtlVolumeDeviceToDosName( IN PUNICODE_STRING DeviceName, OUT PUNICODE_STRING DosName ) / * + + Routine Description: This routine returns a valid DOS path for the given device object . This caller of this routine must call ExFreePool on DosName - > Buffer when it is no longer needed. Arguments: VolumeDeviceObject - Supplies the volume device object . DosName - Returns the DOS name for the volume Return Value: NTSTATUS - - * / { NTSTATUS status = 0 ; UNICODE_STRING driveLetterName = { 0 }; WCHAR driveLetterNameBuf[ 128 ] = { 0 }; WCHAR c = L '\0' ; WCHAR DriLetter[ 3 ] = { 0 }; UNICODE_STRING linkTarget = { 0 }; for (c = L 'A' ; c < = L 'Z' ; c + + ) { RtlInitEmptyUnicodeString(&driveLetterName,driveLetterNameBuf,sizeof(driveLetterNameBuf)); RtlAppendUnicodeToString(&driveLetterName, L "\\??\\" ); DriLetter[ 0 ] = c; DriLetter[ 1 ] = L ':' ; DriLetter[ 2 ] = 0 ; RtlAppendUnicodeToString(&driveLetterName,DriLetter); status = QuerySymbolicLink(&driveLetterName, &linkTarget); if (!NT_SUCCESS(status)) { continue ; } if (RtlEqualUnicodeString(&linkTarget, DeviceName, TRUE)) { ExFreePool(linkTarget. Buffer ); break ; } ExFreePool(linkTarget. Buffer ); } if (c < = L 'Z' ) { DosName - > Buffer = ExAllocatePoolWithTag(PagedPool, 3 * sizeof(WCHAR), 'SOD' ); if (!DosName - > Buffer ) { return STATUS_INSUFFICIENT_RESOURCES; } DosName - >MaximumLength = 6 ; DosName - >Length = 4 ; * DosName - > Buffer = c; * (DosName - > Buffer + 1 ) = ':' ; * (DosName - > Buffer + 2 ) = 0 ; return STATUS_SUCCESS; } return status; } / / c:\\windows\\hi.txt< - - \\device\\harddiskvolume1\\windows\\hi.txt BOOL NTAPI GetNTLinkName(IN WCHAR * wszNTName, OUT WCHAR * wszFileName) { UNICODE_STRING ustrFileName = { 0 }; UNICODE_STRING ustrDosName = { 0 }; UNICODE_STRING ustrDeviceName = { 0 }; WCHAR * pPath = NULL; ULONG i = 0 ; ULONG ulSepNum = 0 ; if (wszFileName = = NULL || wszNTName = = NULL || _wcsnicmp(wszNTName, L "\\device\\harddiskvolume" , wcslen(L "\\device\\harddiskvolume" ))! = 0 ) { return FALSE; } ustrFileName. Buffer = wszFileName; ustrFileName.Length = 0 ; ustrFileName.MaximumLength = sizeof(WCHAR) * MAX_PATH; while (wszNTName[i]! = L '\0' ) { if (wszNTName[i] = = L '\0' ) { break ; } if (wszNTName[i] = = L '\\' ) { ulSepNum + + ; } if (ulSepNum = = 3 ) { wszNTName[i] = UNICODE_NULL; pPath = &wszNTName[i + 1 ]; break ; } i + + ; } if (pPath = = NULL) { return FALSE; } RtlInitUnicodeString(&ustrDeviceName, wszNTName); if (!NT_SUCCESS(MyRtlVolumeDeviceToDosName(&ustrDeviceName, &ustrDosName))) { return FALSE; } RtlCopyUnicodeString(&ustrFileName, &ustrDosName); RtlAppendUnicodeToString(&ustrFileName, L "\\" ); RtlAppendUnicodeToString(&ustrFileName, pPath); ExFreePool(ustrDosName. Buffer ); return TRUE; } BOOL QueryVolumeName(WCHAR ch, WCHAR * name, USHORT size) { WCHAR szVolume[ 7 ] = L "\\??\\C:" ; UNICODE_STRING LinkName; UNICODE_STRING VolName; UNICODE_STRING ustrTarget; NTSTATUS ntStatus = 0 ; RtlInitUnicodeString(&LinkName, szVolume); szVolume[ 4 ] = ch; ustrTarget. Buffer = name; ustrTarget.Length = 0 ; ustrTarget.MaximumLength = size; ntStatus = QuerySymbolicLink(&LinkName, &VolName); if (NT_SUCCESS(ntStatus)) { RtlCopyUnicodeString(&ustrTarget, &VolName); ExFreePool(VolName. Buffer ); } return NT_SUCCESS(ntStatus); } / / \\??\\c:\\windows\\hi.txt - - >\\device\\harddiskvolume1\\windows\\hi.txt BOOL NTAPI GetNtDeviceName(IN WCHAR * filename, OUT WCHAR * ntname) { UNICODE_STRING uVolName = { 0 , 0 , 0 }; WCHAR volName[MAX_PATH] = L""; WCHAR tmpName[MAX_PATH] = L""; WCHAR chVol = L '\0' ; WCHAR * pPath = NULL; int i = 0 ; RtlStringCbCopyW(tmpName, MAX_PATH * sizeof(WCHAR), filename); for (i = 1 ; i < MAX_PATH - 1 ; i + + ) { if (tmpName[i] = = L ':' ) { pPath = &tmpName[(i + 1 ) % MAX_PATH]; chVol = tmpName[i - 1 ]; break ; } } if (pPath = = NULL) { return FALSE; } if (chVol = = L '?' ) { uVolName.Length = 0 ; uVolName.MaximumLength = MAX_PATH * sizeof(WCHAR); uVolName. Buffer = ntname; RtlAppendUnicodeToString(&uVolName, L "\\Device\\HarddiskVolume?" ); RtlAppendUnicodeToString(&uVolName, pPath); return TRUE; } else if (QueryVolumeName(chVol, volName, MAX_PATH * sizeof(WCHAR))) { uVolName.Length = 0 ; uVolName.MaximumLength = MAX_PATH * sizeof(WCHAR); uVolName. Buffer = ntname; RtlAppendUnicodeToString(&uVolName, volName); RtlAppendUnicodeToString(&uVolName, pPath); return TRUE; } return FALSE; } VOID DriverUnload(PDRIVER_OBJECT pDriverObject) { DbgPrint( "Goodbye!\n" ); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) { UNICODE_STRING ustrDeviceName = { 0 }; UNICODE_STRING ustrLinkName = { 0 }; WCHAR * wszDeviceName = L "\\Device\\harddiskvolume1" ; NTSTATUS ntStatus = 0 ; WCHAR DeviceName[MAX_PATH] = L "\\Device\\harddiskvolume1\\windows\\hi.txt" ; WCHAR FileName[MAX_PATH] = { 0 }; WCHAR szDeviceName[MAX_PATH] = { 0 }; RtlInitUnicodeString(&ustrDeviceName, wszDeviceName); ntStatus = MyRtlVolumeDeviceToDosName(&ustrDeviceName, &ustrLinkName); if (NT_SUCCESS(ntStatus)) { DbgPrint( "linkname:%wZ\n" , &ustrLinkName); if (ustrLinkName. Buffer ) { ExFreePool(ustrLinkName. Buffer ); } } if (GetNTLinkName(DeviceName, FileName)) { DbgPrint( "FileName:%ws\n" , FileName); GetNtDeviceName(FileName, szDeviceName); DbgPrint( "szDeviceName:%ws" , szDeviceName); } pDriverObject - >DriverUnload = DriverUnload; return STATUS_SUCCESS; } |
规则的下发方式
- 用dat文件存放规则,dat文件做一些简单加密(防止木马和病毒利用,绕过监测)
- 客户端把dat文件的规则读出,通过DeviceIoControl()发到内核,保存在内核中的链表或者树或者hash表里面,内核在拦截到攻击事件的时候,就会去遍历这个存放规则数据结构,匹配上就弹窗或者自行处理。
放行问题
- 大数据机器学习,智能放行
- 中国杀毒软件层参加国际比赛到很高分,是针对病毒库定制的版本(查杀率很高),和用户的版本不一样,取消比赛成绩
放行的条件
- 内核态的操作不拦截
- 用
ExGetPreviousMode() == KernnelMode
来判断是不是内核态 - 或者用
Irp->RequestorMode == kernelMode
来判断是不是内核态
- 用
- 自己进程的操作不拦截 1
-
在DeviceIoctrlFilter中通过PsGetCurrentProcessId()拿到进程的`PID`
- 系统进程的操作不拦截
- DriverEntry里处于
系统上下文
,再通过PsGetCurrentProcessId()拿到的就是系统进程,以后凡是这些系统进程的操作都放行 - 应用层的Irql一般不会超过APC_LEVEL,即
KeGetCurrentIrql()>APC_LEVEL
放行,只拦截应用层
- DriverEntry里处于
- 白名单中的进程(交了钱的)
- 如果通过HOOK进行监控,放行就是直接调用原来被HOOK的API
- IRP(如果是在过滤驱动进行监控的)
1 2 3 | / / / 把Irp往下发 IoSkipCurrentIrpStackLocation(IpIrp); IoCallDriver(); |
赞赏记录
参与人
雪币
留言
时间
治愈ckt
为你点赞~
2024-3-18 17:24
pysafe
为你点赞~
2023-5-6 10:38
704088
为你点赞~
2023-3-31 00:46
赞赏
他的文章
- [原创]java和smali汇编 2677
- [原创]Android逆向前期准备(下) 4239
- [原创]native层逆向分析(上篇) 13789
- [原创]Java层逆向分析方法和技巧 7244
看原图
赞赏
雪币:
留言: