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).
dd sub_xyz
or provide the binary if possible?