本帖最后由 岁月静好。 于 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++] 纯文本查看 复制代码 还原了SysStart.sys的部分代码
NTSTATUS sub_4010E0(PCWSTR SourceString,PCWSTR String1)
{
UNICODE_STRING DestinationString;
/*
VOID
RtlInitUnicodeString(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
*/
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;
/*
NTSTATUS
ZwOpenKey(
OUT PHANDLE KeyHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
*/
HANDLE KeyHandle;
var_24 = ZwOpenKey(KeyHandle,0xF003,&ObjectAttributes);
if(var_24 <= 0)
{
DbgPrint("ZwOpenKey Wrong\n");
return;
}
else
{
SIZE_T NumberOfBytes;
/*
PVOID
ExAllocatePool(
IN POOL_TYPE PoolType,
IN SIZE_T NumberOfBytes
);
*/
ExAllocatePool(0,NumberOfBytes);
/*
NTSTATUS
ZwQueryValueKey(
IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName,
IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
OUT PVOID KeyValueInformation,
IN ULONG Length,
OUT PULONG ResultLength
);
*/
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);//查找ETHREAD
}
if ( v2 < 0 )
{
DbgPrint(aTestCreatethre);//"[Test] CreateThread Test Failed!\n"
}
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);//"First NtShutdownSystem\n"
}
}
if ( dword_404000 == 2 )
{
sub_4013C0(5000);
}
}
}
[C++] 纯文本查看 复制代码 进程监控的代码。
#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; //盘符
// EPROCESS -> SectionObject
if(MmIsAddressValid((PULONG)(eprocess + 0x138)))
{
object = (*(PULONG)(eprocess + 0x138));
// SECTION_OBJECT -> Segment
if(MmIsAddressValid((PULONG)((ULONG)object + 0x014)))
{
object = *(PULONG)((ULONG)object + 0x014);
// SEGMENT_OBJECT -> ControlArea
// 不是0x018
if(MmIsAddressValid((PULONG)((ULONG)object + 0x0)))
{
object = *(PULONG)((ULONG_PTR)object + 0x0);
// CONTROL_AREA -> FilePointer
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", 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);
}
}
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;
} |