如何列出隐藏的进程?

yyy6 2006-07-26 03:15:54
HANDLEhSnapShot;
PROCESSENTRY32procEntry;

memset(&procEntry, 0, sizeof(procEntry));
procEntry.dwSize = sizeof(procEntry);
hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (hSnapShot != (HANDLE)(-1))
{
if (Process32First(hSnapShot, &procEntry))
{
CString strPath ="";
do
{

CString strProcName=procEntry.szExeFile;
MessageBox(strProcName);

}while(Process32Next(hSnapShot, &procEntry));
}
CloseHandle(hSnapShot);
}
MessageBox("finished.");

结果没有隐藏的进程,而icesword工具可以看到。
如何列出隐藏的进程?
...全文
220 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
ringphone 2006-07-27
  • 打赏
  • 举报
回复
mark
DrSmart 2006-07-26
  • 打赏
  • 举报
回复
00ac: Object: e3065800 GrantedAccess: 00020019
Object: e3065800 Type: (8141b0c0) Key
ObjectHeader: e30657e8
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: REGISTRYMACHINESYSTEMControlSet001
ControlNlsLanguage Groups

首先从进程的 EPROCESS 结构中获得 HANDLE_TABLE 结构的地址
kd> !strct eprocess 82592ae0
!strct eprocess 82592ae0
struct _EPROCESS (sizeof=648)
...
+128 struct _HANDLE_TABLE *ObjectTable = 824E08E8
...

从 HANDLE_TABLE 结构中的 +08 struct _HANDLE_TABLE_ENTRY ***Table 找到句柄表
kd> !strct handle_table 824E08E8
!strct handle_table 824E08E8
struct _HANDLE_TABLE (sizeof=108)
+00 uint32 Flags = 00000000
+04 int32 HandleCount = 0000001f
+08 struct _HANDLE_TABLE_ENTRY ***Table = E3073000
+0c struct _EPROCESS *QuotaProcess = 82592AE0
+10 void *UniqueProcessId = 00000254
+14 int32 FirstFreeTableEntry = 00000021
+18 int32 NextIndexNeedingPool = 00000100
...
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink = 835CC9DC
+58 struct _LIST_ENTRY *Blink = 8105449C
+5c struct _KEVENT HandleContentionEvent
...
+68 struct _LIST_ENTRY *Blink = 824E094C

句柄表的上层表地址为 E3073000,现在我们开始寻找句柄为 0x44 对应的对象

// 句柄 0x44,的上层索引,bits18-25的值为0,偏移为0*4。
// 对应的中层表的地址为 e3073400
kd> dd E3073000+0*4 l 4
dd E3073000+0*4 l 4
e3073000 e3073400 00000000 00000000 00000000

// 句柄 0x44,的中层索引,bits10-17的值为0,偏移为0*4。
// 对应的下层表的地址为 e3073800
kd> dd e3073400+0*4 l 4
dd e3073400+0*4 l 4
e3073400 e3073800 00000000 00000000 00000000

// 句柄 0x44,bits0-9的值为0x44, HANDLE_TABLE_ENTRY 在下层表中的偏移为 0x44*2
kd> dd e3073800+44*2 l 8
dd e3073800+44*2 l 8
e3073888 6139af08 000f003f 62beecc8 000f003f
e3073898 010e86b8 0002000f 010c9cf8 001f0003

我们找到了句柄 0x44 对应的 HANDLE_TABLE_ENTRY,它的第一个32bit,值为 6139af08 ,不空。
我们把它转换为对象指针。

// 转换成对象头的指针,把低3bit设为0,最高位设为1。
// 由于 6139af08 低三位为0,所以不用设置。最高位不为1,通过加 80000000 ,来设置成1。
kd> ? 80000000+6139af08
? 80000000+6139af08
Evaluate expression: -516313336 = e139af08

// 对象指针是对象体的指针,等于对象头指针加0x18
kd> ? e139af08+18
? e139af08+18
Evaluate expression: -516313312 = e139af20

得到了对象指针 e139af20

// 使用 !object 命令,来分析对象。
kd> !object e139af20
!object e139af20
Object: e139af20 Type: (8141b0c0) Key
ObjectHeader: e139af08
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: REGISTRYMACHINE

可以看到这个对象就是前面使用 !handle 命令时,看到的那个对象。
通过句柄 0x44 我们找到了相应的对象。

句柄表所消耗的内存

当进程打开的对象不超过大约256个时,系统只为句柄表分配一个上层表,大小为1KB。一个中层表,大小为1KB。一个下层表,大小为2KB。正好可以放在同一个物理页中。当进程打开的对象超过大约256个时,系统会再分配2个下层表,放在同一个物理页,并把这2个下层表的地址,填入中层表的相应项,这样就可以存放大约256*3=768 个对象的对象头指针。绝大多数情况下,这就够用了。

所以绝大多数情况下,进程的句柄表消耗的物理内存为4K(打开的对象不超过大约256个时)或者8K(打开的对象不超过大约768个时)。

下面我们来看一下刚才进程 internat.exe 的句柄表的情况
上层表地址为 e3073000,上层表第一项对应的中层表地址为 e3073400,
上层表第一项对应的中层表的第一项对应的下层表地址为 e3073800
正是在同一页上,我们显示这一页中的全部内容

kd> dd e3073000 l 400
dd e3073000 l 400
e3073000 e3073400 00000000 00000000 00000000
e3073010 00000000 00000000 00000000 00000000
...
e30733f0 00000000 00000000 00000000 00000000
e3073400 e3073800 00000000 00000000 00000000
e3073410 00000000 00000000 00000000 00000000
...
e30737e0 00000000 00000000 00000000 00000000
e30737f0 00000000 00000000 00000000 00000000
e3073800 00000000 00000001 613d7bf8 000f001f
e3073810 0236a3e8 00100003 01092948 00100003
e3073820 02244748 00100003 010f5f18 00000003
e3073830 0132a7b2 00100020 010f6878 000f000f
e3073840 021fb2a8 00100003 613b3e19 001f0001
e3073850 010e84c8 00000001 61390498 000f001f
e3073860 0108a529 001f0003 010c9220 000f037f
e3073870 010c3dc0 000f01ff 010c9220 000f037f
e3073880 02469968 00100003 6139af08 000f003f
e3073890 62beecc8 000f003f 010e86b8 0002000f
e30738a0 010c9cf8 001f0003 02469d28 001f0003
e30738b0 02469ce8 001f0001 02469ca8 001f0003
e30738c0 02469c68 001f0001 61371d88 000f003f
e30738d0 6139a508 000f003f 63418e08 000f003f
e30738e0 00000000 0000002c 613d20c8 000f0007
e30738f0 00000000 0000001c 00000000 00000020
e3073900 00000000 00000023 00000000 00000022
e3073910 00000000 00000025 00000000 00000024
e3073920 00000000 0000001e 00000000 00000026
e3073930 00000000 00000027 00000000 00000028
e3073940 00000000 0000001f 613c75c8 00020019
e3073950 61325c28 00020019 630657e8 00020019
e3073960 00000000 0000002d 00000000 0000002e
...
e3073fe0 00000000 000000fd 00000000 000000fe
e3073ff0 00000000 000000ff 00000000 ffffffff

HANDLE_TABLE 链

在 Win2k Build 2195 中,所有进程(包括 Idle 进程 )的 HANDLE_TABLE 结构通过 HANDLE_TABLE 结构偏移 +54 处的 LIST_ENTRY HandleTableList 链在一起。

+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink
+58 struct _LIST_ENTRY *Blink

通过全局变量 HandleTableListHead 可以找到这个链。
对于 Win2k Build 2195 ,HandleTableListHead 地址为 8046a140,该地址开始处为一个 LIST_ENTRY 结构。

DrSmart 2006-07-26
  • 打赏
  • 举报
回复
以下是icesword早期版本使用的方法,但是对付现在部分木马还要配合线程环境切换考虑
注意每个系统都不一样,且还要考虑sp,win2000和xp以后的变化比较大,这个工作其实在vista上就可以不用考虑了,保护的太严密了还有那个UAC

Win2k Build 2195 中 EPROCESS 偏移+128 处的 struct HANDLE_TABLE *ObjectTable ,就是指向该进程 HANDLE_TABLE 结构的指针。通过一个进程的 HANDLE_TABLE 结构,我们可以找到这个进程打开的所有对象。我们在程序中获得的各种句柄,就是对象在句柄表中的索引。例如,在程序中打开文件,获得的是一个句柄(HANDLE)。接下来通过这个句柄来对这个文件进行操作。句柄是该文件对象在句柄表中的索引,通过句柄,就可以在句柄表中找到相应的文件对象的指针。就可以对该文件对象进行相应的操作。

通过 EPROCESS 的 +128 struct HANDLE_TABLE *ObjectTable 我们可以找到一个进程的 HANDLE_TABLE 结构,通过 HANDLE_TABLE 结构的 +08 struct _HANDLE_TABLE_ENTRY ***Table 我们可以找到这个进程的句柄表。这个表中放着进程的所有对象的指针。句柄表分三层,最上层表是一个大小为1KB的数组,共有256个元素,每个元素4个字节长,每个元素是一个指向中层表的指针。中层表也是一个大小为1KB的数组,共有256个元素,每个元素4个字节长,每个元素是一个指向下层表的指针。下层表是一个 HANDLE_TABLE_ENTRY 数组,整个数组大小为2KB,共有256个元素,每个元素8个字节长,是一个 HANDLE_TABLE_ENTRY ,HANDLE_TABLE_ENTRY 中保存着指向对象的指针。一个进程有一个上层表,一个上层表最多可以有256个中层表。每个中层表最多可以有256个下层表。每个下层表最多可以有256个对象的指针。


一个句柄被分为三部分,分别做这三个表中的索引,最低10bit(bits0-9)的值乘以2,就得到了在下层表中的偏移。bits10-17这8bit,为中层表的索引,乘以4得到在中层表中的偏移。bits18-25这8bit,为高层表的索引,乘以4得到在高层表中的偏移。

对于一个句柄,我们最后可以在一个下层表中找到对应的 HANDLE_TABLE_ENTRY。HANDLE_TABLE_ENTRY 大小为 8 个字节,由2个32bit组成。如果第一个32bit值不为0,那么第一个32bit就可以转换成一个指向对象头的指针。由于对象头总是32bit对齐的,所以一个对象头的指针的低3bit总是0。所以 HANDLE_TABLE_ENTRY 第一个32bit 的低3bit,被用作标志。由于所有的对象都在系统地址空间(0x80000000-0xFFFFFFFF)中,所以一个对象头的指针的最高位总是1。所以 HANDLE_TABLE_ENTRY 第一个32bit 的最高位也被用作标志。当我们把一个
HANDLE_TABLE_ENTRY 第一个32bit 转换成对象头的指针时,需要把低3bit设为0,最高位设为1。对象指针总是指的对象体的指针,由于对象头在对象体之前,大小为0x18字节,所以对象指针等于对象头指针加0x18。

HANDLE_TABLE 结构在 Win2k Build 2195 中定义如下

kd> !strct HANDLE_TABLE
!strct HANDLE_TABLE
struct _HANDLE_TABLE (sizeof=108)
+00 uint32 Flags
+04 int32 HandleCount
+08 struct _HANDLE_TABLE_ENTRY ***Table
+0c struct _EPROCESS *QuotaProcess
+10 void *UniqueProcessId
+14 int32 FirstFreeTableEntry
+18 int32 NextIndexNeedingPool
+1c struct _ERESOURCE HandleTableLock
+1c struct _LIST_ENTRY SystemResourcesList
+1c struct _LIST_ENTRY *Flink
+20 struct _LIST_ENTRY *Blink
+24 struct _OWNER_ENTRY *OwnerTable
+28 int16 ActiveCount
+2a uint16 Flag
+2c struct _KSEMAPHORE *SharedWaiters
+30 struct _KEVENT *ExclusiveWaiters
+34 struct _OWNER_ENTRY OwnerThreads[2]
uint32 OwnerThread
int32 OwnerCount
uint32 TableSize
+44 uint32 ContentionCount
+48 uint16 NumberOfSharedWaiters
+4a uint16 NumberOfExclusiveWaiters
+4c void *Address
+4c uint32 CreatorBackTraceIndex
+50 uint32 SpinLock
+54 struct _LIST_ENTRY HandleTableList
+54 struct _LIST_ENTRY *Flink
+58 struct _LIST_ENTRY *Blink
+5c struct _KEVENT HandleContentionEvent
+5c struct _DISPATCHER_HEADER Header
+5c byte Type
+5d byte Absolute
+5e byte Size
+5f byte Inserted
+60 int32 SignalState
+64 struct _LIST_ENTRY WaitListHead
+64 struct _LIST_ENTRY *Flink
+68 struct _LIST_ENTRY *Blink

kd> !strct HANDLE_TABLE_ENTRY
!strct HANDLE_TABLE_ENTRY
struct _HANDLE_TABLE_ENTRY (sizeof=8)
+0 void *Object
+0 uint32 ObAttributes
+4 uint32 GrantedAccess
+4 uint16 GrantedAccessIndex
+6 uint16 CreatorBackTraceIndex
+4 int32 NextFreeTableEntry

下面我们使用 kd 来进行说明

kd> !process 0 0
!process 0 0
**** NT ACTIVE PROCESS DUMP ****
...

PROCESS 82592ae0 SessionId: 0 Cid: 0254 Peb: 7ffdf000 ParentCid: 0240
DirBase: 02611000 ObjectTable: 824e08e8 TableSize: 31.
Image: internat.exe
...

// 我们就以进程 internat.exe 为例,注意 ObjectTable: 824e08e8 TableSize: 31

// 使用 !handle 命令,查看 PID为254 的进程的句柄表中的对象
kd> !handle 0 3 254
!handle 0 3 254
processor number 0
Searching for Process with Cid == 254
PROCESS 82592ae0 SessionId: 0 Cid: 0254 Peb: 7ffdf000 ParentCid: 0240
DirBase: 02611000 ObjectTable: 824e08e8 TableSize: 31.
Image: internat.exe

Handle Table at e3073000 with 31 Entries in use
0004: Object: e13d7c10 GrantedAccess: 000f001f
Object: e13d7c10 Type: (8141b760) Section
ObjectHeader: e13d7bf8
HandleCount: 1 PointerCount: 1

0008: Object: 8236a400 GrantedAccess: 00100003
Object: 8236a400 Type: (8141e460) Event
ObjectHeader: 8236a3e8
HandleCount: 1 PointerCount: 1

...

0044: Object: e139af20 GrantedAccess: 000f003f
Object: e139af20 Type: (8141b0c0) Key
ObjectHeader: e139af08
HandleCount: 1 PointerCount: 1
Directory Object: 00000000 Name: REGISTRYMACHINE
进程句柄为 0044 的对象,下面我们将自己通过句柄表找到句柄为44的对象
记住对象的名字 Name: REGISTRYMACHINE
...

15,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧