SSDT表的遍历

//VS2005创建的工程,系统xp sp2

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//stdafx.h文件
#ifndef _WIN32_WINNT		// Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501	// Change this to the appropriate value to target other versions of Windows.
#endif						

#ifdef __cplusplus
extern "C"
{

#endif

#include <ntddk.h>
#include <ntddstor.h>
#include <mountdev.h>
#include <ntddvol.h>

//注意:全局变量要在这里定义

//系统服务描述符表-在ntoskrnl.exe中导出KeServiceDescriptorTable这个表
#pragma pack(1)
typedef struct _ServiceDescriptorTable
{
	//System Service Dispatch Table的基地址
	PVOID ServiceTableBase;
	//SSDT中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。
	PVOID ServiceCounterTable;
	//由 ServiceTableBase 描述的服务的数目。
	unsigned int NumberOfServices;
	//每个系统服务参数字节数表的基地址-系统服务参数表SSPT
	PVOID ParamTableBase;
}*PServiceDescriptorTable;
#pragma pack()

//导出系统服务描述符表SSDT的指针
extern  PServiceDescriptorTable  KeServiceDescriptorTable; 

#ifdef __cplusplus
}
#endif

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//ReadSsdtForFuntion.cpp文件
#include "stdafx.h"

//由SSDT索引号获取当前函数地址,如:
//NtOpenProcess  [[KeServiceDescriptorTable]+0x7A*4]  

void ReadSsdtForFuntionUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS ReadSsdtForFuntionCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS ReadSsdtForFuntionDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

//1.纯汇编读取内核函数的地址
LONG GetFunctionAddr_ASM(PServiceDescriptorTable KeServiceDescriptorTable, LONG lgSsdtIndex);

//2.用指针读取内核函数的地址
LONG GetFunticonAddr(PServiceDescriptorTable KeServiceDescriptorTable, LONG lgSsdtIndex);

#ifdef __cplusplus
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath);
#endif

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath)
{
	UNICODE_STRING DeviceName,Win32Device;
	PDEVICE_OBJECT DeviceObject = NULL;
	NTSTATUS status;
	unsigned i;

	//SSDT表的范围
	LONG lgSsdtNumber = -1;

	RtlInitUnicodeString(&DeviceName,L"\\Device\\ReadSsdtForFuntion0");
	RtlInitUnicodeString(&Win32Device,L"\\DosDevices\\ReadSsdtForFuntion0");

	//设置默认处理例程
	for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
		DriverObject->MajorFunction[i] = ReadSsdtForFuntionDefaultHandler;

	//设置创建例程
	DriverObject->MajorFunction[IRP_MJ_CREATE] = ReadSsdtForFuntionCreateClose;
	//设置关闭例程
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = ReadSsdtForFuntionCreateClose;

	//设置卸载例程
	DriverObject->DriverUnload = ReadSsdtForFuntionUnload;

	//创建设备对象
	status = IoCreateDevice(DriverObject,
							0,
							&DeviceName,
							FILE_DEVICE_UNKNOWN,
							0,
							FALSE,
							&DeviceObject);
	if (!NT_SUCCESS(status))
		return status;
	if (!DeviceObject)
		return STATUS_UNEXPECTED_IO_ERROR;

	DeviceObject->Flags |= DO_DIRECT_IO;
	DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;

	//创建符号连接
	status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
	if (!NT_SUCCESS(status))
		return status;

	//初始化完成,可以工作了
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

	//设置测试断点
	__asm int 3

	//获取SSDT表的范围
	lgSsdtNumber = KeServiceDescriptorTable->NumberOfServices;

	//使用方法1.遍历SSDT
	KdPrint(("使用方法1.遍历SSDT\r\n"));
	for (i = 0; i < lgSsdtNumber; i++)
	{
		KdPrint(("Index:%04X--FunAddr:%08X\r\n", i, GetFunctionAddr_ASM(KeServiceDescriptorTable, i)));
	}

	//使用方法2.遍历SSDT
	KdPrint(("使用方法2.遍历SSDT\r\n"));
	for (i = 0; i < lgSsdtNumber; i++)
	{
		KdPrint(("Index:%04X--FunAddr:%08X\r\n", i, GetFunticonAddr(KeServiceDescriptorTable, i)));
	}

	return STATUS_SUCCESS;
}

//1.使用汇编的方法读取内核函数的地址
LONG GetFunctionAddr_ASM(PServiceDescriptorTable KeServiceDescriptorTable, LONG lgSsdtIndex)
{
	LONG lgSsdtFunAddr = 0;

	//lgSsdtFunAddr = [[KeServiceDescriptorTable]+lgSsdtIndex*4]
	__asm
	{
		push ebx
		push eax
		mov ebx, KeServiceDescriptorTable
		mov ebx, [ebx]	//SSDT表的基地址
		mov eax, lgSsdtIndex
		shl eax, 2
		add ebx, eax
		mov ebx, [ebx]
		mov lgSsdtFunAddr, ebx
		pop  eax
		pop  ebx
	}

	return lgSsdtFunAddr;
}

//2.使用指针的方法获取函数的地址
LONG GetFunticonAddr(PServiceDescriptorTable KeServiceDescriptorTable, LONG lgSsdtIndex)
{
	LONG lgSsdtAddr = 0;
	//获取SSDT表的基址
	lgSsdtAddr = (LONG)KeServiceDescriptorTable->ServiceTableBase;

	PLONG plgSsdtFunAddr = 0;
	//获取内核函数的地址指针
	plgSsdtFunAddr = (PLONG)(lgSsdtAddr+lgSsdtIndex*4);

	//返回内核函数的地址
	return (*plgSsdtFunAddr);
}

void ReadSsdtForFuntionUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING Win32Device;
	RtlInitUnicodeString(&Win32Device,L"\\DosDevices\\ReadSsdtForFuntion0");
	IoDeleteSymbolicLink(&Win32Device);
	IoDeleteDevice(DriverObject->DeviceObject);
}

NTSTATUS ReadSsdtForFuntionCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS ReadSsdtForFuntionDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return Irp->IoStatus.Status;
}

//参考资料:
//郁金香老师讲课资料

时间: 2024-10-16 23:23:16

SSDT表的遍历的相关文章

SSDT表概念详解

SSDT 的全称是 System Services Descriptor Table,系统服务描述符表. 这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来.Ring3下调用的所有函数最终都会先进入到ntdll里面的,比如ReadFile,就会进入ntdll的ZwReadFile SSDT 并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址.服务函数个数等. 1. //系统服务描述符表-在ntoskrnl.exe中导

Lua 多维表的遍历中的赋值

说到Lua的遍历将要使用到循环:先说遍历再说循环: 遇到这样类似结构的一个table Data={ [102]={p1=1,pa={1,2,3}}, [103]={p1=2,pa={2,3,4}}, [105]={p1=4,pa={3,4,5}} } 目的获得key 值与pa的一个表,实现下 1 -- 使用table.insert方法插入到新表中 2 for k,v in pairs(Data) do 3 print(k,v) 4 Data2[k]={}; 5 table.insert(Data

SSDT表详解

SSDT(system service dispatch table) 系统服务分派表 SSPT(system service parameter table) 系统服务参数表 #pragma pack(1)     //SSDT表的结构 typedef struct ServiceDescriptorEntry {     unsigned int *ServiceTableBase;     unsigned int *ServiceCounterTableBase; //Used only

C语言建立有向图的邻接表及其遍历操作

1 /*C语言建立有向图的邻接表及其遍历操作*/ 2 #include"stdio.h" 3 #include"stdlib.h" 4 //图的邻接矩阵储存结构 5 typedef char elemtype; 6 #define maxsize 10 7 #define queuesize 100 8 //边结点的类型定义 9 typedef struct edgenode 10 { 11 int adjvex;//存放邻接的点在顶点表的下标,邻接点 12 str

图的邻接表+深度优先遍历+广度优先遍历

1 /** 2 无向图的邻接表存储 3 深度优先遍历递归 4 广度优先遍历递归+非递归 5 */ 6 #include <stdio.h> 7 #include <string.h> 8 #include <malloc.h> 9 #define N 5 10 #define MAX 50 11 typedef struct A{ 12 int adjvex; 13 struct A* nextArc; 14 }Arc; 15 typedef struct node{

DataTable表的遍历

1. for (int i = 0; i < dt.Rows.Count; i++)            {                for (int j = 0; j < dt.Columns.Count; j++)                {                    sb.Append(dt.Rows[i][j] + "   ");                }                sb.AppendLine();       

图的邻接表(广度优先遍历,深度优先遍历,最小生成树(Kruskal算法))

main.h: #include <iostream> #include <queue> #define DefaultSize 10 #define maxWeight -1 using namespace std; template<typename T,typename E> struct Edge { int dest; E cost; Edge<T,E> *link; Edge(int d=0,int c=0):dest(d),cost(c),li

基于邻接表存储的图的深度优先遍历和广度优先遍历

一.深度优先遍历是连通图的一种遍历策略.其基本思想如下: 设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y).若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过:然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边.上述过程直至从x出发的所有边都已检测过为止. 例如下图中: 1.从0开始,首先找到0的关

HOOK钩子技术5 SSDT Inline Hook

原理 内联钩子的原理在R3和R0下是相同的,就是不改变SSDT表项,而是改变函数内部前几条指令. 内联钩子的典型伪函数为: 恢复原指令 执行目标操作,或改写参数 执行原函数 返回时重新挂钩 demo #include "stdafx.h" #ifdef __cplusplus extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)