【旧文章搬运】PspCidTable攻与防
原文发表于百度空间,2009-03-29
==========================================================================
PspCidTable的攻与防,其实就是进程隐藏与检测所涉及到的一部分工作~~
不管基于PspCidTable的进线程检测,还是抹PspCidTable进行进程对象的隐藏,都涉及到对PspCidTable的遍历.
所以如何安全正确地遍历PspCidTable才是该技术的关键
一、获取PspCidTable的地址
常用的方法是从前面提到的三个查询PspCidTable的函数中特征搜索.
PsLookupProcessThreadByCid()
PsLookupProcessByProcessId()
PsLookupThreadByThreadId()
比如PsLookupProcessByProcessId()中:
lkd> u
nt!PsLookupProcessByProcessId+0x12:
8057ce2f ff8ed4000000 dec dword ptr [esi+0D4h]
8057ce35 ff35e0955680 push dword ptr [nt!PspCidTable (805695e0)] //就是这儿了
8057ce3b e89b1dffff call nt!ExMapHandleToPointer (8056ebdb)
8057ce40 8bd8 mov ebx,eax
这个方法没什么好说的,匹配就是了~
另一种方法是从KPCR中取,我比较喜欢这种方法:
lkd> dt _KPCR ffdff000
nt!_KPCR
+0x000 NtTib : _NT_TIB
...
+0x034 KdVersionBlock : 0x80555038
lkd> dd 0x80555038
0a28000f 030c014c 0000002d
804e0000 ffffffff ffffffff //这里分别是KernelBase和PsLoadedModuleList
...
805550a8 805694d8 //这里是PsLoadedModuleList和PsActiveProcessHead
805550b8 805695e0 8056ba08 //这里是PspCidTable和ExpSystemResourcesList
代码如下:
PHANDLE_TABLE PspCidTable;
_asm
{
mov eax,fs:[0x34]
mov eax,[eax+0x80]
mov eax,[eax]
mov PspCidTable,eax
}
DbgPrint("PspCidTable=0x%08X\n",PspCidTable);
二、如何遍历PspCidTable
第一种方法是使用导出的ExEnumHandleTable,优点是该函数导出了,用起来安全快捷
可能的缺点也是因为被导出了,所以比较容易被XX再XXX,不是足够可靠~
函数原型如下:
NTKERNELAPI
BOOLEAN
ExEnumHandleTable (
PHANDLE_TABLE HandleTable,
EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
PVOID EnumParameter,
PHANDLE Handle
);
typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
);
我们只要自己实现EnumHandleProcedure就可以了,传递给我们的参数有HANDLE_TABEL_ENTRY的指针和对应的句柄.
HandleTableEntry->Object就拿到对象了,接下来嘛,该干啥干啥~
BOOLEAN MyEnumerateHandleRoutine(
IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID EnumParameter
)
{
BOOLEAN Result=FALSE;
ULONG ProcessObject;
ULONG ObjectType;
ProcessObject=(HandleTableEntry->Value)&~; //掩去低三位 ObjectType=*(ULONG*)(ProcessObject-0x10);//取对象类型
if (ObjectType==(ULONG)PsProcessType)//判断是否为Process
{
(*(ULONG*)EnumParameter)++;
//注意PID其实就是Handle,而不是从EPROCESS中取,可以对付伪pid
DbgPrint("PID=%4d\t EPROCESS=0x%08X %s\n",Handle,ProcessObject,PsGetProcessImageFileName((PEPROCESS)ProcessObject));
}
return Result;//返回FALSE继续
}
然后这样调用:
ExEnumHandleTable(PspCidTable,MyEnumerateHandleRoutine,NULL,&hLastHandle);
好了,打开DebugView看结果吧,还不错~~
第二种方法就是自己遍历PspCidTable了,结构嘛前面已经清楚了,和普通句柄表结构一样,不难下手.
自己实现一个山寨的MyEnumHandleTable了,接口和ExEnumHandleTable一样~~
#define MAX_ENTRY_COUNT (0x1000/8) //一级表中的HANDLE_TABLE_ENTRY个数
#define MAX_ADDR_COUNT (0x1000/4) //二级表和三级表中的地址个数
BOOLEAN
MyEnumHandleTable (
PHANDLE_TABLE HandleTable,
MY_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
PVOID EnumParameter,
PHANDLE Handle
)
{
ULONG i,j,k;
ULONG_PTR CapturedTable;
ULONG TableLevel;
PHANDLE_TABLE_ENTRY TableLevel1,*TableLevel2,**TableLevel3;
BOOLEAN CallBackRetned=FALSE;
BOOLEAN ResultValue=FALSE;
ULONG MaxHandle;
//判断几个参数是否有效
if (!HandleTable
&& !EnumHandleProcedure
&& !MmIsAddressValid(Handle))
{
return ResultValue;
}
//取表基址和表的级数
CapturedTable=(HandleTable->TableCode)&~;
TableLevel=(HandleTable->TableCode)&;
MaxHandle=HandleTable->NextHandleNeedingPool;
DbgPrint("句柄上限值为0x%X\n",MaxHandle);
//判断表的等级
switch(TableLevel)
{
case :
{
//一级表
TableLevel1=(PHANDLE_TABLE_ENTRY)CapturedTable;
DbgPrint("解析一级表0x%08x...\n",TableLevel1);
for (i=;i<MAX_ENTRY_COUNT;i++)
{
*Handle=(HANDLE)(i*);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned=EnumHandleProcedure(&TableLevel1[i],*Handle,EnumParameter);
if (CallBackRetned) break;
}
}//end of for i
ResultValue=TRUE; }
break;
case :
{
//二级表
TableLevel2=(PHANDLE_TABLE_ENTRY*)CapturedTable;
DbgPrint("解析二级表0x%08x...\n",TableLevel2);
DbgPrint("二级表的个数:%d\n",MaxHandle/(MAX_ENTRY_COUNT*));
for (j=;j<MaxHandle/(MAX_ENTRY_COUNT*);j++)
{
TableLevel1=TableLevel2[j];
if (!TableLevel1)
break; //为零则跳出
for (i=;i<MAX_ENTRY_COUNT;i++)
{
*Handle=(HANDLE)(j*MAX_ENTRY_COUNT*+i*);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned=EnumHandleProcedure(&TableLevel1[i],*Handle,EnumParameter);
if (CallBackRetned) break;
//DbgPrint("Handle=%d\tObject=0x%08X\n",Handle,(TableLevel1[i].Value)&~3);
}
}//end of for i
}//end of for j
ResultValue=TRUE;
}
break;
case :
{
//三级表
TableLevel3=(PHANDLE_TABLE_ENTRY**)CapturedTable;
DbgPrint("解析三级表0x%08x...\n",TableLevel3);
DbgPrint("三级表的个数:%d\n",MaxHandle/(MAX_ENTRY_COUNT**MAX_ADDR_COUNT));
for (k=;k<MaxHandle/(MAX_ENTRY_COUNT**MAX_ADDR_COUNT);k++)
{
TableLevel2=TableLevel3[k];
if (!TableLevel2)
break; //为零则跳出
for (j=;j<MaxHandle/(MAX_ENTRY_COUNT*);j++)
{
TableLevel1=TableLevel2[j];
if (!TableLevel1)
break; //为零则跳出
for (i=;i<MAX_ENTRY_COUNT;i++)
{
*Handle=(HANDLE)(k*MAX_ENTRY_COUNT*MAX_ADDR_COUNT+j*MAX_ENTRY_COUNT+i*);
if (TableLevel1[i].Object && MmIsAddressValid(TableLevel1[i].Object))
{
//对象有效时,再调用回调函数
CallBackRetned=EnumHandleProcedure(&TableLevel1[i],*Handle,EnumParameter);
if (CallBackRetned) break;
//DbgPrint("Handle=%d\tObject=0x%08X\n",Handle,(TableLevel1[i].Value)&~3);
}
}//end of for i
}//end of for j
}//end of for k
ResultValue=TRUE;
}
break;
default:
{
DbgPrint("Shoud NOT get here!\n");
}
break;
}//end of switch
return ResultValue;
}
在回调函数中,我们可以根据情况作出具体处理.若是检测进程,就像我写的那样,检查一下对象类型是Process的就记录之~
若是抹PspCidTable,则将相应的Object清零,并设置到FirstFree,达到这个Handle就像真的被Destroy了一样的效果~
Futo_enhanced的驱动中是这样写的(稍稍改动了一下,假设是在抹掉一个EPROCESS):
p_tableEntry[a].Object = 0;
p_tableEntry[a].GrantedAccess = PspCidTable->FirstFree;
PspCidTable->FirstFree = pid ;
这里涉及到句柄的分配算法了.这样,基于PspCidTable的进程检测就歇菜了.但是上一篇的分析提到了,进线程退出时会调用ExDestroyHandle()销毁句柄,若找不到就会蓝屏.因此,必须在被保护的目标进程及其线程退出前的某个时候把抹掉的进线程对象再放回去.结束线程其实就是给线程插APC执行PspExitThread(),而PspExitThread()会调用PspCreateThreadNotifyRoutine,因此在这个回调中把线程对象放回去是合适的.同法,进程在退出时调用的PspExitProcess()也会执行PspCreateProcessNotifyRoutine,此时再把进程对象放回去.这里我想如不设置FirstFree为我们抹掉的句柄项,这个被我们抹掉的HANDLE_TABLE_ETNRY项会被保留吗?
另外也可以来个ObjectHook,Fuck掉PsProcessType->TypeInfo->DeleteProcedure和PsThreadType->TypeInfo->DeleteProcedure然后是隐藏掉的进程就照顾一下~~~
下面是PsProcessType的部分内容:
+0x02c DumpProcedure : (null)
+0x030 OpenProcedure : (null)
+0x034 CloseProcedure : (null)
+0x038 DeleteProcedure : 0x805d2cdc void nt!PspProcessDelete+0
+0x03c ParseProcedure : (null)
+0x040 SecurityProcedure : 0x805f9150 long nt!SeDefaultObjectMethod+0
+0x044 QueryNameProcedure : (null)
+0x048 OkayToCloseProcedure : (null)
总之,只要在PspCidTable中找到空位把目标进程的EPROCESS和ETHREAD再放回去,并且其索引与EPROCESS->UniqueProcessId和ETHREAD->Cid.UniqueThread保持一致就可以了.抽点时间写个隐藏进程的Demo练习下~~
【旧文章搬运】PspCidTable攻与防的更多相关文章
- 【旧文章搬运】更正一个枚举PspCidTable时的错误
原文发表于百度空间及看雪论坛,2009-02-27 看雪论坛地址:https://bbs.pediy.com/thread-82919.htm============================= ...
- 【旧文章搬运】PspCidTable概述
原文发表于百度空间,2009-03-28========================================================================== PspCi ...
- 【旧文章搬运】Windows句柄表分配算法分析(一)
原文发表于百度空间,2009-03-30========================================================================== 阅读提示: ...
- 【旧文章搬运】Windbg+Vmware驱动调试入门(四)---VirtualKD内核调试加速工具
原文发表于百度空间,2009-01-09========================================================================== 今天又想起 ...
- 【旧文章搬运】深入分析Win7的对象引用跟踪机制
原文发表于百度空间及看雪论坛,2010-09-12 看雪论坛地址:https://bbs.pediy.com/thread-120296.htm============================ ...
- 【旧文章搬运】Win7 OBJECT_HEADER之TypeIndex解析
原文发表于百度空间,2010-08-09========================================================================== 在Wind ...
- 【旧文章搬运】分析了一下360安全卫士的HOOK(二)——架构与实现
原文发表于百度空间及看雪论坛,2009-10-14 看雪论坛地址:https://bbs.pediy.com/thread-99460.htm 刚发这篇文章的时候,因为内容涉及360的核心产品,文章被 ...
- 【旧文章搬运】再谈隐藏进程中的DLL模块
原文发表于百度空间,2009-09-17========================================================================== 相当老的话 ...
- 【旧文章搬运】Windows句柄分配算法(二)
原文发表于百度空间,2009-04-04========================================================================== 在创建句柄 ...
随机推荐
- 洛谷 P1034 矩形覆盖
P1034 矩形覆盖 题目描述 在平面上有nn个点(n \le 50n≤50),每个点用一对整数坐标表示.例如:当 n=4n=4 时,44个点的坐标分另为:p_1p1(1,11,1),p_2p2( ...
- jquery 禁用/启用滚动条
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Python机器学习--手写体识别(KNN+MLP)
MLP实现 调整参数比较性能结果 # -*- coding: utf-8 -*- """ Created on Wed Aug 30 21:14:38 2017 @aut ...
- Spring boot 整合spring Data JPA+Spring Security+Thymeleaf框架(上)
近期上班太忙所以耽搁了给大家分享实战springboot 框架的使用. 以下是spring boot 整合多个框架的使用. 首先是准备工作要做好. 第一 导入框架所需的包,我们用的事maven 进行 ...
- JNI基础知识
JNI是在学习Android HAL时必须要面临一个知识点,假设你不了解它的机制,不了解它的使用方式,你会被本地代码绕的晕头转向,JNI作为一个中间语言的翻译官在运行Java代码的Android中有着 ...
- BUPT复试专题—字符串转换(2013计院)
题目描述 我们将仅由若干个同一小写字母构成的字符串称之为简单串,例如"aaaa"是一个简单串,而"abcd"则不是简单串.现在给你一个仅由小写字母组成的字符串, ...
- Unity3d插件]EasyTouch简单使用方法
EasyTouch使用 EasyTouch 文件夹[-] 一.效果图 二.操作步骤 1.官方文档上的步骤 2.翻译一下以上的步骤 3.依据官方的这些提示.自己来做一个属于自己的人物遥感控制 对于移动平 ...
- 杭电1708Fibonacci String
Fibonacci String Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 课程的正确步调——Leo鉴书74
<Leo鉴书(第1辑)>已登陆百度阅读.今后还将不断更新,免费下载地址:http://t.cn/RvawZEx 本人第一次站上讲台是1999年,那会儿从中关村回到天津,在一个给成人做计算机 ...
- Java学习之集合
1.ArrayList:采用数组的形式保存对象,这种方式将对象保存在连续的位置中,所以查询效率比较高,但是插入删除时麻烦,并且ArrayList不是线程安全的. 2.Vector:保存对象的方式与Ar ...