-
Notifications
You must be signed in to change notification settings - Fork 12
Advanced hook generation options
-
Generate Hooks for addresses (statically) referencing the current address.
-
Generate Hooks for functions containing code that (statically) references the current address.
-
Generate Hooks for addresses (statically) referencing the current function.
These options are fairly self-explanatory. They are supposed to be used when we are trying to identify which part of the code was run that references the current address, among the many that may reference it.
-
Generate Hooks for functions (statically) referencing the current function for depth X.
The idea behind this is to visualize all calls that may end up calling a certain function. While it can blow out of proportion and hook way too many functions, for a small depth X it can produce useful results and identify callers that are not direct ones, but serve as a visualization of the code path.
-
Generate Hooks for functions (statically) called by current function for depth X.
Similarly, the idea is to see where the code ends up after some function calls. It is recommended to use a small depth value or the output may be too large.
-
Generate a Hook for this (the current) address, through which this dialog was spawned.
This option is selected by default. It is equivalent to right clicking on an address and selecting "Copy Frida Hook Snippet".
-
Generate Hooks for functions (starting from current address, and moving for X elements).
This option is useful when functions that we are interested in are placed close by in the binary. As this is usually the case for similar functions in the code (for example, member functions of a class), it is quite common for these functions to also be placed one after the other in the binary as well.
-
Print the reason(s) why each hook is generated, maximum number of reasons: X.
The plugin in addition to generating hooks, also keeps track of why a certain hook is generated. For example, a function may be requested to be hooked through multiple options. Range hooks, references, by name, etc. This option, enables printing of reasons why a hook was generated for a function. If the list of reasons is too large, it prints up to X reasons.
-
In case of hook generation for functions: Do not include onEnter() / Do not include onLeave() / use Interceptor.replace() .
The first two options are fairly self-explanatory, but they will block printing output of other hook generation options when they are included in the corresponding callback. For example, most hook generation options print their extra information in the
onEnter()
callback, and it will not be included if theonEnter()
is not present. Additionally, in the case that the hook generation option "Include threadID and code indentation on function calls" is selected,onEnter()
/onLeave()
calls will not be excluded as their presence is necessary for that option's functionality.The
Interceptor.replace()
is a very useful call of the Frida Javascript API. It allows for entirely replacing a function with a custom implementation. However in the real world, great care must be taken so that the memory layout is not altered, as this can cause crashes. If for example, Ghidra has identified the number of arguments wrongly (or the Listing Window is not synced with the correct identification of the Decompiler Window), the generated javascript can end up crashing the program. -
Generate Backtace (ACCURATE/FUZZY).
This option utilizes the standard Frida API to generate a backtrace. It should be noted that it is not always reliable (the first caller, that is the first backtrace entry, seems to be more reliable however).
-
In case of hook generation for functions, do not print their parameters.
This option is self explanatory, it does not print the parameters.
-
In case of function parameter printing, their names should be printed as well.
This option, instead of printing
args[0]
,args[1]
in the parameters, it prints them with their name as they appear in the Decompiler Window. It is useful when symbols are known to Ghidra. -
For function beginnings, do not use OnEnter()/OnLeave() methods at all, but generate hooks treating them as normal addresses.
If an adress is at the start of a function, then normally
onEnter()
/onLeave()
methods are created in its hook. This option forces the address to be treated as any other address, withoutonEnter()
/onLeave()
methods.This will also cause the plugin execution to not follow any code paths that assume that the address is at the start of a function.
-
Generate Hook Script and not Snippet, registering interceptors through method X.
This is a highly useful option. Under the default setting, selecting this option is equivalent to right clicking an address and selecting "Copy Frida Hook Script". It creates skeleton code that registers the interceptors after two seconds. This is done as libraries may not be loaded immediately, so the code waits a little bit and then tries to register the interceptors.
If the interceptors are attempted to be registered before the library is loaded, they will not be registered. If however they are registered a significant amount of time after the library is loaded, maybe the code that is to be hooked has already run. As such, the two last options of this hook generation option allow for registering the interception, as soon as a library is loaded. This is done by hooking
dlopen()
andLoadLibrary()
calls, observing when they are called to load the library in question, and then establishing the hooks.
-
Generate hooks for functions whose name matches the a (case insensitive) regular expression.
This option is probably the most useful of all. In case symbols are known to Ghidra, then this allows hooking of functions that share a similar name. It may be the case that multiple functions appear related to a certain functionality (based on their name), but we don't know which of them are called when that functionality is invoked. So, we can hook them all, and see which ones are actually called when that functionality is run.
-
Generate hooks for functions whose mangled name matches a (case insensitive) regular expression.
This is similar to the above, but in this case the mangled symbols may also include parameter types.
-
Generate hook skeleton for a memory instruction pattern, being (Special) Copied from the Instruction Pattern Search window.
Hooking by memory pattern may be the best way to port hooks to newer binary versions. We can go to Ghidra's Instruction Pattern Search -> select some of the String Previews -> Copy Special -> Selected Instructions and paste the output (hex/binary) string in the text box. This will generate a hook that will try to identify code in every loaded module (it searches the .text segments), based on the instruction pattern given to it. If that code is found, a sample interception stub is created that will hook on that code.
-
Generate hooks for all exported symbols.
This option is useful when we want to identify how code lands onto a library, that is what function is called first inside the library. This of course assumes that the typical way of function calling is performed, by resolving an external symbol and jumping into it. If the program does not do a
CALL <external_function>
and say, only jumps into a random part of the library we are hooking, the hooks will not be triggered. -
Generate hooks for all imported symbols through ApiResolver('module').
This, along the previous option, can help build a complete picture of how a library interacts with its environment. It uses the Frida ApiResolver API to hook on all identified imports of the library. The user can then see in which cases the code leaves the current library and jumps on external functionalitites.
-
Create and initialize data structures that associate the hooked addresses with function names, accessible from javascript.
It may be the case that Ghidra somehow knows function names, that Frida does not. External symbol files, custom Ghidra scripts that extract symbols from the binary's data structures, or simply reversing, may allow Ghidra to be able to associate a human-friendly name with a function. This information however is not necessarily propagated/known to Frida at runtime. This option creates the following data structures related to the hooked addresses only (that is, not for all functions):
var dict_from_current_addresses_to_function_names; var dict_from_function_names_to_function_start_addresses; var dict_from_current_addresses_to_function_start_addresses; var dict_from_function_start_addresses_to_function_names;
As such, it is possible to be able to programmatically interact with the function names, using the
this.context.pc
instruction pointer (of the address that was hooked) as the starting variable.As stated, these data structures do not contain all functions, but only the ones that have code inside them that is hooked. Creating code that passes information on all function names to Frida can generate tens of thousands of lines, will require a separate script and is out of scope of this plugin.
-
Add javascript code in every hook generated.
This option will insert the provided javascipt code in every hook. The typical use case is to insert code that uses the
this.context.pc
and performs a functionality. The code should be given as an one-liner.It should be noted that if
onEnter()
calls are stripped, the injected code will not run as it is placed in anonEnter()
callback. -
Add try/catch blocks for Interceptor calls in order to not stop in case of error.
This option is highly useful and recommended to be used when a big number of hooks is to be generated. As Frida registers the interceptors, it may be the case that it fails to register one for some reason (perhaps due to not having a lot of space to overwrite). This will throw an exception and cause all other interception hooks that come later in the javascript code to not register as well.
This option bypasses that problem, wrapping each interception attempt with a try/catch block.
-
Include threadID and code indentation on function calls.
This option prints the current threadID for every function console output, and indents based on the call depth (relative to the currently hooked functions and not the total depth relative to all thread functions).
It is useful as code indentation helps in figuring out who calls who. Functions that are hooked and nested inside other hooked functions, will appear indented to the right.
If this option is checked, the hook generation option that does not output
OnEnter()
/OnLeave()
functions will be ignored. -
Do not hook Thunk Functions even if they fall into the range of the addresses to be hooked / Do not hook External Functions even if they fall into the range of the addresses to be hooked .
In case of multiple function calls, hooking these functions may add too many or failed hooks, or even block the hooking of a larger function if the thunk/external function code is close to its beginning.