diff --git a/CHANGELOG.md b/CHANGELOG.md index 531aaa758c..f8487f9376 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### New Features +- IDA extractor: support dynamically resolve APIs stored in global variables that have been renamed #2201 @Ana06 + ### Breaking Changes ### New Rules (0) diff --git a/README.md b/README.md index a50c90a250..c646b987fb 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ Please learn to write rules and contribute new entries as you find interesting t If you use IDA Pro, then you can use the [capa explorer](https://github.com/mandiant/capa/tree/master/capa/ida/plugin) plugin. capa explorer helps you identify interesting areas of a program and build new capa rules using features extracted directly from your IDA Pro database. +It also uses renamed global variables with dynamically resolved API names for better analysis result. ![capa + IDA Pro integration](https://github.com/mandiant/capa/blob/master/doc/img/explorer_expanded.png) diff --git a/capa/features/extractors/ida/insn.py b/capa/features/extractors/ida/insn.py index e031b7a598..e118baa0d3 100644 --- a/capa/features/extractors/ida/insn.py +++ b/capa/features/extractors/ida/insn.py @@ -5,9 +5,11 @@ # Unless required by applicable law or agreed to in writing, software distributed under the License # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and limitations under the License. +import re from typing import Any, Dict, Tuple, Iterator import idc +import ida_ua import idaapi import idautils @@ -81,11 +83,27 @@ def extract_insn_api_features(fh: FunctionHandle, bbh: BBHandle, ih: InsnHandle) # tuple (, , ) for name in capa.features.extractors.helpers.generate_symbols(api[0], api[1]): yield API(name), ih.address + return # check calls to extern functions for api in check_for_api_call(insn, get_externs(fh.ctx)): # tuple (, , ) yield API(api[1]), ih.address + return + + # extract dynamically resolved APIs stored in renamed globals (renamed for example using `renimp.idc`) + if insn.Op1.type == ida_ua.o_mem: + op_addr = insn.Op1.addr + op_name = idaapi.get_name(op_addr) + # check that the memory address has a name and a type + if (not op_name.startswith("off_")) and idc.get_type(op_addr): + # Remove suffix used in repeated names, for example _0 in VirtualFree_0 + match = re.match(r"(.+)_\d+", op_name) + if match: + op_name = match.group(1) + yield API(op_name), ih.address + if capa.features.extractors.helpers.is_aw_function(op_name): + yield API(op_name[:-1]), ih.address # extract IDA/FLIRT recognized API functions targets = tuple(idautils.CodeRefsFrom(insn.ea, False)) diff --git a/capa/ida/plugin/README.md b/capa/ida/plugin/README.md index 4bf3616cbb..b17157dcaa 100644 --- a/capa/ida/plugin/README.md +++ b/capa/ida/plugin/README.md @@ -81,6 +81,7 @@ can update using the `Settings` button. * Double-click the `Address` column to navigate your Disassembly view to the address of the associated feature * Double-click a result in the `Rule Information` column to expand its children * Select a checkbox in the `Rule Information` column to highlight the address of the associated feature in your Disassembly view +* Re-analyse if you rename global variables used to store dynamically resolved APIs as capa will use them to improve the analysis. #### Tips for Rule Generator