岁月静好。 发表于 2015-11-11 10:41

小白之病毒分析- 网吧某监控软件。

本帖最后由 岁月静好。 于 2015-11-11 13:25 编辑

前几天上传的样本,得到众基友指点后自己分析,第一次发分析帖流程可能有些混乱,大牛勿喷,有错误请指出,小白在学习中...在此感谢指点过我的人。


概述:Jw.exe为一个自解压文件,启动后释放出AnnexPro.exe,MainPro.exe,SysStart.sys,mswinsock.dll,MainProWbj.dll,CMClient,dll六个文件,详细分析了AnnexPro与MainPro两个文件,行为在下方都有详细说明,绿色部分为代码块,红色部分为关键说明。相关文件:AnnexPro.exeMainPro.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.004069FEpSecurity = NULLInitialOwner = FALSEMutexName = "Global\Z_ANNEXPRO_ONE_FLAG"
0x2 CreateMutexA pSecurity = NULLInitialOwner = FALSEMutexName = "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                  ;00C7E8E44D 5AMZ                                  BytesToRead = 40 (64.)         pBytesRead = 00C7E8D8         pOverlapped = NULL         创建一个名为MainPro的文件,读取文件,Buffer内容4D 5A,PE结构,可执行文件 文件已dump出来
0x7 Call AnnexPro.004258B0 jmp to shell32.ShellExecuteAShellExecuteA最终调用会在CreateProcessWCreateProcessW          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。
0x1RegOpenKeyExA 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程序启动时首先创建随机数,暂不知道有何作用004190ACCall 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,0x4Call dword ptr ds:[<&msvcrt.rand>]          ;rand()
0x3通用注入流程:CreateProcess->GetThreadContext->ReadProcessMemory->ZwUnmapViewOfSection->VirtualAllocEx->WriteProcessMemory ->SetThreadContext->ResumeThread怀疑使用的API:MoveFileA GetMoudleHandleA CharNextA GetTempFileNameA GetTempPathA CreateDirectoryASHFileOperationA
Mov edi,dword ptr ds:[<&kernel32.GetProcAdress>]Push dump.00433B54             ;EnumProcess 列出系统的所有进程,包括详细文件名以及引用的所有动态库文件Push esiCall edi                           ;Call GetProcAddress 查找指定DLL的导出函数地址
Push dump.00433B40             ;EuumProcessMoudlesPush esiCall ediMov ebx,eaxPush dump.00433B28            ;GetMoudleFileNameExAPush esiMov dword ptr ss:,ebxCall edi
Push ecxPush 0x1000Push edxCall ebpEnumProcess
0x4004039F1Push eaxPush 0x0Push 0x410Call dword ptr ds:[<&kernel32.OpenProcess>];打开进程返回句柄,为后面使用
00403A17Push ecxPush 0x1000Push edxPush esiCall dword ptr ss: EnumProcessModules;枚举获取进程的所有模块
00403A3CPush 0x104Push eaxPush ecxPush esiCall dword ptr ss GetModuleFileNameExA;根据进程句柄获取进程文件名这里循环遍历进程,取得所有进程的加载的模块信息以及进程文件信息
0x5程序启动时send断下来Call to send from CMClient.005429F4Socket = 0x308Data = 001CF7A0DataSize = 97Flags = 0此处为Data内容
继续运行,在rand处断下,分析为第二段的内容,往下跟应该会有创建进程文件等操作。Push 0xFF ;255Push eaxCall dword ptr ds: ;ws2_32.gethostname 获取本机名称Lea ecx,dword ptr ss:Push ecxCall dword ptr ds: ;ws2_32.gethostbyname
Call dword ptr ds:;kernel32.GetComputerNameA
Call dword ptr ds: ;ws2_32.socketMov edi,dword ptr ds: ; ws2_32.WASCreateEventCall ediCall dword ptr ds: ;ws2_32.ntohsCall dword ptr ds: ;ws2_32.bind上面部分是socket操作,取得本机的一些信息,下面创建线程,设置线程优先级,至此“随机进程”还未出现,操作应该还在后面00419515    mov edi,dword ptr ds: ; kernel32.CreateThread 创建线程lea edx,dword ptr ss:push ebxpush edxpush 0x0push esipush MainPro.0041ADC0push 0x0push 0x0Call edi
Mov ebx,dword ptr ds:;kernel32.SetThreadPriority 设置线程优先级Push 0xFPush eaxMov dword ptr ds:,eaxCall ebx
rand函数地址004198f5 字符串地址00434244“以连接到服务器”思路:根据测试情况,MainPro.exe在连接服务器后会产生随机进程,因此在00434244出下断,说明已经连接服务器,创建进程的动作应该在后面,跟进。此后的操作Call 004126A0Call 004068A0Call 00411C20Call 004123A0Call dword ptr ds: kernel32.CreateProcessA在004125E6此处找到了进程创建操作,在这之上调用了GetSystemDirectory取得windows的系统目录。
IDA找到代码位置直接F5看操作。

v1处应为string(“xxx”),把v1的值拷贝给ComnandLine,之后调用CreateProcessA创建进程。分析到此完成。








MainPro.exe启动后进程的的监控情况,驱动实现,原理:利用PsSetCreateProcessNotifyRoutine函数。

还原了SysStart.sys的部分代码

NTSTATUS sub_4010E0(PCWSTR SourceString,PCWSTR String1)
{
      UNICODE_STRING DestinationString;
      
      /*
      VOID
    RtlInitUnicodeString(
                                                      IN OUT PUNICODE_STRINGDestinationString,
                                                      IN PCWSTRSourceString
    );
      */
      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 PHANDLEKeyHandle,
                              IN ACCESS_MASKDesiredAccess,
                              IN POBJECT_ATTRIBUTESObjectAttributes
    );
      */
      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_TYPEPoolType,
                                        IN SIZE_TNumberOfBytes
    );
    */
                ExAllocatePool(0,NumberOfBytes);
      
      /*
      NTSTATUS
      ZwQueryValueKey(
                                                IN HANDLEKeyHandle,
                                                IN PUNICODE_STRINGValueName,
                                                IN KEY_VALUE_INFORMATION_CLASSKeyValueInformationClass,
                                                OUT PVOIDKeyValueInformation,
                                                IN ULONGLength,
                                                OUT PULONGResultLength
    );
      */      
      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);//" 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);
                }         
      }
      
}
进程监控的代码。
#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;
}

我只做我自己 发表于 2015-11-16 19:39

网吧有公安部门安装的监控软件,你可以分析分析,爆爆菊花啥的

pleianth 发表于 2015-11-23 12:02

感谢分享
页: [1]
查看完整版本: 小白之病毒分析- 网吧某监控软件。