FunctionMonitor
The FunctionMonitor
plugin notifies other plugins of function calls and returns.
Suppose that you are writing a plugin that needs to monitor calls to a function that starts at address 0x400120
in a
process called my.exe
. Your plugin also wants to monitor all returns from that function.
Proceed as follows:
Create a new plugin. You can use the
Example
plugin as a template.Obtain the instance of the
FunctionMonitor
plugin in theinitialize()
method of the plugin.Register a handler for the
onCall
signal provided byFunctionMonitor
.In the call handler, check the current program counter to determine if this is a function that you want to process further or not. You can also use information about callers and callees provided by the signal to make this decision.
In the call handler, register a return handler, if necessary.
Do not forget to add
my.exe
to the configuration ofProcessExecutionDetector
ins2e-config.lua
.
The following part shows the code that implements the steps explained above.
// 1. Write a new analysis plugin (e.g., based on the Example plugin)
void Example::initialize() {
// 2. Get an instance of the FunctionMonitor plugin
FunctionMonitor *monitor = s2e()->getPlugin<FunctionMonitor>();
// 3. Get a notification when a function is called
monitor->onCall.connect(sigc::mem_fun(*this, &Example::onCall));
}
To monitor the function located at 0x400120
, write the following handlers:
void Example::onCall(S2EExecutionState *state, const ModuleDescriptorConstPtr &source,
const ModuleDescriptorConstPtr &dest, uint64_t callerPc, uint64_t calleePc,
const FunctionMonitor::ReturnSignalPtr &returnSignal) {
// Filter out functions we don't care about
if (state->regs()->getPc() != 0x400120) {
return;
}
// If you do not want to track returns, do not connect a return signal.
// Here, we pass the program counter to the return handler to identify the function
// from which execution returns.
returnSignal->connect(
sigc::bind(sigc::mem_fun(*this, &Example::onRet), 0x400120));
}
void Example::onRet(S2EExecutionState *state, const ModuleDescriptorConstPtr &source,
const ModuleDescriptorConstPtr &dest, uint64_t returnSite,
uint64_t functionPc) {
getDebugStream(state) << "Execution returned from function " << hexval(functionPc) << "\n";
}
Call/return handlers are paired: whenever the return instruction is executed and the stack pointer corresponds to the one at the call instruction, the return handler tied to that call is executed.
You can pass as many parameters as you want to your call or return handlers. For this, you can use the fsigc++
bind
feature.
Note
You can also instrument functions from Lua code using the LuaFunctionInstrumentation
plugin.