8000 Hooks · carbonblack/binee Wiki · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
John Holowczak edited this page Aug 14, 2019 · 4 revisions

Binee's hook system follows a common format across the entire project. Each hook emulates a single function within a dynamically loaded library, and are broken into 2 categories: Partial hooks and Full hooks.

  • Partial hooks capture the proper function parameters for tracking purposes, but allow the functi 8000 on to continue forward without intervention from Binee.
  • Full hooks have the the same base functionality as partial hooks and instead will divert the function call out of the Unicorn emulator and into Binee. Full hooks allows us to define an in-place custom function for the hook, and often times will inject its own return value back into the emulator, skipping over the original function call. The emulation will then continue forward as if the native function call was made, leveraging information returned from the Binee hook itself.

For a missing hook, binee's output will prepend and append two stars (**) to the function name. This indicates that a hook is missing and will need to be added

Adding Hooks

Binee hooks are organized by library name. All hooks for functions within a library must be placed in the library's associated golang source file and subsequent hooks setup function within the respective operating system directory. The hook aggregate function is typically of the format <libraryname>hooks(). For example, if you want to hook the kernelbase.dll function CreateFileA in Binee, you would place the hook definition within the Kernelbasehooks() function within kernelbase.go in the windows directory from the Binee project root.

Note: As Windows is actively migrating kernel32 functions and into kernelbase, we opted to house hooks for both DLL's within the windows/kernelbase.go file.

The Hook Structure

Binee's hook structure is as follows:

type Hook struct {
	Name        string
	Parameters  []string
	Fn          func(*WinEmulator, *Instruction) bool
	Implemented bool
	Values      []interface{}
	Return      uint64
	HookStatus  string
	Lib         string
}
Typically the hooks we implement in Binee use the `Parameters`, `Fn`, and `Return` fields. 

Partial Hooks

Partial hooks are what make up most of the hooks within Binee. The scaffold for creating a partial hook:

emu.AddHook("<lib name>", "<function name>", &Hook{
    Parameters: []string{"argument1", "stringarg1:a", "unicodearg:w"},
})

Parameter names should reflect those indicated by official documentation for the applicable library. If documentation of a function does not exist and the parameter names are not known, the format unknownX is sufficient. Currently we do not indicate whether an argument is a pointer, so please do not include * in the parameter name to indicate as such. All argument types have no syntactic sugar with the exception of ASCII and widechar (utf8) strings. Any arguments to a function that are strings should prepend :a and :w for ASCII and widechar strings, respectively.

In the case of Windows, we are not currently leveraging the lib name field, and for any hook targetting Windows this can just be passed in as a blank string.

Full Hooks

Full hooks follow the same format as partial hooks, but also provide a Fn key in the Hook map to indicate the function we are replacing the function call with when emulating. This function can either be inline or can reference a function defined in the same library file. In the case of the Windows emulator, the function must have the return type:

func(emu *WinEmulator, instruction *Instruction) bool

Here is the scaffold for Windows emulator hooks:

emu.AddHook("<lib name>", "<function name>", &Hook{
    Parameters: []string{"argument1", "stringarg1:a", "unicodearg:w"},
    Fn: func(emu *WinEmulator, in *Instruction) bool {
        ...do stuff...
        return createdHookElsewhere(emu, in, <args values>...)(emu, in)
    },
})

These functions will almost always return some variation of the SkipFunction*() methods within windows/hooks.go, which have the necessary return type as outlined above. In fact, if we just want to skip over the function call and provide a static return value (or no return value), a full hook could be in the format:

emu.AddHook("<lib name>", "<function name>", &Hook{
    Parameters: []string{"argument1", "stringarg1:a", "unicodearg:w"},
    Fn:         SkipFunctionStdCall(true, 0x1),
    },
})

Currently Binee has a way to handle skipping functions invoked with both the stdcall and cdecl calling concentions. These skip functions takes a boolean to indicate if there is a value being returned (passed into the eax register) and the value that will be returned

Full hooks are typically used for handling system-level function calls, any type of I/O, or anything that may cause the process emulation to not proceed further.

Clone this wiki locally
0