User Tools

Site Tools


reverse_engineering:ghidra:create_a_project

This is an old revision of the document!


Create a Ghidra project

Scope of this section is not to explain how to use Ghidra, but how to create a project based on pre-made ROM dump.

As time of writing, this guide can be applied to Digic 6,7,8,X models running EOS firmware variant. This includes some non-EOS cameras (like PowerShot SX740 HS) and excludes some EOS ones (eg M10) which run PowerShot firmware variant. For later, refer to CHDK Wiki.

Preparation

What you need:

Loading main ROM image into Ghidra

First, select the file that contains actual code. On Digic 6 cameras there's only “ROM1.bin”, Digic 7, 8 and X models use ROM0.bin and (in most cases) ROM1.bin, where ROM0.bin contains the code.

Simply drag and drop ROM file into a project window. Import dialog will pop up.

Following settings are required:

Language: For Digic 6 and up select ARM, v7, little endian, default compiler

Options: In this dialog we define at what memory address image will be loaded.

  • Block name: as you wish, but something meaningful is recommended (eg ROM0, ROM1)
  • Base Address:
    • Digic 6: ROM1 loads at 0xFE000000
    • Digic 7,8,x: ROM0 loads at 0xE0000000
  • Leave all other options as default.

Close by clicking OK on all dialogs, and then acknowledge the import result. File will appear in a project.

Initial analysis

Click twice on newly imported file. It will bring up “Code Browser” window.

Ghidra will ask if you want to perform auto analysis now - select No.

Load 2nd ROM file (where applicable)

Go to File → Add to program. Select second ROM file. Import dialog will appear, but this time it will have language settings already in place.

Open Options, set Block name to something meaningful and Base Address to 0xF0000000 for Digic 7,8,X

Fix memory map

Navigate to Window → Memory Map. In rows representing loaded ROM images uncheck tick in “W” (writable) column. This may affect analysis, and affects decompiler results.

Add other memory regions

Skip this step if you don't have a list of romcopy regions. It will result in incomplete project that may be missing important pieces (especially on Digic 6).

You can obtain it from QEMU (see: Running firmware in QEMU).

It can be also obtained by reading decompiled code, that will be available in incomplete project.

Run disassembly

Jump to second level (DryOS) bootloader address (press 'G' in Listing window):

CPU Address
Digic 6 0xFE0A0000
Digic 7,8 0xE0040000
Digic X 0xE0100000

Press F12 to disassemble in Thumb mode. Wait for Ghidra to finish a task - it will discover a lot of functions so it will take some time.

After it is done, we name that function firmware_entry

Run auto analysis

Navigate to Analysis → Auto analysis “<file_name>”.

There's no good answer on what should be selected here (some tools may even crash Ghidra), but as a rule of thumb:

  • Disable “Non-returning functions - discovered”
  • Disable “Embedded Media”.
  • Disable “Create Address Tables”. In worst cases this option exhausts system memory and crashes Ghidra.

Run the analysis - it will take a long time. After it is done, you may want to run “one shot” analysis for Embedded media and for Create Address Tables - but YMMV.

ROMCOPY regions from static analysis

this may want moving to a separate wiki entry later

While qemu -d romcpy is (arguably) the easiest way to obtain list of all chunks moved from ROM to RAM, it is imperfect.

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” are false positives, and sometimes it misses other bits.

QEMU result might be slightly off as compared to code, as reads/writes are often aligned to bigger chunks.

Obtaining list of ROMCOPY regions from DryOS (2nd stage) bootloader

Navigate to firmware_entry. Look in the decompiled code for for loops. Some will just write zeroes (we are not interested in those), other read from one address (in code rom range) and write to another address.

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 = &DAT_e101ced8;
for (dst = &DAT_00004000; dst < &DAT_00023770; dst = dst + 1) {
  *dst = *src;
  src = src + 1;
}

Example, from SX740.102:

source to:start to:end size
0xe101ced8 0x4000 0x23770 0x1F770
0xe103c648 0x23770 0x59f14 0x367A4
- 0x59f14 0xddd1c ram erase
0xe1072dec 0xdf002800 0xdf00339c 0xB9C
- 0xdf00339c 0xdf0033a8 ram erase
reverse_engineering/ghidra/create_a_project.1647081639.txt.gz · Last modified: 2022/03/12 11:40 by kitor