Cross-references, or more commonly referred to as xrefs, are used to identify references (usage/call or declaration) of a particular function, string, variable, etc. Example — if you’ve identified a particular function (a VM check) being called inside another subroutine (installation of a backdoor), you might be interested in knowing other calls to the same function.
Categories of Cross-references
Cross-references can be categorized as follows:
- Code cross-references
- Data cross-references
Let’s explore the two in a short section next.
Code cross-references are used to identify relationships between function calls, declarations, or jumps. Let’s take a look at an example.
Here, we can see that loc_1000D325 has a code cross-reference to sub_1000D2F9+19. It suggests that this location is accessed by the function (sub_*) at the address 1000D2F9 and an offset of 0x19 into the function. Next, the arrow shows us that the code is at a lower address than the reference and the ‘j’ suggests it’s a jump.
Much like this jump, there are several other cross-reference types as I’ll discuss later on.
Much like code cross-references, data cross-references can help us keep track of data being accessed or written throughout the binary. For example, you might find an IP address being referenced in a few functions; using xrefs, you can identify all those functions easily.
Here, we can see several data strings being referenced in functions. For example, the aThePidofProces_1 is being referenced in the function, sub_1000D5B0 and at on offset of 0x264. The direction is upwards again suggesting the function is at a lower address than string’s address.
For the DATA XREF to aCopySToSSucces you can see two cross-references being listed. IDA restricts listing multiple references by default. You can change this setting and show as many references as you want. It is under ‘Options’ — ‘General’ — ‘Cross-references’.
If you’ve identified an offset or a function and would like to list all cross-references, you can simply do so by selecting the label and pressing ‘X’ to list all cross-references to that particular label (or identifier).
‘CTRL+X’ shows us cross-references to the address (cursor’s selection does not matter as it is worked with addresses not identifiers). ‘CTRL+J’ shows us cross-references from the address
Here, we can find the following information:
- Direction: Whether the target reference is at a higher (Down) or lower (Up) address
- Type: Type of the cross-reference
- Address/Text: Address of the target reference and the actual code/text at that particular address
Similarly, we can also view the information in a graphical view. Select ‘View’, Go into ‘Graphs’ and select either of the three xref charts available. You can:
- View xrefs from the identifier (where the reference ‘goes to’)
- View xrefs to the identifier (where the reference ‘comes from’)
- Use a custom xref chart with several customization options (this is particularly helpful in larger binaries and to filter out unhelpful identifiers)
Types of Cross-references
From the official Hex-Rays documentation , we can find 13 types of cross-references. A few of these cross-reference types are listed below:
- O: Offset — Address is taken by the identifier selected by the cursor (there’s no read or write operation here)
- R: Read access — Data is being read from the address
- W: Write access — Data is being written at the address
- J: Far (Inter-segment) jump — Code being jumped to is in a different code segment than the current segment
- j: Near (Intra-segment) jump — Code being jumped to is in the same code segment as the identifier
- P: Far (Inter-segment) call — Call is in a different code segment
- p: Near (Intra-segment) call — Call is in the same code segment
Cross-references can be really helpful when reversing binaries. You can quickly identify the purpose of a function by identifying its calls or look for interesting code by the data it references. Hopefully, this guide was a quick hands-on to getting started with cross-references.