`
thecloud
  • 浏览: 885851 次
文章分类
社区版块
存档分类
最新评论

WinNT & Win2K下实现进程的完全隐藏

 
阅读更多
-----------转自:http://antghazi.yeah.net

WinNT & Win2K下实现进程的完全隐藏


面对众多的计算机高手,考虑许久,终于还是决定出来献丑一下
,文章内尽量使用最简洁易懂的词汇及例子来介绍,希望能够对一些
初学与进阶者有所帮助。
关于进程的隐藏,98下的例子数不胜数。WinNT/Win2K下的隐藏
方法,西祠的高手shotgun在去年的6月就已经在网上发布出实例《揭
开木马的神秘面纱<四>》 ,我也多次拜读他的文章,对他的计算机
水平及热心帮助朋友的作风十分敬佩。这里也可算是对shotgun的文
章的补充与深入介绍吧,好了,闲话少说。
在WinNT下"真正隐藏进程"这一说法,可以讲是根本不可能实现,只
要我们的程序是以进程内核的形式运行,都是不可能逃离CTRL+ALT+
DEL的法眼。那么奇怪了,这岂不是与我们的标题《WinNT & Win2K下
实现进程的完全隐藏》相矛盾吗?是的,实际上应该是:以非进程方
式执行目标代码,而逃避进程查看器的检查,从而达到"进程隐藏"的
目的。
我们这里用的,是在宿主进程中,以线程的方式执行我们的代码。实
现起来非常简单。首先,我们先建立一个不执行任何语句的线程
DWORD stdcall ThreadProc(LPVOID *lpVoid){
return 0;
}
然后,将线程代码拷备至宿主进程所能够执行的任何地方(即页面属
性为PAGGE_EXECUTE_READWRITE),如:共享内存影射区、宿主进程内
。这里我们选择宿主进程,拷备的时侯,我们需要先在宿主进程中使
用VirtualAllocEx函数申请一段内存,然后再使用WriteProcessMemory
将线程体写入宿主进程中。
以上工作完成后,我们便可CreateRemoteThread函数激活其执行。下面给出一个完整的例子
//远程线程执行体
DWORD __stdcall ThreadProc (void *lpPara){
return 0;
}
int main(int argc, char* argv[]){
const DWORD THREADSIZE=1024*4;//暂定线程体大小为4K,实际上
没这么大,稍后我将会介绍
DWORD byte_write;
//获得指定进程ID句柄,并设其权限为PROCESS_ALL_ACCESS,992是
宿进程的ID号,获取ID号的方法这里我就不多讲了
HANDLE hWnd = ::OpenProcess (PROCESS_ALL_ACCESS,FALSE,992);
if(!hWnd)return 0;
void *pRemoteThread =::VirtualAllocEx(hWnd,0,THREADSIZE,MEM_COMMIT
| MEM_RESERVE,PAGE_EXECUTE_READWRITE);//申请
if(!pRemoteThread)return 0;
if(!::WriteProcessMemory(hWnd,pRemoteThread,&ThreadProc,THREADSIZE
,0))//写入进程
return 0;
//启动线程
HANDLE hThread = ::CreateRemoteThread (hWnd ,0,0,(DWORD (
__stdcall *)(void *))pRemoteThread ,NULL,0,&byte_write);
if(!hThread){ //还有内存分配未释放
return 0;
}
return 0;
}
到这里,对于隐藏的方法就算告一段落,相信看过的朋友对这个思路
有个非常明确的概念了吧。

在理解隐藏的方法后,我们着重开始写线程的执行部分了。如下:
DWORD __stdcall ThreadProc(void *lpPara){
MessageBox(NULL,"hello","hello",0);
return 0;
}
编译执行后,你会发现出现一个非法操作错误,为什么呢?在我们以
段页式内存管理的win2K操作系统中,编译时会把所有的常量编译在
PE文件的.data节中,而代码段则在.text中,所以,我们拷备到宿主
进程中的代码是在.text中的代码,MessageBox(NULL,(char *)指针
,p,0);所指向的地址是本进程的内存虚拟地址。而在宿主进程中是无
法访问的。解决的方法很简单,按旧照搬的将"hello"也拷备到目标
进程中,然后再引用。同理,MessageBox函数地址编译时,也是保存
在.Import中,写过Win2k病毒的朋友都知道,所有常量与函数入口地
址都需在代码段定义与得出,我们这里也与他有点类似。言归正传,
同样情况我们也把函数的入口地址一起写入目标进程中。

//先定义参数结构
typedef struct _RemotePara{//参数结构
char pMessageBox[12];
DWORD dwMessageBox;
}RemotePara;
//付值
RemotePara myRemotePara;
::ZeroMemory(&myRemotePara,sizeof(RemotePara));
HINSTANCE hUser32 = ::LoadLibrary ("user32.dll");
myRemotePara.dwMessageBox =(DWORD) ::GetProcAddress (hUser32 , "MessageBoxA");
strcat(myRemotePara.pMessageBox,"hello/0");
//写进目标进程
RemotePara *pRemotePara =(RemotePara *) ::VirtualAllocEx (hWnd
,0,sizeof(RemotePara),MEM_COMMIT,PAGE_READWRITE);//注意申请
空间时的页面保护属性
if(!pRemotePara)return 0;
if(!::WriteProcessMemory (hWnd ,pRemotePara,&myRemotePara,sizeof
myRemotePara,0))return 0;
//启动进将参数传递进入
HANDLE hThread = ::CreateRemoteThread (hWnd ,0,0,(DWORD (__stdcall
*)(void *))pRemoteThread ,pRemotePara,0,&byte_write);
if(!hThread){
return 0;
}

好了,就这么简单,下在给出一个弹出一个MessageBox的实例:

// RemoteThread.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef struct _RemotePara{//参数结构
char pMessageBox[12];
DWORD dwMessageBox;
}RemotePara;
//远程线程
DWORD __stdcall ThreadProc (RemotePara *lpPara){
typedef int (__stdcall *MMessageBoxA)(HWND,LPCTSTR,LPCTSTR
,DWORD);//定义MessageBox函数
MMessageBoxA myMessageBoxA;
myMessageBoxA =(MMessageBoxA) lpPara->dwMessageBox ;//得到函数入口地址
myMessageBoxA(NULL,lpPara->pMessageBox ,lpPara->pMessageBox,0);//call
return 0;
}
void EnableDebugPriv();//提升应用级调试权限

int main(int argc, char* argv[]){
const DWORD THREADSIZE=1024*4;
DWORD byte_write;
EnableDebugPriv();//提升权限
HANDLE hWnd = ::OpenProcess (PROCESS_ALL_ACCESS,FALSE,992);
if(!hWnd)return 0;
void *pRemoteThread =::VirtualAllocEx(hWnd,0,THREADSIZE,
MEM_COMMIT| MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if(!pRemoteThread)return 0;
if(!::WriteProcessMemory(hWnd,pRemoteThread,&ThreadProc,THREADSIZE,0))
return 0;

//再付值
RemotePara myRemotePara;
::ZeroMemory(&myRemotePara,sizeof(RemotePara));
HINSTANCE hUser32 = ::LoadLibrary ("user32.dll");
myRemotePara.dwMessageBox =(DWORD) ::GetProcAddress (hUser32
, "MessageBoxA");
strcat(myRemotePara.pMessageBox,"hello/0");
//写进目标进程
RemotePara *pRemotePara =(RemotePara *) ::VirtualAllocEx
(hWnd ,0,sizeof(RemotePara),MEM_COMMIT,PAGE_READWRITE);//注
意申请空间时的页面属性
if(!pRemotePara)return 0;
if(!::WriteProcessMemory (hWnd ,pRemotePara,&myRemotePara
,sizeof myRemotePara,0))return 0;

//启动线程
HANDLE hThread = ::CreateRemoteThread (hWnd ,0,0,(DWORD
(__stdcall *)(void *))pRemoteThread ,pRemotePara,0,&byte_write
);
if(!hThread){
return 0;
}
return 0;
}


//提升权限
void EnableDebugPriv( void )
{
HANDLE hToken;
LUID sedebugnameValue;
TOKEN_PRIVILEGES tkp;

if ( ! OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
return;
if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) ){
CloseHandle( hToken );
return;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
CloseHandle( hToken );
}

好了,程序编译执行后会在进程号为992的进程中创建一线程,弹出
hello对话框。是不是非常简单呢!
这里有几个地方需要注意的:
1、远程线程在宿主进程中申请空间时,空间大小的确定了是我一直
无法解决的问题。我曾使用两个贴近一起的线程,以线程间的距离大
小,并加上参数大小,作为申请空间时,仍然会出现非法操作,如下

static void StartThread (LPVOID *lpPara){
return ;
}
static void EndThread(LPVOID *lpPara){
return;
}
然后使用DWORD dwLenght = (DWORD)((char *)&StartThread - (char
*)&EndThread);//得到StartThread线程代码长度,
dwLenght += sizeof(ThreadPara);
仍会出现非法操作让我很迷惑。在win2k中,线程的默认堆栈的页大
小是4KB,这里我在为线程申请内存时,申请的大小暂时使用一个常
数,始终为4KB的倍数,选取时尽量取大,在线程可成功运行后,再
一点点改小。办法是笨了点,如这里的朋友有更好的方法,请不吝赐
教。
2、什么时侯,什么参数是需要从外部传递进来的呢?我这里并没有
一个十分有力的答案,我的理解是:PE文件中除了.text节以外的所
有节,均需使用外部参数传递到线程中使用,如:.rsrc、.data、rdata
等其他的15个节。在我们实际编写的过程中,初学者并不知道我们的
代码会编译在什么地方,这个时侯,我们可以在运行的时侯ALT + 8
(VC中快捷键)反编译过来,一般有lea eax p、push offset p等取
地址语句,这个时侯,我们大都需要以参数传递进来。所以,大家在
编写的时侯,一定要注意参数,因为线程的执行是在别的进程中,一
个普通权限的应用程序是无法跨越进程来调试其他进程的。包括VC,
也无法调试我们的远程线程,熟悉汇编的朋友,可用softice调试,
这需要一定的功底。
3、权限,这一点很重要,shotgun在这方面也介绍得很清楚了,网上
相关的文章也很多,我就不多说了。文中的EnableDebugPriv函数可
使本进程在internet、winLogin、lsass等进程中创建线程。win2k的
进程查看器无法将其杀除。
4、进程ID获方法较多,如:EnumProcesses、CreateToolhelp32Snapshot
/Process32First/Process32Next、NtQuerySystemInformation等函
数均可,为减少代码,例子中的进程ID是直接在进程查看器中得到的


最后,我们再回到shotgun的文章中,这时侯我们因已经非常清楚他
的方法中为何会多出一个DLL文件了。远程线程的线程体本身就是LoadLibrary
函数,即,线程的入口地址就是LoadLibrary的入口地址,这是系统
Kernel32.dll中的函数,任何进程都可调用。线程中使用LoadLibrary
函数将我们的DLL加载到系统空间内,线程一执行,我们的DLL就开始
工作了。线程执行结束后,别忘了使用VirtualFreeEx将其申请的内
存区释放。
两种方法一比较,很明显:
1、在使用DLL时,创建十分简单,也不需要太多的操作系统与内存操
作知识,并可直接调试DLL文件。实现起来比较简单。
2、直接拷备到进程中的方法稍为复杂一点,一不小心,很容易出现
非法操作。当然,也去掉那了个让人讨厌DLL文件。程序执行后,很
难找到他的来源地,是除了病毒以外的木马隐藏的首选方法。

这里我大量参考了nongmin.cn(农民)程序的源码,他的程序对我的帮
助非常大。虽然未有谋面,但对他的计算机水平与作为十分的敬佩,
并尊从他的作风,以后我所写的所有非商业软件或小代码,均以源码
好计算机,从事计算机工作的朋友们共勉。
分享到:
评论

相关推荐

    windows编程资料大全

    那么奇怪了,这岂不是与我们的标题《WinNT & Win2K下实现进程的完全隐藏》相矛盾吗?是的,实际上应该是:以非进程方式执行目标代码,而逃避进程查看器的检查,从而达到"进程隐藏"的目的。 我们这里用的,是在宿主...

    Windows Sysinternals Suite v2019.06.29.zip

    创建 Win2K NTFS 符号链接。 LDMDump 转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。 ListDLLs 列出所有当前加载的 DLL,包括加载位置及其版本号。2.0 版将打印已加载...

    注册表批量修改权限命令

    创建 Win2K NTFS 符号链接。 LDMDump 转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。 ListDLLs 列出所有当前加载的 DLL,包括加载位置及其版本号。2.0 版将打印已加载模块...

    调试开发工具集

    创建 Win2K NTFS 符号链接。 LDMDump 转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。 ListDLLs 列出所有当前加载的 DLL,包括加载位置及其版本号。2.0 版将打印已加载模块...

    SysinternalsSuite

     创建 Win2K NTFS 符号链接。  LDMDump  转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。  ListDLLs  列出所有当前加载的 DLL,包括加载位置及其版本号。2.0 版将打印...

    微软Sysinternals Suite工具包 2018.12.18 官方版.zip

    创建 Win2K NTFS 符号链接。LDMDump 转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。ListDLLs 列出所有当前加载的 DLL,包括加载位置及其版本号。2.0 版将打印已加载模块...

    cmd操作命令和linux命令大全收集

    3. Nslookup-------IP地址侦测器 ,是一个 监测网络中 DNS 服务器是否能正确实现域名解析的命令行工具。它在 Windows NT/2000/XP 中均可使用,但在 Windows 98 中却没有集成这一个工具。 4. explorer-------打开...

    Sysinternals 微软系统监控实用工具

    创建 Win2K NTFS 符号链接。 LDMDump v1.02(2006 年 11 月 1 日) 转储逻辑磁盘管理器在磁盘上的数据库内容,其中说明了 Windows 2000 动态磁盘的分区情况。 ListDLLs v2.25(2006 年 11 月 1 日) 列出所有当前...

    升级MaxDOS71

    1.为装好的Win2K/XP/2K3/VISTA/2008系统加入DOS入口,方便维护与备份还原系统. 2.支持进入DOS时设置密码,密码采用MD5加密,纯绿色软件,不写引导区. 3.内置200多种网卡驱动,实现GHOST网络刻隆及DOS下访问局域网的共享...

    MaxDOS_71PXE_G115.rar

    1. 为装好的Win2K/XP/2K3/VISTA/2008系统加入DOS入口,方便维护与备份还原系统. 2. 支持进入DOS时设置密码,密码采用MD5加密,纯绿色软件,不写引导区. 3. 内置200多种网卡驱动,实现GHOST网络刻隆及DOS下访问局域网的...

Global site tag (gtag.js) - Google Analytics