上节课老师讲错了属性是最后两位,0xfffffffc,并且从句柄表中取出来的值也要-1才能用通过逆向PsLookupProcessByProcessId可以知道
//关键代码
v4 = (struct _KPROCESS **)ExMapHandleToPointer(ProcessId);
//->
v2 = (volatile signed __int32 *)ExpLookupHandleTableEntry(NewIrql);
if ( v2 )
{
while ( 1 )
{
v3 = *v2;
if ( (*v2 & 1) != 0 )
{
//_InterlockedCompareExchange这个函数就是比较1,3参数一样就把值给参数1
if ( _InterlockedCompareExchange(v2, v3 - 1, v3) == v3 )
return v2;
}
之后讲了利用系统使用ExpLookupHandleTableEntry判断是否超过最大句柄返回0,就不会蓝屏(老师说这里会返回0)
if ( (a2 & 0xFFFFFFFC) >= this[13] )
return 0;
但是事实上当你把PID修改为0时,系统调用时并不会返回,他会按部就班的去寻找这个PID的句柄。没有蓝屏只是因为这个PID的进程没有退出或者根本就没有时,软件的退出才不会蓝屏,所以如果你把PID修改为4(system的PID)时也不会蓝屏。但是你要是按照条件去做这个判断时比如说填个0XFFFF FFFF时还是会蓝屏的
VOID ClearHandleTableByPid(ULONG pid) {
UNICODE_STRING funcName = { 0 };
RtlInitUnicodeString(&funcName, L"PsLookupProcessByProcessId");
PUCHAR targetAddr = MmGetSystemRoutineAddress(&funcName);
if (!targetAddr) {
DbgPrint("MmGetSystemRoutineAddress\n");
return;
}
PULONG PspCidTable = 0;
USHORT keyWord = 0x3d8b;
for (size_t i = 0; i < 100; i++) {
if (!(*(PUSHORT)targetAddr - keyWord)) {
PspCidTable = *(PULONG)(targetAddr + 2);
DbgPrint("PspCidTable:%p\n", PspCidTable);
}
targetAddr++;
}
pid /= 4;
ULONG handleTableDir = pid / HANDLE_TABLE_SIZE;
ULONG handleEntry = pid % HANDLE_TABLE_SIZE;
handleTableDir = (*(PULONG)(*PspCidTable) & 0xfffffffc) + sizeof(PVOID) * handleTableDir;
handleEntry = *(PULONG)handleTableDir + handleEntry * 8;
HANDLE handle = (ULONG)(*(PHANDLE)handleEntry) & 0xfffffffc;
memset(handleEntry, 0, 8);
DbgPrint("handle:%p\n", handle);
DWORD offset = GetProcessIdOffset();
*(PULONG)((PUCHAR)handle + offset) = 0;
}