2005年7月26,浏览邮件的时候瑞星监控提示正在浏览的邮件带病毒“Exploit.HHCtrl.b“,我向来对病毒很敏感,我机器中毒了?扫描一下,没有,很好。既然是病毒,研究一下,把监控关掉,把邮件下载下来,用记事本打开(病毒再厉害,这个操作不会中毒吧,心里一阵窃笑):
%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%21DOCTYPE%20HTML%20PUBLIC%20%22%2D%2F%2FW3C%2F%2FDTD%20HTML%204%2E01%20Transitional%2F%2FEN%22%3E%0D%0A%3Chtml%3E%0D%0A%3Chead%3E%0D%0A%3Cmeta%20http%2Dequiv%3D%22Content%2DType%22%20content%3D%22text%2Fhtml%3B%20charset%3Dgb2312%22%3E%0D%0A%3Ctitle%3E%u817E%u8BAF%u516C%u53F8%u5173%u4E8EQQ%u5728%u7EBF%u65F6%u957F%u7B49%u7EA7%u7684%u516C%u544A%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%0D%0A%3Cbody%3E%0D%0A%3Cdiv%20align%3D%22center%22%3E%0D%0A%20%20%3Cp%3E%3Cstrong%3E%u817E%u8BAF%u516C%u53F8%u5173%u4E8EQQ%u5728%u7EBF%u65F6%u957F%u7B49%u7EA7%u7684%u516C%u544A%3C%2Fstrong%3E%3C%2Fp%3E%0D%0A%20%20%3Cp%20align%3D%22
...
看了一下,哈哈哈,这堆垃圾,想迷惑我,没门。原理很简单:
网页中嵌入某个*.gif,这不是一个真正的图片文件,而是某一段PE文件可执行代码,浏览网页的时候,自动被保存到ie temp文件夹中,然后通过上述乱码将其执行,执行一些既定的操作,这可是木马啊(那个可执行文件的代码给弄丢了,贴不上来)。这段乱码是简单地编码了一下,%号后的两位用十六进制表示,如开头的:%20%20%20%20,20表示空格,以后的都是以%开头然后跟两位数字或字母或组合,手动翻译很麻烦,编个程序:
//...
CFile cfile1, destfile;
char buf1[3];
const int nCount = sizeof(buf1);
LPCTSTR lpszFileName1 = "QQ_Virtus.txt";
LPCTSTR lpszFileName2 = "desfile.txt";
UINT nOpenFlages1 = CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone;
UINT nOpenFlages2 = CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary | CFile::shareDenyNone;
CFileException *pError = NULL;
if ( (!cfile1.Open(lpszFileName1, nOpenFlages1, pError)) ||
(!destfile.Open(lpszFileName2, nOpenFlages2, pError)) )
{
AfxMessageBox("Cann't open the file!", 0, 0);
return;
}
int size1 = 0;
bool tag = false; // 用来标记是否找到了%
int i = nCount - 3;
char *str1 = new char[2];
unsigned long j = 0;
int temp1 = 0;
int temp2 = 0;
unsigned long sizeoffile = cfile1.GetLength();
cfile1.Seek(j, CFile::begin);
do
{
size1 = cfile1.Read(buf1, nCount);
if ( (buf1[i] == '%') && (buf1[i+1] !='u') ) // %后有u表示u后面的四个字母或数字组成一个汉字
{// 当指针指向的缓冲区第一个字符为%时,就转换%后面的两个字节为ASCII码,然后存入目标文件
tag = true;
switch(buf1[i+1]) // 转换成十进制
{// 高位部分
case '0': temp1 = 0 * 16; break;
case '1': temp1 = 1 * 16; break;
case '2': temp1 = 2 * 16; break;
case '3': temp1 = 3 * 16; break;
case '4': temp1 = 4 * 16; break;
case '5': temp1 = 5 * 16; break;
case '6': temp1 = 6 * 16; break;
case '7': temp1 = 7 * 16; break;
case '8': temp1 = 8 * 16; break;
case '9': temp1 = 9 * 16; break;
case 'A': temp1 = 10 * 16; break;
case 'B': temp1 = 11 * 16; break;
case 'C': temp1 = 12 * 16; break;
case 'D': temp1 = 13 * 16; break;
case 'E': temp1 = 14 * 16; break;
case 'F': temp1 = 15 * 16; break;
default: break;
}
switch(buf1[i+2])
{ // 低位部分
case '0': temp2 = 0; break;
case '1': temp2 = 1; break;
case '2': temp2 = 2; break;
case '3': temp2 = 3; break;
case '4': temp2 = 4; break;
case '5': temp2 = 5; break;
case '6': temp2 = 6; break;
case '7': temp2 = 7; break;
case '8': temp2 = 8; break;
case '9': temp2 = 9; break;
case 'A': temp2 = 10; break;
case 'B': temp2 = 11; break;
case 'C': temp2 = 12; break;
case 'D': temp2 = 13; break;
case 'E': temp2 = 14; break;
case 'F': temp2 = 15; break;
default: break;
}
int temp = temp1 + temp2; // atoi()得到的数是16进制的, 应该转换成10进制
buf1[i] = __toascii(temp); // 转换成ASCII码
char bufsize1[1]; // 把转换后的ASCII码存入目标文件
bufsize1[0] = buf1[i];
destfile.Write(bufsize1, sizeof(bufsize1));
cfile1.Seek(j +=3, CFile::begin); // 继续向前移动指针3字节, 找下一个%
}
else if ( (buf1[i+1] == '%') && (buf1[i+2] !='u') )
{ // 如果缓冲区中%在第2个位置,则把%前的一个字符存入目标文件
tag = true;
char bufsize2[1];
bufsize2[0] = buf1[i];
destfile.Write(bufsize2, sizeof(bufsize2));
cfile1.Seek(j += 1, CFile::begin); // 指针向前移动一个字节
}
else if ( (buf1[i+2] == '%') && (buf1[i] !='u') )
{// 如果缓冲区中的%在第三个位置,则把%前的两个字符存入目标文件
tag = true;
char bufsize3[2];
bufsize3[0] = buf1[i];
bufsize3[1] = buf1[i+1];
destfile.Write(bufsize3, sizeof(bufsize3));
cfile1.Seek(j += 2, CFile::begin); // 指针向前移动两个字节,找下一个%
}
if (tag)
{
tag = false;
continue; // 继续向前找
}
else
{
destfile.Write(buf1, nCount); // 没有找到%则把这些字符存入目标文件
tag = false;
cfile1.Seek(j += 3, CFile::begin); //指针向前移动三字节,找下一个%
}
}while((j <= sizeoffile));
cfile1.Close();
destfile.Close();
HDC hdc;
HWND hwnd;
/*%u817E%u8BAF%u516C%u53F8%u5173%u4E8EQQ%u5728%u7EBF%u65F6%u957F%u7B49%u7EA7%u7684%u516C%u544A*/
CString strcn = "/xFF/xFE/x7E/x81/xAF/x8B/x6C/x51/xF8/x53/x73/x51"
"/x4E/x8E/x57/x28/x7E/xBF/x65/xF6/x95/x7F/x7B/x49/x7E/xA7/x76"
"/x84/x51/x6C/x54/x4A";
TextOut(hdc, 20, 20, strcn,strcn.GetLength());
char buf1[3];
const int nCount = sizeof(buf1);
LPCTSTR lpszFileName1 = "QQ_Virtus.txt";
LPCTSTR lpszFileName2 = "desfile.txt";
UINT nOpenFlages1 = CFile::modeRead | CFile::typeBinary | CFile::shareDenyNone;
UINT nOpenFlages2 = CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary | CFile::shareDenyNone;
CFileException *pError = NULL;
if ( (!cfile1.Open(lpszFileName1, nOpenFlages1, pError)) ||
(!destfile.Open(lpszFileName2, nOpenFlages2, pError)) )
{
AfxMessageBox("Cann't open the file!", 0, 0);
return;
}
int size1 = 0;
bool tag = false; // 用来标记是否找到了%
int i = nCount - 3;
char *str1 = new char[2];
unsigned long j = 0;
int temp1 = 0;
int temp2 = 0;
unsigned long sizeoffile = cfile1.GetLength();
cfile1.Seek(j, CFile::begin);
do
{
size1 = cfile1.Read(buf1, nCount);
if ( (buf1[i] == '%') && (buf1[i+1] !='u') ) // %后有u表示u后面的四个字母或数字组成一个汉字
{// 当指针指向的缓冲区第一个字符为%时,就转换%后面的两个字节为ASCII码,然后存入目标文件
tag = true;
switch(buf1[i+1]) // 转换成十进制
{// 高位部分
case '0': temp1 = 0 * 16; break;
case '1': temp1 = 1 * 16; break;
case '2': temp1 = 2 * 16; break;
case '3': temp1 = 3 * 16; break;
case '4': temp1 = 4 * 16; break;
case '5': temp1 = 5 * 16; break;
case '6': temp1 = 6 * 16; break;
case '7': temp1 = 7 * 16; break;
case '8': temp1 = 8 * 16; break;
case '9': temp1 = 9 * 16; break;
case 'A': temp1 = 10 * 16; break;
case 'B': temp1 = 11 * 16; break;
case 'C': temp1 = 12 * 16; break;
case 'D': temp1 = 13 * 16; break;
case 'E': temp1 = 14 * 16; break;
case 'F': temp1 = 15 * 16; break;
default: break;
}
switch(buf1[i+2])
{ // 低位部分
case '0': temp2 = 0; break;
case '1': temp2 = 1; break;
case '2': temp2 = 2; break;
case '3': temp2 = 3; break;
case '4': temp2 = 4; break;
case '5': temp2 = 5; break;
case '6': temp2 = 6; break;
case '7': temp2 = 7; break;
case '8': temp2 = 8; break;
case '9': temp2 = 9; break;
case 'A': temp2 = 10; break;
case 'B': temp2 = 11; break;
case 'C': temp2 = 12; break;
case 'D': temp2 = 13; break;
case 'E': temp2 = 14; break;
case 'F': temp2 = 15; break;
default: break;
}
int temp = temp1 + temp2; // atoi()得到的数是16进制的, 应该转换成10进制
buf1[i] = __toascii(temp); // 转换成ASCII码
char bufsize1[1]; // 把转换后的ASCII码存入目标文件
bufsize1[0] = buf1[i];
destfile.Write(bufsize1, sizeof(bufsize1));
cfile1.Seek(j +=3, CFile::begin); // 继续向前移动指针3字节, 找下一个%
}
else if ( (buf1[i+1] == '%') && (buf1[i+2] !='u') )
{ // 如果缓冲区中%在第2个位置,则把%前的一个字符存入目标文件
tag = true;
char bufsize2[1];
bufsize2[0] = buf1[i];
destfile.Write(bufsize2, sizeof(bufsize2));
cfile1.Seek(j += 1, CFile::begin); // 指针向前移动一个字节
}
else if ( (buf1[i+2] == '%') && (buf1[i] !='u') )
{// 如果缓冲区中的%在第三个位置,则把%前的两个字符存入目标文件
tag = true;
char bufsize3[2];
bufsize3[0] = buf1[i];
bufsize3[1] = buf1[i+1];
destfile.Write(bufsize3, sizeof(bufsize3));
cfile1.Seek(j += 2, CFile::begin); // 指针向前移动两个字节,找下一个%
}
if (tag)
{
tag = false;
continue; // 继续向前找
}
else
{
destfile.Write(buf1, nCount); // 没有找到%则把这些字符存入目标文件
tag = false;
cfile1.Seek(j += 3, CFile::begin); //指针向前移动三字节,找下一个%
}
}while((j <= sizeoffile));
cfile1.Close();
destfile.Close();
HDC hdc;
HWND hwnd;
/*%u817E%u8BAF%u516C%u53F8%u5173%u4E8EQQ%u5728%u7EBF%u65F6%u957F%u7B49%u7EA7%u7684%u516C%u544A*/
CString strcn = "/xFF/xFE/x7E/x81/xAF/x8B/x6C/x51/xF8/x53/x73/x51"
"/x4E/x8E/x57/x28/x7E/xBF/x65/xF6/x95/x7F/x7B/x49/x7E/xA7/x76"
"/x84/x51/x6C/x54/x4A";
TextOut(hdc, 20, 20, strcn,strcn.GetLength());
//...
//其中%u516C%u53F8%u5173...之类的Unicode没有转换,(脑袋胀,不想想了)
把其翻译过来吧:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>
...
(其中%u516C%u53F8%u5173等等是汉字的Unicode代码,高位与低位交叉,换位后变成汉字)
这是html语言了,简单。
...
原理搞清楚了,收工。
欢迎各位朋友指正,谢谢!
2006.2.20 修正