Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI Fuzz相关研究 #70

Open
xinali opened this issue Dec 8, 2020 · 0 comments
Open

GUI Fuzz相关研究 #70

xinali opened this issue Dec 8, 2020 · 0 comments
Labels

Comments

@xinali
Copy link
Owner

xinali commented Dec 8, 2020

GUI Fuzz相关研究

最近在研究windows GUI程序的fuzz问题,为了提高一些效率,测试了各种办法,虽然最终没有帮助到我目前需要测试的程序,但是还是把最近折腾的技术记录一下,以后可能还会继续做一些延申的研究,到时可能会持续更新

Dynamorio wrap研究

Dynamorio是一整套的动态执行框架,其中包含了很多功能,目前windows下最流行的winafl就是用它做的代码覆盖率监控。最近也研究了不少它的东西,这次是想用它的wrap apiGUI程序的部分函数进行更改,或者替代,以提高fuzz的效率,先来看一下wrap涉及到最主要的两个的API

generic_func_t dr_get_proc_address(
    module_handle_t lib, /* 导出函数的module */
    const char *name     /* 需要wrap的导出函数 */
    )

得到导出函数后,对其进行wrap

DR_EXPORT bool drwrap_wrap(
    app_pc func,     /* dr_get_proc_address 返回值 */ 
    void(*)(void *wrapcxt, OUT void **user_data) pre_func_cb, /* 导出函数前向处理 */
    void(*)(void *wrapcxt, void *user_data) post_func_cb      /* 导出函数后向处理 */
)

有了这两个函数,比如我们来编写一下,记录程序堆分配过程中用到mallocfree的情况

#include "stdafx.h"
#include <fstream>
#include "dr_api.h"
#include "drmgr.h"
#include "drwrap.h"
using namespace std;

static void event_exit(void);
static void wrap_malloc_pre(void *wrapcxt, OUT void **user_data);
static void wrap_malloc_post(void *wrapcxt, void *user_data);
static void wrap_free_pre(void *wrapcxt, OUT void **user_data);

ofstream LogFile;
#define MALLOC_ROUTINE_NAME "malloc"
#define FREE_ROUTINE_NAME "free"

static void module_load_event(void *drcontext, const module_data_t *mod, bool loaded)
{
	app_pc towrap = (app_pc)dr_get_proc_address(mod->handle, MALLOC_ROUTINE_NAME);
	if (towrap != NULL)
	{
		bool ok = drwrap_wrap(towrap, wrap_malloc_pre, wrap_malloc_post);

		if (!ok)
		{
			dr_fprintf(STDERR, "[-] Could not wrap 'malloc': already wrapped?\n");
			DR_ASSERT(ok);
		}
	}

	towrap = (app_pc)dr_get_proc_address(mod->handle, FREE_ROUTINE_NAME);
	if (towrap != NULL)
	{
		bool ok = drwrap_wrap(towrap, wrap_free_pre, NULL);

		if (!ok)
		{
			dr_fprintf(STDERR, "[-] Could not wrap 'free': already wrapped?\n");
			DR_ASSERT(ok);
		}
	}
}

DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[])
{
	LogFile.open("memprofile.out");

	dr_set_client_name("DynamoRIO Sample Client 'wrap'", "http://dynamorio.org/issues");
	dr_log(NULL, LOG_ALL, 1, "Client 'wrap' initializing\n");

	if (dr_is_notify_on()) 
	{
		dr_enable_console_printing();
		dr_fprintf(STDERR, "[*] Client wrap is running\n");
	}

	drmgr_init();
	drwrap_init();
	dr_register_exit_event(event_exit);
	drmgr_register_module_load_event(module_load_event);
}

static void event_exit(void)
{
	drwrap_exit();
	drmgr_exit();
}

static void wrap_malloc_pre(void *wrapcxt, OUT void **user_data)
{
	/* malloc(size) or HeapAlloc(heap, flags, size) */
	//size_t sz = (size_t)drwrap_get_arg(wrapcxt, 2); // HeapAlloc
	size_t sz = (size_t)drwrap_get_arg(wrapcxt, 0); // malloc

	LogFile << "[*] malloc(" << dec << sz << ")"; // log the malloc size
}

static void wrap_malloc_post(void *wrapcxt, void *user_data)
{
	int actual_read = (int)(ptr_int_t)drwrap_get_retval(wrapcxt);
	LogFile << "\t\t= 0x" << hex << actual_read << endl;
}

static void wrap_free_pre(void *wrapcxt, OUT void **user_data)
{
	int addr = (int)drwrap_get_arg(wrapcxt, 0);
	LogFile << "[*] free(0x" << hex << addr << ")" << endl;
}

编译之后测试

D:\tmp\DynamoRIO\bin32\drrun.exe -c .\Debug\WrapMallocFree.dll -- calc.exe

效果

image-20201208164023321

记录了calc进程启动过程中mallocfree的使用。

这种运用在fuzz GUI程序可能会经常用到,比如我们wrap

MessageBox 禁止弹出MessageBox
ShowWindow 不显示窗口
CreateWindow 在post过程中返回创建失败

为了提高fuzz的效率,我们可能会用到更多的控制窗口的程序,以提高窗口fuzz的效率

SetWindowsHookExA消息阻断研究

SetWindowsHookExA是windows官方提供的可以hook windows消息的API

语法

HHOOK SetWindowsHookExA(
  int       idHook,
  HOOKPROC  lpfn,
  HINSTANCE hmod,
  DWORD     dwThreadId
);

我们可以通过载入特定的dll,在需要hook的位置hook特定的windows消息

// dllmain.cpp : Defines the entry point for the DLL application.

#include "pch.h"

#include <fstream>
#include <iostream>
#include <exception>
#include <ctime>

#define _CRT_SECURE_NO_WARNINGS

std::ofstream LogFile;

HMODULE hinst;
HHOOK hhk = NULL;

LRESULT CALLBACK WNDProc(int code, WPARAM wParam, LPARAM lParam)
{
	if (code >= 0) 
	{
		char time_buffer[4096];
		__time64_t long_time;
		struct tm new_time;

		_time64(&long_time);
		localtime_s(&new_time, &long_time);
		snprintf(time_buffer, 4096, "%02d/%02d/%02d %02d:%02d:%02d", new_time.tm_mon + 1, new_time.tm_mday, new_time.tm_year % 100, new_time.tm_hour, new_time.tm_min, new_time.tm_sec);

		LogFile << "------" << time_buffer  << "------" << std::endl;
		PCWPSTRUCT wnd_stru = (PCWPSTRUCT)lParam;
		LogFile << " [-] window: " << wnd_stru->hwnd << std::endl;
		LogFile << " [-] message: " << wnd_stru->message << std::endl;
		LogFile << " [-] wParam: " << wnd_stru->wParam << std::endl;
		LogFile << " [-] lParam: " << wnd_stru->lParam << std::endl;
		// return CallNextHookEx(hhk, code, wParam, lParam);
	}
	return CallNextHookEx(hhk, code, wParam, lParam);
}

extern "C" __declspec(dllexport) void HookInstall(unsigned long threadID)
{
	hhk = SetWindowsHookEx(WH_CALLWNDPROC, WNDProc, hinst, threadID);
	LogFile << "install hook done" << std::endl;
}

extern "C" __declspec(dllexport) void HookUninstall()
{
	UnhookWindowsHookEx(hhk);
}


BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	LogFile.open("Hook.out");
	hinst = hModule;
	return TRUE;
}

在创建进程时,可以利用widnows detours载入dll

const char* dll_path = "D:\\Dropbox\\code\\xfuzzer\\xdb\\Debug\\MessageHook.dll";
if (!DetourCreateProcessWithDllExA(NULL, 
                                   cmd,
                                   NULL,
                                   NULL,
                                   inherit_handles,
                                   DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | CREATE_SUSPENDED,
                                   NULL,
                                   NULL,
                                   &si,
                                   &pi,
                                   dll_path,
                                   NULL))
{
    FATAL("CreateProcess failed, GLE=%d.\n", GetLastError());
}
ResumeThread(pi.hThread);

在进程的入口点,安装钩子

void OnEntrypoint()
{
    HMODULE *module_handles = NULL;
    DWORD num_modules = GetLoadedModules(&module_handles);
    for (DWORD i = 0; i < num_modules; i++)
    {
        char base_name[MAX_PATH];
        GetModuleBaseNameA(child_handle, module_handles[i], (LPSTR)(&base_name), sizeof(base_name));
        if (trace_debug_events)
            printf("Debugger: Loaded module %s at %p\n", base_name, (void *)module_handles[i]);
		if (strcmp(base_name, "MessageHook.dll") == 0)
		{
			HMODULE hHook = LoadLibraryA("D:\\Dropbox\\code\\xfuzzer\\xdb\\Debug\\MessageHook.dll");
			Install install = (Install)GetProcAddress(hHook, "HookInstall"); // 安装钩子
			if (install == NULL)
			{
				FATAL("Get CallWndProc failed!\n");
			}
			install(child_thread_id);
			printf("install done\n");
		}
        OnModuleLoaded((void *)module_handles[i], base_name);
    }
    if (module_handles)
        free(module_handles);

    child_entrypoint_reached = true;

    if (trace_debug_events)
        printf("Debugger: Process entrypoint reached\n");
}

来看看效果

image-20201208171825612

记录的窗口过程消息

image-20201208175529390

fuzz GUI程序时,如果我们能够直接block消息的传递,就可以减少很多的麻烦,提升不少的效率。

暂时就这么多,里面有很多细节来不及写,有兴趣的可以联系我

参考

Function Wrapping and Replacing Extension

Dynamic Binary Instrumentation Primer

@xinali xinali added the fuzzing label Dec 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant