原创】PspCidTable杂谈
来源:互联网 发布:网络协查函怎么开 编辑:程序博客网 时间:2024/04/30 14:04
标 题: 【原创】PspCidTable杂谈
作 者: sudami
时 间: 2008-02-15,21:31
链 接: http://bbs.pediy.com/showthread.php?t=59680
今天再次看了gz1X牛的文章,回忆了许多知识. 哈哈. 玩了很长时间游戏,写点儿文字算是对自责的一种安慰
要说R0枚举隐藏进程, 只是对没有抹掉PspCidTable而言的.gz1X牛提示了2种方法:
偶觉得都不是很保险(假设暂且PspCidTable没有被抹掉), ExEnumHandleTable、PsLookupProcessByProcessId等都可以做手脚,简单的inline hook之类的.再说这些函数最终还是通过 PHANDLE_TABLE结构中的TableCode得到一些HANDLE_TABLE_ENTRY,到其中的Object里,取得相应的进程对象. 还不如自己来完成,嘿嘿. 安全感啊~
"第8个男人" 的code里面就做的很好,找到PspCidTable后自己搜索所有的进程对象就行了:
//----------------------------------------------------------------------
VOID
IsValidProcess ()
/*++
Author : 第8个男人
Leaner : sudami [xiao_rui_119@163.com]
Time : 08/02/15
参数 : NULL
返回 : NULL
功能 :
给出PspCidTable的地址,结合_EXHANDLE、HANDLE_TABLE、HANDLE_TABLE_ENTRY
搜索到每个进程对象,纪录之.
前提条件: 假设暂且PspCidTable没有被抹掉
--*/
{
ULONG PspCidTable;
ULONG TableCode;
ULONG table1,table2;
ULONG object,objectheader;
ULONG NextFreeTableEntry;
ULONG processtype,type;
ULONG flags;
ULONG i;
PspCidTable = GetCidAddr(); // 搜索PsLookupProcessByProcessId函中的特征串即可
processtype = GetProcessType();
if (PspCidTable == 0) {
return ;
} else { //TableCode的低2位决定句柄表的级数
TableCode = *(PULONG) ( *(PULONG) PspCidTable );
if ( (TableCode & 3) == 0 ) { // 0级
table1 = TableCode;
table2 = 0;
} else if ( (TableCode & 3 ) == 1 ) { // 1级
TableCode = TableCode & 0xfffffffc;
table1 = *(PULONG)TableCode;
table2 = *(PULONG)( TableCode + 4 );
}
// 对cid从0x0到0x4e1c进行遍历
for (i = 0; i < 0x4e1c; i++) {
if (i <= 0x800) { // 第一张表中
if (MmIsAddressValid( (PULONG)(table1 + i*2) )) {
// HANDLE_TABLE_ENTRY地址 + PID * 2 ---> 对象的地址
object = *(PULONG)( table1 + i*2 );
if (MmIsAddressValid( (PULONG)(table1 + i*2 + NEXTFREETABLEENTRY) )) {
// 验证HANDLE_TABLE_ENTRY的合法性,这在ExEnumHandleTable函数的代码中也有
// 正常的_HANDLE_TABLE_ENTRY中NextFreeTableEntry应该为0
NextFreeTableEntry = *(PULONG)(table1 + i*2 + NEXTFREETABLEENTRY);
if (NextFreeTableEntry == 0) {
// 去掉低3位掩码标志
object = ((object | 0x80000000) & 0xfffffff8); // 转换为对象(体)指针
objectheader = (ULONG) /
OBJECT_TO_OBJECT_HEADER(object); // 获取对象(头)指针
if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);
if (type == processtype) { // 是否为进程对象
flags = *(PULONG)( (ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS) );
if ((flags&0xc) != 0xc)
RecordInfo( object ); //flags显示进程没有退出
}
}
}
}
}
} else { // 第2张表
if (table2 != 0) {
// 步骤同上,只是object的获取为: HANDLE_TABLE_ENTRY地址 + (PID- 0x800)*2
if (MmIsAddressValid( (PULONG)(table2 + (i - 0x800)*2) )) {
object = *(PULONG)(table2 + (i - 0x800)*2);
if (MmIsAddressValid((PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY))) {
NextFreeTableEntry=*(PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY);
if (NextFreeTableEntry==0x0) {
object = ((object | 0x80000000) & 0xfffffff8);
objectheader = (ULONG) OBJECT_TO_OBJECT_HEADER(object);
if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);
if(type == processtype) {
flags = *(PULONG) ((ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS));
if ((flags&0xc) != 0xc)
RecordInfo(object);
}
}
}
}
}
}
}
}
}
}
当然,用ExEnumHandleTable也是不错的. Windbg把它的实现看了一遍, 和WRK上的无任何出入[XP SP2], 实现起来也很方便
R3下就更简单了.一阵OpenProcess就把部分隐藏进程揪出来了:
#include <iostream.h>
#include <stdio.h>
#include <windows.h>
void main()
{
int a = 0;
for (int i=0;i<=65535;i+=4) {
if(OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,i)!= 0) {
a++;
cout << "ProcessID: " << i << endl;
CloseHandle(&i);
}
}
cout << "Total Counts = " << a << endl;
}
不过俺看了下,好像有些进程没有显示出来,比如SVCHOST.exe、SMSS.EXE...
嘿嘿,结合下面这些就更好搞了 [V大语录]:
其实,隐藏进程越来越难了,保护进程还让其稳定更加不易. 但俺们小菜还是需要掌握这些老掉的技术的,不断学习,不断进步
目前通过job杀进程MS很流行,内存清零也很厉害(就怕attach不上),插APC,杀线程之流的....杀杀IS等不在话下.
不过一般搜索到未导出的PspTerminateProcessByPointer,再深入点儿把这个函数,甚至PspExitThread 都自己实现一遍(用Windbg看了遍PspTerminateThreadByPointer,发现和WRK上的一样.哈哈,没有任何出入 [XP SP2]), Kill掉大部分进程是木有问题的,不过像KV2008这样猥亵的家伙在投递APC上下了手脚,就要先恢复了inline hook再杀了.
炉子牛的R0那个干掉KV2008的好像就是这样搞的.哈哈, 丢个驱动在这里,供有兴趣的IDA look之(应该无壳). R3下搞KV 炉子出了个录象,很神秘的样子,不过好像是成功了.哈哈
对了.炉子牛(又是炉子...)放了个simple task, R3下的简单管理器 [VB],---
检测隐藏进程的思路很科普:
一个EnumProcess or ToolHelp32来做对照, 一个ZwQuerySsytemInformation来走过场,一个从0 到65535的遍历OpenProcess来达到PspCidTable的效果. 3个途径来扫盲式的检测,方法是科普点儿.
结束进程部分很扫盲(原作者: EST的willy123牛):
ZwCreateJobObject-->ZwAssignProcessToJobObject-->ZwTerminateJobObject
对付IS这样inlie hook 了NtOpenProcess等的就用了一种很和谐的方法,FlowerCode提供滴.不过是VB写的, 俺无聊把其转化为了C描述,方便些:
//--------------------------------------------------------------
// btw: 头文件的那些申明自己写咯~
// 调用前要有SE_DEBUG权限
HANDLE
SDM_OpenProcess (
DWORD dwDesiredAccess,
BOOL bInhert,
DWORD ProcessId,
BOOL bOpenIt,
LPDWORD aryPids
)
/*++
原作者 : FlowerCode | 炉子 [VB]
转换者 : sudami [xiao_rui_119@163.com] [C]
Time : 08/02/12
参数 :
dwDesiredAccess - 希望以怎样的方式打开进程
bInhert - 是否有继承权限
ProcessId - PID
bOpenIt - 是要打开进程,还是要保存所有进程ID
paryPids - 保存PID的数组
返回 :
成功 - 指定的进程句柄
失败 - 0
功能 :
1. 复制来复制去,总之是要获得指定进程的句柄
2. 用普通方法得到所有进程ID
--*/
{
ULONG cbBuffer = 0x1000; //先设定一个较小的缓冲空间
ULONG uRetSzie;
ULONG NumOfHandle = 0;
PCHAR pBuffer = NULL;
PVOID pOneEprocess = 0;
CLIENT_ID cid;
NTSTATUS st;
OBJECT_ATTRIBUTES oa;
PROCESS_BASIC_INFORMATION pbi;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO h_info;
HANDLE hProcessToDup, hProcessCur, hProcessToRet;
oa.Length = sizeof (OBJECT_ATTRIBUTES);
oa.RootDirectory = 0;
oa.ObjectName = 0;
oa.Attributes = 0;
oa.SecurityDescriptor = 0;
oa.SecurityQualityOfService = 0;
if (bInhert) {
oa.Attributes |= OBJ_INHERIT;
}
if (bOpenIt) {
// 看能否直接得到句柄
cid.UniqueProcess = (HANDLE) (ProcessId + 1);
cid.UniqueThread = 0;
st = NtOpenProcess (&hProcessToRet, dwDesiredAccess, &oa, &cid);
if (NT_SUCCESS (st)) {
return hProcessToRet;
}
::MessageBox (NULL, "NtOpenProcess 失败", "=。=!", MB_OK);
}
// 传递16号获得所有句柄,可能被hook过;不管了,走过场~
do {
st = ZwQuerySystemInformation( /*SystemHandleInformation*/16, /
pBuffer, cbBuffer, &uRetSzie );
if (st == STATUS_INFO_LENGTH_MISMATCH) {
free( pBuffer);
cbBuffer *= 2;
pBuffer = (PCHAR) malloc (cbBuffer);
} else if ( !NT_SUCCESS (st) ) {
free( pBuffer);
::MessageBox (NULL, "ZwQuerySystemInformation失败", ".", MB_OK);
return 0;
}
} while (st == STATUS_INFO_LENGTH_MISMATCH);
NumOfHandle = (ULONG) pBuffer;
h_info = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO) ( (ULONG)pBuffer + 4 );
/*
// 获得进程对象类型
pOneEprocess = h_info[0].Object;
g_pObjectTypeProcess = *(PULONG) ( (ULONG)pOneEprocess - OBJECT_HEADER_SIZE /
+ OBJECT_TYPE_OFFSET );
*/
for (ULONG i = 0; i < NumOfHandle; i++) {
aryPids[i] = h_info[i].UniqueProcessId;
if (bOpenIt) {
::MessageBox (NULL, "333", "=。=!", MB_OK);
if ( 5 == h_info[i].ObjectTypeIndex) { // 是进程的句柄,打开它
cid.UniqueProcess = (HANDLE)h_info[i].UniqueProcessId;
st = NtOpenProcess (&hProcessToDup, PROCESS_DUP_HANDLE, &oa, &cid);
if (NT_SUCCESS (st)) { // 复制该句柄后赋予全部权限,以便调用ZwQuery*时顺利进行
st = ZwDuplicateObject (hProcessToDup, (PHANDLE)h_info[i].HandleValue, (HANDLE)-1,/
&hProcessCur, PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ATTRIBUTES);
if (NT_SUCCESS (st)) { // 查看复制的句柄是否为我们想要的
st = ZwQueryInformationProcess (hProcessCur, ProcessBasicInformation,/
&pbi, sizeof(pbi), 0);
if (NT_SUCCESS (st)) {
if (ProcessId == pbi.UniqueProcessId ) {
// 若是想要的PID,就把该句柄按照希望的访问权限复制,然后返回
st = ZwDuplicateObject (hProcessToDup, (PHANDLE)h_info [i].HandleValue,/
(HANDLE)-1, &hProcessToRet, dwDesiredAccess,/
OBJ_INHERIT, DUPLICATE_SAME_ATTRIBUTES);
ZwClose (hProcessCur);
ZwClose (hProcessToDup);
return hProcessToRet;
}
}
}
ZwClose (hProcessCur);
}
ZwClose (hProcessToDup);
}
}
}
return 0;
}
顺便问下: 要抹掉PspCidTable中指定的进程容易,抹CSRSS.exe的也容易,什么挂SwapContext的,自己实现线程调度rootkit.com上的PHIDE2 engine也实现了(颇为复杂,引擎写的很漂亮),还有啥改ETHREAD,EPROCESS, flag等DKOM类的...好多好多.但是一个内存暴力搜索不就都出来了.这可怎么隐藏啊 ...
-------------------------------------------------------------------------------------------------------
参考资料:
(1) 基于pspCidTable的进程检测技术
(2) 句柄啊,3层表啊,ExpLookupHandleTableEntry啊
(3) PsLookupProcessByProcessId执行流程
(4) PspTerminateThreadByPointer
(5) WRK,ReactOS
作 者: sudami
时 间: 2008-02-15,21:31
链 接: http://bbs.pediy.com/showthread.php?t=59680
今天再次看了gz1X牛的文章,回忆了许多知识. 哈哈. 玩了很长时间游戏,写点儿文字算是对自责的一种安慰
要说R0枚举隐藏进程, 只是对没有抹掉PspCidTable而言的.gz1X牛提示了2种方法:
"第8个男人" 的code里面就做的很好,找到PspCidTable后自己搜索所有的进程对象就行了:
//----------------------------------------------------------------------
VOID
IsValidProcess ()
/*++
Author : 第8个男人
Leaner : sudami [xiao_rui_119@163.com]
Time : 08/02/15
参数 : NULL
返回 : NULL
功能 :
给出PspCidTable的地址,结合_EXHANDLE、HANDLE_TABLE、HANDLE_TABLE_ENTRY
搜索到每个进程对象,纪录之.
前提条件: 假设暂且PspCidTable没有被抹掉
--*/
{
ULONG PspCidTable;
ULONG TableCode;
ULONG table1,table2;
ULONG object,objectheader;
ULONG NextFreeTableEntry;
ULONG processtype,type;
ULONG flags;
ULONG i;
PspCidTable = GetCidAddr(); // 搜索PsLookupProcessByProcessId函中的特征串即可
processtype = GetProcessType();
if (PspCidTable == 0) {
return ;
} else { //TableCode的低2位决定句柄表的级数
TableCode = *(PULONG) ( *(PULONG) PspCidTable );
if ( (TableCode & 3) == 0 ) { // 0级
table1 = TableCode;
table2 = 0;
} else if ( (TableCode & 3 ) == 1 ) { // 1级
TableCode = TableCode & 0xfffffffc;
table1 = *(PULONG)TableCode;
table2 = *(PULONG)( TableCode + 4 );
}
// 对cid从0x0到0x4e1c进行遍历
for (i = 0; i < 0x4e1c; i++) {
if (i <= 0x800) { // 第一张表中
if (MmIsAddressValid( (PULONG)(table1 + i*2) )) {
// HANDLE_TABLE_ENTRY地址 + PID * 2 ---> 对象的地址
object = *(PULONG)( table1 + i*2 );
if (MmIsAddressValid( (PULONG)(table1 + i*2 + NEXTFREETABLEENTRY) )) {
// 验证HANDLE_TABLE_ENTRY的合法性,这在ExEnumHandleTable函数的代码中也有
// 正常的_HANDLE_TABLE_ENTRY中NextFreeTableEntry应该为0
NextFreeTableEntry = *(PULONG)(table1 + i*2 + NEXTFREETABLEENTRY);
if (NextFreeTableEntry == 0) {
// 去掉低3位掩码标志
object = ((object | 0x80000000) & 0xfffffff8); // 转换为对象(体)指针
objectheader = (ULONG) /
OBJECT_TO_OBJECT_HEADER(object); // 获取对象(头)指针
if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);
if (type == processtype) { // 是否为进程对象
flags = *(PULONG)( (ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS) );
if ((flags&0xc) != 0xc)
RecordInfo( object ); //flags显示进程没有退出
}
}
}
}
}
} else { // 第2张表
if (table2 != 0) {
// 步骤同上,只是object的获取为: HANDLE_TABLE_ENTRY地址 + (PID- 0x800)*2
if (MmIsAddressValid( (PULONG)(table2 + (i - 0x800)*2) )) {
object = *(PULONG)(table2 + (i - 0x800)*2);
if (MmIsAddressValid((PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY))) {
NextFreeTableEntry=*(PULONG)((table2+(i-0x800)*2)+NEXTFREETABLEENTRY);
if (NextFreeTableEntry==0x0) {
object = ((object | 0x80000000) & 0xfffffff8);
objectheader = (ULONG) OBJECT_TO_OBJECT_HEADER(object);
if (MmIsAddressValid( (PULONG)(objectheader + TYPE) )) {
type = *(PULONG)(objectheader + TYPE);
if(type == processtype) {
flags = *(PULONG) ((ULONG)object + /
GetPlantformDependentInfo(OFFSET_EPROCESS_FLAGS));
if ((flags&0xc) != 0xc)
RecordInfo(object);
}
}
}
}
}
}
}
}
}
}
当然,用ExEnumHandleTable也是不错的. Windbg把它的实现看了一遍, 和WRK上的无任何出入[XP SP2], 实现起来也很方便
R3下就更简单了.一阵OpenProcess就把部分隐藏进程揪出来了:
#include <iostream.h>
#include <stdio.h>
#include <windows.h>
void main()
{
int a = 0;
for (int i=0;i<=65535;i+=4) {
if(OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,i)!= 0) {
a++;
cout << "ProcessID: " << i << endl;
CloseHandle(&i);
}
}
cout << "Total Counts = " << a << endl;
}
不过俺看了下,好像有些进程没有显示出来,比如SVCHOST.exe、SMSS.EXE...
嘿嘿,结合下面这些就更好搞了 [V大语录]:
目前通过job杀进程MS很流行,内存清零也很厉害(就怕attach不上),插APC,杀线程之流的....杀杀IS等不在话下.
不过一般搜索到未导出的PspTerminateProcessByPointer,再深入点儿把这个函数,甚至PspExitThread 都自己实现一遍(用Windbg看了遍PspTerminateThreadByPointer,发现和WRK上的一样.哈哈,没有任何出入 [XP SP2]), Kill掉大部分进程是木有问题的,不过像KV2008这样猥亵的家伙在投递APC上下了手脚,就要先恢复了inline hook再杀了.
炉子牛的R0那个干掉KV2008的好像就是这样搞的.哈哈, 丢个驱动在这里,供有兴趣的IDA look之(应该无壳). R3下搞KV 炉子出了个录象,很神秘的样子,不过好像是成功了.哈哈
对了.炉子牛(又是炉子...)放了个simple task, R3下的简单管理器 [VB],---
检测隐藏进程的思路很科普:
一个EnumProcess or ToolHelp32来做对照, 一个ZwQuerySsytemInformation来走过场,一个从0 到65535的遍历OpenProcess来达到PspCidTable的效果. 3个途径来扫盲式的检测,方法是科普点儿.
结束进程部分很扫盲(原作者: EST的willy123牛):
ZwCreateJobObject-->ZwAssignProcessToJobObject-->ZwTerminateJobObject
对付IS这样inlie hook 了NtOpenProcess等的就用了一种很和谐的方法,FlowerCode提供滴.不过是VB写的, 俺无聊把其转化为了C描述,方便些:
//--------------------------------------------------------------
// btw: 头文件的那些申明自己写咯~
// 调用前要有SE_DEBUG权限
HANDLE
SDM_OpenProcess (
DWORD dwDesiredAccess,
BOOL bInhert,
DWORD ProcessId,
BOOL bOpenIt,
LPDWORD aryPids
)
/*++
原作者 : FlowerCode | 炉子 [VB]
转换者 : sudami [xiao_rui_119@163.com] [C]
Time : 08/02/12
参数 :
dwDesiredAccess - 希望以怎样的方式打开进程
bInhert - 是否有继承权限
ProcessId - PID
bOpenIt - 是要打开进程,还是要保存所有进程ID
paryPids - 保存PID的数组
返回 :
成功 - 指定的进程句柄
失败 - 0
功能 :
1. 复制来复制去,总之是要获得指定进程的句柄
2. 用普通方法得到所有进程ID
--*/
{
ULONG cbBuffer = 0x1000; //先设定一个较小的缓冲空间
ULONG uRetSzie;
ULONG NumOfHandle = 0;
PCHAR pBuffer = NULL;
PVOID pOneEprocess = 0;
CLIENT_ID cid;
NTSTATUS st;
OBJECT_ATTRIBUTES oa;
PROCESS_BASIC_INFORMATION pbi;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO h_info;
HANDLE hProcessToDup, hProcessCur, hProcessToRet;
oa.Length = sizeof (OBJECT_ATTRIBUTES);
oa.RootDirectory = 0;
oa.ObjectName = 0;
oa.Attributes = 0;
oa.SecurityDescriptor = 0;
oa.SecurityQualityOfService = 0;
if (bInhert) {
oa.Attributes |= OBJ_INHERIT;
}
if (bOpenIt) {
// 看能否直接得到句柄
cid.UniqueProcess = (HANDLE) (ProcessId + 1);
cid.UniqueThread = 0;
st = NtOpenProcess (&hProcessToRet, dwDesiredAccess, &oa, &cid);
if (NT_SUCCESS (st)) {
return hProcessToRet;
}
::MessageBox (NULL, "NtOpenProcess 失败", "=。=!", MB_OK);
}
// 传递16号获得所有句柄,可能被hook过;不管了,走过场~
do {
st = ZwQuerySystemInformation( /*SystemHandleInformation*/16, /
pBuffer, cbBuffer, &uRetSzie );
if (st == STATUS_INFO_LENGTH_MISMATCH) {
free( pBuffer);
cbBuffer *= 2;
pBuffer = (PCHAR) malloc (cbBuffer);
} else if ( !NT_SUCCESS (st) ) {
free( pBuffer);
::MessageBox (NULL, "ZwQuerySystemInformation失败", ".", MB_OK);
return 0;
}
} while (st == STATUS_INFO_LENGTH_MISMATCH);
NumOfHandle = (ULONG) pBuffer;
h_info = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO) ( (ULONG)pBuffer + 4 );
/*
// 获得进程对象类型
pOneEprocess = h_info[0].Object;
g_pObjectTypeProcess = *(PULONG) ( (ULONG)pOneEprocess - OBJECT_HEADER_SIZE /
+ OBJECT_TYPE_OFFSET );
*/
for (ULONG i = 0; i < NumOfHandle; i++) {
aryPids[i] = h_info[i].UniqueProcessId;
if (bOpenIt) {
::MessageBox (NULL, "333", "=。=!", MB_OK);
if ( 5 == h_info[i].ObjectTypeIndex) { // 是进程的句柄,打开它
cid.UniqueProcess = (HANDLE)h_info[i].UniqueProcessId;
st = NtOpenProcess (&hProcessToDup, PROCESS_DUP_HANDLE, &oa, &cid);
if (NT_SUCCESS (st)) { // 复制该句柄后赋予全部权限,以便调用ZwQuery*时顺利进行
st = ZwDuplicateObject (hProcessToDup, (PHANDLE)h_info[i].HandleValue, (HANDLE)-1,/
&hProcessCur, PROCESS_ALL_ACCESS, 0, DUPLICATE_SAME_ATTRIBUTES);
if (NT_SUCCESS (st)) { // 查看复制的句柄是否为我们想要的
st = ZwQueryInformationProcess (hProcessCur, ProcessBasicInformation,/
&pbi, sizeof(pbi), 0);
if (NT_SUCCESS (st)) {
if (ProcessId == pbi.UniqueProcessId ) {
// 若是想要的PID,就把该句柄按照希望的访问权限复制,然后返回
st = ZwDuplicateObject (hProcessToDup, (PHANDLE)h_info [i].HandleValue,/
(HANDLE)-1, &hProcessToRet, dwDesiredAccess,/
OBJ_INHERIT, DUPLICATE_SAME_ATTRIBUTES);
ZwClose (hProcessCur);
ZwClose (hProcessToDup);
return hProcessToRet;
}
}
}
ZwClose (hProcessCur);
}
ZwClose (hProcessToDup);
}
}
}
return 0;
}
顺便问下: 要抹掉PspCidTable中指定的进程容易,抹CSRSS.exe的也容易,什么挂SwapContext的,自己实现线程调度rootkit.com上的PHIDE2 engine也实现了(颇为复杂,引擎写的很漂亮),还有啥改ETHREAD,EPROCESS, flag等DKOM类的...好多好多.但是一个内存暴力搜索不就都出来了.这可怎么隐藏啊 ...
-------------------------------------------------------------------------------------------------------
参考资料:
(1) 基于pspCidTable的进程检测技术
(2) 句柄啊,3层表啊,ExpLookupHandleTableEntry啊
(3) PsLookupProcessByProcessId执行流程
(4) PspTerminateThreadByPointer
(5) WRK,ReactOS
- 原创】PspCidTable杂谈
- pspcidtable杂谈
- 【原创】remove some info from pspcidtable WIN7X64
- pspcidtable
- pspCidTable
- PspCidTable
- PspCidTable概述
- PspCidTable概述
- 关于PspCidTable
- 门户网站与搜索引擎之杂谈[原创]
- javascript杂谈 半整合半原创篇
- 句柄表和pspcidtable
- 枚举PspCidTable利用API
- PspCidTable攻与防
- PspCidTable 完全解读
- PspCidTable进程枚举
- Pspcidtable遍历进程
- 杂谈
- 【PKM实施】我的构建式学习方法?其实学校学的知识还是有用的嘛....
- 中国队输球原因
- 重要通知
- 温故的片段
- 利用X-window配置错误入侵Linux
- 原创】PspCidTable杂谈
- 托福iBT考试必背句型!!
- 机器智能将会在2029年达到人类的水平
- 存在,不代表合理
- 当 Hibernate 遇上 Spring(转)
- asp.net+sql2005+Ajax.net在发布站点时出现的问题
- 未来世界(12章)
- TOEFL写作例子集
- 托福iBT写作必背200句