1- /* radare2 - LGPL - Copyright 2015-2024 - pancake */
1+ /* radare2 - LGPL - Copyright 2015-2025 - pancake */
22
3- #include <r_types.h>
4- #include <r_util.h>
5- #include <r_lib.h>
63#include <r_bin.h>
74
85typedef struct sbl_header {
96 ut32 load_index ;
10- ut32 version ; // (flash_partition_version) 3 = nand
11- ut32 paddr ; // This + 40 is the start of the code in the file
12- ut32 vaddr ; // Where it's loaded in memory
13- ut32 psize ; // code_size + signature_size + cert_chain_size
14- ut32 code_pa ; // Only what's loaded to memory
7+ ut32 version ; // (flash_partition_version) 3 = nand
8+ ut32 paddr ; // This + 40 is the start of the code in the file
9+ ut32 vaddr ; // Where it's loaded in memory
10+ ut32 psize ; // code_size + signature_size + cert_chain_size
11+ ut32 code_pa ; // Only what's loaded to memory
1512 ut32 sign_va ;
1613 ut32 sign_sz ;
17- ut32 cert_va ; // Max of 3 certs?
14+ ut32 cert_va ; // Max of 3 certs?
1815 ut32 cert_sz ;
1916} SblHeader ;
2017
21- // TODO move this global into the bf->bobj
22- static R_TH_LOCAL SblHeader sb = {0 };
18+ /* Per-file SblHeader stored in bf->bo->bin_obj. Helper to fetch it. */
19+ static SblHeader * sbl_from_bf (RBinFile * bf ) {
20+ return (bf && bf -> bo && bf -> bo -> bin_obj ) ? (SblHeader * )bf -> bo -> bin_obj : NULL ;
21+ }
22+
23+ static void sbl_destroy (RBinFile * bf ) {
24+ if (!bf || !bf -> bo ) {
25+ return ;
26+ }
27+ if (bf -> bo -> bin_obj ) {
28+ R_FREE (bf -> bo -> bin_obj );
29+ bf -> bo -> bin_obj = NULL ;
30+ }
31+ }
32+
33+ static bool parse_sbl (RBuffer * b , SblHeader * h ) {
34+ if (!b || !h ) {
35+ return false;
36+ }
37+ int ret = r_buf_fread_at (b , 0 , (ut8 * )h , "10i" , 1 );
38+ if (!ret ) {
39+ return false;
40+ }
41+ return true;
42+ }
2343
2444static bool check (RBinFile * bf , RBuffer * b ) {
2545 R_RETURN_VAL_IF_FAIL (b , false);
2646 ut64 bufsz = r_buf_size (b );
47+ SblHeader h = { 0 };
48+ if (!parse_sbl (b , & h )) {
49+ return false;
50+ }
2751 if (sizeof (SblHeader ) < bufsz ) {
28- int ret = r_buf_fread_at (b , 0 , (ut8 * )& sb , "10i" , 1 );
29- if (!ret ) {
30- return false;
31- }
32- #if 0
33- eprintf ("V=%d\n" , sb .version );
34- eprintf ("PA=0x%08x sz=0x%x\n" , sb .paddr , sb .psize );
35- eprintf ("VA=0x%08x sz=0x%x\n" , sb .vaddr , sb .psize );
36- eprintf ("CODE=0x%08x\n" , sb .code_pa + sb .vaddr + 40 );
37- eprintf ("SIGN=0x%08x sz=0x%x\n" , sb .sign_va , sb .sign_sz );
38- if (sb .cert_sz > 0 ) {
39- eprintf ("CERT=0x%08x sz=0x%x\n" , sb .cert_va , sb .cert_sz );
40- } else {
41- eprintf ("No certificate found.\n" );
42- }
43- #endif
44- if (sb .version != 3 ) { // NAND
52+ if (h .version != 3 ) { // NAND
4553 return false;
4654 }
47- if (sb .paddr + sizeof (SblHeader ) > bufsz ) { // NAND
55+ if (h .paddr + sizeof (SblHeader ) > bufsz ) { // NAND
4856 return false;
4957 }
50- if (sb .vaddr < 0x100 || sb .psize > bufsz ) { // NAND
58+ if (h .vaddr < 0x100 || h .psize > bufsz ) { // NAND
5159 return false;
5260 }
53- if (sb .cert_va < sb .vaddr ) {
61+ if (h .cert_va < h .vaddr ) {
5462 return false;
5563 }
56- if (sb .cert_sz >= 0xf0000 ) {
64+ if (h .cert_sz >= 0xf0000 ) {
5765 return false;
5866 }
59- if (sb .sign_va < sb .vaddr ) {
67+ if (h .sign_va < h .vaddr ) {
6068 return false;
6169 }
62- if (sb .sign_sz >= 0xf0000 ) {
70+ if (h .sign_sz >= 0xf0000 ) {
6371 return false;
6472 }
65- if (sb .load_index < 1 || sb .load_index > 0x40 ) {
73+ if (h .load_index < 1 || h .load_index > 0x40 ) {
6674 return false; // should be 0x19 ?
6775 }
68- // TODO: Add more checks here
76+ // TODO: Add more checks here
6977 return true;
7078 }
7179 return false;
7280}
7381
7482static bool load (RBinFile * bf , RBuffer * b , ut64 loadaddr ) {
75- return check (bf , b );
83+ if (!bf || !bf -> bo ) {
84+ return false;
85+ }
86+ SblHeader * hdr = R_NEW0 (SblHeader );
87+ if (!parse_sbl (b , hdr )) {
88+ R_FREE (hdr );
89+ return false;
90+ }
91+ bf -> bo -> bin_obj = hdr ;
92+ return true;
7693}
7794
7895static ut64 baddr (RBinFile * bf ) {
79- return sb .vaddr ; // XXX
96+ SblHeader * sbl = sbl_from_bf (bf );
97+ return sbl ? sbl -> vaddr : 0 ; // XXX
8098}
8199
82- static RList * entries (RBinFile * bf ) {
83- RList * ret = r_list_newf (free );
84- if (ret ) {
85- RBinAddr * ptr = R_NEW0 (RBinAddr );
86- if (ptr ) {
87- ptr -> paddr = 40 + sb .code_pa ;
88- ptr -> vaddr = 40 + sb .code_pa + sb .vaddr ;
89- r_list_append (ret , ptr );
100+ static RList * entries (RBinFile * bf ) {
101+ RList * ret = r_list_newf (free );
102+ RBinAddr * ptr = R_NEW0 (RBinAddr );
103+ SblHeader * sbl = sbl_from_bf (bf );
104+ if (!sbl ) {
105+ // try to read header directly from buffer as a fallback
106+ SblHeader h = { 0 };
107+ if (!parse_sbl (bf -> buf , & h )) {
108+ r_list_free (ret );
109+ return NULL ;
90110 }
111+ ptr -> paddr = 40 + h .code_pa ;
112+ ptr -> vaddr = 40 + h .code_pa + h .vaddr ;
113+ } else {
114+ ptr -> paddr = 40 + sbl -> code_pa ;
115+ ptr -> vaddr = 40 + sbl -> code_pa + sbl -> vaddr ;
91116 }
117+ r_list_append (ret , ptr );
92118 return ret ;
93119}
94120
95- static RList * sections (RBinFile * bf ) {
96- RBinSection * ptr = NULL ;
97- RList * ret = NULL ;
98- int rc ;
99-
100- if (!(ret = r_list_new ())) {
101- return NULL ;
102- }
103- ret -> free = free ;
104- rc = r_buf_fread_at (bf -> buf , 0 , (ut8 * )& sb , "10i" , 1 );
105- if (!rc ) {
106- r_list_free (ret );
107- return false;
121+ static RList * sections (RBinFile * bf ) {
122+ RList * ret = r_list_newf (free );
123+ SblHeader * sbl = sbl_from_bf (bf );
124+ SblHeader h_local ;
125+ SblHeader * h = sbl ;
126+ if (!h ) {
127+ int rc = r_buf_fread_at (bf -> buf , 0 , (ut8 * )& h_local , "10i" , 1 );
128+ if (!rc ) {
129+ r_list_free (ret );
130+ return false;
131+ }
132+ h = & h_local ;
108133 }
109134
110135 // add text segment
111- if (!(ptr = R_NEW0 (RBinSection ))) {
112- return ret ;
113- }
114- ptr -> name = strdup ("text" );
115- ptr -> size = sb .psize ;
116- ptr -> vsize = sb .psize ;
117- ptr -> paddr = sb .paddr + 40 ;
118- ptr -> vaddr = sb .vaddr ;
136+ RBinSection * ptr = R_NEW0 (RBinSection );
137+ ptr -> name = strdup ("text" );
138+ ptr -> size = h -> psize ;
139+ ptr -> vsize = h -> psize ;
140+ ptr -> paddr = h -> paddr + 40 ;
141+ ptr -> vaddr = h -> vaddr ;
119142 ptr -> perm = R_PERM_RX ; // r-x
120143 ptr -> add = true;
121144 ptr -> has_strings = true;
122145 r_list_append (ret , ptr );
123146
124- if (!(ptr = R_NEW0 (RBinSection ))) {
125- return ret ;
126- }
127- ptr -> name = strdup ("sign" );
128- ptr -> size = sb .sign_sz ;
129- ptr -> vsize = sb .sign_sz ;
130- ptr -> paddr = sb .sign_va - sb .vaddr ;
131- ptr -> vaddr = sb .sign_va ;
147+ ptr = R_NEW0 (RBinSection );
148+ ptr -> name = strdup ("sign" );
149+ ptr -> size = h -> sign_sz ;
150+ ptr -> vsize = h -> sign_sz ;
151+ ptr -> paddr = h -> sign_va - h -> vaddr ;
152+ ptr -> vaddr = h -> sign_va ;
132153 ptr -> perm = R_PERM_R ; // r--
133154 ptr -> has_strings = true;
134155 ptr -> add = true;
135156 r_list_append (ret , ptr );
136157
137- if (sb .cert_sz && sb .cert_va > sb .vaddr ) {
138- if (!(ptr = R_NEW0 (RBinSection ))) {
139- return ret ;
140- }
158+ if (h -> cert_sz && h -> cert_va > h -> vaddr ) {
159+ ptr = R_NEW0 (RBinSection );
141160 ptr -> name = strdup ("cert" );
142- ptr -> size = sb . cert_sz ;
143- ptr -> vsize = sb . cert_sz ;
144- ptr -> paddr = sb . cert_va - sb . vaddr ;
145- ptr -> vaddr = sb . cert_va ;
161+ ptr -> size = h -> cert_sz ;
162+ ptr -> vsize = h -> cert_sz ;
163+ ptr -> paddr = h -> cert_va - h -> vaddr ;
164+ ptr -> vaddr = h -> cert_va ;
146165 ptr -> perm = R_PERM_R ; // r--
147166 ptr -> has_strings = true;
148167 ptr -> add = true;
@@ -151,30 +170,37 @@ static RList* sections(RBinFile *bf) {
151170 return ret ;
152171}
153172
154- static RBinInfo * info (RBinFile * bf ) {
173+ static RBinInfo * info (RBinFile * bf ) {
155174 RBinInfo * ret = R_NEW0 (RBinInfo );
156- if (R_LIKELY (ret )) {
157- ret -> file = strdup (bf -> file );
158- ret -> bclass = strdup ("bootloader" );
159- ret -> rclass = strdup ("mbn" );
160- ret -> os = strdup ("MBN" );
161- ret -> arch = strdup ("arm" );
162- ret -> machine = strdup (ret -> arch );
163- ret -> subsystem = strdup ("mbn" );
164- ret -> type = strdup ("sbl" ); // secondary boot loader
165- ret -> bits = 16 ;
166- ret -> has_va = true;
167- ret -> has_crypto = true; // must be false if there' no sign or cert sections
168- ret -> has_pi = false;
169- ret -> has_nx = false;
170- ret -> big_endian = false;
171- ret -> dbg_info = false;
172- }
175+ ret -> file = strdup (bf -> file );
176+ ret -> bclass = strdup ("bootloader" );
177+ ret -> rclass = strdup ("mbn" );
178+ ret -> os = strdup ("MBN" );
179+ ret -> arch = strdup ("arm" );
180+ ret -> machine = strdup (ret -> arch );
181+ ret -> subsystem = strdup ("mbn" );
182+ ret -> type = strdup ("sbl" ); // secondary boot loader
183+ ret -> bits = 16 ;
184+ ret -> has_va = true;
185+ ret -> has_crypto = true; // must be false if there' no sign or cert sections
186+ ret -> has_pi = false;
187+ ret -> has_nx = false;
188+ ret -> big_endian = false;
189+ ret -> dbg_info = false;
173190 return ret ;
174191}
175192
176193static ut64 size (RBinFile * bf ) {
177- return sizeof (SblHeader ) + sb .psize ;
194+ SblHeader * sbl = sbl_from_bf (bf );
195+ if (sbl ) {
196+ return sizeof (SblHeader ) + sbl -> psize ;
197+ }
198+ // fallback: try reading header directly
199+ SblHeader h = { 0 };
200+ if (parse_sbl (bf -> buf , & h )) {
201+ return sizeof (SblHeader ) + h .psize ;
202+ }
203+ return 0 ;
178204}
179205
180206RBinPlugin r_bin_plugin_mbn = {
@@ -192,6 +218,7 @@ RBinPlugin r_bin_plugin_mbn = {
192218 .entries = & entries ,
193219 .sections = & sections ,
194220 .info = & info ,
221+ .destroy = & sbl_destroy ,
195222};
196223
197224#ifndef R2_PLUGIN_INCORE
0 commit comments