There's a "formula" but you'll actually need to look inside the executable file (although this formula can be simplified based on some assumptions).
- Get the in memory address (Virtual Address) of the instruction / data you are interested in. [VA]
- Get the base address of the module where the instruction / data lies. [MODBASE]
- Subtract MODBASE from VA, you obtain what is called a Relative Virtual Address [RVA]:
- Open the binary file (e.g. *.exe or *.dll) with a PE file parser / editor and look at the section headers.
- Find in which section your RVA lies.
- Once you have found the section in which the RVA is, obtain the section Relative Virtual Address. [SECRVA].
- Subtract SECRVA from RVA, you then obtain an [OFFSET].
- Get the RawAddress [SECRAWADDR] of the section you found at 5.
- Add [OFFSET] to [SECRAWADDR], the result is the offset of the instruction / data you are searching for in the binary file.
- OFFSET + SECRAWADDR = INSDATAOFFSET (offset of the instruction or data in the file on disk).
Assumption
Usually (I insist on usually, sometimes it is not the case), [SECRVA] will be 0x1000 for the first section - which happens to be the code section - and its [SECRAWADDR] will be 0x400.
So if you are searching for the offset of an instruction based on its address in memory, you can usually assume that:
SECRVA = 0x1000
SECRAWADDR = 0x400
Example
Example based on cmd.exe.
Let's say I'm searching for this code at 0x1C34B0
when the program is loaded into memory:
CPU Disasm
Address Hex dump Command Comments
001C34B0 /$ E8 B3040000 CALL 001C3968
001C34B5 .^ E9 2EFEFFFF JMP 001C32E8
Notice the instruction opcodes (bytes) are: 0xE8B3040000
VA = 0x1C34B0
- Searching for the module base in memory (use a debugger or ProcessExplorer; the interesting column here is simply called "Base" in process explorer.):
MODBASE = 0x1B0000
VA - MODBASE = RVA ; 0x1C34B0 - 0x1B0000 = 0x134B0
; RVA = 0x134B0
Opening binary file in PE editor (I use CFF explorer):
- Let see in which section 0x134B0 lies:
first section is .text, its Virtual Address is 0x1000 and its Virtual Size is 0x23E4C (so the end of the section is at 0x1000 + 0x23E4C = 0x24E4C
).
Is 0x134B0 between 0x1000 and 0x24E4C?
0x1000 >= 0x134B0 < 0x24E4C
-> True: so the address lies in the .text section.
Note: repeat the same process for each section until you have found the right one.
SECRVA = 0x1000
(section Virtual Address)
RVA - SECRVA = OFFSET ; 0x134B0 - 0x1000 = 0x124B0
SECRAWADDR = 0x400
(section Raw Address)
OFFSET + SECRAWADDR = INSDATAOFFSET ; 0x124B0 + 0x400 = 0x128B0
If we look at 0x128B0
in the file we have:
So we have found exactly the same bytes in file (0xE8B3040000
) than in memory.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…