[note]枚举进程之二(句柄表分析篇)

继续接着上篇,这一篇说下句柄表,关于handletable,其实也已经相当科普了~基础知识还是学习下吧.

继续引用下V大的思路.

 3.通过pspCidTable获得进程表c
4.通过handletablelisthead获得进程表d
5.通过csrss的handletable用2种方法枚举获得进程表e和f
6.通过扫描当前进程的handletable获得进程表g

 

在解释如何通过这些思路枚举进程的时候,我们还是先来熟悉下句柄表吧.

在这里推荐阅读教主的<<Windows句柄表格式>>

 

在Windows中,每一个进程都有一个句柄表(handletable),

在EPROCESS进程对象中,+0xc4,就能找到句柄表指针.

lkd> dt _eprocess 899af020 
nt!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER 0x1cb5694`beedc756
   +0x078 ExitTime         : _LARGE_INTEGER 0x0
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : 0x000014f4
   +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x805648b8 - 0x89b5e6a8 ]
   +0x090 QuotaUsage       : [3] 0x1068
   +0x09c QuotaPeak        : [3] 0x1068
   +0x0a8 CommitCharge     : 0x716
   +0x0ac PeakVirtualSize  : 0x37f4000
   +0x0b0 VirtualSize      : 0x37cd000
   +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0xba5dc014 - 0x89b5e6d4 ]
   +0x0bc DebugPort        : (null)
   +0x0c0 ExceptionPort    : 0xe2206aa0
   +0x0c4 ObjectTable      : 0xe6766350 _HANDLE_TABLE

 

而句柄表是一个_HANDLE_TABLE 结构.下面就来看看这个结构的成员.

lkd> dt _HANDLE_TABLE 0xe6766350
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0xe1e64000 //指向句柄表的存储结构,真正意义上的动态三层句柄表.
   +0x004 QuotaProcess     : 0x899af020 _EPROCESS // 所属进程的EPRCESS,这里是枚举进程所需要的~
   +0x008 UniqueProcessId  : 0x000014f4   // 所属进程的PID
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK // 句柄表锁,仅在句柄表扩展时使用, HANDLE_TALBE_LOCKS = 4
   +0x01c HandleTableList  : _LIST_ENTRY [ 0x80565ba8 - 0xe4330bcc ] // 句柄表的双链.将系统范围内所有的句柄表链接在一起,这是枚举进程所需要的,

//其实和 ActiveList 是同一个道理,隐藏也是一样的.而这一个双链结构的链表头就是HandleTableListHead,那么表g和表d的实现就很容易了~
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null)
   +0x02c ExtraInfoPages   : 0
   +0x030 FirstFree        : 0x180
   +0x034 LastFree         : 0
   +0x038 NextHandleNeedingPool : 0x800  // 下一次句柄表扩展的起始句柄索引.其实也就是当前句柄表池的上界.
   +0x03c HandleCount      : 93  //正在使用的句柄表数量.
   +0x040 Flags            : 0
   +0x040 StrictFIFO       : 0y0

 

通过上面的分析,表g和表d的实现其实已经呼之欲出了:使用PsGetCurrentProcess()获得当前的EPROCESS结构pCurrentProcess;

然后pHandleTable=pCurrentProcess + 0xc4;然后获得HandleTable结构.再然后遍历那个_List_Entry,就能遍历所有进程的Handle_Table,

然后就获得所有进程的EPROCESS,从而实现对进程的枚举.

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
NTSTATUS HandletablelistheadEnumProcess()
{
PLIST_ENTRY HanTableListHead
= NULL;
NTSTATUS nResult;
PLIST_ENTRY CurrTable
= NULL;
PEPROCESS PEprocess
= NULL;
PLIST_ENTRY HandleTableList
= NULL;
ULONG ulNeededSize, uLoop, uKernelSta,NtoskrnlLast;
PMODULE_LIST pModuleList
= NULL;
// 获取内核模块基址
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
{

return STATUS_UNSUCCESSFUL;
}
ZwQuerySystemInformation(SystemModuleInformation,
& ulNeededSize, 0 , & ulNeededSize);
pModuleList
= (PMODULE_LIST)ExAllocatePoolWithTag(NonPagedPool, ulNeededSize, ' han ' );
nResult
= ZwQuerySystemInformation(SystemModuleInformation, pModuleList, ulNeededSize, NULL);
if (NT_SUCCESS(nResult))
{
// ntoskrnl is always first there
uKernelSta = (ULONG) pModuleList -> a_Modules[ 0 ].p_Base;
NtoskrnlLast
= (ULONG) pModuleList -> a_Modules[ 0 ].p_Base + (ULONG) pModuleList -> a_Modules[ 0 ].d_Size;
}
ExFreePoolWithTag(pModuleList,
' han ' );
// 获取Handletablelisthead地址
PHANDLE_TABLE HandleTable =* (PHANDLE_TABLE * )((ULONG)PsGetCurrentProcess() + HandleTableOffset);
HandleTableList
= (PLIST_ENTRY)((ULONG)HandleTable + HandleTableListOffset);
for (CurrTable = HandleTableList -> Flink;CurrTable != HandleTableList;CurrTable = CurrTable -> Flink)
{
if ((ULONG)CurrTable > uKernelSta && (ULONG)CurrTable < NtoskrnlLast)
{
HanTableListHead
= CurrTable;
break ;
}

}

// 开始枚举
for (CurrTable = HanTableListHead -> Flink;
CurrTable
!= HanTableListHead;
CurrTable
= CurrTable -> Flink)
{
PEprocess
= * (PEPROCESS * )((PUCHAR)CurrTable - HandleTableListOffset + QuotaProcessOffset);
if (PEprocess)
{

FindAndCheckProcess(FALSE,(ULONG)PEprocess);
}
}

return STATUS_SUCCESS;
}

通过扫描当前进程的handletable获得进程表g

通过handletablelisthead获得进程表d

枚举的思路还是和上面一样,关键是要获取handletablelisthead的地址.

要找到HeadleTableListHead,我们要注意到HandleTableListHead是一个全局的内核变量,

因此它一定是在内核文件的某一个段(Section)里面,并且HandleTableList的其他成员是在动态分配的内存中,

所以总是受到内核地址空间的限制。根据这些,我们需要得到任何一个进程的HandleTable的指针,

然后遍历链表直到找到定位在这个内核地址空间的成员,那么这个成员就是HandleTableListHead了. 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
// 通过自身的HANDLETABLE枚举进程
NTSTATUS FromCruentProEnumProcess()
{
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
{

return STATUS_UNSUCCESSFUL;
}
PEPROCESS PCurrentProc
= IoGetCurrentProcess();

PLIST_ENTRY CurrList
= NULL;
PEPROCESS PEprocess,Ptemp
= PCurrentProc;
ULONG Phandle;
PLIST_ENTRY PCurrentHandleList
= NULL;
// __
// HandleTableOffset = 0xc4
// HandleTableListOffset = 0x1c
// QuotaProcessOffset = 0x04
do
{
Phandle
= (ULONG)( * (PULONG)((ULONG)PCurrentProc + HandleTableOffset));

PCurrentHandleList
= (PLIST_ENTRY)(Phandle + HandleTableListOffset);
CurrList
= PCurrentHandleList -> Flink;


// __
PEprocess = * (PEPROCESS * )((PUCHAR)CurrList - HandleTableListOffset + QuotaProcessOffset);
if (PEprocess)
{
// FindAndCheckProcess()函数检测进程的有效性..
FindAndCheckProcess(FALSE,(ULONG)PEprocess);
}
else
{
return STATUS_UNSUCCESSFUL;
}
// ULONG Phandle=(ULONG)(*(PULONG)((ULONG)PCurrentProc+HandleTableOffset));
PCurrentProc = PEprocess;

}
while (PCurrentProc != Ptemp);

return STATUS_SUCCESS;

}

 

 

转载于:https://www.cnblogs.com/Tbit/archive/2010/09/18/1828524.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值