首页
社区
课程
招聘
[求助]大家帮忙看一看 HookSetValueKey函数为什么不能保护注册表的键值
发表于: 2012-6-13 13:58 4577

[求助]大家帮忙看一看 HookSetValueKey函数为什么不能保护注册表的键值

2012-6-13 13:58
4577
#include "ntddk.h"

#define MaxBuf  1024
#define MAXPATHLEN 1024

#define NT_DEVICE_NAME      L"\\Device\\ProtectRegistryValueKey"
#define DOS_DEVICE_NAME     L"\\DosDevices\\ProtectRegistryValueKey"

#define IOCTL_PROTECT_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)

VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp);
NTSTATUS DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

typedef struct _FILE_NAMES_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    ULONG FileNameLength;
    WCHAR FileName[1];
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;

#pragma pack(1)        //SSDT表的结构
typedef struct ServiceDescriptorEntry {
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()

__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;       

/*这个是查询某个函数的地址的一个宏*/
#define SYSTEMSERVICE(_function)  KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]

NTSYSAPI
NTSTATUS
NTAPI
ObQueryNameString(
    IN PVOID Object,
    PUNICODE_STRING Name,
    ULONG MaximumLength,
    PULONG ActualLength
    );

///////////////////////////////////////////////////////////

NTSYSAPI
NTSTATUS
NTAPI
ZwSetValueKey(IN HANDLE  KeyHandle,
IN PUNICODE_STRING  ValueName,
IN ULONG  TitleIndex  OPTIONAL,
IN ULONG  Type,
IN PVOID  Data,
IN ULONG  DataSize
);

typedef NTSTATUS (*ZWSETVALUEKEY)(IN HANDLE  KeyHandle,
IN PUNICODE_STRING  ValueName,
IN ULONG  TitleIndex  OPTIONAL,
IN ULONG  Type,
IN PVOID  Data,
IN ULONG  DataSize
);

ZWSETVALUEKEY RealZwSetValueKey;

/////////////////////////////////////////////////////////

PVOID GetPointer( HANDLE handle )
{

  PVOID         pKey;
  DbgPrint("*******Enter GetPointer()*******\n");

  if(!handle) return NULL;
  //取得指针
  if( ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, &pKey, NULL ) != STATUS_SUCCESS )
  {
      pKey = NULL;
  }

  DbgPrint("*******Leave GetPointer()*******\n");
  return pKey;
}

NTSTATUS HookZwSetValueKey( IN HANDLE  KeyHandle,
IN PUNICODE_STRING  ValueName,
IN ULONG  TitleIndex  OPTIONAL,
IN ULONG  Type,
IN PVOID  Data,
IN ULONG  DataSize)

{

NTSTATUS rc;
UNICODE_STRING *pUniName;  //定义得到修改注册表的UNI路径
ULONG actualLen;
ANSI_STRING keyname,
             akeyname,
                m_keyname,
             m_akeyname;       //定义得到修改注册表的UNI路径

PVOID pKey;
RtlUnicodeStringToAnsiString( &akeyname, ValueName, TRUE);
RtlUnicodeStringToAnsiString( &m_akeyname, ValueName, TRUE);
RtlUpperString(&akeyname,&m_akeyname);
RtlFreeAnsiString(&m_akeyname);

DbgPrint("*******Enter HookZwSetValueKey()*******\n");

if( pKey = GetPointer( KeyHandle))
{
  pUniName = ExAllocatePool( NonPagedPool, 512*2+2*sizeof(ULONG));
  pUniName->MaximumLength = 512*2;
  if( NT_SUCCESS( ObQueryNameString( pKey, pUniName, MAXPATHLEN, &actualLen)))
  {
   RtlUnicodeStringToAnsiString( &keyname, pUniName, TRUE);
   keyname.Buffer=_strupr(keyname.Buffer);
   akeyname.Buffer=_strupr(akeyname.Buffer);
   RtlUnicodeStringToAnsiString( &m_keyname, pUniName, TRUE);
   RtlUpperString(&keyname,&m_keyname);
   RtlFreeAnsiString(&m_keyname);

  DbgPrint("===在这里调用strcmp函数用来比较注册表的键值是否是 \\REGISTRY\\MACHINE\\SOFTWARE\\TEST \n");

   if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\TEST") == 0)
   {
     if(strcmp(akeyname.Buffer,"TEST") ==0)
     {
       RtlFreeAnsiString(&akeyname);
       RtlFreeAnsiString(&keyname);

     //下面的2个return语句都是我经过测试的了。但为什么不能够保护注册表的这个对应键值呢?

       return 0;
    //return STATUS_ACCESS_DENIED;   


     }
   }

   RtlFreeAnsiString(&keyname);
  }
}
RtlFreeAnsiString(&akeyname);

DbgPrint("调用 rc=RealZwSetValueKey(KeyHandle,ValueName,TitleIndex,Type,Data,DataSize);\n");
rc=RealZwSetValueKey(KeyHandle,ValueName,TitleIndex,Type,Data,DataSize);

DbgPrint("*******Leave HookZwSetValueKey()*******\n");
return rc;

}

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
        //卸载时会调用
        UNICODE_STRING DeviceLinkString;
        PDEVICE_OBJECT DeviceObjectTemp1=NULL;
        PDEVICE_OBJECT DeviceObjectTemp2=NULL;

        DbgPrint("驱动程序卸载...\n");

        RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
        IoDeleteSymbolicLink(&DeviceLinkString);
        if(DriverObject)
        {
                DeviceObjectTemp1=DriverObject->DeviceObject;
                while(DeviceObjectTemp1)
                {
                        DeviceObjectTemp2=DeviceObjectTemp1;
                        DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
                        IoDeleteDevice(DeviceObjectTemp2);
                }
        }  
        DbgPrint("设备已经卸载\n");

        DbgPrint("修复SSDT表\n");

      _asm
      {
        cli
        mov eax,cr0
        and eax,not 10000h  //清除cr0的WP位
        mov cr0,eax
      }
       
    (ZWSETVALUEKEY)(SYSTEMSERVICE(ZwSetValueKey)) =RealZwSetValueKey;

     _asm
     {
        mov eax,cr0
        or eax,not 10000h  //恢复cr0的WP位
        mov cr0,eax
        sti
      }

     DbgPrint("驱动卸载完毕.\n");
}

NTSTATUS DispatchCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
       
        DbgPrint("*****Enter DispatchCreate()\n");

        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        DbgPrint("*****Leave DispatchCreate()\n");

        return Irp->IoStatus.Status;

}

NTSTATUS DispatchClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
       
        DbgPrint("*****Enter DispatchClose()\n");

        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        DbgPrint("*****Leave DispatchClose()\n");

        return Irp->IoStatus.Status;

}

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp)
{
       
        NTSTATUS nStatus = STATUS_SUCCESS;
        ULONG IoControlCode = 0;
        PIO_STACK_LOCATION IrpStack = NULL;

        PCHAR buffer = NULL;
        PMDL mdl = NULL;

        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;

        IrpStack = IoGetCurrentIrpStackLocation(Irp);
        IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;

        switch(IoControlCode)
        {

       
        case IOCTL_PROTECT_CONTROL:
                       
                DbgPrint("**********************************\n");
                DbgPrint("IOCTL_PROTECT_CONTROL 被调用,通讯成功!\n");                       
                DbgPrint("**********************************\n");       
                                               
                break;
                       

        default:
                DbgPrint("未知请求包被调用\n");
                nStatus = STATUS_INVALID_VARIANT;
                break;
        }

        nStatus = Irp->IoStatus.Status;

        IoCompleteRequest(Irp,IO_NO_INCREMENT);

        return nStatus;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING theRegistryPath)
{
        //驱动入口函数
        NTSTATUS        ntStatus = STATUS_SUCCESS;
        UNICODE_STRING  ntDeviceName;
        UNICODE_STRING  DeviceLinkString;
        PDEVICE_OBJECT  deviceObject = NULL;

        DbgPrint("驱动程序加载...\n");

        RtlInitUnicodeString( &ntDeviceName, NT_DEVICE_NAME );

        ntStatus = IoCreateDevice(
                DriverObject,
                0,
                &ntDeviceName,
                FILE_DEVICE_UNKNOWN,
                0,
                FALSE,
                &deviceObject );

        if ( !NT_SUCCESS( ntStatus ) )
        {
                DbgPrint("无法创建驱动设备");
                return ntStatus;
        }

        RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
        ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&ntDeviceName);

        if(!NT_SUCCESS(ntStatus))
        {
                return ntStatus;
        }

        DriverObject->MajorFunction[IRP_MJ_CREATE] =DispatchCreate;
        DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;

        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;

        DriverObject->DriverUnload = OnUnload;

        DbgPrint("驱动程序已经启动\n");

        DbgPrint("修改SSDT表...\n");

      _asm
      {
        cli
        mov eax,cr0
        and eax,not 10000h  //清除cr0的WP位
        mov cr0,eax
      }

        //保存原始的内核函数 ZwSetValueKey的地址
        RealZwSetValueKey =(ZWSETVALUEKEY)(SYSTEMSERVICE(ZwSetValueKey));

        (ZWSETVALUEKEY)(SYSTEMSERVICE(ZwSetValueKey)) = HookZwSetValueKey;

     _asm
     {
        mov eax,cr0
        or eax,not 10000h  //恢复cr0的WP位
        mov cr0,eax
        sti
      }

        DbgPrint("驱动程序加载完毕.\n");

        return STATUS_SUCCESS;
}

驱动程序是不会蓝屏了,也可以加载,可以和应用层一起配合运行。假设在我的XP 32位系统下有一个注册表项 \\REGISTRY\\MACHINE\\SOFTWARE\\TEST, 它的键值为TEST

那么在HookZwSetValueKey函数里面,在if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\TEST") == 0)语句块里面
无论我设置return 的返回值为return 0;  还是设置为return STATUS_ACCESS_DENIED;  
为什么不能够保护注册表的这个对应键值呢? 即这个键值还是可以被修改、被删除。

请问大家,HookZwSetValueKey函数代码里面有写错吗?
哪里写的不对了?
还是return 值用的不对?
如果不对,应该改成什么?

谢谢了!

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 601
活跃值: (256)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
2
if( pKey = GetPointer( KeyHandle))
这话话永远是TRUE,而且GetPointer()也总会返回NULL,ObQueryNameString()不会成功,无法继续比较,返回什么都无所谓了,错就错在ObReferenceObjectByHandle(),要获取CmpKeyObjectType,不知道你跟过没有
2012-6-13 14:18
0
雪    币: 557
活跃值: (444)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
3
这个ObReferenceObjectByHandle函数没有用错啊。我刚才也用WinDbg单步跟踪了。
2012-6-13 16:01
0
雪    币: 557
活跃值: (444)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
4
能够说的详细一些吗?
2012-6-13 16:02
0
游客
登录 | 注册 方可回帖
返回
//