首页
社区
课程
招聘
[求助]关于Ring0下获取SSDT原始地址碰到的问题
发表于: 2010-5-17 12:18 16209

[求助]关于Ring0下获取SSDT原始地址碰到的问题

2010-5-17 12:18
16209
网上找的一段ring0获取SSDT原始地址的代码:
地址:http://www.debugman.com/read.php?tid=1254
加了个头文件后可以编译,虚拟机下运行成功.但是在自己的机子上,却运行出错

Kernel ImageBase: 0x00400000
Kernel Base: 0x804D8000
Kernel Module Path: \SystemRoot\System32\ntkrnlpa.exe
SSDT BaseAddress: 0x8A3BD948, SSDT Count: 0x13D
SSDT RAW: 0x09EE5947
Read File Error!

此时
Kernel base = 0x804D8000 , size = 0x0020D000  
KeServiceDescriptorTable->ServiceTableBase = 0x8A3BD948 

 

SSDT表明显不在Kernel模块中啊...这要怎么得到SSDT的RVA呢?

大牛们指点一下

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (15)
雪    币: 207
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
似乎有点线索了...
我本机的SSDT Count应该为0x11c,这里却是0x13D,说明被扩展了,,,,

从Xuetr中可以看出是金山毒霸()扩展的,,,

也就是说,,现在的KeServiceDescriptorTable->ServiceTableBase指向的并不是原始那份,而是金山的KAVSafe.sys所复制和扩展的...
2010-5-17 12:40
0
雪    币: 47
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
lkd> dd KeServiceDescriptorTable
8055d700  80505460 00000000 0000011c 805058d4
原来金山毒霸是这么玩的阿00!
2010-5-17 12:55
0
雪    币: 88
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
看样子,一般的杀毒软件都会自己先hook掉 ssdt啊
2010-5-17 15:09
0
雪    币: 379
活跃值: (152)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
5
重定位pe文件就可以,因为ssdt其实就是存放nt开头的导出文件,
2010-5-17 15:25
0
雪    币: 379
活跃值: (152)
能力值: ( LV12,RANK:330 )
在线值:
发帖
回帖
粉丝
6
我写的在ring3下得到ssdt原始地址:
http://bbs.pediy.com/showthread.php?t=112838
2010-5-17 15:27
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
7
直接读导出表获得KeServiceDescriptorTable……或者由文件TableBase反推到内存TableBase基地址
2010-5-18 10:55
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
8
解析磁盘文件即可
2010-5-18 12:33
0
雪    币: 466
活跃值: (165)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
9
标签一下。打算学这个技术了
2010-5-19 19:24
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
10
/*****************************************************************************************
*
*函数名:FindModuleByAddress
*功能描述:根据函数地址查找所属模块
*
******************************************************************************************/
/*****************************************************************************************
*
*	原理:	利用ZwQuerySystemInformation传入SystemModuleInformation(11)得到系统模块列表
*			得到每个模块的起始和结束地址
*			比对地址,在那个范围就属于哪个模块
*			得到模块名
*
******************************************************************************************/
#include "refresh.h"
void FindModuleByAddress( ULONG Address, PVOID buffer)
{
	NTSTATUS status;
	ULONG size;
	ULONG i;
	ULONG minAddress;
	ULONG maxAddress;
	PSYSMODULELIST List;

	ZwQuerySystemInformation( SystemModuleInformation ,&size,0,&size);
	KdPrint(("[FindModuleByAddress] size:0x%x\n",size));
	List=(PSYSMODULELIST)ExAllocatePool(NonPagedPool,size);
	if(List==NULL)
	{
		KdPrint(("[FindModuleByAddress] malloc memory failed\n"));
		return ;
	}

	status=ZwQuerySystemInformation(SystemModuleInformation,List,size,0);
	if(!NT_SUCCESS(status))
	{
		KdPrint(("[FindModuleByAddress] query failed\n"));
		//打印错误
		KdPrint(("[FindModuleByAddress] status: 0x%x\n",status));
		ExFreePool( List );
		return ;
	}
	//得到了模块链表
	//判断模块名
	for( i=0; i<List->ulCount; i++)
	{	
		//得到模块的范围
		minAddress = (ULONG)List->smi[i].Base;
		maxAddress = minAddress + List->smi[i].Size;
		//判断地址
		if( Address >= minAddress && Address <= maxAddress )
		{
			memcpy( buffer, List->smi[i].ImageName,sizeof(List->smi[i].ImageName));
			KdPrint(("[FindModuleByAddress] modulename: %s\n",buffer));
			//释放内存
			ExFreePool(List);
			break;
		}
	}
}
/***************************************************************************************
*
*	函数名:GetOriFunctionAddress
*	功能描述:得到原始SSDT表中函数地址
*
****************************************************************************************/
/***************************************************************************************
*
*	原理:	找到内核文件,获取基址BaseAddress
*			根据内核文件查找SSDT表的文件偏移SSDTFileOffset = SSDTRVA-(节RVA-节Offset)
*			读取函数的文件偏移FunctionFileOffset
*			VA=BaseAddress+FunctionFileOffset-00400000=800d8000 + FunctionFileOffset
*
*****************************************************************************************/
/****************************************************************************************
*
*	根据RVA查找所在的文件偏移:FileOffset = Rva- (节Rva - 节Offset)
*	找到区块表
*****************************************************************************************/
ULONG FindFileOffsetByRva( ULONG ModuleAddress,ULONG Rva)
{
	PIMAGE_DOS_HEADER dos;
	PIMAGE_FILE_HEADER file;
	PIMAGE_SECTION_HEADER section;
	//区块数目
	ULONG number;
	ULONG i;
	ULONG minAddress;
	ULONG maxAddress;
	ULONG SeFileOffset;
	ULONG FileOffset;

	dos = (PIMAGE_DOS_HEADER)ModuleAddress;
	file = (PIMAGE_FILE_HEADER)( ModuleAddress + dos->e_lfanew + 4 );
	//得到区块数量
	number = file->NumberOfSections;
	KdPrint(("[FindFileOffsetByRva] number :0x%x\n",number));
	//得到第一个区块地址
	section = (PIMAGE_SECTION_HEADER)(ModuleAddress + dos->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + file->SizeOfOptionalHeader);
	for( i=0;i<number;i++)
	{
		minAddress = section[i].VirtualAddress;
		maxAddress = minAddress + section[i].SizeOfRawData;
		SeFileOffset = section[i].PointerToRawData;
		if( Rva > minAddress && Rva < maxAddress)
		{
			KdPrint(("[FindFileOffsetByRva] minAddress :0x%x\n",minAddress));
			KdPrint(("[FindFileOffsetByRva] SeFileOffset :0x%x\n",SeFileOffset));
			FileOffset = Rva - ( minAddress - SeFileOffset);
			KdPrint(("[FindFileOffsetByRva] FileOffset :0x%x\n",FileOffset));
			break ;
		}
	}
	return FileOffset;
}

//路径解析出子进程名
void  GetModuleName( char *ProcessPath, char *ProcessName)
{
	ULONG n = strlen( ProcessPath) - 1;
	ULONG i = n;
	KdPrint(("%d",n));
	while( ProcessPath[i] != '\\')
	{
		i = i-1;
	}
	strncpy( ProcessName, ProcessPath+i+1,n-i);
}

/****************************************************************************************
*
*	根据传入的服务号得到函数原始地址
*
****************************************************************************************/
ULONG FindOriAddress( ULONG index )
{
	//根据传入的index得到函数VA地址
	//重定位函数地址
	//BaseAddress - 0x00400000 + *(PULONG)(FileOffset+(index*4))
	//ZwQuerySystemInformation得到内核文件基地址
	//得到SSDT表的地址
	//得到SSDT RVA 查找SSDT RVA所在的节
	NTSTATUS status;
	ULONG size;
	ULONG BaseAddress;
	ULONG SsdtRva;
	ULONG FileOffset = 0;

	PSYSMODULELIST list;
	char Name[32]={0};
	char PathName[256] = "\\SystemRoot\\system32\\";
	ANSI_STRING name;
	UNICODE_STRING modulename;

	OBJECT_ATTRIBUTES  object_attributes;
	IO_STATUS_BLOCK io_status = {0};
	HANDLE hFile;
	//读取的位置
	ULONG location;
	LARGE_INTEGER offset;
	ULONG address;

	//得到需要申请的内存大小
	ZwQuerySystemInformation( SystemModuleInformation,&size,0,&size );
	//申请内存
	list = (PSYSMODULELIST) ExAllocatePool( NonPagedPool,size );
	//验证是否申请成功
	if( list == NULL)
	{
		//申请失败
		KdPrint(("[FindOriAddress] malloc memory failed\n"));
		ExFreePool(list);
		return 0;
	}
	status = ZwQuerySystemInformation( SystemModuleInformation,list,size,0);
	if( !NT_SUCCESS( status ))
	{
		//获取信息失败
		KdPrint(("[FindOriAddress] query failed\n"));
		KdPrint(("[FindOriAddress] status:0x%x\n",status));
		ExFreePool(list);
		return 0;
	}
	//得到模块基址,第一个模块为内核文件
	BaseAddress = (ULONG )list->smi[0].Base;
	KdPrint(("[FindOriAddress] BaseAddress:0x%x\n",BaseAddress));
	//分离出内核文件名
	GetModuleName(list->smi[0].ImageName,Name);
	KdPrint(("[FindOriAddress] processname:%s\n",Name));
	strcat(PathName,Name);
	RtlInitAnsiString(&name,PathName);
	RtlAnsiStringToUnicodeString(&modulename,&name,TRUE);
	KdPrint(("[FindOriAddress] modulename: %wZ\n",&modulename));
	ExFreePool(list);
	//经验证地址正确
	//得到SSDT表的Rva
	SsdtRva = (ULONG)KeServiceDescriptorTable->ServiceTableBase - BaseAddress;
	//验证
	KdPrint(("[FindOriAddress] SsdtRva:0x%x\n",SsdtRva));
	//根据RVA查找文件偏移,//得到文件偏移了
	FileOffset= FindFileOffsetByRva( BaseAddress,SsdtRva);
	KdPrint(("[FindOriAddress] FileOffset:0x%x\n",FileOffset));
	//读取的位置
	location = FileOffset + index * 4;
	offset.QuadPart =location;
	KdPrint(("[FindOriAddress] location:0x%x\n",location));
	//利用ZwReadFile读取文件
	//初始化OBJECT_ATTRIBUTES结构
	InitializeObjectAttributes( 
		&object_attributes,
		&modulename,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL,
		NULL);
	//打开文件
	status = ZwCreateFile(
		&hFile,
		FILE_EXECUTE | SYNCHRONIZE,
		&object_attributes,
		&io_status,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ,
		FILE_OPEN,
		FILE_NON_DIRECTORY_FILE |
		FILE_RANDOM_ACCESS |
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);
	if( !NT_SUCCESS( status ))
	{
		KdPrint(("[FindOriAddress] open error\n"));
		KdPrint(("[FindOriAddress] status = 0x%x\n", status));
		ZwClose( hFile );
		return 0;
	}
	status = ZwReadFile(
		hFile,
		NULL,
		NULL,
		NULL,
		NULL,
		&address,
		sizeof(ULONG),
		&offset,
		NULL);
	if( !NT_SUCCESS( status ))
	{
		KdPrint(("[FindOriAddress] read error\n"));
		KdPrint(("[FindOriAddress] status = 0x%x\n", status));
		ZwClose( hFile );
		return 0;
	}
	KdPrint(("[FindOriAddress] address:0x%x\n",address));
	//重定位
	address = BaseAddress - 0x00400000 + address;
	KdPrint(("[FindOriAddress] Oriaddress:0x%x\n",address));
	//释放动态分配的内存
	RtlFreeUnicodeString(&modulename);
	ZwClose( hFile );
	return address;
}
/******************************************************************************************
*
*	得到SSDT Shadow当前地址
*   1、KeServiceDescriptorTable -  0x40 + 0x10
*   2、搜索KeAddSystemServiceTable函数,特征码
*   3、Kthread->ServiceTable指向
*	4、MJ提出的搜索特定内存
*
*******************************************************************************************/
//方式1,XP下-0x40;
ULONG GetSSDTShadowAddress1()
{
	ULONG address;
	ULONG ssdt;
	ssdt = (ULONG)KeServiceDescriptorTable;
	address = ssdt - 0x30;
	KdPrint(("[GetSSDTShadowAddress] ssdt:0x%x\n",ssdt));
	KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));
	return address;
}
//方式2
ULONG GetSSDTShadowAddress2()
{
	ULONG address;
	PUCHAR addr;
	PUCHAR p;
	addr = (PUCHAR)KeAddSystemServiceTable;
	for( p=addr; p<addr+PAGE_SIZE; p++)
	{
		if(*(PUSHORT)p == 0x888D)
		{
			address = *(PULONG)((ULONG)p+2);
			break;
		}
	}
	address = address + 0x10;
	KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));
	return address;
}
//方式3
ULONG GetSSDTShadowAddress3()
{
	return 0;
}
//方式4
ULONG GetSSDTShadowAddress4()
{
	return 0;
}
/*********************************************************************************
*
*	获得win32k.sys基址
*	1、ZwQuerySystemInformation
*	2、遍历DriverSection链表
*
**********************************************************************************/
ULONG GetWin32Base1()
{
	NTSTATUS status;
	ULONG i;
	ULONG size;
	ULONG address;
	PSYSMODULELIST List;
	
	ZwQuerySystemInformation( SystemModuleInformation ,&size,0,&size);
	KdPrint(("[FindModuleByAddress] size:0x%x\n",size));
	List=(PSYSMODULELIST)ExAllocatePool(NonPagedPool,size);
	if (List==NULL)
	{
		KdPrint(("[FindModuleByAddress] malloc memory failed\n"));
		ExFreePool( List );
		return 0;
	}

	status=ZwQuerySystemInformation(SystemModuleInformation,List,size,0);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("[FindModuleByAddress] query failed\n"));
		//打印错误
		KdPrint(("[FindModuleByAddress] status: 0x%x\n",status));
		ExFreePool( List );
		return 0;
	}
	for ( i=0; i < List->ulCount; i++ )
	{
		
			if( strcmp(List->smi[i].ImageName,"\\SystemRoot\\System32\\win32k.sys") == 0)
			{
				KdPrint(("[GetWin32Base]name :%s\n",List->smi[i].ImageName));
				address = (ULONG)List->smi[i].Base;
				KdPrint(("[GetWin32Base1] win32k.sys address:0x%x\n",address));	
			}
			
	}
	return address;
}
/*********************************************************************************************
*
*	驱动对象DRIVER_OBJECT中的DRIVER_SECTION
*	LDR_DATA_TABLE_ENTRY结构包含系统加载模块链表及基址
*
*
**********************************************************************************************/
ULONG  GetWin32Base2( PDRIVER_OBJECT driver)
{
	PLIST_ENTRY pList = NULL;
	PLDR_DATA_TABLE_ENTRY pLdr = NULL;
	ULONG BaseAddress = 0;
	pList = ( (PLIST_ENTRY)driver->DriverSection )->Flink;
	do
	{
		pLdr = CONTAINING_RECORD(
			pList,
			LDR_DATA_TABLE_ENTRY,
			InLoadOrderLinks
			);
		if( pLdr->EntryPoint != NULL && pLdr->FullDllName.Buffer!= NULL )
		{
			if( !_wcsicmp( pLdr->FullDllName.Buffer, L"\\SystemRoot\\System32\\win32k.sys"))
			{
				BaseAddress = (ULONG )pLdr->DllBase;
				KdPrint(("[GetWin32Base2] win32k.sys address:0x%x\n",BaseAddress));
				break ;
			}
		}
		pList = pList->Flink;
	}while( pList != ((PLIST_ENTRY)driver->DriverSection)->Flink );
	return BaseAddress;
}
/****************************************************************************************
*
*	根据传入的服务号得到Shadow 函数原始地址
*
****************************************************************************************/
ULONG FindShadowOriAddress( ULONG index )
{
	//内核文件win32k.sys基地址
	//得到SSDT Shadow表的地址
	//得到文件偏移
	NTSTATUS status;
	ULONG size;
	ULONG BaseAddress;
	ULONG ShadowBase;
	ULONG ShadowAddress;
	ULONG SsdtRva;
	ULONG FileOffset = 0;
	UNICODE_STRING modulename;


	OBJECT_ATTRIBUTES  object_attributes;
	IO_STATUS_BLOCK io_status = {0};
	HANDLE hFile;
	//读取的位置
	ULONG location;
	LARGE_INTEGER offset;
	ULONG address;

	BaseAddress = GetWin32Base1();
	KdPrint(("[FindShadowOriAddress] BaseAddress:0x%x\n",BaseAddress));
	//经验证地址正确
	ShadowBase = GetSSDTShadowAddress2();
	ShadowAddress = *(PULONG)ShadowBase;
	KdPrint(("[FindShadowOriAddress] ShadowAddress:0x%x\n",ShadowAddress));
	//得到SSDT表的Rva
	SsdtRva = ShadowAddress - BaseAddress;
	//验证
	KdPrint(("[FindOriAddress] SsdtRva:0x%x\n",SsdtRva));
	//读取的位置
	location = SsdtRva + index * 4;
	offset.QuadPart =location;
	KdPrint(("[FindOriAddress] location:0x%x\n",location));
	//利用ZwReadFile读取文件
	//初始化OBJECT_ATTRIBUTES结构
	RtlInitUnicodeString(&modulename, L"\\SystemRoot\\system32\\win32k.sys");
	InitializeObjectAttributes( 
		&object_attributes,
		&modulename,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL,
		NULL);
	//打开文件
	status = ZwCreateFile(
		&hFile,
		FILE_EXECUTE | SYNCHRONIZE,
		&object_attributes,
		&io_status,
		NULL,
		FILE_ATTRIBUTE_NORMAL,
		FILE_SHARE_READ,
		FILE_OPEN,
		FILE_NON_DIRECTORY_FILE |
		FILE_RANDOM_ACCESS |
		FILE_SYNCHRONOUS_IO_NONALERT,
		NULL,
		0);
	if( !NT_SUCCESS( status ))
	{
		KdPrint(("[FindOriAddress] open error\n"));
		KdPrint(("[FindOriAddress] status = 0x%x\n", status));
		ZwClose( hFile );
		return 0;
	}
	status = ZwReadFile(
		hFile,
		NULL,
		NULL,
		NULL,
		NULL,
		&address,
		sizeof(ULONG),
		&offset,
		NULL);
	if( !NT_SUCCESS( status ))
	{
		KdPrint(("[FindOriAddress] read error\n"));
		KdPrint(("[FindOriAddress] status = 0x%x\n", status));
		ZwClose( hFile );
		return 0;
	}
	KdPrint(("[FindOriAddress] address:0x%x\n",address));
	address = address;
	KdPrint(("[FindOriAddress] Oriaddress:0x%x\n",address));
	ZwClose( hFile );
	return address;
}
2010-5-19 19:27
0
雪    币: 34
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
搜一下KiInitSystem()
mov     eax, ds:_KiServiceLimit   // ssdt数量
push    10h
pop     ecx
mov     ds:dword_48B528, eax
; ...
; ...
mov     ds:_KeServiceDescriptorTable, offset _KiServiceTable  // ssdt由KiServiceTable初始化的
2010-5-19 20:18
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
12
ShadowsSSDT查找KeAddXX那个函数方法相当不稳定,我自己测试过,在虚拟机上找到的是SSDT,要移动一个SSDT大小才是ShadowsSSDT,但是实际电脑上却不是这样的,一运行就蓝屏,比较稳妥的方法是从Win32k.sys驱动入口搜索进去获取
引用文章如下:
http://hi.baidu.com/%D0%A1%C2%B9%BD%A3/blog/item/92c302dc65b1751f49540318.html
读文件取ShadowSSDT函数地址2010-05-17 00:31ShadowSSDT定位,从前听说可以从KeServiceDescriptorTable进去获取地址,自己测试奇怪的是winbug里面看到一

个ShadowsSSDT地址,跑内存去看发现居然是SSDT,这个加一才是正确的ShadowsSSDT,于是虚拟机测试成功了,

到了真实电脑上测试,立马蓝屏,于是打算寻找其它获取途径,直接拿win32开刀,调试之略有心得

方法如下:

从DriverEntry(PE入口点)进去,可以找到设置ShadowSSDT的代码,提取出来就好了,代码相当简单

指令格式如下:Windows 7,XP下通用
push Offset Shadow SSDT

call KeAddSystemServiceTable

所以结构体如下:

typedef struct _RAW_ShadowSSDT
{
unsigned char PushOp;//0x68
unsigned long TableRva;
unsigned short CallOp;//0x15ff
unsinged long KeIn;

}RAW_SHADOWSSDT,*PRAW_SHADOWSSDT;

至于界限,当然可以从这附近取得,但是不通用,所以读取时注意就可以了表以00000101 01000000结尾
ULONG GetRvaOffShadowTableFromFile(UCHAR* Base)
{
UCHAR * Pointer,*OpeCode=0;
Pointer=Base;
int Len=0;
while((Len=SizeOfCode(Pointer,&OpeCode))>0)
{
   if(*OpeCode==0xc2)
    break;
   if(*OpeCode==0x68)
   {
    PRAW_SHADOWSSDT pCode=(PRAW_SHADOWSSDT)Pointer;
    if(pCode->CallOp==0x15ff)
    {
     return pCode->TableRva;
    }
   }
   Pointer+=Len;

}

return 0;
}
最后插一句,表里面的OFFSET换算到实际内存地址是 Offset-ImageBase+模块基地址
表里面的OFFSET换算到内存文件地址是 Offset-ImageBase+文件读进来开始处
方法优点,稳定,保险(注意由于)KeServiceDescriptorTable,调用本来就比较少,可以改掉函数里的地址,这样再去读,就XXX了,自己在虚拟机里居然看这个地址是SSDT,显然被改成SSDT也是可以的
还有顺便可以把Inline Hook检测带上了……
运行某ARK结果如下:

Index:01d8当前地址:bf8f301e   原始地址:bf8f301e 挂钩类型0
Index:01d9当前地址:bf864d59   原始地址:bf864d59 挂钩类型0
Index:01da当前地址:bf803708   原始地址:bf803708 挂钩类型0
Index:01db当前地址:bf8085fa   原始地址:bf8085fa 挂钩类型3000、、inline
Index:01dc当前地址:f3ef2764   原始地址:bf89ad17 挂钩类型200
Index:01dd当前地址:bf8978a3   原始地址:bf8978a3 挂钩类型0
Index:01de当前地址:bf8bfcd0   原始地址:bf8bfcd0 挂钩类型0
Index:01df当前地址:bf911ae1   原始地址:bf911ae1 挂钩类型0
Index:01e0当前地址:bf913655   原始地址:bf913655 挂钩类型0
Index:01e1当前地址:bf911e8f   原始地址:bf911e8f 挂钩类型0
Index:01e2当前地址:bf913db4   原始地址:bf913db4 挂钩类型0
Index:01e3当前地址:f3ef27a6   原始地址:bf803ba4 挂钩类型200
Index:01e4当前地址:bf9109b0   原始地址:bf9109b0 挂钩类型0
Index:01e5当前地址:bf878b08   原始地址:bf878b08 挂钩类型0
Index:01e6当前地址:bf9118b8   原始地址:bf9118b8 挂钩类型0
Index:01e7当前地址:bf826d2d   原始地址:bf826d2d 挂钩类型
2010-5-19 22:37
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
13
4种方式获取SSDTShadow地址
//得到SSDTShadow地址
//方式1,XP下-0x40;
ULONG GetSSDTShadowAddress1()
{
	ULONG address;
	ULONG ssdt;
	ssdt = (ULONG)KeServiceDescriptorTable;
	address = ssdt - 0x30;
	KdPrint(("[GetSSDTShadowAddress] ssdt:0x%x\n",ssdt));
	KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));
	return address;
}
//方式2  搜索KeAddSystemServiceTable
ULONG GetSSDTShadowAddress()
{
	ULONG address;
	PUCHAR addr;
	PUCHAR p;
	addr = (PUCHAR)KeAddSystemServiceTable;
	for( p=addr; p<addr+PAGE_SIZE; p++)
	{
		if(*(PUSHORT)p == 0x888D)
		{
			address = *(PULONG)((ULONG)p+2);
			break;
		}
	}
	address = address + 0x10;
	KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address));
	return address;
}
//方式3  遍历系统线程  TableCode指向
ULONG GetSSDTShadowAddress3()
{
	//遍历线程
	ULONG i;
	NTSTATUS status;
	ULONG thread;
	ULONG address=0;
	for( i=8; i<32768; i=i+4)
	{
		status = PsLookupThreadByThreadId( (HANDLE)i,&(PETHREAD)thread);
		if(NT_SUCCESS(status))
		{
			if( *(PULONG)(thread+0x0e0) != (ULONG)KeServiceDescriptorTable )
			{
				address =  *(PULONG)(thread+0x0e0);
				break ;
			}
		}
	}
	return address;
}
//方式4  ,MJ所说的暴力搜索KeAddSystemServiceTable有效内存
//获取KeServiceDescriptorTableShadow地址
ULONG GetAddressOfShadowTable()
{
    unsigned int i;
    unsigned char *p;
    unsigned int dwordatbyte;
    
    UNICODE_STRING usKeAddSystemServiceTable;
    
    RtlInitUnicodeString(&usKeAddSystemServiceTable, 
         L"KeAddSystemServiceTable"); 
    p = (unsigned char*)MmGetSystemRoutineAddress(&usKeAddSystemServiceTable); 

    for(i = 0; i < 4096; i++, p++)
    {
       __try
       {
           dwordatbyte = *(unsigned int*)p;
       }
       __except(EXCEPTION_EXECUTE_HANDLER)
       {
           return 0;
       }

       if(MmIsAddressValid((PVOID)dwordatbyte))
       {
          if(memcmp((PVOID)dwordatbyte, &KeServiceDescriptorTable, 16) == 0)
          {
             if((PVOID)dwordatbyte == &KeServiceDescriptorTable)
             {
                continue;
             }
             return dwordatbyte;
          }
       }
    }
    return 0;
}
2010-5-19 23:08
0
雪    币: 170
活跃值: (90)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
14
不可盲目乱用,直接ctrl+c 和ctrl+v的读者,请先理解原理后,变通着用。4种方法,均可。
2010-5-19 23:09
0
雪    币: 246
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
竹君,你的方法如果ssdt表被杀毒软件更改了,你的 SsdtRva = (ULONG)KeServiceDescriptorTable->ServiceTableBase - BaseAddress不就对了吗?对应的文件便宜也是错误的
2010-5-20 11:11
0
雪    币: 246
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
不就不对了吗?对应的偏移也是错的吧?
2010-5-20 13:35
0
游客
登录 | 注册 方可回帖
返回
//