reverse_engineering:ghidra:memory_map
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
reverse_engineering:ghidra:memory_map [2022/03/13 15:33] – created kitor | reverse_engineering:ghidra:memory_map [2022/03/13 19:47] (current) – [QEMU] kitor | ||
---|---|---|---|
Line 14: | Line 14: | ||
Visual explanation may make more sense. Image below contains a complete memory map for EOS R 1.8.0 (7.3.9) ROM. | Visual explanation may make more sense. Image below contains a complete memory map for EOS R 1.8.0 (7.3.9) ROM. | ||
- | Cacheable | + | Uncacheable |
- | Because DryOS loads some chunks into locations inside that region (see '' | + | Because DryOS loads some chunks into locations inside that region (see '' |
- | {{ : | + | Later all remaining " |
+ | {{: | ||
+ | ===== Sourcing information about ROMCOPY regions ===== | ||
+ | |||
+ | There are two possible sources: QEMU and static analysis. | ||
+ | |||
+ | Ideally you want to do both, as each method has it pros and cons. | ||
+ | |||
+ | ==== QEMU ==== | ||
+ | |||
+ | [[reverse_engineering: | ||
+ | |||
+ | File is generated using naïve approach - QEMU watches all the memory transfers and tries to write down any bulk transfer from ROM location to somewhere else. This means that file will contain false positives, as well as may be missing some data. | ||
+ | |||
+ | === '' | ||
+ | |||
+ | Example file from SX740.102: | ||
+ | |||
+ | < | ||
+ | dd if=ROM0.BIN of=SX740.0xDF001000.bin bs=1 skip=$((0x88F0)) count=$((0x400)) | ||
+ | dd if=ROM0.BIN of=SX740.0xDF000000.bin bs=1 skip=$((0x8CF0)) count=$((0x100)) | ||
+ | dd if=ROM0.BIN of=SX740.0x40100000.bin bs=1 skip=$((0x8E0C)) count=$((0x12EA0)) | ||
+ | dd if=ROM0.BIN of=SX740.0x40700000.bin bs=1 skip=$((0x0)) count=$((0x4900)) | ||
+ | dd if=ROM0.BIN of=SX740.0x1F1740.bin bs=1 skip=$((0x40000)) count=$((0x230)) | ||
+ | dd if=ROM0.BIN of=SX740.0x4000.bin bs=1 skip=$((0x101CED8)) count=$((0x55F14)) | ||
+ | dd if=ROM0.BIN of=SX740.0xDF002800.bin bs=1 skip=$((0x1072DEC)) count=$((0xB9C)) | ||
+ | </ | ||
+ | |||
+ | If you are not familiar with '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Thus in this example, '' | ||
+ | |||
+ | === Extracting chunks === | ||
+ | |||
+ | You can run this script in terminal (it has no executable flag and shebang, thus you may want to do '' | ||
+ | |||
+ | This is not necessarily needed, as ROMCPY regions can be defined in Ghidra without extracting files. | ||
+ | |||
+ | ==== Static firmware analysis ==== | ||
+ | |||
+ | 2nd way is to make a temporary Ghidra project, but load only code ROM image. This is enough to disassemble / decompile DryOS bootloader and find all the important regions simply by looking at the decompiled code. | ||
+ | |||
+ | While qemu '' | ||
+ | |||
+ | First of all, it includes all things - including bootloader FROMUTIL that is not needed and may mess up analysis ( it is not available after DryOS boots anyway). 2nd, it just tries to detect bulk memory moves - so a lot of "small regions" | ||
+ | |||
+ | QEMU result might be slightly off as compared to code, as reads/ | ||
+ | |||
+ | === Obtaining list of ROMCOPY regions from DryOS (2nd stage) bootloader === | ||
+ | |||
+ | Navigate to '' | ||
+ | |||
+ | Read the code, note down each source address, destination start address and destination end address. Calculate region sizes. | ||
+ | |||
+ | In disassembled code those may look like: | ||
+ | < | ||
+ | // src holds address of data source in rom | ||
+ | src = & | ||
+ | |||
+ | // loop reads src, writes to dst and increases both pointers by 1 | ||
+ | // as long as " | ||
+ | for (dst = & | ||
+ | *dst = *src; | ||
+ | src = src + 1; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Example, from SX740.102: | ||
+ | ^ source | ||
+ | | '' | ||
+ | | '' | ||
+ | | - | < | ||
+ | | '' | ||
+ | | - | < | ||
+ | |||
+ | ===== Adding ROMCOPY regions to Memory Map ===== | ||
+ | |||
+ | As mentioned before, there are two methods to add a ROMCOPY region to memory map. | ||
+ | |||
+ | Both methods are equally good, so select which one is easier for you. | ||
+ | |||
+ | You will need to repeat this step for each ROMCOPY region. | ||
+ | |||
+ | ==== via Memory map: ==== | ||
+ | |||
+ | In '' | ||
+ | |||
+ | * Block Types: select "Byte mapped" | ||
+ | * Source address: self explanatory | ||
+ | * Start address: start of " | ||
+ | * Length: length of a block (note: it will accept input as decimal if you don't use '' | ||
+ | * Block name: Something meaningful, like a memory address | ||
+ | * Select Read, | ||
+ | |||
+ | ==== via "Add to program": | ||
+ | |||
+ | Go to '' | ||
+ | |||
+ | ===== Defining rest of the memory map ===== | ||
+ | |||
+ | As explained before, ther regions (notably: RAM) will overlap with ROMCOPY regions defined in previous steps. | ||
+ | |||
+ | ==== Source of data ==== | ||
+ | |||
+ | As a rule of thumb: | ||
+ | * RAM starts at '' | ||
+ | * There' | ||
+ | * Size of RAM depends on model. | ||
+ | * '' | ||
+ | |||
+ | Memory map for [[https:// | ||
+ | |||
+ | ==== Adding regions ==== | ||
+ | |||
+ | As a reminder: Regions (mostly RAM) will overlap with ROMCOPY regions defined earlier. Unfortunately that is not possible (" | ||
+ | |||
+ | In '' | ||
+ | |||
+ | * Block Types: leave " | ||
+ | * Start address: start of memory block | ||
+ | * Length: length of a block (note: it will accept input as decimal if you don't use '' | ||
+ | * Block name: Something meaningful, like a memory address | ||
+ | * Select Read,Write flags | ||
+ | * Leave " | ||
reverse_engineering/ghidra/memory_map.txt · Last modified: 2022/03/13 19:47 by kitor