简单易懂的SSDT学习心得

      在这篇心得开始,说点其他的。之前参加百度校园招聘的时候,面试官问我什么是SSDT,已经HOOK SSDT的实现过程。自己明明知道,可是我一下答上来,所以我找出来以前学习的心得,贴出来,好备份吧!我这篇心得呢!是代码与文字一起加载在一起的,学习就想读书的时候一样,书看到哪里笔记就做到哪里。这样方便理解。如果代价复制黏贴来学,不会影响的,一边看代码一边看笔记哟!其实我平时写代码不是这样的……都是规范化哟!这里是心得而已,大家不要见外。

//环境:XP + VS2008 +WDK
//SSDT
//我先讲讲 SSDT 保护进程与**OpenProcess 的关系
//在应用层中,如果想要使用API函数 结束某个进程 首先要得到这个进程的PID
//然后用 OpenProcess()函数 获取这个进程的 句柄 Handle
//最后用 TerminateProcess() 函数,使用获得的句柄 Handle 结束这个进程
//思路就是这样,内核就是换成内核函数

//那SSDT 如何修改 ZwOpenProcess(),修改后变成什么??
//因为SSDT表中 保存的都是系统服务函数地址(内核调用的函数地址)
//输入一个 函数名 通过KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)]
//它就能找到函数的地址了
//说说里面的东西是什么吧!
//_function,将它强制转换成PUCHAR 就获得了这个函数的地址。
//为什么+1呢?
//  Windows对内存的分配,是采用的分页管理。其中有个CR0寄存器,
//这个寄存器有一个位 管理 内存的 读或写 的标识
//CRO 如果为1,则可以读/写/执行;
//如果为0,则只可以读/执行。SSDT,IDT的页属性在默认下都是只读,可执行的,但不能写。
//所以 要 +1 则把这一位设置成1这样 SSDT页属性为可读/写/执行

//

//Protect.c

//

#include "ntddk.h"

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


//解释解释 内联汇编吧!
//取消内存保护 就是将内存属性设置为 1  变得可读、可写、可执行
//1--寄存器的中断标志位清0,不允许中断
//2--将CRO 内存页属性默认标识 放入寄存器 eax
//3--入栈
//4--0x10000 取反 ,与eax 相加 eax 变成1
//5--将CRO 置为 1
//恢复内存保护 我就不多说,举一反三
//取消内存保护

// 对于取消内存保护 和 恢复内存保护还有另外一个方法
// 取消用 _asm cli //不允许中断
// 恢复用 _asm sti //允许中断
//在 DriverEntry 验证了 我的说法。
#define DisableMemProtect()\
{\
 __asm cli\
 __asm mov eax,cr0\
 __asm push eax\
 __asm and eax,(~0x10000)\
 __asm mov cr0,eax\
}
//恢复内存保护
#define RecoverMemProtect()\
{\
 __asm pop eax\
 __asm or eax,0x10000\
 __asm mov cr0,eax\
 __asm sti\
}

long pid = -1; //应用层 与 驱动层 通信的PID 进程 要记得初始化

//使用 DeviceIoControl函数 与 IoControl Code Ring3/Ring0 通信
#define IOCTL_PROTECT_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

//函数声明

//操作派遣函数
NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp); //

//卸载驱动
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);

#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()

//KeServiceDescriptorTable 是未公开的结构体,但是定义一次就可以使用。至于为什么我也不知道
//但是在《寒江独钓》里面又讲
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; //变量名是不能变的,因为是从外部导入

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

//这是 未公开的 内核 函数ZwOpenProcess 的原型, 和KeServiceDescriptorTable 一样定义一次就可以用了
NTSYSAPI NTSTATUS NTAPI ZwOpenProcess(OUT PHANDLE ProcessHandle,
           IN ACCESS_MASK DesiredAccess,
           IN POBJECT_ATTRIBUTES ObjectAttributes,
           IN PCLIENT_ID ClientId OPTIONAL);


//生成一个与原ZwOpenProcess()函数一样的 模板 用于保存
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,
          IN ACCESS_MASK DesiredAccess,
          IN POBJECT_ATTRIBUTES ObjectAttributes,
          IN PCLIENT_ID ClientId OPTIONAL);

ZWOPENPROCESS OldZwOpenProcess; //保存原来的ZwOpenProcess() 函数


//用来替换的新函数 里面的操作 你自己看着办吧!爱咋整 咋整 技术牛大话
NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes,
        IN PCLIENT_ID ClientId OPTIONAL)
{
 
 NTSTATUS nStatus = STATUS_SUCCESS;
 if((long)ClientId->UniqueProcess == pid)
 {
  DbgPrint("The Protect PID:%ld\n",pid);
  return STATUS_ACCESS_DENIED;
 }

 //做其他处理
 nStatus = OldZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId); //其他程序也需要调用这个函数
 return STATUS_SUCCESS;
}
//卸载时会调用
//******************************************************
// 函数名称: DriverUnload(IN PDRIVER_OBJECT DriverObject)
// 功能描述: 负责驱动程序的卸载操作
// 参数列表: DriverObject驱动对象
// 返回值: 返回状态
//******************************************************
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
 
 UNICODE_STRING DeviceLinkString;
 PDEVICE_OBJECT DeviceObjectTemp1=NULL;
 PDEVICE_OBJECT DeviceObjectTemp2=NULL;

 DbgPrint("Unload Driver...\n");

 RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
 IoDeleteSymbolicLink(&DeviceLinkString);
 if(DriverObject)
 {
  DeviceObjectTemp1=DriverObject->DeviceObject;
  while(DeviceObjectTemp1)
  {
   DeviceObjectTemp2=DeviceObjectTemp1;
   DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
   IoDeleteDevice(DeviceObjectTemp2);
  }
 } 
 
 //卸载后,修复SSDT
 DisableMemProtect();
 //使用InterlockedExchangePointer(),函数进行交换,效果是一样的
 //InterlockedExchangePointer(&(SYSTEMSERVICE(ZwOpenProcess)),OldZwOpenProcess);
 (ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)) = OldZwOpenProcess;
 RecoverMemProtect();
 DbgPrint("Unload Compelete.\n");
}

//分发函数
//************************************************************************
// 函数名称: DeviceDispatch(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp)
// 功能描述: 负责驱动程序的卸载操作
// 参数列表: DeviceObject 设备对象
//           Irp  请求
// 返回值: 返回状态
//************************************************************************
NTSTATUS DeviceDispatch(IN PDEVICE_OBJECT  DeviceObject,IN PIRP  Irp)
{
 
 NTSTATUS nStatus = STATUS_SUCCESS;
 ULONG IoControlCode = 0;
 PIO_STACK_LOCATION IrpStack = NULL;

 long* inBuf = NULL;
 char* outBuf = NULL;
 ULONG inSize = 0;
 ULONG outSize = 0;
 PCHAR buffer = NULL;
 PMDL mdl = NULL;

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

 IrpStack = IoGetCurrentIrpStackLocation(Irp);

 switch(IrpStack->MajorFunction)
 {
 case IRP_MJ_CREATE:
  
  break;
 case IRP_MJ_CLOSE:
  
  break;
 case IRP_MJ_DEVICE_CONTROL:
  
  IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
  switch(IoControlCode)
  {
  case IOCTL_PROTECT_CONTROL: //上面的宏
   inSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
   outSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;   
   inBuf = (long*)Irp->AssociatedIrp.SystemBuffer;
  
   pid = *inBuf; //将从Ring3 获得 PID 传给 Ding0的 pid
   
   strcpy(Irp->UserBuffer,"SUCCESS!\n");//
   break;
  default:
   break;
  }
  break;
 default:
  DbgPrint("Other IRP\n");
  break;
 }

 nStatus = Irp->IoStatus.Status;

 IoCompleteRequest(Irp,IO_NO_INCREMENT);//IO请求完成

 return nStatus;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING theRegistryPath)
{
 //驱动入口函数
 NTSTATUS        Status = STATUS_SUCCESS;
 UNICODE_STRING  DeviceName;     //设备名
 UNICODE_STRING  DeviceLinkString; //设备连接符
 PDEVICE_OBJECT  deviceObject = NULL;

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

 RtlInitUnicodeString( &DeviceName, NT_DEVICE_NAME );

 //创建一个驱动设备
 Status = IoCreateDevice(
  DriverObject,
  0,
  &DeviceName,
  FILE_DEVICE_UNKNOWN,
  0,
  FALSE,
  &deviceObject );

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

 RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);//初始化连接符
 Status=IoCreateSymbolicLink(&DeviceLinkString,&DeviceName);//创建连接符

 if(!NT_SUCCESS(Status)) //创建失败
 {
  return Status;
 }
 //分发函数
 DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceDispatch;
 DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceDispatch;
 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceDispatch;
 DriverObject->DriverUnload = DriverUnload;

 //修改 ZwOpenProcess 函数地址 这里修改成功 就可以实现功能了
 //修改前要保存原来的函数地址
 //DisableMemProtect(); //取消内存保护 _asm cli 看到没有其实是等效的
 _asm cli
 OldZwOpenProcess =(ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)); //保存
 _asm sti
 //RecoverMemProtect(); //恢复内存保护 _asm sti 看到没有其实是等效的

 DisableMemProtect(); //取消内存保护
 (ZWOPENPROCESS)(SYSTEMSERVICE(ZwOpenProcess)) = NewZwOpenProcess; //修改
 RecoverMemProtect();//恢复内存保护

 return STATUS_SUCCESS;
}

 

//----------------------------Ring3代码-----------------

//main.cpp

//主要功能就是为了传一个PID 给驱动程序

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winioctl.h>

#define IOCTL_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main()
{
 long pid = 0;
 char ret[4096];
 DWORD ReBytes = 0;
 HANDLE hDevice=CreateFile("\\\\.\\ProtectProcess",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(hDevice==INVALID_HANDLE_VALUE)
 {
  printf("CreateFile() GetLastError reports %d\n",GetLastError());
  return 0;
 }

 memset(ret,0,4096);
 printf("Please Input a PID to Protect:");

 scanf("%ld",&pid);
 DeviceIoControl(hDevice,IOCTL_CONTROL,&pid,sizeof(long),ret,4096,&ReBytes,NULL);

 printf("Protect %s\n",ret);

 CloseHandle(hDevice);
 system("pause");
 return 0;
}

 

//操作工程:
1--用DriverMonitor 加载驱动 ,加载成功显示“Driver Started Seccessfully”如图:
 
 
2-驱动加载后,编译运行main.cpp用一个 txt 文档做测试,输入进程PID,如图:
 
 
 
3--结束进程,如图:
 
 
4-- 效果,如图:
 
 
哈哈,成功了!你也应该成功了吧!
//不得不感谢看雪
http://bbs.pediy.com/showthread.php?t=42422&highlight=%E5%BF%85%E5%A4%87+%E5%A4%87%E7%BB%9D+%E7%BB%9D%E6%8A%80
 
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值