decaf 接口用法
来源:互联网 发布:三国吴国知乎 编辑:程序博客网 时间:2024/06/06 07:36
最近跟着老师做一个关于decaf的项目,因此对读的文章做点笔记。
- 简介
decaf是一个虚拟机,为开发者提供了许多调用接口,可以在运行时Hook。使用这些接口可以完全在客户机之外检索OS-level semantics(操作系统级别的语义),例如进程、系统API、按键、网络等。 - 样例插件
以下插件可以指定一个你想要追踪的进程,并在进程开始时打印进程名。
当DECAF加载该插件,它将首先调用init_plugin(void)
,可以通过plugin_interface_t
(DECAF_main.h) 定义插件的行为。但最重要的是指定plugin_cleanup
接口,通常用这个接口释放分配给该插件的资源,不这么做DECAF可能会崩。plugin_interface_t
还可以为DECAF定义你自己的命令,以便运行时与插件交互。
#include "DECAF_types.h" #include "DECAF_main.h" #include "DECAF_callback.h" #include "DECAF_callback_common.h" #include "vmi_callback.h" #include "utils/Output.h" #include "DECAF_target.h"//basic stub for plugins static plugin_interface_t my_interface; static DECAF_Handle processbegin_handle = DECAF_NULL_HANDLE;char targetname[512];// 当客户系统中开始一个新进程时callback被调用static void my_loadmainmodule_callback(VMI_Callback_Params params) { if(strcmp(params->cp.name,targetname)==0) DECAF_printf("Process %s you spcecified starts \n",params->cp.name); } // 执行monitor_proc命令的处理器 void do_monitor_proc(Monitor* mon, const QDict* qdict) { //复制被监测进程的名字 if ((qdict != NULL) && (qdict_haskey(qdict, "procname"))) { strncpy(targetname, qdict_get_str(qdict, "procname"), 512); } targetname[511] = '\0'; }static int my_init(void) { DECAF_printf("Hello World\n"); //为创建进程与移除进程注册 processbegin_handle =VMI_register_callback(VMI_CREATEPROC_CB, &my_loadmainmodule_callback, NULL); if (processbegin_handle == DECAF_NULL_HANDLE){ DECAF_printf("Could not register for the create or remove proc events\n"); } return (0);}// 当插件卸载时调用该函数static void my_cleanup(void) { DECAF_printf("Bye world\n"); // 注销进程的启动与退出的调用 if (processbegin_handle != DECAF_NULL_HANDLE) { VMI_unregister_callback(VMI_CREATEPROC_CB, processbegin_handle); processbegin_handle = DECAF_NULL_HANDLE; }} // 支持插件的命令,在plugin_cmds.h中 static mon_cmd_t my_term_cmds[] = { {.name = "monitor_proc", .args_type = "procname:s?", .params = "[procname]", .help = "Run the tests with program [procname]" }, {NULL, NULL, }, };//该函数通过DECAF注册插件接口(plugin_interface)。该接口用于注册自定义命令,让DECAF清楚插件卸载后调用哪个卸载函数,等等 plugin_interface_t init_plugin(void) { my_interface.mon_cmds = my_term_cmds; my_interface.plugin_cleanup = &my_cleanup; my_init(); return (&my_interface);}
在函数init_plugin(void)
中,我们用my_term_cmds
定义自己的命令。在my_term_cmds
,我们指定命令名、命令处理程序,命令参数和帮助信息。plugin_cleanup
也由my_cleanup
定义。
在my_init()
中我们注册VMI_CREATEPROC_CB
调用以及它的处理器my_loadmainmodule_callback
。故当一个进程开始时,DECAF会调用my_loadmainmodule_callback()
,并且从它的参数中可以得到进程PID、名称和CR3。故你可以检查该检查是否是你用monitor_proc命令指定的进程,若是则打印进程名。当然,我们还可以做许多其他事,例如可以在这里注册DECAF_INSN_BEGIN_CB回调与其处理程序。在它的处理程序中,我们检查它是否属于指定的进程,并使用下面的代码打印出指令。
uint32_t target_cr3; static void my_insn_begin_callback(DECAF_Callback_Params* params) { if(params->ib.env->cr[3]==target_cr3) { DECAF_printf("EIP 0x%08x \n",params->ib.env->eip); }} //当客户系统中开始一个新进程时该callback被调用 static void my_loadmainmodule_callback(VMI_Callback_Params params) { if(strcmp(params->cp.name,targetname)==0){ DECAF_printf("Process %s you spcecified starts \n",params->cp.name); target_cr3=params->cp.cr3; DECAF_register_callback(DECAF_INSN_BEGIN_CB, &my_insn_begin_callback,NULL); } }
有一个需要注意的是VMI_register_callback的第三个参数,如果它是NULL,这意味着这个回调将在整个过程中一直被调用。如果指针指向1,那么这个回调将一直被调用。如果指针指向0,则此回调被禁用。其他类型的回调注册函数也遵循此约定。
现在就已经知道了如何注册或注销,启用或禁用回调了。
3. Hook API
对恶意软件分析时,api跟踪对于理解恶意软件的行为是至关重要的。传统的分析工具通过在不同的容易绕过的(尤其是被Rootkit绕过)层次上hook api来实现api跟踪。DECAF可以在虚拟机外更可靠得跟踪API。你可以在你的插件中hook任意的API或者EIP。在hookapitest插件中展现了如何hook api以及检索api参数。
现在,我们修改上面的样例代码来hook api NtCreateFile
并从栈中检索它的参数。首先,当目标进程开始时(my_loadmainmodule_callback
被调用时),我们通过hookapi_hook_function_byname注册了api hook。在下面的代码中,当客户系统调用NtCreateFile
时,NtCreateFile_call
将会被调用。对于被标记为“IN”的参数,你可以在栈中检索到它,但是对于“OUT”参数,当NtCreateFile返回时它才被赋值。为了处理这种情况,我们使用hookapi_hook_return
hook api 的返回值。当NtCreateFile_call
被调用,NtCreateFile返回的返回地址在EBP,我们应该把这个返回值传递给hookapi_hook_return
函数,另外,你可以通过hookapi_hook_return
的第三个、第四个参数把数据传递给NtCreateFile_ret
。在NtCreateFile_ret
中,我们在栈上检索文件句柄。在返回时,EBP存储第一个参数——文件句柄的地址,我们使用DECAF_read_mem
从EBP中读取该文件句柄。你还可以在hookapitests/custom_handlers.c中找到更复杂的参数检索函数,但它们的基本原理都是相同的。
正确检索参数的关键在于正确地理解“地址”。地址有三种:客户操作系统的虚拟地址、客户操作系统的物理地址和主机操作系统的虚拟地址。EBP的值为客户操作系统的虚拟地址。DECAF_read_mem
获取客户机操作系统内存中指定虚拟地址存放的内容。有时,参数的API是一个指针,你需要先读这个指针的值,然后使用decaf_read_mem
读取指针指向的内存。
另一件需要注意的事情是字符集问题。Windows内部使用unicode字符,如果你得到一些不可读的编码,你可能需要将其转换为可读的字符集。
以下为代码
DECAF_handle ntcreatefile_handle;typedef struct { uint32_t call_stack[12]; //参数与返回地址 DECAF_Handle hook_handle;}NtCreateFile_hook_context_t;/* NTSTATUS NtCreateFile( Out PHANDLE FileHandle, In ACCESS_MASK DesiredAccess, In POBJECT_ATTRIBUTES ObjectAttributes, Out PIO_STATUS_BLOCK IoStatusBlock, _In_opt_ PLARGE_INTEGER AllocationSize, In ULONG FileAttributes, In ULONG ShareAccess, In ULONG CreateDisposition, In ULONG CreateOptions, In PVOID EaBuffer, In ULONG EaLength ); */ static void NtCreateFile_ret(void *param) { NtCreateFile_hook_context_t *ctx = (NtCreateFile_hook_context_t *)param; DECAF_printf("NtCreateFile exit:"); hookapi_remove_hook(ctx->hook_handle); uint32_t out_handle; DECAF_read_mem(NULL, ctx->call_stack[1], 4, &out_handle); DECAF_printf("out_handle=%08x\n", out_handle); free(ctx);}static void NtCreateFile_call(void *opaque) { DECAF_printf("NtCreateFile entry\n"); NtCreateFile_hook_context_t ctx = (NtCreateFile_hook_context_t) malloc(sizeof(NtCreateFile_hook_context_t)); if(!ctx) //run out of memory return; DECAF_read_mem(NULL, cpu_single_env->regs[R_ESP], 12*4, ctx->call_stack); ctx->hook_handle = hookapi_hook_return(ctx->call_stack[0],NtCreateFile_ret, ctx, sizeof(*ctx));}static void my_loadmainmodule_callback(VMI_Callback_Params* params) { if(strcmp(params->cp.name,targetname)==0){ DECAF_printf("Process %s you spcecified starts \n",params->cp.name); target_cr3=params->cp.cr3;/// @ingroup hookapi /// install a hook at the function entry by specifying module name and function name /// @param mod module name that this function is located in /// @param func function name /// @param is_global flag specifies if this hook should be invoked globally or only in certain execution context (when should_monitor is true) /// @param cr3 the memory space that this hook is installed. 0 for all memory spaces. /// @param fnhook address of function hook /// @param opaque address of an opaque structure provided by caller (has to be globally allocated) // @param sizeof_opaque size of the opaque structure (if opaque is an integer, not a pointer to a structure, sizeof_opaque must be zero) /// @return a handle that uniquely identifies this hook /// Note that the handle that is returned, might not actually be active yet - you can check the eip value of the handle to find out /// the default value is 0. ntcreatefile_handle = hookapi_hook_function_byname( "ntdll.dll", "NtCreateFile", 1, target_cr3, NtCreateFile_call, NULL, 0); } }
文章来源:decaf-platform - decaf_plugins.wiki
- decaf 接口用法
- Decaf-platform安装篇
- decaf-platform - plugin_sample.wiki
- [DeCAF]DeCAF: A Deep Convolutional Activation Featurefor Generic Visual Recognition
- DECAF PLATFORM 编译安装小结
- libcurl用法 接口函数用法
- Externalizable接口的用法
- 接口的用法
- IConfigurationSectionHandler 接口的用法
- 接口的有关用法
- Enumeration接口的用法
- Externalizable接口的用法
- Struts2-Modeldriven接口用法
- OLE接口用法
- 标识接口的用法
- 接口的用法
- c#接口的用法
- IConvertible接口用法揭秘
- IntelliJ Idea 常用快捷键列表
- 实现一个函数,将一个字符串中的空格替换成“ ”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We Are Happy
- Shopping Offers问题及解法
- 连接数据库语句
- Python基础小笔记《2017-09-24》
- decaf 接口用法
- Android之使用AIDL进行IPC(一)
- [笔记]关于tarjan求连通分量 & 缩点
- iOS Compiling IB documents for earlier than iOS 7 is no longer supported
- 我的seajs实例
- python tornado 模板扩展
- SQL,计算group by分组后组内不同值的数量
- nginx配置多站点访问
- Eclipse+Tomcat+MAVEN+SVN项目完整环境搭建