Let's assume that you want to find address of non-exported CrashdmpCallTable in kernel. Usual old school way is to find unicode string "\SystemRoot\System32\Drivers\crashdmp.sys" and then to find reference to in .text section - if you are lucky enough this will be somewhere in middle of function IopLoadCrashdumpDriver. But on arm64 loading of address splitted in pair of instructions and even worse - values depends from address of instruction. Let`s see how it looks:
Output from cmdline disasm for each of opcodes:
and
What are the options?
Sure you can try to disasm whole .text section and hope that sooner or later the right piece of code will be found
Or perhaps add some optimization. First thing to notice is that you always know address of instruction in arm64. So next thing is to check if some instruction is ADRP or ADD - you can use some bitmasks magic for this (see file aarch64-tbl.h from GNU binutils). And only when you have the right instructions you can use disassembler to extract immediate values. So algo looks like
Some results. Reference to string was found at offset 1AE704 from start of .text section - this is 0x6B9C1 opcodes. Disasm was called only 0xB3C1 times - 0x273C for ADRP and 0x7C3B for ADD
.text:00000001401AF700 6A 01 00 90 ADRP X10, #aSystemrootSy_0@PAGE ; "\\SystemRoot\\System32\\Drivers\\crashd"...
.text:00000001401AF704 48 C1 09 91 ADD X8, X10, #aSystemrootSy_0@PAGEOFF ; "\\SystemRoot\\System32\\Drivers\\crashd"...
Output from cmdline disasm for each of opcodes:
armpatched.exe 6A010090
Disassembled: adrp x10, 2c000
This instruction is AD_INSTR_ADRP and is part of group AD_G_DataProcessingImmediate
This instruction has 4 decode fields (from left to right):
0x1, 0, 0xb, 0xa
This instruction has 2 operands (from left to right):
This operand is of type AD_OP_REG
Register: x10 size 40
This operand is of type AD_OP_IMM
Immediate type: AD_IMM_ULONG
Value: 0x2c000
and
armpatched.exe 48C10991
Disassembled: add x8, x10, #0x270
This instruction is AD_INSTR_ADD and is part of group AD_G_DataProcessingImmediate
This instruction has 7 decode fields (from left to right):
0x1, 0, 0, 0, 0x270, 0xa, 0x8
This instruction has 3 operands (from left to right):
This operand is of type AD_OP_REG
Register: x8 size 40
This operand is of type AD_OP_REG
Register: x10 size 40
This operand is of type AD_OP_IMM
Immediate type: AD_IMM_ULONG
Value: 0x270
What are the options?
Sure you can try to disasm whole .text section and hope that sooner or later the right piece of code will be found
Or perhaps add some optimization. First thing to notice is that you always know address of instruction in arm64. So next thing is to check if some instruction is ADRP or ADD - you can use some bitmasks magic for this (see file aarch64-tbl.h from GNU binutils). And only when you have the right instructions you can use disassembler to extract immediate values. So algo looks like
- make array of addresses for each RXX register with NULL as initial value
- check with bitmask for adrp or add current opcode
- disasm instruction
- store for ADRP address using register as index
- for ADD check if previous ADRP was not too far - bcs it can be in some previous function, so I add check for 40 bytes
- if address from ADRP + current imm value from ADD == your reference - stop
Some results. Reference to string was found at offset 1AE704 from start of .text section - this is 0x6B9C1 opcodes. Disasm was called only 0xB3C1 times - 0x273C for ADRP and 0x7C3B for ADD