浅析木马服务端的生成技术
你可以在“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://www.cnxhacker.com/Article/program/hacker/200612/7418.html