恶意程序的沙盒执行部分 前面介绍了对执行恶意程序采集到log 进行分析的过程, 现在我们介绍下沙盒执行部分, 与前面的代码是运行在 host 机器上不同, 这部分代码是运行在 虚拟机 guest 机器上的 。 [analyzer\windows\analyzer.py] 一、注入cuckoomon.dll 到恶意程序进程空间, cuckoomon.dll 将监视恶意程序的行为如 API 调用及其参数 创建 PipeServer 用来和注入的模块通信。 以 exe 为例, 创建进程运行恶意程序 注入cuckoomon.dll到恶意程序进程。[代码察看 analyzer\windows\modules\packages] 如果pipe收到 " PROCESS:" 命令, 表示恶意程序正在创建子进程 或者修改别的进程空间内容,那么这个进程也会被注入cuckoomon.dll。 注入 cuckoomon.dll 到malware 程序。 注入的步骤是: 在恶意程序的进程空间分配一块内存 在分配的内存内填写 cuckoomon.dll 的路径 使用CreateRemoteThread 或者 QueueUserAPC调用系统函数 loadLibrary load cuckoomon.dll 进恶意程序的进程空间. 注意 loadlibrary 函数在kernel32.dll 中, 而 kernel32.dll 影射的地址在每个进程中是一样的. 所以我们可以直接将 loadlibrary 函数地址直接用在恶意程序的进程空间, 但是loadlibrary(path) 的参数 path 的地址一定是在恶意程序的地址空间. 以下是 dll 注入的python 代码 class Process: """Windows process.""" def inject(self, dll=os.path.join("dll", "cuckoomon.dll"), apc=False): """Cuckoo DLL injection. @param dll: Cuckoo DLL path. @param apc: APC use. """ if self.pid == 0: log.warning("No valid pid specified, injection aborted") return False if not self.is_alive(): log.warning("The process with pid %d is not alive, injection " "aborted" % self.pid) return False dll = randomize_dll(dll) if not dll or not os.path.exists(dll): log.warning("No valid DLL specified to be injected in process " "with pid %d, injection aborted" % self.pid) return False arg = KERNEL32.VirtualAllocEx(self.h_process, None, len(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) if not arg: log.error("VirtualAllocEx failed when injecting process with " "pid %d, injection aborted (Error: %s)" % (self.pid, get_error_string(KERNEL32.GetLastError()))) return False bytes_written = c_int(0) if not KERNEL32.WriteProcessMemory(self.h_process, arg, dll + "\x00", len(dll) + 1, byref(bytes_written)): log.error("WriteProcessMemory failed when injecting process " "with pid %d, injection aborted (Error: %s)" % (self.pid, get_error_string(KERNEL32.GetLastError()))) return False kernel32_handle = KERNEL32.GetModuleHandleA("kernel32.dll") load_library = KERNEL32.GetProcAddress(kernel32_handle, "LoadLibraryA") config_path = os.path.join(os.getenv("TEMP"), "%s.ini" % self.pid) with open(config_path, "w") as config: cfg = Config("analysis.conf") config.write("host-ip={0}\n".format(cfg.ip)) config.write("host-port={0}\n".format(cfg.port)) config.write("pipe={0}\n".format(PIPE)) config.write("results={0}\n".format(PATHS["root"])) config.write("analyzer={0}\n".format(os.getcwd())) config.write("first-process={0}\n".format(Process.first_process)) Process.first_process = False if apc or self.suspended: log.info("Using QueueUserAPC injection") if not self.h_thread: log.info("No valid thread handle specified for injecting " "process with pid %d, injection aborted" % self.pid) return False if not KERNEL32.QueueUserAPC(load_library, self.h_thread, arg): log.error("QueueUserAPC failed when injecting process " "with pid %d (Error: %s)" % (self.pid, get_error_string(KERNEL32.GetLastError()))) return False log.info("Successfully injected process with pid %d" % self.pid) else: event_name = "CuckooEvent%d" % self.pid self.event_handle = KERNEL32.CreateEventA(None, False, False, event_name) if not self.event_handle: log.warning("Unable to create notify event..") return False log.info("Using CreateRemoteThread injection") new_thread_id = c_ulong(0) thread_handle = KERNEL32.CreateRemoteThread(self.h_process, None, 0, load_library, arg, 0, byref(new_thread_id)) if not thread_handle: log.error("CreateRemoteThread failed when injecting " + "process with pid %d (Error: %s)" % (self.pid, get_error_string(KERNEL32.GetLastError()))) KERNEL32.CloseHandle(self.event_handle) self.event_handle = None return False else: KERNEL32.CloseHandle(thread_handle) return True 上面介绍了如何注入 cuckoomon.dll 到恶意程序的地址空间。 下面接着介绍 cuckoomon.dll工作原理。 二、cuckoomon.dll工作原理 Cuckoo Sandbox的核心模块是cuckoomon.dll, 使用 hook技术拦截恶意软件的执行。cuckoo sandbox 可以监控windows 可执行文件, office 文件 (Microsoft Word, Microsoft Excel), PDF 文件, 及其它运行在用户模式的各种程序。 他的位置在cockoo/analyzer/windows/dll/cuckoomon.dll. 他的源代码:https://github.com/cuckoobox/cuckoomon cuckoomon.dll 的 DllMain() 会调用 set_hooks() , 然后 设置 CuckooEvent, 通知 成功hook , 让挂起的恶意程序继续运行。 先看看这个数据结构: typedef struct _hook_t { const wchar_t *library; // 被hook的api的库 const char *funcname; // 被hook的 api 名字 // instead of a library/funcname combination, an address can be given // as well (this address has more priority than library/funcname) void *addr; // 被hook的api的地址 // pointer to the new function void *new_func; // // "function" which jumps over the trampoline and executes the original // function call void **old_func; //成功hook后指向 gate // allow hook recursion on this hook? // (see comments @ hook_create_pre_gate) int allow_hook_recursion; // this hook has been performed int is_hooked; unsigned char gate[128]; // 存放callgate 代码 unsigned char pre_gate[128]; //存放 pre_gate代码 unsigned char hook_data[32]; // 间接跳转时候存放跳转目的地址 } hook_t; 然后分析函数 void set_hooks() { // the hooks contain the gates as well, so they have to be RWX DWORD old_protect; VirtualProtect(g_hooks, sizeof(g_hooks), PAGE_EXECUTE_READWRITE, &old_protect); hook_disable(); // now, hook each api : ) g_hooks是一个静态数组,数组内容是希望hook的 windows api for (int i = 0; i < ARRAYSIZE(g_hooks); i++) { hook_api(&g_hooks, HOOKTYPE); } hook_enable(); } 可见最重要的工作是在函数 hook_api 中执行。 int hook_api(hook_t *h, int type) { // 创建调用门指令代码 // 修改 原api 的第一条指令为跳转指令,跳转到调用门代码执行 } 具体看cuckoo的源代码, 短短几十行代码, 就实现了hook 机制。 |
转载于:https://blog.51cto.com/sevemal/1397666