关于PspCidTable的寻找,我是通过PsLookupProcessByProcessId查找特征码寻找pspCidTable和32位没什么区别。
疑问:我想在KPCR中的KdVersionBlock中寻找,但是64位系统不知道为什么总是NULL,各位牛牛知道的求科普~
寻找PspCidTable:
SIZE_T FindCidTable()
{
SIZE_T CidTableAddr = 0;
UNICODE_STRING ustPsFuncName;
RtlInitUnicodeString(&ustPsFuncName, L"PsLookupProcessByProcessId");
PUCHAR startAddr = (PUCHAR)MmGetSystemRoutineAddress(&ustPsFuncName);
//DbgPrint("startAddr:0x%02X,startAddr+1:0x%02X\n", *startAddr, *(startAddr+1));
for (ULONG64 i = 0; i < 100; i++)
{
if (*(startAddr + i) == 0x48 &&
*(startAddr + i + 1) == 0x8b &&
*(startAddr + i + 2) == 0x0d)
{
CidTableAddr = (SIZE_T)(*(PULONG)(startAddr + i + 3) + (startAddr + i + 3 + 4)) & 0xFFFFFFFEFFFFFFFF;
DbgPrint("CidTableAddr:%p\n", CidTableAddr);
break;
}
}
return CidTableAddr;
}
相关结构:
原32位结构:
typedef struct _HANDLE_TABLE{ ULONG TableCode; PEPROCESS QuotaProcess; PVOID UniqueProcessId; EX_PUSH_LOCK HandleLock; LIST_ENTRY HandleTableList; EX_PUSH_LOCK HandleContentionEvent; PHANDLE_TRACE_DEBUG_INFO DebugInfo; LONG ExtraInfoPages; ULONG Flags; ULONG StrictFIFO: 1; LONG FirstFreeHandle; PHANDLE_TABLE_ENTRY LastFreeHandleEntry; LONG HandleCount; ULONG NextHandleNeedingPool;} HANDLE_TABLE, *PHANDLE_TABLE;
现在x64结构:
typedef struct _HANDLE_TABLE
{
ULONG64 TableCode;
PEPROCESS QuotaProcess;
PVOID UniqueProcessId;
EX_PUSH_LOCK HandleLock;
LIST_ENTRY HandleTableList;
EX_PUSH_LOCK HandleContentionEvent;
PHANDLE_TRACE_DEBUG_INFO DebugInfo;
LONG ExtraInfoPages;
ULONG Flags;
//ULONG StrictFIFO : 1;
LONG64 FirstFreeHandle;
PHANDLE_TABLE_ENTRY LastFreeHandleEntry;
LONG HandleCount;
ULONG NextHandleNeedingPool;
} HANDLE_TABLE, *PHANDLE_TABLE;
32位和64位结构体有点差别,注意LONG64 FirstFreeHandle;
其他的和32位没啥区别,就是一级表和二级表的数量 分别为:
#define MAX_ENTRY_COUNT (0x1000/16) //一级表中的 HANDLE_TABLE_ENTRY个数
#define MAX_ADDR_COUNT (0x1000/8) //二级表和 三级表中的地址个数
之后就是便利的核心代码了,方法是自己山寨ExEnumerateHandleRoutine
NTSTATUS EnumProcessByPspCidTable()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PHANDLE_TABLE pHandleTable = NULL;
pHandleTable =(PHANDLE_TABLE)*(PSIZE_T)FindCidTable();
HANDLE hHanel;
UNICODE_STRING usObGetObjectType;
DbgPrint("pHandleTable:%p\n", pHandleTable);
获取system eprocess 结构,我这win7 是个二级表,为了方便我直接写了,关于句柄表可以看博客http://blog.csdn.net/zfdyq0
//PEPROCESS process = (PEPROCESS)(*(PULONG)(*(PULONG)(pHandleTable->TableCode & 0xfffffff0)+8)&0xfffffff8);
RtlInitUnicodeString(&usObGetObjectType, L"ObGetObjectType");
g_pObGetObjectType = MmGetSystemRoutineAddress(&usObGetObjectType);
DbgPrint("g_pObGetObjectType:%p\n", g_pObGetObjectType);
MyEnumHandleTable(pHandleTable, MyEnumerateHandleRoutine, NULL, &hHanel);
return status;
}
BOOLEAN MyEnumerateHandleRoutine(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
)
{
BOOLEAN Result = FALSE;
ULONG64 ProcessObject;
POBJECT_TYPE ObjectType;
PVOID Object;
UNICODE_STRING ustObjectName;
UNREFERENCED_PARAMETER(EnumParameter);
UNREFERENCED_PARAMETER(ustObjectName);
ProcessObject = (HandleTableEntry->Value)&~7; //掩去低三位
Object = (PVOID)((ULONG64)HandleTableEntry->Object&~7);
ObjectType = g_pObGetObjectType(Object);
if (MmIsAddressValid(HandleTableEntry))
{
if (ObjectType == *PsProcessType)//判断是否为Process
{
//注意PID其实就是Handle,而 不是从EPROCESS中取,可以对付伪pid
UCHAR* szName = PsGetProcessImageFileName((PEPROCESS)ProcessObject);
stcProcessInfo[nProcessCount].hProcessID = Handle;
RtlCopyMemory(stcProcessInfo[nProcessCount].szName, szName, strlen(szName) + 1);
nProcessCount++;
DbgPrint("PID=%4d\t EPROCESS=0x%p %s\n", Handle, ProcessObject, PsGetProcessImageFileName((PEPROCESS)ProcessObject));
}
}
return Result;//返回FALSE继续
}
//自己实现一个山寨的MyEnumHandleTable,接口和ExEnumHandleTable一样
#define MAX_ENTRY_COUNT (0x1000/16) //一级表中的 HANDLE_TABLE_ENTRY个数
#define MAX_ADDR_COUNT (0x1000/8) //二级表和 三级表中的地址个数
BOOLEAN
MyEnumHandleTable(
PHANDLE_TABLE HandleTable,
MY_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
PVOID EnumParameter,
PHANDLE Handle
)
{
ULONG64 i, j, k;
ULONG_PTR CapturedTable;
ULONG64 TableLevel;
PHANDLE_TABLE_ENTRY TableLevel1, *TableLevel2, **TableLevel3;
BOOLEAN CallBackRetned = FALSE;
BOOLEAN ResultValue = FALSE;
ULONG64 MaxHandle;
//判断几个参数是否有效
if (!HandleTable
&& !EnumHandleProcedure
&& !MmIsAddressValid(Handle))
{
return ResultValue;
}
//取表基址和表的级数
CapturedTable = (HandleTable->TableCode)&~3;
TableLevel = (HandleTable->TableCode) & 3;
MaxHandle = HandleTable->NextHandleNeedingPool;
DbgPrint("句柄上限值为0x%X\n", MaxHandle);
//判断表的等级
switch (TableLevel)
{
case 0:
{
//一级表
TableLevel1 = (PHANDLE_TABLE_ENTRY)CapturedTable;
DbgPrint("解析一级表 0x%p...\n", TableLevel1);
for (i = 0; i < MAX_ENTRY_COUNT; i++)
{
*Handle = (HANDLE)(i * 4);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned = EnumHandleProcedure(&TableLevel1[i], *Handle, EnumParameter);
if (CallBackRetned) break;
}
}
ResultValue = TRUE;
}
break;
case 1:
{
//二级表
TableLevel2 = (PHANDLE_TABLE_ENTRY*)CapturedTable;
DbgPrint("解析二级表 0x%p...\n", TableLevel2);
DbgPrint("二级表的个 数:%d\n", MaxHandle / (MAX_ENTRY_COUNT*4));
for (j = 0; j < MaxHandle / (MAX_ENTRY_COUNT * 4); j++)
{
TableLevel1 = TableLevel2[j];
if (!TableLevel1)
break; //为零则跳出
for (i = 0; i < MAX_ENTRY_COUNT; i++)
{
*Handle = (HANDLE)(j*MAX_ENTRY_COUNT * 4 + i * 4);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned = EnumHandleProcedure(&TableLevel1[i], *Handle, EnumParameter);
if (CallBackRetned) break;
}
}
}
ResultValue = TRUE;
}
break;
case 2:
{
//三级表
TableLevel3 = (PHANDLE_TABLE_ENTRY**)CapturedTable;
DbgPrint("解析三级表 0x%p...\n", TableLevel3);
DbgPrint("三级表的个 数:%d\n", MaxHandle / (MAX_ENTRY_COUNT * 4 * MAX_ADDR_COUNT));
for (k = 0; k < MaxHandle / (MAX_ENTRY_COUNT * 4 * MAX_ADDR_COUNT); k++)
{
TableLevel2 = TableLevel3[k];
if (!TableLevel2)
break; //为零则跳出
for (j = 0; j < MaxHandle / (MAX_ENTRY_COUNT * 4); j++)
{
TableLevel1 = TableLevel2[j];
if (!TableLevel1)
break; //为零则跳出
for (i = 0; i < MAX_ENTRY_COUNT; i++)
{
*Handle = (HANDLE)(k*MAX_ENTRY_COUNT*MAX_ADDR_COUNT + j*MAX_ENTRY_COUNT + i * 4);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned = EnumHandleProcedure(&TableLevel1[i], *Handle, EnumParameter);
if (CallBackRetned) break;
}
}
}
}
ResultValue = TRUE;
}
break;
default:
{
DbgPrint("Shoud NOT get here!\n");
}
break;
}
return ResultValue;
}