3

When I press the X key (list x-refs) on a function (sub_xyz) to see which functions call it, I only saw dd offset sub_xyz twice, with no call sub_xyz instructions.

There is no another place that write call sub_xyz

How can I see which functions are calling sub_xyz? Is this just IDA being confused?

  • Can you take a screenshot of the area around the dd sub_xyz or provide the binary if possible? – Avery3R Jul 30 '18 at 19:38
  • That not possible. What do I need to look there? Is that anti debugging? – Keystone Jul 30 '18 at 19:43
4

Although Nirlzr's answer explains it pretty well, here's an example that considers C++ code and vtables are present. The code is taken from here

#include <iostream>
using namespace std;
class Vehicle {
public:
  virtual void ApplyBreaks() { cout << "Vehicle Break" << endl; }
  virtual void ApplyHorns() { cout << "Vehicle Horns" << endl; }
};

int main() {
  Vehicle *v = new Vehicle();
  v->ApplyBreaks(); // Calls vehicle ApplyBreak
  v->ApplyHorns();  // Calls vehicle ApplyHorn
}

Compiling with g++ and opening in IDA references to ApplyBreaks are such.

References to ApplyBreaks

This is very common in C++ applications to have function references in vtables. Additionally while init in Vehicle this vtable is set in the object as you can see here.

contructor

While calling member functions for this class in main the addresses are accessed like an array with offsets defined at compile time.

gdb vtable dump

At main+48 the first(0th) member ApplyBreaks is accessed and at main+71 ApplyHorns is accessed which is next to ApplyBreaks.

  • Yeah, VTables are kind of a very common scenario this could happen in. Maybe I should have put more focus on that. Great answer, +1 :) – NirIzr Jul 31 '18 at 18:08
2

If there are no other references, this indicates there are no call sub_xyz (that IDA identified, at least). Instead, IDA only identified one cross-reference to sub_xyz, and that reference was a hardcoded offset in a data variable.

Usually, there's a piece of code that accesses that data and indirectly calls the function, so you could search for cross-references to that data area. You should note the reference does not have to reference where the sub_xyz's offset it. Instead, sub_xyz's offset may be part of a bigger structure (or an array, or an array of structures), which may be enumerated. You'll need to search for references that point around that area (these could also be offsets to areas with higher addresses which are then being subtracted).

Lets have an example

Assume that when looking up cross-references to sub_xyz you've found only one, at address 00008540 depicted below.

unk_00008538
    00008538    dd offset sub_foo
    0000853c    dd aFuncionFoo      ; "Function Foo"
    00008540    dd offset sub_xyz       <- our sub_xyz reference
    00008544    dd aFunctionXYZ     ; "Function XYZ"
    00008548    dd offset sub_abc
    0000854c    dd aFunctionABC     ; "Function ABC"

You can notice above dd offset sub_xyz (located at address 00008540) you've got an offset to another subroutine, sub_foo (located at 00008538), and that although there're no cross-references to dd offset sub_xyz (at 00008540) there are cross-references to dd offset sub_foo (at 00008538).

You can also notice there's another subroutine offset at 00008548, and that after every subroutine offset there's another offset, to a string that coincidentally has the function's name in it. This is obviously a relatively easy example and we can assume these are actually three instances of a structure with two members each, that may be define like that:

typedef struct FunctionDefinition
{
    void* func_addr;
    char* func_name;
} _FunctionDefinition;

We can also guess we found an array of three instances of the FunctionDefinition structure, and that some piece of code enumerates the array and traverses all the functions.

A more sophisticated example can include, for example, an array of functions and their network message identifier, where a function handling a network command is dispatched depending on the type of message received, for example. You can also have found a global object of any class if you're dealing with C++, or perhaps even a function virtual table. The options are endless, and you'll need to figure it out using the specific scenario you encounter and and additional info you can gather (say, the code referencing that bigger structure or array).

  • There is no call sub_xyz and I saw dd sub_xyz twice in xref, so you tell seach xref in the area of sub_xyz and looking call to there? – Keystone Jul 30 '18 at 19:51
  • @Keystone I've added an example, i hope this will help you understand this better. – NirIzr Jul 30 '18 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.