找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 10620|回复: 15

扫盲贴,HOOK SSDT 短文一篇(通过MDL修改内存保护机制)

 火.. [复制链接]

90

主题

473

回帖

2

精华

钻石会员

积分
3261
发表于 2010-8-23 17:23:59 | 显示全部楼层 |阅读模式
找了好长时间
找到一个好帖子
分享一下
给像我这样的菜鸟

通过最近学习驱动,觉得进步还是很大的
起码知道sys是什么东西了
然后学习API时,有很多参数,
这对以前学习api时很有帮助
过去看到api就头疼,
现在再看看那些api,就觉得很简单啦

90

主题

473

回帖

2

精华

钻石会员

积分
3261
 楼主| 发表于 2010-8-23 17:25:04 | 显示全部楼层

扫盲贴,HOOK SSDT 短文一篇(通过MDL修改内存保护机制)

扫盲贴,HOOK SSDT 短文一篇(通过MDL修改内存保护机制)


作 者: 梧桐
时 间:
2008-12-06,23:01
链 接:
http://bbs.pediy.com/showthread.php?t=78218
//author:梧桐
//转载请注明出处
------------------------很不华丽的分割线------------------------------------------------------
本文章仅供那些在驱动开发门外徘徊的程序爱好者参考和学习,大牛就绕过吧,
如有错误的地方,还请多多指出,不胜感激。
------------------------很不华丽的分割线------------------------------------------------------
      
对于Driver
一词儿,我想大家都不陌生,它是工作在ring0下的,正是因为如此,它不不能够快速上手的,更多的时候你要熟悉它的技术资料和接口,还要熟悉底层工作的原理,一不小心搞个BSOD,那是会非常郁闷的。
     
好了,现在让我们步入正题,首先确认你已经安装好了DDK(学习驱动开发,推荐WINXP DDK 2600、 Windows XP,   
VS2003),配置好了你的开发环境(DDK
Wizard),在VS20003里添加WINDDK路径。
     打开VS2003,Tools选项,选取
Options(如下图):

然后,我们找到 Projects(工程),选取VC++
Directories,添加WINDDK路径:

配置好这些环境以后,我们开始与驱动的亲密接触吧。
     
先来建立一个驱动的工程:

那些默认的选项,全部取消掉:

接着点 Finish ,删除 Header Files、Resource Files,此时,DDK
Wizard 已经为我们建立了一套Driver模板了,但细看,是不是感觉非常非常的乱?
     
OK,我们把它K掉,现在我们自己来打造一个简单的入口点。
   
代码:#include "ntddk.h"
//Unload
VOID UnLoad(IN PDRIVER_OBJECT DriverObject)
{
     DbgPrint("UnLoad Driver.\n");
}
//EntryPoint.
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
             IN PUNICODE_STRING RegistryPath)
{
    DriverObject->DriverUnload = UnLoad;
    //TODO
    return STATUS_SUCCESS;
}     在
DriverName.WXP上点Build,看看objchk\i386目录下产生的Sys文件,OK,Cool吧,当然,我们这个驱动连任何功能都没有的,Cool是很Cool,就是Cool得没内涵了,那么我们来实现点什么功能呢,好吧,让我们来对SSDT挂钩一下吧。
     
要挂钩SSDT,就必须先要由内核到处一个KeServiceDescriptorTable,那么我们还要先定义一个KeServiceDescriptorTable类型的的结构体:
代码:typedef struct ServiceDescriptorEntry
{
          unsigned int *ServiceTableBase;
          unsigned int *ServiceCounterTableBase; //Used only in checked build
          unsigned int NumberOfServices;
          unsigned char *ParamTableBase;
} SSDTEntry;     
定义了KSDT的结构,那么我们想想要HOOK那个函数呢,好吧,就以ZwTerminateProcess为例,我们开动,首先定义一个ZwTerminateProcess函数结构,函数原型:
代码:ZwTerminateProcess(
          IN HANDLE ProcessHandle OPTIONAL,
          IN NTSTATUS ExitStatus
          );结构定义:
代码:typedef NTSTATUS(*_ZwTerminateProcess)(
                  IN HANDLE ProcessHandle OPTIONAL,
                  IN NTSTATUS ExitStatus
                  );     
我们要HOOK
ZwTerminateProcess,那么我们是不是要先找出它在KSDT中的位置呢,没错,那么我们来定义一个通过SSDT服务号得到函数地址的宏以达到我们的目的:
代码:#define    GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)];     
想要达到改写SSDT的目的,那么首先要解决的是内存保护机制的问题,众所周知,Windows的某些版本对内存区域启用了写保护的功能,在XP和2003中更为常见,SSDT是只读的,那怎么办呢?
     
有的网友此刻估计已经明白了。
     没错,就是 Memory Descriptor List,简称
MDL。有的同学可能会问了,MDL究竟是个什么东西呢?从字面意思看,不难理解,内存描述符列表。MDL包含了内存区域的起始、拥有者proc、字节数、标记等。OK,我们需要先定义一个MDL的指针。
代码:PMDL MDLSystemCall;
     
定义了MDL的指针以后,我们要通过MAPPED系列的参数来使内存拥有可写性,然后锁定内存中的MDL,那么我们就要定义一个PVOID的指针,来供MmMap操作。
     
代码:PVOID *MappedSCT;     
代码片段:
代码:MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!MDLSystemCall)
    return STATUS_UNSUCCESSFUL;     
那么,建立了MDL,是不是该填充一下页数组啊?
     
对的,没错。
     
代码:MmBuildMdlForNonPagedPool(MDLSystemCall);
MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写
MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode);     
我们转入HOOK话题,继续。
     刚才我们已经定义了 ZwTerminateProcess
的结构。
     
代码:Old_ZwTerminateProcess = (_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess));     
获取没被HOOK之前的ZwTerminateProcess在KSDT中的索引,保存。
     
那么下一步呢,就是干掉他了,替换为我们的函数,那么我们是不是要构造一个自己的函数过程呢,恩,没错。
     
代码:NTSTATUS NewZwTerminateProcess(
                  IN HANDLE ProcessHandle OPTIONAL,
                  IN NTSTATUS ExitStatus
                  )
{
    //TODO
    return STATUS_SUCCESS;
}     
在过程里要怎么玩,全看你自己了。
     
下面就是替换函数了,修改SSDT中函数地址指向的位置,下面是宏定义:
代码:#define GetIndex(_foo) *(PULONG)((PUCHAR)_foo+1)
#define HookOn(_Old,_New) InterlockedExchange((PLONG)&MappedSCT[GetIndex(_Old)] ,(LONG)_New)     
代码:MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!MDLSystemCall)
    return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(MDLSystemCall);
MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写
MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode);
HookOn(ZwTerminateProcess, NewZwTerminateProcess);
return STATUS_SUCCESS;完整代码:
代码:///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2008 -
///
/// Original filename: NtHook.c
/// Project            : NtHook
/// Date of creation : 2008-11-20
/// Author(s)          : 梧桐
///
/// Purpose            :
///
/// Revisions:
///    0000 [2008-11-20] Initial revision.
///
///////////////////////////////////////////////////////////////////////////////
#include "ntddk.h"
#pragma pack(1)
typedef struct ServiceDescriptorEntry
{
          unsigned int *ServiceTableBase;
          unsigned int *ServiceCounterTableBase; //Used only in checked build
          unsigned int NumberOfServices;
          unsigned char *ParamTableBase;
} SSDTEntry;
__declspec(dllimport)    SSDTEntry KeServiceDescriptorTable;
#pragma pack()
NTKERNELAPI NTSTATUS ZwTerminateProcess(
                  IN HANDLE ProcessHandle OPTIONAL,
                  IN NTSTATUS ExitStatus
                  );
typedef NTSTATUS(*_ZwTerminateProcess)(
                  IN HANDLE ProcessHandle OPTIONAL,
                  IN NTSTATUS ExitStatus
                  );
_ZwTerminateProcess Old_ZwTerminateProcess;
#define GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)]
PMDL    MDSystemCall;
PVOID *MappedSCT;
#define GetIndex(_Function) *(PULONG)((PUCHAR)_Function+1)
#define HookOn(_Old, _New)    \
         (PVOID) InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New)
#define UnHook(_Old, _New)    \
         InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New)
NTSTATUS NewZwTerminateProcess(
                  IN HANDLE ProcessHandle OPTIONAL,
                  IN NTSTATUS ExitStatus
                  )
{
    return STATUS_SUCCESS;
}
//Unload
VOID UnLoad(IN PDRIVER_OBJECT DriverObject)
{
     DbgPrint("UnLoad Driver.\n");
     //卸载Hook
     UnHook( ZwTerminateProcess, Old_ZwTerminateProcess);
     //解锁、释放MDL
     if(MDSystemCall)
     {
        MmUnmapLockedPages(MappedSCT, MDSystemCall);
        IoFreeMdl(MDSystemCall);
     }
}
//EntryPoint.
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
             IN PUNICODE_STRING RegistryPath)
{
    DriverObject->DriverUnload = UnLoad;
   
    //找出旧函数地址并保存
    Old_ZwTerminateProcess =(_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess));
    MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
    if(!MDSystemCall)
      return STATUS_UNSUCCESSFUL;
    MmBuildMdlForNonPagedPool(MDSystemCall);
    MDSystemCall->MdlFlags = MDSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
    MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode);
    //安装HOOK
    HookOn( ZwTerminateProcess, NewZwTerminateProcess);
    return STATUS_SUCCESS;
}
工程附件:http://xlick.3video.cn/1.zip
一段类似的代码
#include "ntddk.h"
ULONG pid=1548;
#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; //变量名是不能变的,因为是从外部导入
//取函数在SSDT中的位置
#define SYSTEMSERVICE(_function)
KeServiceDescriptorTable.ServiceTableBase[
*(PULONG)((PUCHAR)_function+1)]
//取函数的索引
#define SYSCALL_INDEX(_Function)
*(PULONG)((PUCHAR)_Function+1)
//修改函数的地址
#define HOOK_SYSCALL(_Function,
_Hook, _Orig ) _Orig = (PVOID) InterlockedExchange( (PLONG)
&m_Mapped[SYSCALL_INDEX(_Function)], (LONG) _Hook)
PMDL m_MDL;
PVOID
*m_Mapped;
NTSYSAPI NTSTATUS NTAPI ZwOpenProcess(OUT PHANDLE ProcessHandle,IN
ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID
ClientId OPTIONAL);
NTSYSAPI NTSTATUS NTAPI ZwTerminateProcess(IN HANDLE
ProcessHandle OPTIONAL,IN NTSTATUS ExitStatus);
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,IN ACCESS_MASK
DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId
OPTIONAL);
typedef NTSTATUS (*ZWTERMINATEPROCESS)(IN HANDLE ProcessHandle
OPTIONAL,IN NTSTATUS ExitStatus);
NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK
DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId
OPTIONAL);
NTSTATUS NewZwTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,IN
NTSTATUS ExitStatus);
NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS
*pEProcess);
ZWOPENPROCESS OldZwOpenProcess = NULL;
ZWTERMINATEPROCESS
OldZwTerminateProcess = NULL;
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
//卸载时会调用
PVOID
Oldfun =
NULL;
HOOK_SYSCALL(ZwOpenProcess,OldZwOpenProcess,Oldfun);
HOOK_SYSCALL(ZwTerminateProcess,OldZwTerminateProcess,Oldfun);
if(m_MDL){
   
MmUnmapLockedPages(m_Mapped,m_MDL);
   
IoFreeMdl(m_MDL);
}
KdPrint(("驱动卸载完毕.\n"));
}
NTSTATUS NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK
DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId
OPTIONAL)
{
if((long)ClientId->UniqueProcess ==
pid)
{
   KdPrint(("保护进程,打开操作 PID:%ld\n",pid));
   
return STATUS_ACCESS_DENIED;
}
//剩下的交给我们的原函数
return
OldZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);
}
NTSTATUS NewZwTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,IN NTSTATUS
ExitStatus)
{
NTSTATUS nStatus = STATUS_SUCCESS;
PEPROCESS
EPROCESSPROTECT = NULL;
PEPROCESS EPROCESSKILL =
NULL;
//我们要保护的进程的PID存在变量pid里,使用PsLookupProcessByProcessId可以通过PID获得EPROCESS
PsLookupProcessByProcessId((ULONG)pid,&EPROCESSPROTECT);
//通过ProcessHandle来获得当前要结束的进程的EPROCESS
if
(ObReferenceObjectByHandle(ProcessHandle,GENERIC_READ,NULL,KernelMode,&EPROCESSKILL,0)
== STATUS_SUCCESS)
{
   
//如果要结束的是我们需要保护的进程,这里分两种情况
   if (EPROCESSPROTECT==
EPROCESSKILL)
   {
    if (EPROCESSPROTECT !=
PsGetCurrentProcess())
   
{//情况一:当前进程不是我们所保护的进程
     
//换句话说也就是其他进程试图结束我们所保护的进程,当然不能让他结束
     
KdPrint(("[-]进程保护,外部程序试图关闭保护进程\n"));
     nStatus =
STATUS_ACCESS_DENIED;
    }else{
     
//当我们程序点击关闭也是使用的TermianteProcess,
     
//所以这种情况下当前进程是我们所保护的进程,则正常退出
     
KdPrint(("[-]进程保护,程序自身退出请求!\n"));
   
}
   
   }
}
//剩下的交给我们的原函数
if
(nStatus != STATUS_SUCCESS)
   return
nStatus;
else
   return
OldZwTerminateProcess(ProcessHandle,ExitStatus);
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING
theRegistryPath)
{
NTSTATUS        
ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject =
NULL;
DriverObject->DriverUnload = OnUnload;
m_MDL =
MmCreateMdl(NULL,KeServiceDescriptorTable.ServiceTableBase,KeServiceDescriptorTable.NumberOfServices*4);
if(!m_MDL)
{
   
return
STATUS_UNSUCCESSFUL;
}
//非分页内存
MmBuildMdlForNonPagedPool(m_MDL);
m_MDL->MdlFlags
= m_MDL->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
//锁定
m_Mapped =
MmMapLockedPages(m_MDL,
KernelMode);
HOOK_SYSCALL(ZwOpenProcess,NewZwOpenProcess,OldZwOpenProcess);
HOOK_SYSCALL(ZwTerminateProcess,NewZwTerminateProcess,OldZwTerminateProcess);
return
STATUS_SUCCESS;
}

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 17:48:15 | 显示全部楼层
额......SSDT而已

90

主题

473

回帖

2

精华

钻石会员

积分
3261
 楼主| 发表于 2010-8-23 19:28:31 | 显示全部楼层
哪位高手能解释一下这个宏的具体意思
或者说解释一下这个宏的用法
#define HookOn(_Old,_New) InterlockedExchange((PLONG)&MappedSCT[GetIndex(_Old)] ,(LONG)_New)

90

主题

473

回帖

2

精华

钻石会员

积分
3261
 楼主| 发表于 2010-8-23 20:44:46 | 显示全部楼层
ls的高手,你能不能说点有用的?
这个是基础,那个也是基础
难道你真是高手?
就是高手也不用这样吧?

别一天到晚把自己扮演个绝世高手好吗?

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:00:06 | 显示全部楼层
"扫盲贴",难道不是基础吗?
我不是高手,我不是神牛.OK爷爷是,OK神牛,OK高手.
我又不是绝世高手,本身就不是.
OK爷爷连点下脚料都不会.
这样说行吧,SSDT对于我来说就是下脚料.

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:13:43 | 显示全部楼层
我是2MBit,256KByte的网络.怎么上紫水晶这么慢.

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:23:19 | 显示全部楼层
我可以不是高手,要按比例计算.
要是我不是高手了,恐怕OK爷爷连那个"扫盲"里面的......
省略掉一些......性质的词语.
不想破坏论坛和谐.
不想重蹈HoviDelphic当年的覆辙,不用TeslaAngela是因为历史的事用历史的名字.
当年是高手对阵.
我不想搞一个......
如果这样,恐怕Bound也要成为历史了.
......

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:24:26 | 显示全部楼层
"......"聪明人可以根据语境揣摩出是什么......这一切都是为了论坛和谐//////

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:25:14 | 显示全部楼层
我的积分变成255了,貌似是UCHAR的最大值,请问OK爷爷知道吗?
恐怕不知道吧......

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:25:53 | 显示全部楼层
还说......
我看......
这次是大面积省略了,不会有人看出来了.

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:26:11 | 显示全部楼层
256,庆祝一下!

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:31:35 | 显示全部楼层
每发一个回复积分就增加了0.25
每发一个主题积分就增加了6除以2.5
每发一个附件加分就增加了1.5
所以发附件最合算

90

主题

473

回帖

2

精华

钻石会员

积分
3261
 楼主| 发表于 2010-8-23 21:32:10 | 显示全部楼层
唉,和你这么辩论,没什么实际意义啊
我只知道,如果一个高手明明知道这个问题而不回答,是对的,但是讽刺挖苦别人就不对了。
我还知道,如果一个高手明明知道这个问题而回答,这才是大家很佩服的高手。
论坛欢迎这样的高手
而不是像你这样到处打击菜鸟的高手哦

真正的高手,好像不是想你这样滴
得,不想和你辩论这样得问题了~
实在没意思~~~
因为你帮过我解决了一个问题
还是要谢谢你啊
言重之处,别介意。
放心吧,以后再不麻烦你了
谢谢

6

主题

196

回帖

0

精华

铜牌会员

菜鸟

积分
52
发表于 2010-8-23 21:33:39 | 显示全部楼层
我从本帖所有的回复(包括本回复)总共是10贴,现在积分259,按照刚才的公式,我赚了2.5分.
如果我发两个附件,就是3分,还是发附件合算,灌水是没用的.

8

主题

31

回帖

0

精华

铂金会员

积分
2031
发表于 2014-8-1 21:30:39 | 显示全部楼层
必须学习
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表