主页 PC知识 网管技术 黑客帝国 安全技术 开放系统 程序设计 搜索 技术论坛

 

相关联接
 
RHU本级分类

编程语言
程序代码
WIN/*NIX编程
其他类别
JAVA专区

 
RHU阅读排行
·在LinuxShell程序中进行身份验证
·截获流经本机网卡的IP数据包
·枚举进程和杀进程的小工具
·从蓝屏最小的asp木马来看C/S木马的编写
·用tc+iptables+HTB解决ADSL宽带速度瓶颈技术
·通过 Visual C++ 的编程模型和编译器优化增强您的应用程序
·Windows管道技术简述
·利用键盘钩子开发按键发音程序
·一个Linux病毒原型分析
·XP终端服务远程登录批处理

 
 
RHU最新文章
·Webshell下破解计算机管理员密码
·打造XP下可运行的微型PE文件(292字节)
·Win32平台下的Rootkit习作
·Linux如何在系统运行过程中修改内核参数
·Shell编程:Linux系统环境程序设计之路
·汇编创建简单的窗口
·深入浅出Win32多线程程序设计之线程控制
·VC实现Win2000下屏蔽Ctrl+Alt+Del键
·隐藏任意进程 目录/文件 注册表 端口
·Windows 的多线程程序设计初步 

 
 
RHU相关搜索









 
 
RHU广而告之

 
 
>您的位置:首页 -> 程序设计 -> WIN/*NIX编程
浅析木马服务端的生成技术

作者:RHU-TAC编辑员 来自:RHU网络采集 时间:2005-5-20 双击滚屏 收藏本页 字体:


点击 查看RHU2004全年文章


有些木马在解压缩之后只会有一个客户端程序,用户可以通过在客户端的一些设置工作来自动生成针对性比较强的服务端程序,例如特定的端口、击键木马的邮件地址、密码、SMTP服务器等等。在本文中,我将简要地探讨这一技术的实现。
从“生成”的这个事实来看,我们可以猜想客户端程序可能本身绑有一段自定义的二进制数据,这段二进制数据实质上就是一个服务端的模板。在用户进行了设置工作之后,客户端就会将设置完成的这些特定数据填充到这个模板之中,然后再通过写文件的操作将这段已经配置完毕的二进制数据模板生成一个特定的服务端程序,如下图所示:



打个比方来说,邮局有很多空白的信封。你在买下一个信封之后,在信封上填写邮政编码、收件人地址和姓名,然后再将你的信件装入信封糊好,这就成为了你所特有的一封信件了。——希望我这么解释能够让你明白我下面将要在操作的大致过程。
下面我要实现一个名为“MsgBox生成器”的演示程序,你可以在客户端进行MessageBox的标题和文本的设置,然后程序就会在C:\下生成一个名为MsgBox.exe的“Hello, World”程序,这个弹出的MessageBox就是你先前在客户端所设置的那样。运行界面如下图:



好了,那么我先来设计生成服务端的功能。为了十足地模仿木马程序,我使用Win32 ASM来编写服务端程序,代码如下:

.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.data
szTitle db “Hello”, 0
szText db “Hello, World”, 0

.code
start:
invoke MessageBox, NULL, addr szText, addr szTitle, MB_OK or MB_ICONINFORMATION
invoke ExitProcess, NULL
end start

如你所见,这正是Iczelion在他的Win32汇编教程中编写的那个“Hello, World”,你可以利用MASM32将这段源代码编译链接,生成一个MsgBox.exe,在此我就利用这个程序来充当我要生成的服务端。
现在需要考虑的问题是,如何将这个MsgBox.exe嵌入到客户端程序中?一个最好想,也是最直观的办法是利用一个BYTE数组来放置MsgBox.exe的二进制数据(CIH病毒就是这样,它专门准备了一个PE文件头),然后再使用API函数CreateFile将这段二进制数据写成文件。部分代码如下:

BYTE bySrvData[] = {
  0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
  0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
  0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  // 由于篇幅略去以下所有数据-_-#...
};
BOOL CreateServer()
{
  HANDLE hFile;
  DWORD dwWritten;
  hFile = CreateFile("C:\\MsgBox.exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
  if (hFile == NULL)
    return FALSE;
  WriteFile(hFile, (LPCVOID)bySrvData, sizeof(bySrvData), &dwWritten, NULL);
  CloseHandle(hFile);
  return TRUE;
}
 
好了,代码到此为止。虽然它可以胜利完成任务,但是你一定不愿意编写这样的代码——对于MsgBox.exe的数据部分,它实在太冗长了(我算了一笔账,对于编译完成的MsgBox.exe,它只有不到3KB的大小,但是如果把它的二进制数据像上面那样保存成文本文件,这个文本文件就会拥有15KB的体积)。况且,这仅仅是一个“Hello, World!”程序,那么换成真正的木马服务端程序又会怎么样呢?而且,很多的服务端是用高级语言编写的,它们动辄会拥有几十KB的体积!
现在我们只能别无选择地换一个角度考虑如何来解决这个问题:除了用BYTE数组,还有别的方法可以将MsgBox.exe放入客户端程序中吗?
答案是肯定的,那就是利用EXE文件的自定义资源。在解说如何使用自定义资源之前,我先大体介绍一下我要使用的几个API:
·FindResource:查找一个资源。由于我们是要将这个服务端作为EXE的自定义资源形式放在EXE之中,所以在释放它之前必须首先找到它才可以。
·SizeofResource:获得资源的尺寸,装载资源时使用。
·LoadResource:装载资源,将资源的二进制数据装载到内存中。
·LockResource:锁定资源,将内存中的资源数据锁定。
好了,你可以通过查阅MSDN来了解这几个函数的详细功能及参数,这里我就不赘述了。我的整个思路如下:
1.将MsgBox.exe作为客户端程序的二进制资源一同编译。
2.在生成MsgBox.exe服务端的时候,使用以上的几个API函数读取这一段二进制资源数据。
3.将这段二进制数据保存为文件。
现在我来实现第1步。首先你将MsgBox.exe改名为MsgBox.bin作为一个二进制文件,并将这个文件放入客户端源代码的文件夹下。然后,向客户端的资源脚本(.rc文件)中导入这个二进制资源,如下图所示:

 

这时候,VC会弹出一个对话框提示,如下图:



你可以在“Resource Type”中随意填写你的资源类型,这个类型名称就是我们将要在FindResource函数的第三个参数lpType中使用的资源类型,我这里以“Server”为例。
这样,我就能够以资源的方式来使用这段数据了。我的代码如下:

BOOL CreateServer()
{
  HRSRC hResInfo;
  HGLOBAL hResData;
  DWORD dwSize, dwWritten;
  HANDLE hFile;
  // 查找所需的资源
  hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_SERVER), "Server");
  if (hResInfo == NULL)
    return FALSE;
  // 获得资源尺寸
  dwSize = SizeofResource(NULL, hResInfo);
  // 装载资源
  hResData = LoadResource(NULL, hResInfo);
  if (hResData == NULL)
    return FALSE;
  // 写文件
  hFile = CreateFile("C:\\MsgBox.exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
  if (hFile == NULL)
    return FALSE;
  WriteFile(hFile, (LPCVOID)LockResource(hResData), dwSize, &dwWritten, NULL);
  CloseHandle(hFile);
  return TRUE;
}

到这里,如何生成服务端的问题就已经解决了,现在我来讨论如何自定义服务端的数据。我还是以一个例子来解释这个问题,下面是一段代码,也就是一个MessageBox的调用过程:

TCHAR strContext[] = "Hello, World!";
TCHAR strTitle[] = "Hello";
MessageBox(NULL, strContext, strTitle, MB_OK);

以上代码相对应的汇编代码为:

push 0 ; 最后一个参数MB_OK
lea  eax,[ebp-18h]
push eax ; 第3个参数strTitle
lea  ecx,[ebp-10h]
push ecx ; 第2个参数strContext
push 0 ; 第1个参数NULL
call dword ptr [__imp__MessageBoxA@16 (0042a2ac)] ; 函数调用

也就是说,MessageBox的调用过程是传入了两个字符串地址,那么我们只需要将字符串所指向的内容进行改变,就可以达到修改MessageBox显示结果的目的了。
那么,又如何来确定在MsgBox.exe中那两个字符串的位置呢?在这里,我玩弄了一个小把戏,就是将原来MsgBox.asm的.data段改为:

.data
szTitle db 100 dup('A')
szText db 100 dup('B')

你也许会对这段代码颇为不解。不过我还是请你先按照上面的步骤将这个新的源文件编译链接,然后再改名为MsgBox.bin,最后导入到客户端的资源中。现在,你可以打开那个二进制资源MsgBox.bin看一看,相信你一定会在某个位置找到像下面这样的东西:



这样一来,你就会很容易地发现,标题的相对偏移量是0x800,文本的相对偏移量是0x864——这也就是我定义那一连串'A'和'B'的用意了。
现在,就可以编写我在本文开始所提到的“MsgBox生成器”了,它的核心代码如下:

HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize, dwWritten;
LPBYTE p;
HANDLE hFile;
TCHAR szTitle[100], szText[100];
// 查找所需的资源
hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_SERVER), "Server");
if (hResInfo == NULL)
{
  MessageBox(hDlg, "查找资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
  break;
}
// 获得资源尺寸
dwSize = SizeofResource(NULL, hResInfo);
// 装载资源
hResData = LoadResource(NULL, hResInfo);
if (hResData == NULL)
{
  MessageBox(hDlg, "装载资源失败!", "错误", MB_OK | MB_ICONINFORMATION);
  break;
}
// 为数据分配空间
p = (LPBYTE)GlobalAlloc(GPTR, dwSize);
if (p == NULL)
{
  MessageBox(hDlg, "分配内存失败!", "错误", MB_OK | MB_ICONINFORMATION);
  break;
}
// 复制资源数据
CopyMemory((LPVOID)p, (LPCVOID)LockResource(hResData), dwSize);
// 获取标题和文本,并复制数据
GetDlgItemText(hDlg, IDC_EDT_TITLE, szTitle, 100);
GetDlgItemText(hDlg, IDC_EDT_TEXT, szText, 100);
CopyMemory((LPVOID)(p + 0x800), (LPCVOID)szTitle, 100);
CopyMemory((LPVOID)(p + 0x864), (LPCVOID)szText, 100);
// 创建文件,写数据
hFile = CreateFile("C:\\MsgBox.exe", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile != NULL)
  WriteFile(hFile, (LPCVOID)p, dwSize, &dwWritten, NULL);
else
{
  MessageBox(hDlg, "创建文件失败!", "错误", MB_OK | MB_ICONINFORMATION);
  GlobalFree((HGLOBAL)p);
  break;
}
// 收尾工作,释放资源
CloseHandle(hFile);
GlobalFree((HGLOBAL)p);

到这里,这一技术的核心部分基本上就已经讲完了。对于一个实际的木马程序服务端而言,你只需要把MsgBox的标题和文本替换为相应的端口号和邮件地址就可以了。另外,对于用C/C++、Delphi等高级语言所编写的服务端模板,它的尺寸肯定会大大超过一个汇编写成的程序,这样的话查找要替换的字符串或者数值就肯定会花些时间了。

本文配套代码用SDK编写,在Windows XP Professional + VC 6.0下编译通过,下载地址:http://home.nuc.edu.cn/~titilima/sample/msgbox.zip


OVER

[1] 页 RedHyphone.Union 投稿邮箱
[特别声明]:
本站文章大多搜索转载自网络中,如果侵犯了您的权利,请告之我们。本站将立即删除。
本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
查看评论】【向上滚屏】【关闭窗口】【 打印
-相关文章
  • openSUSE 11.1 Final - 正式发布
  • [视频]Opera Mini 4.2 正式版发布
  • dll注入系统进程(开源代码)
  • 认知盲区 解惑双网卡双线路DNS解析
  • FlashFXP 简体中文版 3.7.5 Build 1303 Beta[烈火]
  • -文章评论 (关闭)
    ·还没有相关的评论!

    网上大名:
    红旋风网络技术联盟 RHUTech.Union
     
    Copyright © 2000-2007 RedHyphone.Union All Rights Reserved. 红旋风联盟版权所有.皖ICP备05011033号
    中国红旋风网络技术联盟 | www.RedHyphone.net
    Mailto:Redhyphone@gamil.com