本帖最后由 岁月静好。 于 2015-11-11 13:25 编辑
前几天上传的样本,得到众基友指点后自己分析,第一次发分析帖流程可能有些混乱,大牛勿喷,有错误请指出,小白在学习中...在此感谢指点过我的人。
概述:Jw.exe为一个自解压文件,启动后释放出AnnexPro.exe,MainPro.exe,SysStart.sys,mswinsock.dll, MainProWbj.dll,CMClient,dll六个文件,详细分析了AnnexPro与MainPro两个文件,行为在下方都有详细说明,绿色部分为代码块,红色部分为关键说明。 相关文件:AnnexPro.exe MainPro.exe
行为预览:Annexo.exe行为:
根据观察监控信息来看,Annexo.exe添加开机自启动,Annexo.exe创建互斥体检查是否启动MainPro.exe,如果发现进程被关闭则调用ShellExecuteA创建进程。如果自身进程被关闭,则调用ZwShutdownSystem关机(该为5秒检测一次),还有创建进程快照,检查窗口是否存在及文件是否完整等操作,下面流程未列出
0x1 mov edx,AnnexPro.0044FB0C ;ASCI"Global\Z_ANNEXPRO_ONE_FLAG" CALL to CreateMutexA from AnnexPro.004069FE pSecurity = NULL InitialOwner = FALSE MutexName = "Global\Z_ANNEXPRO_ONE_FLAG"
0x2 CreateMutexA pSecurity = NULL InitialOwner = FALSE MutexName = "Global\AnnexPro_MainPro_DrvStart" 创建互斥体检查程序是否启动运行,判断信号互斥量是否存在,防止二次行为
0x3 OpenMutexA Access = 0x1F0001 Inheritable = FALSE MutexName = "Global\Z_NEEDAUTOUPDATE_TWO_FLAG" 打开与当前进程文件同名的信号互斥量,判断信号互斥量是否存在
0x4 CreateFileA FileName = "\\.\SysStart" Access = GENERIC_READ|GENERIC_WRITE ShareMode = 0 pSecurity = NULL Mode = OPEN_EXISTING Attributes = 0 hTemplateFile = NULL 创建文件SysStart.sys,目录在system/dirvers
0x5 CreateFileA FileName = "C:\Documents and Settings\Administrator\桌面\1\log\\2015102810.txt" Access = GENERIC_WRITE ShareMode = FILE_SHARE_READ pSecurity = NULL Mode = CREATE_ALWAYS Attributes = NORMAL hTemplateFile = NULL 创建文件log\\2015102810.txt,将取到的信息存入文件中 文件格式: 2015-10-28 10:25:03:==========Run========== 2015-10-28 10:25:03:Last Build : 2015年8月6日14:01:14
0x6 ReadFile hFile = 000001A0 (window) Buffer = 00C7E898 ;00C7E8E4 4D 5A MZ BytesToRead = 40 (64.) pBytesRead = 00C7E8D8 pOverlapped = NULL 创建一个名为MainPro的文件,读取文件,Buffer内容4D 5A,PE结构,可执行文件 文件已dump出来
0x7 Call AnnexPro.004258B0 jmp to shell32.ShellExecuteA ShellExecuteA最终调用会在CreateProcessW CreateProcessW ModuleFileName = "C:\Documents and Settings\Administrator\桌面\1\MainPro.exe" CommandLine = ""C:\Documents and Settings\Administrator\桌面\1\MainPro.exe" " pProcessSecurity = NULL pThreadSecurity = NULL InheritHandles = FALSE CreationFlags = CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT|CREATE_DEFAULT_ERROR_MODE pEnvironment = NULL CurrentDir = "C:\Documents and Settings\Administrator\桌面\1\" pStartupInfo = 00175D10 pProcessInfo = 00175D5C 创建进程启动MainPro.exe,当MainPro.exe进程不存在时则会继续进行创建。
Annexo.exe调用api的时候都是通过一个jmp跳到系统领空,而不是一般程序的直接调用,这样在导入表中就无法查找到这些重要的api,如下图所示:
MainPro.exe行为: MainPro.exe启动联网后会随机创建进程,因此在CreateProcess等系列函数下断点,没有断下来,根据监控信息得知,Hook了NtCreateProcess,NtCreateProcessEx这两个函数,联网会触发收发包函数send,recv函数下断点,随机进程名称,随机进程路径在rand函数下断点。MainPro.exe在调用api的时候也是通过一个jmp跳到系统领空,而不是一般程序的直接调用,这样在导入表中就无法查找到这些重要的api。
0x1 RegOpenKeyExA hKey = HKEY_LOCAL_MACHINE;主键 Subkey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Run";子键 Reserved = 0x0;保留 Access = KEY_ALL_ACCESS;权限 pHandle = 0012FEF0 打开注册表HKEY_LOCAL_MACHINE->SOFTWARE\Microsoft\Windows\CurrentVersion\Run 看程序是否自动启动 数值名称:MicroBvd 数值数据:C:\WINDOWS\System32\AnnexPro.exe
0x2 程序启动时首先创建随机数,暂不知道有何作用 004190AC Call dword ptr ds:[<&winmm.timeGetTime>] ;记录开始时间 xor edx,edx ;edx寄存器清零 Mov ecx,03E8 ;ecx = 0X3E8 Div ecx ;ecx做除法 Push edx ;余数,将余数做参数 Call dword ptr ds:[<&msvcrt.srand>] ;srand(edx) Add esp,0x4 Call dword ptr ds:[<&msvcrt.rand>] ;rand()
0x3 通用注入流程: CreateProcess->GetThreadContext->ReadProcessMemory->ZwUnmapViewOfSection->VirtualAllocEx->WriteProcessMemory ->SetThreadContext->ResumeThread 怀疑使用的API: MoveFileA GetMoudleHandleA CharNextA GetTempFileNameA GetTempPathA CreateDirectoryA SHFileOperationA
Mov edi,dword ptr ds:[<&kernel32.GetProcAdress>] Push dump.00433B54 ;EnumProcess 列出系统的所有进程,包括详细文件名以及引用的所有动态库文件 Push esi Call edi ;Call GetProcAddress 查找指定DLL的导出函数地址
Push dump.00433B40 ;EuumProcessMoudles Push esi Call edi Mov ebx,eax Push dump.00433B28 ;GetMoudleFileNameExA Push esi Mov dword ptr ss:[esp+0xAC],ebx Call edi
Push ecx Push 0x1000 Push edx Call ebp EnumProcess
0x4 004039F1 Push eax Push 0x0 Push 0x410 Call dword ptr ds:[<&kernel32.OpenProcess>];打开进程返回句柄,为后面使用
00403A17 Push ecx Push 0x1000 Push edx Push esi Call dword ptr ss:[esp+0xB4] EnumProcessModules;枚举获取进程的所有模块
00403A3C Push 0x104 Push eax Push ecx Push esi Call dword ptr ss[esp+0x90] GetModuleFileNameExA;根据进程句柄获取进程文件名 这里循环遍历进程,取得所有进程的加载的模块信息以及进程文件信息
0x5 程序启动时send断下来 Call to send from CMClient.005429F4 Socket = 0x308 Data = 001CF7A0 DataSize = 97 Flags = 0 此处为Data内容
继续运行,在rand处断下,分析为第二段的内容,往下跟应该会有创建进程文件等操作。 Push 0xFF ;255 Push eax Call dword ptr ds:[0x42D800] ;ws2_32.gethostname 获取本机名称 Lea ecx,dword ptr ss:[esp+0x14] Push ecx Call dword ptr ds:[0x42D80C] ;ws2_32.gethostbyname
Call dword ptr ds:[0x42D11C];kernel32.GetComputerNameA
Call dword ptr ds:[0x42D7E8] ;ws2_32.socket Mov edi,dword ptr ds:[0x42D7C4] ; ws2_32.WASCreateEvent Call edi Call dword ptr ds:[0x42D7E4] ;ws2_32.ntohs Call dword ptr ds:[0x42D7F8] ;ws2_32.bind 上面部分是socket操作,取得本机的一些信息,下面创建线程,设置线程优先级,至此“随机进程”还未出现,操作应该还在后面 00419515 mov edi,dword ptr ds:[0x42D10C] ; kernel32.CreateThread 创建线程 lea edx,dword ptr ss:[esp+0x8] push ebx push edx push 0x0 push esi push MainPro.0041ADC0 push 0x0 push 0x0 Call edi
Mov ebx,dword ptr ds:[0x42D198] ;kernel32.SetThreadPriority 设置线程优先级 Push 0xF Push eax Mov dword ptr ds:[esi+0x164],eax Call ebx
rand函数地址004198f5 字符串地址00434244“以连接到服务器” 思路:根据测试情况,MainPro.exe在连接服务器后会产生随机进程,因此在00434244出下断,说明已经连接服务器,创建进程的动作应该在后面,跟进。 此后的操作Call 004126A0 Call 004068A0 Call 00411C20 Call 004123A0 Call dword ptr ds:[0x42D108] kernel32.CreateProcessA在004125E6此处找到了进程创建操作,在这之上调用了GetSystemDirectory取得windows的系统目录。
v1处应为string(“xxx”),把v1的值拷贝给ComnandLine,之后调用CreateProcessA创建进程。 分析到此完成。
MainPro.exe启动后进程的的监控情况,驱动实现,原理:利用PsSetCreateProcessNotifyRoutine函数。
[C++] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 还原了SysStart.sys的部分代码
NTSTATUS sub_4010E0( PCWSTR SourceString, PCWSTR String1)
{
UNICODE_STRING DestinationString;
NTSTATUS var_28 = 0;
UNICODE_STRING ValueName;
RtlInitUnicodeString(&DestinationString,SourceString);
RtlInitUnicodeString(&ValueName,SourceString);
ObjectAttributes.Length = 0x18;
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.Attrbutes = 0x40;
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.SecurityDescriptor = 0;
ObjectAttributes.SecurityQualityOfService = 0;
HANDLE KeyHandle;
var_24 = ZwOpenKey(KeyHandle,0xF003,&ObjectAttributes);
if (var_24 <= 0)
{
DbgPrint( "ZwOpenKey Wrong\n" );
return ;
}
else
{
SIZE_T NumberOfBytes;
ExAllocatePool(0,NumberOfBytes);
NumberOfBytes = 0x110;
var_24 = ZwQueryValueKey(KeyHandle,&ValueName,2,KeyValueInformation,NumberOfBytes);
if (var_24 >= 0)
{
}
else
{
DbgPrint( "ZwQueryValueKey Wrong:%08x\n" );
}
}
}
NTSTATUS sub_401450()
{
HANDLE ThreadHandle;
NTSTATUS v2;
UNICODE_STRING DestinationString;
KeInitializeEvent(&Event, SynchronizationEvent, 1u);
RtlInitUnicodeString(&DestinationString, L "This is a string for test!\n" );
v2 = PsCreateSystemThread(&ThreadHandle, 0, 0, 0, &ClientId, StartRoutine, &DestinationString);
if ( ThreadHandle )
{
PsLookupThreadByThreadId(ClientId.UniqueThread, &Object);
}
if ( v2 < 0 )
{
DbgPrint(aTestCreatethre);
}
ZwClose(ThreadHandle);
return KeWaitForSingleObject(&Event, 0, 0, 0, 0);
}
void StartRoutine( PVOID StartContext)
{
KeSetEvent(&Event,0,0);
while (!byte_4044CC)
{
dword_4044C0 = 1;
sub_4013C0(5000);
if ( dword_4044C0 == 1 && dword_404000 == 1 )
{
if ( dword_4044C4 )
{
DbgPrint(aNtshutdownsyst);
NtShutdownSystem(0);
}
else
{
dword_4044C4 = 1;
DbgPrint(aFirstNtshutdow);
}
}
if ( dword_404000 == 2 )
{
sub_4013C0(5000);
}
}
}
|
[C++] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 进程监控的代码。
#include <ntifs.h>
#include "ntddk.h"
#define MAX_PATH 256
VOID GetProcessPath( ULONG eprocess, PUNICODE_STRING pFilePath)
{
ULONG object;
PFILE_OBJECT FilePointer;
UNICODE_STRING name;
if (MmIsAddressValid(( PULONG )(eprocess + 0x138)))
{
object = (*( PULONG )(eprocess + 0x138));
if (MmIsAddressValid(( PULONG )(( ULONG )object + 0x014)))
{
object = *( PULONG )(( ULONG )object + 0x014);
if (MmIsAddressValid(( PULONG )(( ULONG )object + 0x0)))
{
object = *( PULONG )(( ULONG_PTR )object + 0x0);
if (MmIsAddressValid(( PULONG )(( ULONG )object + 0x024)))
{
object=*( PULONG )(( ULONG )object + 0x024);
}
else return ;
}
else return ;
}
else return ;
}
else return ;
FilePointer = (PFILE_OBJECT)object;
ObReferenceObjectByPointer(
( PVOID )FilePointer,
0,
NULL,
KernelMode);
RtlVolumeDeviceToDosName(FilePointer->DeviceObject, &name);
RtlCopyUnicodeString(pFilePath, &name);
RtlAppendUnicodeStringToString(pFilePath, &FilePointer->FileName);
ObDereferenceObject(FilePointer);
}
VOID ProcessNotifyRoutine(
IN HANDLE ParentId,
IN HANDLE ProcessId,
IN BOOLEAN Create
)
{
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS pEprocess = NULL;
UNICODE_STRING uniPath;
uniPath.Length = 0;
uniPath.MaximumLength = MAX_PATH * 2;
uniPath.Buffer = ( PWSTR )ExAllocatePool(NonPagedPool, uniPath.MaximumLength);
if (Create)
{
DbgPrint( "*******----有----新----进----程----创----建----*******\r\n" );
DbgPrint( "父进程信息\r\n" );
DbgPrint( " PID: %d\r\n" , ParentId);
status = PsLookupProcessByProcessId(ParentId, &pEprocess);
if (NT_SUCCESS(status))
{
GetProcessPath(pEprocess, &uniPath);
DbgPrint( " 路径: %wZ\r\n" , &uniPath);
}
DbgPrint( "创建进程信息\r\n" );
DbgPrint( " PID: %d\r\n" , ProcessId);
status = PsLookupProcessByProcessId(ProcessId, &pEprocess);
if (NT_SUCCESS(status))
{
GetProcessPath(pEprocess, &uniPath);
DbgPrint( " 路径: %wZ\r\n" , &uniPath);
}
}
else
{
DbgPrint( "*******----有----旧----进----程----退----出----*******\r\n" );
DbgPrint( "退出进程信息\r\n" );
DbgPrint( " PID: %d\r\n" , ProcessId);
status = PsLookupProcessByProcessId(ProcessId, &pEprocess);
if (NT_SUCCESS(status))
{
GetProcessPath(pEprocess, &uniPath);
DbgPrint( " 路径: %wZ\r\n" , &uniPath);
}
}
ExFreePool(uniPath.Buffer);
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
DbgPrint( "Stop Process Create/Delete Mon\r\n" );
status = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, TRUE);
if (!NT_SUCCESS(status))
{
DbgPrint( "Call PsSetCreateProcessNotifyRoutine Error!\r\n" );
DbgPrint( "Status Code: 0x%08X" , status);
}
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
DbgPrint( "Start Process Create/Delete Mon\r\n" );
pDriverObject->DriverUnload = DriverUnload;
status = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE);
if (!NT_SUCCESS(status))
{
DbgPrint( "Call PsSetCreateProcessNotifyRoutine Error!\r\n" );
DbgPrint( "Status Code: 0x%08X" , status);
return status;
}
return status;
}
|
|