问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
64位下使用回调函数实现监控
安全工具
64位下使用回调函数实现监控 下功夫 64位下使用回调函数实现监控
0x00 前言 ======= 在32位的系统下,我们想要实现某些监控十分简单,只需要找到对应的API实现挂钩操作即可检测进程。但在64位系统下随着`Patch Guard`的引入,导致我们如果继续使用挂钩API的方式进行监控会出现不可控的情况发生。微软也考虑到了用户程序的开发,所以开放了方便用户调用的系统回调API函数,在64位系统下的监控,使用系统回调相对于直接hook的方式往往是更值得青睐的一方 0x01 进程监控&保护 ================ PsSetCreateProcessNotifyRoutineEx --------------------------------- 这个函数主要是设置进程回调监控进程创建与退出 ```c++ NTSTATUS PsSetCreateProcessNotifyRoutineEx( [in] PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, [in] BOOLEAN Remove ); ``` ![image-20220429152901611.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-7580ed6613f5eaeb2dddb07ca0ea62f15fe8df9f.png) `PsSetCreateProcessNotifyRoutineEx`这个函数并不是随便就能够使用的,微软为了确保安全性要求拥有数字签名的驱动才能够使用此函数。这里微软如何检测是否有数字签名呢?这里就使用到了强制完整性检查 强制完整性检查是一种确保正在加载的二进制文件在加载前需要使用签名的策略,`IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY`标志在链接时通过使用`/integritycheck`链接器标志在PE头中进行设置,让正在加载的二进制文件必须签名,这个标志使windows内存管理器在加载时对二进制文件进行签名检查 那么微软就是通过加载二进制文件时是否存在标志来确认驱动的发布者身份是否为已知状态,这就是强制完整性检查 ![image-20220429154355018.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-cfc2fa36c42965cecd503113a709c59623c59725.png) 这里在内核里面,windows使用到`MmVerifyCallbackFunction`这个内核函数来判断 ![image-20220429160658091.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-7242f155004f3cc8423e847294c14489b8166511.png) 到IDA里面继续跟`MmVerifyCallbackFunction`这个函数,发现其逻辑就是通过比较`[rax+68h]`是否包含了0x20来判断是否拥有正确的数字签名 ![image-20220429160758206.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-1760a6bef307733203d866b01310f596c9d82170.png) 这里的`rax`表示`DriverSection`,而`DriverSection`指向的是`_LDR_DATA_TABLE_ENTRY`结构,那么`[rax + 0x68]`指向的就是`ProcessStaticImport` ![image-20220429161209373.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-7346e41ce28843e2debfa19847c16481fe348b2d.png) 那么如果我们要使用`PsSetCreateProcessNotifyRoutineEx`这个函数就需要拥有数字签名,这里我们就可以将`DriverObject->DriverSection->Flags`的值与`0x20`按位或即可 这里我们就可以编写一个绕过强制完整性检查的函数,注意一下在32位和64位结构体的定义不同,需要分开定义 ```c++ BOOLEAN bypass_signcheck(PDRIVER_OBJECT pDriverObject) { #ifdef _WIN64 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG64 __Undefined1; ULONG64 __Undefined2; ULONG64 __Undefined3; ULONG64 NonPagedDebugInfo; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG64 __Undefined6; ULONG CheckSum; ULONG __padding1; ULONG TimeDateStamp; ULONG __padding2; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; #else typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG unknown1; ULONG unknown2; ULONG unknown3; ULONG unknown4; ULONG unknown5; ULONG unknown6; ULONG unknown7; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY; #endif PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20; return TRUE; } ``` 到这里我们就已经绕过了微软的强制完整性检查,能够调用`PsSetCreateProcessNotifyRoutineEx`函数,可以看到`PsSetCreateProcessNotifyRoutineEx`的第一个参数指向`CREATE_PROCESS_NOTIFY_ROUTINE_EX`,来执行我们需要执行的回调函数,这里我们继续看`PCREATE_PROCESS_NOTIFY_ROUTINE_EX`这个结构 ![image-20220429204914968.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-3c785fbe39846c6b8ada4728e5f2a82a37a1564a.png) PCREATE\_PROCESS\_NOTIFY\_ROUTINE\_EX ------------------------------------- 第一个参数是`Process`,指向`EPROCESS`结构,第二个参数`ProcessId`就是PID,第三个参数`CreateInfo`是一个指向`PS_CREATE_NOTIFY_INFO`的指针,当它为`NULL`时表明进程退出,不为`NULL`时表明进程创建,里面存储着要创建的进程信息 ```c++ PCREATE_PROCESS_NOTIFY_ROUTINE_EX PcreateProcessNotifyRoutineEx; void PcreateProcessNotifyRoutineEx( [_Inout_] PEPROCESS Process, [in] HANDLE ProcessId, [in, out, optional] PPS_CREATE_NOTIFY_INFO CreateInfo ) {...} ``` msdn的定义如下 ![image-20220429153441738.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-81fca4d91b474856ed4a0125e113d825fe3abf48.png) 然后我们再去看一下`PS_CREATE_NOTIFY_INFO` PS\_CREATE\_NOTIFY\_INFO ------------------------ ```c++ typedef struct _PS_CREATE_NOTIFY_INFO { SIZE_T Size; union { ULONG Flags; struct { ULONG FileOpenNameAvailable : 1; ULONG IsSubsystemProcess : 1; ULONG Reserved : 30; }; }; HANDLE ParentProcessId; CLIENT_ID CreatingThreadId; struct _FILE_OBJECT *FileObject; PCUNICODE_STRING ImageFileName; PCUNICODE_STRING CommandLine; NTSTATUS CreationStatus; } PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO; ``` msdn定义如下 ![image-20220429153522913.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-426916941ec2916ff3a05ec68e603637994ee011.png) 这里的话我们要注意两个值,一个是`ImageFileName`即要创建的进程名,一个是`CreationStatus`,我们可以看到msdn里面说驱动程序可以将此值修改为错误代码以防止创建进程,这里我们如果想阻止进程创建就可以把这个值设置为`STATUS_UNSUCCESSFUL` ![image-20220429205611615.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-219778a8d3e383aa034c4dff77f536133fad3784.png) 我们去WRK里面看一下实现,这个API是64位才有的,所以在WRK里面是没有`PsSetCreateProcessNotifyRoutineEx`这个函数的,但是在32位下有一个`PsSetCreateProcessNotifyRoutine`,我们看一下 ![image-20220429224629521.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-f9295804162680e0140360b6fea9f2e16505c5cb.png) 通过源码可以发现是操作数组,这个数组里面存放的是我们填写的回调,而操作系统会依次调用回调,那我们跟随数组查看发现是个定长数组,里面只有8项,在64位系统下,这个数组的长度变为了64项 ![image-20220429224711652.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-d92222e714bd81a0f37f84b761562417de63012a.png) 根据`PCREATE_PROCESS_NOTIFY_ROUTINE_EX`的结构定义回调函数 ```c++ VOID CreateProcessNotifyEx( __inout PEPROCESS Process, __in HANDLE ProcessId, __in_opt PPS_CREATE_NOTIFY_INFO CreateInfo ); ``` 那么我们这里通过`PsSetCreateProcessNotifyRoutineEx`设置回调函数,通过判断`status`的返回值判断回调函数是否设置成功 ```c++ NTSTATUS SetReFunction() { NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)CreateProcessNotifyEx, FALSE); if (!NT_SUCCESS(status)) { DbgPrint("回调函数设置失败, status=%X", status); } else { DbgPrint("进程监控已开启\r\n"); } } ``` 然后进行回调函数的实现 ```c++ VOID CreateProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo) ``` 首先判断`CreateInfo`的值,如果为`NULL`则表示进程退出,如果不为`NULL`才为进程的创建 ```c++ if (CreateInfo == NULL) { DbgPrint("进程退出\n"); return; } ``` 那么这里通过`PsGetProcessImageFileName`获取进程名之后进行判断,如果是我们想要拦截的进程就通过设置`CreationStatus`的值为`STATUS_UNSUCCESSFUL`来阻止进程的创建 ```c++ else { pszImageFileName = PsGetProcessImageFileName(Process); if (pszImageFileName) DbgPrint("新创建的进程是:%s\r\n", pszImageFileName); if (strcmp(pszImageFileName, "test.exe") == 0) { CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; DbgPrint("拦截进程:%s成功\r\n", pszImageFileName); } } ``` 这里我们的回调函数就已经完成,这里需要注意,在卸载驱动的时候就需要将回调函数摘除,否则新创建或者退出的进程会因为找不到回调函数而导致蓝屏 ```c++ VOID DriverUnload(IN PDEVICE_OBJECT driverObject) { NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)CreateProcessNotifyEx, TRUE); if (!NT_SUCCESS(status)) { DbgPrint("回调函数删除失败\r\n status=%X", status); } else { DbgPrint("回调函数成功删除\r\n"); } DbgPrint("驱动卸载完成\r\n"); } ``` 实现效果 ---- 首先注册一下驱动 ![image-20220429214350741.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-2cd94bc0c78212c30bfcc73606a49d7ee1f036ab.png) 然后这里首先执行一下我们的exe ![image-20220429214415641.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-654157af5b762bb97b7ffdfa6be8bcbe931d5bd1.png) 然后加载我们的驱动可以看到这里`test.exe`已经不能够运行 ![image-20220429214524382.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-ff0090a595aa811fc46c8215ba6a66f434e17b2d.png) 那么这里我们再卸载一下驱动可以发现又可以运行成功 ![image-20220429214549454.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-2253c377f5e5ab66bf0c6f32625e232b7d8ccd7a.png) 这里可能有点不太明显,我们将拦截的exe改成`notepad.exe`看下效果 ![image-20220429214919018.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-f83a73b33822e2f8c88f2793df58363d72b4bace.png) 启动驱动可以看到这里启动失败 ![image-20220429215206415.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-c8775364a024e660d94d43267d3fa4df67bc74c9.png) 卸载驱动即可启动成功 ![image-20220429215220347.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-2fa24608d80b362a384e062b14da7889ec291bfd.png) 0x02 线程监控&保护 ================ PsSetCreateThreadNotifyRoutine ------------------------------ 线程监控使用到的API相对于进程监控简单,使用到`PsSetCreateThreadNotifyRoutine`,而这个值并不能像进程操作的API一样进行操作,这里我们首先先使用这个API来进行线程的监控 ```c++ NTSTATUS PsSetCreateThreadNotifyRoutine( [in] PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine ); ``` `NotifyRoutine`指向`PCREATE_THREAD_NOTIFY_ROUTINE` ![image-20220429220131292.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-3299f78d81231369a8bf07d21004392288bf5a14.png) `PcreateThreadNotifyRoutine`的结构如下,第一个参数为PID,第二个参数为TID,第三个参数表示是创建线程还是删除线程,创建线程则为`TRUE`,删除线程则为`FALSE` ```c++ PCREATE_THREAD_NOTIFY_ROUTINE PcreateThreadNotifyRoutine; void PcreateThreadNotifyRoutine( [in] HANDLE ProcessId, [in] HANDLE ThreadId, [in] BOOLEAN Create ) {...} ``` 那么我们这里就可以写出`CREATE_THREAD_NOTIFY_ROUTINE`函数 ```c++ VOID CreateThreadNotifyRoutine(HANDLE ProcessId, HANDLE ThreadId, BOOLEAN Create) { if (Create) { DbgPrint("新创建的线程ID为:%d,所属进程ID为:%d\r\n", ThreadId, ProcessId); } else { DbgPrint("新销毁的线程ID为:%d,所属进程ID为:%d\r\n", ThreadId, ProcessId); } } ``` 这里如果要将函数摘除,就需要用到`PsRemoveCreateThreadNotifyRoutine`函数,定义如下 ```c++ NTSTATUS PsRemoveCreateThreadNotifyRoutine( [in] PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine ); ``` ```c++ NTSTATUS status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); if (!NT_SUCCESS(status)) { DbgPrint("回调函数删除失败\r\n status=%X", status); } else { DbgPrint("回调函数成功删除\r\n"); } ``` 我们如果想让进行线程的保护该如何操作呢?我们想要阻止线程的创建,就首先要找到对应的进程,再去进行拦截,因为在64位下都是通过回调的方式实现,那么我们就可以通过找到线程回调的地址,然后直接改为`ret`即可起到拦截线程创建的效果 > 1.通过PID找到EPROCESS > > 2.通过TID找到ETHREAD > > 3.通过EPROCESS得到进程路径 > > 4.通过进程路径对应进程名 > > 5.判断进程名是否相同 > > <1>若相同则找到线程回调函数的地址修改内容为ret > > <2>若不相同则退出 那么我们该如何找到线程回调函数的地址呢?这里查阅资料后发现,3环将回调函数的地址放在了`ETHREAD + 0x410`偏移的`Win32StartAddress`里面 ![image-20220430095707467.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-54bdf2a0ce2c40d8988d4bb595ba1abe523a2a23.png) 那么这里我们就能进行函数的编写,首先我们通过`PsSetCreateThreadNotifyRoutine`注册一个线程回调函数 ```c++ NTSTATUS status = PsSetCreateThreadNotifyRoutine(CreateThreadNotify); if (!NT_SUCCESS(status)) { DbgPrint("回调函数设置失败, status=%X", status); } else { DbgPrint("线程监控已开启\r\n"); } ``` 然后我们再去写`CreateThreadNotify`这个回调函数,首先获取`EPROCESS`、`ETHREAD`,然后通过`EPROCESS`获取进程名 ```c++ status = PsLookupProcessByProcessId(ProcessId, &Process); if (!NT_SUCCESS(status)) return; status = PsLookupThreadByThreadId(ThreadId, &Thread); pszImageName = PsGetProcessImageFileName(Process); ``` 然后再判断进程名是否为我们要保护的线程 ```c++ if (strstr(pszImageName, "notepad") != NULL) ``` 定位到回调函数的地址判断内存空间是否可用 ```c++ pWin32Address = *(UCHAR**)((UCHAR*)Thread + 0x410); if (MmIsAddressValid(pWin32Address)) ``` 这里的话定位到了回调函数的地址,如果我们要修改回调函数的值就要修改页保护属性,但是在64位下是不允许使用内联汇编的,这里的话就需要使用到汇编生成`.obj`文件来使用 ```c++ ClosePageProtect(); if (MmIsAddressValid(pWin32Address)) { *pWin32Address = 0xC3; } OpenPageProtect(); ``` 修改完成之后这里我们使用`ObDereferenceObject`,减少引用计数 ```c++ if( Process ) ObDereferenceObject(Process); if( Thread ) ObDereferenceObject(Thread); ``` 这里因为我在win10 x64上做的实验,这里在关闭保护属性的时候一直报错导致`0xC3`一直修改不成功,这里就不放图了 0x03 模块监控&保护 ================ PsSetLoadImageNotifyRoutine --------------------------- 和之前的函数一样都是指向一个结构,这里是`LOAD_IMAGE_NOTIFY_ROUTINE` ```c++ NTSTATUS PsSetLoadImageNotifyRoutine( [in] PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine ); ``` ![image-20220430101555138.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-06ebf2c0e8fb271fea10cc8e55f99de7fb17d1f3.png) PLOAD\_IMAGE\_NOTIFY\_ROUTINE ----------------------------- 这里第一个参数是指向缓冲的Unicode字符串的指针,用于标识可执行映像文件,第二个参数表示PID,第三个参数指向`IMAGE_INFO` ```c++ PLOAD_IMAGE_NOTIFY_ROUTINE SetLoadImageNotifyRoutine; void SetLoadImageNotifyRoutine( _In_opt_ PUNICODE_STRING FullImageName, _In_ HANDLE ProcessId, _In_ PIMAGE_INFO ImageInfo ) { ... } ``` IMAGE\_INFO ----------- ```c++ typedef struct _IMAGE_INFO { union { ULONG Properties; struct { ULONG ImageAddressingMode : 8; ULONG SystemModeImage : 1; ULONG ImageMappedToAllPids : 1; ULONG ExtendedInfoPresent : 1; ULONG MachineTypeMismatch : 1; ULONG ImageSignatureLevel : 4; ULONG ImageSignatureType : 3; ULONG ImagePartialMap : 1; ULONG Reserved : 12; }; }; PVOID ImageBase; ULONG ImageSelector; SIZE_T ImageSize; ULONG ImageSectionNumber; } IMAGE_INFO, *PIMAGE_INFO; ``` 具体成员的作用如下 > - Properties > ImageAddressingMode > 始终设置为IMAGE\_ADDRESSING\_MODE\_32BIT。 > - SystemModeImage > 设置为一个用于新加载的内核模式组件(如驱动程序),或者对于映射到用户空间的映像设置为 0。 > - ImageMappedToAllPids > 始终设置为0。 > - ExtendedInfoPresent > 如果设置了ExtendedInfoPresent标志,则IMAGE\_INFO结构是图像信息结构的较大扩展版本的一部分(请参阅IMAGE\_INFO\_EX)。在Windows Vista中添加。有关详细信息,请参阅本备注部分的“扩展版本的图像信息结构”。 > - MachineTypeMismatch > 始终设置为 0。在Windows 8 / Windows Server 2012中添加。 > - ImageSignatureLevel > 代码完整性标记为映像的签名级别。该值是ntddk.h中的#define SE*SIGNING\_LEVEL* \*常量之一。在Windows 8.1 / Windows Server 2012 R2中添加。 > - ImageSignatureType > 代码完整性标记为映像的签名类型。该值是在ntddk.h中定义的SE\_IMAGE\_SIGNATURE\_TYPE枚举值。在Windows 8.1 / Windows Server 2012 R2中添加。 > - ImagePartialMap > 如果调用的映像视图是不映射整个映像的部分视图,则该值不为零; 0如果视图映射整个图像。在Windows 10 / Windows Server 2016中添加。 > - Reserved > 始终设置为 0。 > - ImageBase > 设置为映像的虚拟基地址。 > - ImageSelector > 始终设置为 0。 > - ImageSize > 映像的虚拟大小(以字节为单位)。 > - ImageSectionNumber > 始终设置为 0。 那么我们首先还是定义一下回调函数 ```c++ void SetLoadImageNotifyRoutine( _In_opt_ PUNICODE_STRING FullImageName, _In_ HANDLE ProcessId, _In_ PIMAGE_INFO ImageInfo ) ``` 我们的回调函数在接收到消息的时候模块已经加载完成了,那么这里我们就只能够进行模块的卸载操作,在模块的`ImageInfo`结构里面提供了加载的`ImageBase`,那么我们只需要找到OEP,即可计算得到`DriverEntry`的地址。那么我们找到入口点函数的地址之后,就可以修改错误码为`STATUS_ACCESS_DENIED`即`0xC0000022`,就能够达到卸载驱动模块的效果 ```c++ mov eax, 0xC0000022 ret ``` 对应的硬编码为`B8 22 00 00 C0 C3` 那么这里我们就可以进行卸载驱动模块函数的编写,首先定义指针指向OEP ```c++ PIMAGE_DOS_HEADER pDosHeader = pLoadImageBase; PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)pDosHeader + pDosHeader->e_lfanew); PVOID pAddressOfEntryPoint = (PVOID)((PCHAR)pDosHeader + pNtHeaders->OptionalHeader.AddressOfEntryPoint); ``` 然后写入shellcode,通过`MmCreateMdl`写入,我们知道在内核里面是不能够随便进行读写操作的,这里就可以通过MDL写入的方式映射到虚拟内存实现shellcode的写入 ```c++ ULONG CodeSize = 6; UCHAR pShellCode[6] = { 0xB8, 0x22, 0x00, 0x00, 0xC0, 0xC3 }; PMDL pMdl = MmCreateMdl(NULL, pAddressOfEntryPoint, CodeSize); ``` 使用`MmBuildMdlForNonPagedPool`更新MDL对物理内存的描述并映射到虚拟内存,然后写入数据,释放MDL ```c++ MmBuildMdlForNonPagedPool(pMdl); PVOID pVoid = MmMapLockedPages(pMdl, KernelMode); RtlCopyMemory(pVoid, pShellCode, ulShellCodeSize); MmUnmapLockedPages(pVoid, pMdl); IoFreeMdl(pMdl); ``` 然后我们再尝试对DLL模块进行卸载,这里的话就不能像卸载驱动模块直接在入口点返回,因为DLL的入口点函数的返回值并不能够确定DLL能否加载成功。这里windows提供了一个未文档化的函数`MmUnmapViewOfSection`用来卸载进程中已经加载的模块 那么我们要想卸载模块,首先就肯定要获取所有的模块,使用到`PsSetLoadImageNotifyRoutine`设置回调函数来获取模块的加载信息 windows为了避免死锁,在进行模块加载回调函数的时候不能够进行其他操作,也就是说我们想要卸载DLL模块则需要等所有模块加载完毕之后才能进行卸载操作 这里来进行函数的编写 ```c++ NTSTATUS NoLoadDll(HANDLE ProcessId, PVOID pImageBase) { NTSTATUS status = STATUS_SUCCESS; PROCESS pEProcess = NULL; status = PsLookupProcessByProcessId(ProcessId, &pEProcess); if (!NT_SUCCESS(status)) { DbgPrint("PsLookupProcessByProcessId error : %d\n", status); return status; } status = MmUnmapViewOfSection(pEProcess, pImageBase); if (!NT_SUCCESS(status)) { DbgPrint("MmUnmapViewOfSection error : %d\n", status); return status; } return status; } ``` 实现效果 ---- 这里要实现的效果就是阻止`DriverTest.sys`的加载 ![image-20220430150950600.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-a2ba491e150444780d13b9fdbe6b3b5b9d0925c6.png) 首先启动我们的监控驱动,然后加载`DriverTest.sys`可以看到拒绝访问 ![image-20220430151042590.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-a2d08c66ec3bb98244f6d3a8b71626a85ae190fb.png) 然后再卸载我们的监控驱动之后`DriverTest.sys`加载成功 ![image-20220430151057848.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-61eed006015b3fec2ad5de22ad3d2a8594377862.png) 然后我们再尝试注入`Test.dll`,可以看到注入失败 ![image-20220430151343201.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-6c8e7c0d8fe535531cdb531b377c6ff1c23b5479.png) 我们再去xp上尝试一下,首先加载驱动 ![image-20220430151753570.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-2e210324a106bc17e8a12b569dc33d860420095b.png) 当我们打开一个程序的时候都会打印出当前进程加载的dll模块 ![image-20220430153535149.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-dfbeb92dca9d492d4646088fa68ffab49dfdf80d.png) 然后注入DLL,也是被拦截 ![image-20220430153848221.png](https://shs3.b.qianxin.com/attack_forum/2022/06/attach-f600a1041bfe1b75038ed6e7615f1141aaf79539.png)
发表于 2022-09-05 09:36:16
阅读 ( 6346 )
分类:
安全开发
0 推荐
收藏
0 条评论
请先
登录
后评论
cca
7 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!