1313// limitations under the License.
1414
1515use gimli:: { EndianRcSlice , Endianity , RunTimeEndian , SectionId } ;
16+ use object:: { Object , ObjectSection , ObjectSymbol } ;
1617
1718use binaryninja:: {
1819 binary_view:: { BinaryView , BinaryViewBase , BinaryViewExt } ,
@@ -135,7 +136,7 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
135136 } ;
136137 // If the section has the compressed bit set
137138 if ( section_flags & 2048 ) != 0 {
138- // Get section, trim header, decompress, return
139+ // Get section, trim header, decompress, and apply relocations before returning
139140 let compressed_header_size = view. address_size ( ) * 3 ;
140141
141142 let offset = section. start ( ) + compressed_header_size as u64 ;
@@ -145,23 +146,26 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
145146 let ch_type = endian. read_u32 ( & ch_type_vec) ;
146147
147148 if let Ok ( buffer) = view. read_buffer ( offset, len) {
148- match ch_type {
149- 1 => {
150- return Ok ( EndianRcSlice :: new (
151- buffer. zlib_decompress ( ) . get_data ( ) . into ( ) ,
152- endian,
153- ) ) ;
154- }
155- 2 => {
156- return Ok ( EndianRcSlice :: new (
157- zstd:: decode_all ( buffer. get_data ( ) ) ?. as_slice ( ) . into ( ) ,
158- endian,
159- ) ) ;
160- }
161- x => {
162- return Err ( Error :: UnknownCompressionMethod ( x) ) ;
163- }
164- }
149+ let mut decompressed = match ch_type {
150+ 1 => buffer. zlib_decompress ( ) . get_data ( ) . to_vec ( ) ,
151+ 2 => zstd:: decode_all ( buffer. get_data ( ) ) ?,
152+ x => return Err ( Error :: UnknownCompressionMethod ( x) ) ,
153+ } ;
154+
155+ let section_name_owned = section. name ( ) . to_string_lossy ( ) . into_owned ( ) ;
156+ let is_little =
157+ matches ! ( view. default_endianness( ) , Endianness :: LittleEndian ) ;
158+ apply_relocations_with_object (
159+ view,
160+ & section_name_owned,
161+ & mut decompressed,
162+ is_little,
163+ ) ;
164+
165+ return Ok ( EndianRcSlice :: new (
166+ Rc :: from ( decompressed. into_boxed_slice ( ) ) ,
167+ endian,
168+ ) ) ;
165169 }
166170 }
167171 }
@@ -172,8 +176,12 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
172176 if len == 0 {
173177 Ok ( EndianRcSlice :: new ( Rc :: from ( [ ] ) , endian) )
174178 } else {
179+ let mut data = view. read_vec ( offset, len) ;
180+ let section_name_owned = section. name ( ) . to_string_lossy ( ) . into_owned ( ) ;
181+ let is_little = matches ! ( view. default_endianness( ) , Endianness :: LittleEndian ) ;
182+ apply_relocations_with_object ( view, & section_name_owned, & mut data, is_little) ;
175183 Ok ( EndianRcSlice :: new (
176- Rc :: from ( view . read_vec ( offset , len ) . as_slice ( ) ) ,
184+ Rc :: from ( data . into_boxed_slice ( ) ) ,
177185 endian,
178186 ) )
179187 }
@@ -183,11 +191,150 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
183191 "__{}" ,
184192 & section_name[ 1 ..section_name. len( ) . min( 15 ) ]
185193 ) ) {
194+ let mut data = view. read_vec ( section. start ( ) , section. len ( ) ) ;
195+ apply_relocations_with_object (
196+ view,
197+ section. name ( ) . to_string_lossy ( ) . as_ref ( ) ,
198+ & mut data,
199+ matches ! ( view. default_endianness( ) , Endianness :: LittleEndian ) ,
200+ ) ;
186201 Ok ( EndianRcSlice :: new (
187- Rc :: from ( view . read_vec ( section . start ( ) , section . len ( ) ) . as_slice ( ) ) ,
202+ Rc :: from ( data . into_boxed_slice ( ) ) ,
188203 endian,
189204 ) )
190205 } else {
191206 Ok ( EndianRcSlice :: new ( Rc :: from ( [ ] ) , endian) )
192207 }
193208}
209+
210+ fn read_int ( bytes : & [ u8 ] , is_little_endian : bool ) -> u64 {
211+ let mut value = 0u64 ;
212+ if is_little_endian {
213+ for ( i, byte) in bytes. iter ( ) . enumerate ( ) {
214+ value |= ( * byte as u64 ) << ( i * 8 ) ;
215+ }
216+ } else {
217+ for ( i, byte) in bytes. iter ( ) . enumerate ( ) {
218+ value |= ( * byte as u64 ) << ( 8 * ( bytes. len ( ) - 1 - i) ) ;
219+ }
220+ }
221+ value
222+ }
223+
224+ fn write_int ( bytes : & mut [ u8 ] , value : u64 , is_little_endian : bool ) {
225+ if is_little_endian {
226+ for ( i, byte) in bytes. iter_mut ( ) . enumerate ( ) {
227+ * byte = ( value >> ( i * 8 ) ) as u8 ;
228+ }
229+ } else {
230+ let len = bytes. len ( ) ;
231+ for ( i, byte) in bytes. iter_mut ( ) . enumerate ( ) {
232+ let shift = 8 * ( len - 1 - i) ;
233+ * byte = ( value >> shift) as u8 ;
234+ }
235+ }
236+ }
237+
238+ fn apply_relocations_with_object (
239+ view : & BinaryView ,
240+ section_name : & str ,
241+ data : & mut [ u8 ] ,
242+ is_little_endian : bool ,
243+ ) -> bool {
244+ let Some ( file_bytes) = read_entire_view ( view) else {
245+ return false ;
246+ } ;
247+
248+ let Ok ( file) = object:: File :: parse ( & * file_bytes) else {
249+ return false ;
250+ } ;
251+
252+ let Some ( obj_section) = file. section_by_name ( section_name) else {
253+ return false ;
254+ } ;
255+
256+ let mut applied = false ;
257+
258+ for ( offset, relocation) in obj_section. relocations ( ) {
259+ let size_bits = relocation. size ( ) ;
260+ if size_bits == 0 {
261+ continue ;
262+ }
263+ let size = ( size_bits / 8 ) as usize ;
264+ if size == 0 || size > 8 {
265+ continue ;
266+ }
267+
268+ let offset = offset as usize ;
269+ if offset + size > data. len ( ) {
270+ continue ;
271+ }
272+
273+ let mut base = 0i128 ;
274+ let mut target_section_name: Option < & str > = None ;
275+
276+ match relocation. target ( ) {
277+ object:: RelocationTarget :: Symbol ( symbol_index) => {
278+ let Ok ( symbol) = file. symbol_by_index ( symbol_index) else {
279+ continue ;
280+ } ;
281+ if let Some ( section_index) = symbol. section_index ( ) {
282+ let Ok ( target_section) = file. section_by_index ( section_index) else {
283+ continue ;
284+ } ;
285+ if let Ok ( name) = target_section. name ( ) {
286+ target_section_name = Some ( name) ;
287+ }
288+ base += target_section. address ( ) as i128 ;
289+ }
290+ base += symbol. address ( ) as i128 ;
291+ }
292+ object:: RelocationTarget :: Section ( section_index) => {
293+ let Ok ( target_section) = file. section_by_index ( section_index) else {
294+ continue ;
295+ } ;
296+ if let Ok ( name) = target_section. name ( ) {
297+ target_section_name = Some ( name) ;
298+ }
299+ base += target_section. address ( ) as i128 ;
300+ }
301+ _ => { }
302+ }
303+
304+ if let Some ( name) = target_section_name {
305+ if !is_debug_related_section ( name) {
306+ continue ;
307+ }
308+ } else {
309+ continue ;
310+ }
311+
312+ if relocation. kind ( ) != object:: RelocationKind :: Absolute {
313+ continue ;
314+ }
315+
316+ let _existing = read_int ( & data[ offset..offset + size] , is_little_endian) as i128 ;
317+ let addend = relocation. addend ( ) as i128 ;
318+ let value = base. wrapping_add ( addend) as u64 ;
319+ write_int ( & mut data[ offset..offset + size] , value, is_little_endian) ;
320+ applied = true ;
321+ }
322+
323+ applied
324+ }
325+
326+ fn read_entire_view ( view : & BinaryView ) -> Option < Vec < u8 > > {
327+ let len = view. len ( ) ;
328+ if len == 0 || len > usize:: MAX as u64 {
329+ return None ;
330+ }
331+ let data = view. read_vec ( 0 , len as usize ) ;
332+ if data. len ( ) as u64 != len {
333+ return None ;
334+ }
335+ Some ( data)
336+ }
337+
338+ fn is_debug_related_section ( name : & str ) -> bool {
339+ name. starts_with ( ".debug" ) || name. starts_with ( ".zdebug" )
340+ }
0 commit comments