Skip to main content
The scope:calls allows to match and analyze specific function calls in the binary, including tracking dataflow between parameters and return values.
ParameterDescriptionTypeRequired
toCalled function(s) to identify in the binarystring, AddressValue, or CallsToQueryYes
whereLua expression used to filter function callsLua expressionNo
usingLua expression specifying parameter annotations for the dataflow engineLua expressionYes
withLua function to execute for each matching call sitefun(project: ProjectHandle, context: CallSiteTable)Yes

Syntax

scope:calls{
    to = <target>,
    where = <conditions>,
    using = <annotations>,
    with = <function>
}

Reference

to

The to argument specifies the called function(s) to identify in the binary. It can be a string (function name), an AddressValue (function address), or a CallsToQuery with pattern matching options.

where

The where argument specifies a Lua expression that is used to filter function calls. The only allowed variable in the expression is caller, which exposes the following methods:
  • caller:named "name": returns true if the caller function name matches the provided name.
  • caller:has_call "name": returns true if the caller contains a call to the specified function.
  • caller:has_calls {"name1", "name2"}: returns true if the caller contains calls to all the specified functions.
  • caller:calls "name": returns the table of call-site addresses for the specified function.

using

The using argument accepts a Lua expression that specifies how parameters should be annotated for the dataflow engine.
  • callees: allows annotations to be assigned to parameters and the returned value for arbitrary function calls
  • parameters: allows annotations to be assigned to the analysed function parameters
The parameters attribute is used to annotate the parameters of the function being analyzed, while the callees attribute is used to annotate the parameters and outputs of functions that are called within the function being analyzed.
Do not use the same annotation several times.
Note: The function var:named "Name" creates a named annotation for tracking a specific variable in the dataflow.

with

The with argument specifies the Lua function to execute for each matching call site in the binary file.

Example

Let’s consider the following function:
int FunctionA(int v1, char v2, int *v3) {
  int val = 3;
  long r = FunctionB(val, "hello");

  FunctionC(v1, val, r);
  return r;
}
The following rule will be able to identify the function call to FunctionC:
scopes = scope:calls{
  to = "FunctionC",
  where = caller:named "FunctionA" and caller:has_call "FunctionB",
  using = {
    callees = {
      FunctionB = {output = var:named "Out", inputs = {var:named "VarC1", _}}
    },
    -- `parameters` indicates the parameters of FunctionA
    parameters = {var:named "VarB1", _, _}, -- `_` is a placeholder
  },
  with = function(project, context)

    local arg1 = context.inputs[1]
    if arg1 ~= nil and arg1.annotation == "VarB1" then
      -- The first parameter of `FunctionA` is propagated to the first parameter of `FunctionC`
    end

    local arg2 = context.inputs[2]
    if arg2 ~= nil and arg2.annotation == "VarC1" then
      -- The first parameter of `FunctionB` is propagated to the second parameter of `FunctionC`
    end

    local arg3 = context.inputs[3]
    if arg3 ~= nil and arg3.annotation == "Out" then
      -- The return value of `FunctionB` is propagated to the third parameter of `FunctionC`
    end
  end
}
In this example, we track three different values in FunctionA:
  1. The first parameter of FunctionA (annotated as “VarB1”) is passed as the first parameter to FunctionC.
  2. The first parameter of FunctionB (annotated as “VarC1”) is passed as the second parameter to FunctionC.
  3. The return value of FunctionB (annotated as “Out”) is passed as the third parameter to FunctionC.
The _ placeholders in the annotations indicate parameters we don’t need to track.