Skip to content

Comments

Add RzBin plugin for Qualcomm peripheral images (.mdt).#4953

Merged
Rot127 merged 3 commits intorizinorg:devfrom
Rot127:bin-mdt
Jun 11, 2025
Merged

Add RzBin plugin for Qualcomm peripheral images (.mdt).#4953
Rot127 merged 3 commits intorizinorg:devfrom
Rot127:bin-mdt

Conversation

@Rot127
Copy link
Member

@Rot127 Rot127 commented Mar 1, 2025

DO NOT SQUASH

Your checklist for this pull request

  • I've read the guidelines for contributing to this repository.
  • I made sure to follow the project's coding style.
  • I've documented every RZ_API function and struct this PR changes.
  • I've added tests that prove my changes are effective (required for changes to RZ_API).
  • I've updated the Rizin book with the relevant information (if needed).

Detailed description

I am sick of using the wonky Python scripts. And then load the whole pseudo-ELF binary, it doesn't resolve the nested ELF file(s) properly and just generally hurts my wish for order.

Also this allows for future extension, automatic decompression and such.

Besides this, it is just convenient to have.

Example, loading an modem.mdt. The symbols from the embedded ELF file (modem.b32) can be listed directly. No need to work with broken ob:

> rizin  modem.mdt 
WARNING: Failed to initialize section header.
 -- Print the contents of the current block with the 'p' command
[0x8b800000]> is
nth      paddr      vaddr bind   type   size lib name                                                  
-------------------------------------------------------------------------------------------------------
  1 0x000276d8 0x000266d8 GLOBAL FUNC     28     sys_sbrk_override
  2 0x0002a67c 0x0002967c GLOBAL FUNC     12     qurt_sem_destroy
  3 0x00038e68 0x00037e68 GLOBAL FUNC      4     smp2p_wait_multiple
  4 0x000281ec 0x000271ec GLOBAL FUNC     16     qurtos_reclaim_stack_pages
  5 0x00027978 0x00026978 GLOBAL FUNC     60     qurt_trampoline
  6 0x00026930 0x00025930 GLOBAL FUNC     24     qurt_mutex_destroy
  7 0x0002637c 0x0002537c GLOBAL FUNC     80     devcfg_blob_append
  8 0x00012a90 0x00011a90 GLOBAL FUNC     96     crc_16_step
  9 0x00036fd8 0x00035fd8 GLOBAL FUNC     24     qmi_idl_get_inherited_service_object
 10 0x00013354 0x00012354 GLOBAL FUNC     16     free
 11 0x0002748c 0x0002648c GLOBAL FUNC     72     sys_Mtxdst
...

Example sections of the embedded ELFs:

     paddr   size      vaddr  vsize align perm name                    type flags 
----------------------------------------------------------------------------------
0x00000000    0x0 0x0054ffff    0x0   0x0 ---- load-test.b03.0x0            
0x00001000 0x3ec0 0x00550000 0x3ec0   0x0 -rwx load-test.b03.start          
0x00005000   0x54 0x00554000   0x54   0x0 -r-x load-test.b03.init           
0x00006000 0x6088 0x00555000 0x6088   0x0 -r-x load-test.b03.text           
...

Example of oml:

 1 fd: 4 +0x00000000 0x89201c18 - 0x89201fff --- mmap.load-test.b01
 2 fd: 5 +0x00000000 0x89200000 - 0x89201c17 --- vmap.load-test.b01
 3 fd: 6 +0x00000000 0xfe030000 - 0xfe0aefff r-x mmap.load-test.b02
 4 fd: 7 +0x00000000 0xfe000000 * 0xfe02ffff r-x vmap.load-test.b02
 5 fd: 8 +0x00001000 0x00550000 - 0x00553ebf r-x vmap.load-test.b03.LOAD0
 6 fd: 8 +0x00005000 0x00554000 - 0x0055b763 r-x vmap.load-test.b03.LOAD1
 7 fd: 9 +0x00000000 0x0055d0a8 - 0x0055df03 rw- mmap.load-test.b03.LOAD2
 8 fd: 8 +0x0000d000 0x0055c000 - 0x0055d0a7 r-- vmap.load-test.b03.LOAD2
 9 fd: 10 +0x00000000 0xc80c94f4 - 0xc80c9567 r-- vmap.load-test.b04.reloc-targets
10 fd: 11 +0x00000388 0xc80c9388 - 0xc80c94e9 --- vmap.load-test.b04..strtab
11 fd: 12 +0x00000034 0xc80c9034 - 0xc80c90bb r-x vmap.load-test.b04..text
12 fd: 11 +0x0000022c 0xc80c922c - 0xc80c9387 --x vmap.load-test.b04..rela.text
13 fd: 11 +0x000000bc 0xc80c90bc - 0xc80c922b --- vmap.load-test.b04..symtab
14 fd: 11 +0x00000000 0xc80c9000 - 0xc80c9033 r-- vmap.load-test.b04.ehdr

Example of iH:

iH
==== MDT Segment 0 ====
     priv_p_flags: 0b00000111: layout | ELF
 -- ELF HEADER BEGIN -- 
0x00000000  MAGIC       7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
0x00000010  Type        0x0002
0x00000012  Machine     0x00a4
0x00000014  Version     0x00000001
0x00000018  Entrypoint  0x8b800000
0x0000001c  PhOff       0x00000034
0x00000020  ShOff       0x00000000
0x00000024  Flags       0x0067
0x00000028  EhSize      52
0x0000002a  PhentSize   32
0x0000002c  PhNum       35
0x0000002e  ShentSize   40
0x00000030  ShNum       0
0x00000032  ShStrndx    0
 --- ELF HEADER END --- 

==== MDT Segment 1 ====
     priv_p_flags: 0b00000010: | MBN hash segment
 -- MBN AUTH HEADER BEGIN -- 
0x00 image_id:   kMbnImageDsp2 (0xc)
0x04 version:    0x6
0x08 paddr:      0x0
0x0c vaddr:      0x0
0x10 psize:      0x1f90
0x14 code_pa:    0x690
0x18 sign_va:    0x9b000488
0x1c sign_sz:    0x100
0x20 cert_va:    0x9b000488
0x24 cert_sz:    0x1800
 --- MBN AUTH HEADER END --- 

==== MDT Segment 2 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 3 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 4 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 5 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 6 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 7 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 8 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 9 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 10 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 11 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 12 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 13 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 14 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 15 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 16 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 17 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 18 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 19 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 20 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 21 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 22 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 23 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 24 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 25 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 26 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 27 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 28 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 29 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 30 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 31 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 32 ====
     priv_p_flags: 0b00001000: reloc | ELF
 -- ELF HEADER BEGIN -- 
0x00000000  MAGIC       7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
0x00000010  Type        0x0003
0x00000012  Machine     0x00a4
0x00000014  Version     0x00000001
0x00000018  Entrypoint  0x00000000
0x0000001c  PhOff       0x00000034
0x00000020  ShOff       0x00072fc0
0x00000024  Flags       0x0067
0x00000028  EhSize      52
0x0000002a  PhentSize   32
0x0000002c  PhNum       4
0x0000002e  ShentSize   40
0x00000030  ShNum       25
0x00000032  ShStrndx    24
 --- ELF HEADER END --- 

==== MDT Segment 33 ====
     priv_p_flags: 0b00001000: reloc | Unidentified
==== MDT Segment 34 ====
     priv_p_flags: 0b00001000: reloc | Unidentified

Some questions to discuss:

This needs access to the ELF RzBin functions. Re-implementing all the ELF parsing doesn't make sense. But including everything a third or fourth time via bin_elf.inc (how it was done so far) is not ok either.
So I choose a middle ground here. I exposed versions of commonly used ELF parsing functions in elf_parser. They don't rely on RzBinFile, but take only the ELF object. This allows access for other RzBin plugins which rely on ELF files.

BUT, the design of the ELF module, only allows to be used either as ELF32 or ELF64. This is due to the ELF module being implemented twice with macros. This means every single module depending on it also is forced to copy itself (once for 32 and once for 64bit). Or am I missing something?

Unfortunately, due to this this bin loader only supports 32bit firmwares for now. Which is a shame, because these peripheral images are also used for AArch64 based sub-components.

Test plan

Added

Closing issues

...

@notxvilka
Copy link
Contributor

This needs access to the ELF RzBin functions. Reimplementing everything doesn't make sense. But including everything a third or fourth time neither (the current approach is not ok IMHO). Are you finewith exposing some of the ELF parsers and getters as RZ_IPI. Generally this would allow access for other RzBin plugins which have nested ELF files.

You could see how it's done for PE and MDMP currently.

@Rot127
Copy link
Member Author

Rot127 commented Mar 17, 2025

You could see how it's done for PE and MDMP currently.

PE has proper header files to include. So I would expose the elf functions as well like this.

@Rot127
Copy link
Member Author

Rot127 commented Mar 30, 2025

I open this for review now so you folks can give some early comment. Especially on the ELF thingy (see above). But no need to do a full review. It is mostly about the ELF thing and the overall mdt design.

@codecov
Copy link

codecov bot commented Apr 5, 2025

Codecov Report

Attention: Patch coverage is 54.46717% with 423 lines in your changes missing coverage. Please review.

Project coverage is 44.55%. Comparing base (181c74f) to head (853cb8c).
Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
librz/bin/format/mdt/mdt.c 62.29% 79 Missing and 82 partials ⚠️
librz/bin/format/mbn/mbn.c 23.12% 110 Missing and 3 partials ⚠️
librz/bin/format/mbn/mbn.h 4.47% 63 Missing and 1 partial ⚠️
librz/bin/format/elf/elf_parser.c 66.95% 25 Missing and 13 partials ⚠️
librz/bin/p/bin_elf.inc 70.37% 3 Missing and 13 partials ⚠️
librz/bin/bin.c 41.66% 6 Missing and 8 partials ⚠️
librz/bin/format/elf/elf64_parser.c 77.58% 13 Missing ⚠️
librz/bin/format/elf/elf.c 71.42% 1 Missing and 1 partial ⚠️
librz/bin/p/bin_mdt.c 90.90% 1 Missing and 1 partial ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
librz/bin/format/elf/elf_ehdr.c 60.15% <100.00%> (ø)
librz/bin/format/elf/elf_info.c 71.03% <100.00%> (+0.18%) ⬆️
librz/bin/p/bin_cgc.c 3.38% <ø> (ø)
librz/bin/p/bin_elf.c 100.00% <100.00%> (ø)
librz/bin/p/bin_elf64.c 40.00% <100.00%> (ø)
librz/include/rz_bin.h 43.47% <ø> (ø)
librz/bin/format/elf/elf.c 77.77% <71.42%> (-0.42%) ⬇️
librz/bin/p/bin_mdt.c 90.90% <90.90%> (ø)
librz/bin/format/elf/elf64_parser.c 77.58% <77.58%> (ø)
librz/bin/bin.c 58.99% <41.66%> (-0.52%) ⬇️
... and 5 more

... and 22 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 181c74f...853cb8c. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Rot127 Rot127 force-pushed the bin-mdt branch 2 times, most recently from 117ee01 to 0fe69db Compare April 10, 2025 11:03
Copy link
Contributor

@notxvilka notxvilka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring along the way! Please address my comments and it will be good to go.

@notxvilka
Copy link
Contributor

BUT, the design of the ELF module, only allows to be used either as ELF32 or ELF64. This is due to the ELF module being implemented twice with macros. This means every single module depending on it also is forced to copy itself (once for 32 and once for 64bit). Or am I missing something?

Yes, I am afraid this is the case. ELF parser was refactored multiple times during its lifetime, gradually becoming more untangled and modular but there are still many warts left, including the need to extract relocation processing and parsing into a separate file at the very least. I think for now, you can do a copy and add support for 64-bit modules, we will deal with more refactoring later. It's already the case for the ELF after all.

@Rot127 Rot127 force-pushed the bin-mdt branch 3 times, most recently from 09b32e4 to 853cb8c Compare June 11, 2025 12:38
@Rot127
Copy link
Member Author

Rot127 commented Jun 11, 2025

DO NOT SQUASH

@Rot127 Rot127 enabled auto-merge (rebase) June 11, 2025 15:12
Rot127 added 3 commits June 11, 2025 10:13
It exposes commonly used ELF parsing functions in elf_parser.
They don't rely on RzBinFile but take only the ELF object.
This allows access for other RzBin plugins which rely on ELF files.
It loads .mdt firmware layout files, searches for the other parts in the same directory and loads them.
It resolves symbols, sections etc automatically, and maps them according to the layout
to the virtual address space.

- The iH command provides details about each firmware part as well.
- Memory maps and segment names are prefixed with the parts file name to make them distinct.
- If a firmware part is an ELF library it loads, and resolves its functions, segments etc.

Due to the design of the ELF binary plugin (code duplication with macros for 32/64bit versions),
this only supports 32bit firmware images for now.
This can relatively easily be fixed, by duplicating this plugin but including the 64bit ELF headers.
This requires more tests though.
@Rot127 Rot127 merged commit 1f6c614 into rizinorg:dev Jun 11, 2025
34 of 35 checks passed
@Rot127 Rot127 deleted the bin-mdt branch June 11, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants