Skip to content

Commit

Permalink
MachO::Binary::shift_command: fix exports of dyld (#1133)
Browse files Browse the repository at this point in the history
* MachO::Binary::shift_command: fix shift of dyld exports

Despite the field name `address` it stores a file offset.

Co-authored-by: Richard Dzenis <[email protected]>

* MachO::Binary::shift_command: fix comparison in DyldExportsTrie update

`ExportInfo` is meant to be updated if `info.address()` is beyond the
point where shift happens; however, offset comparison was reversed.

Additionally, compare with `from_offset`, because despite the field name
`address` it stores a file offset.

Co-authored-by: Richard Dzenis <[email protected]>

* Add macho/test_exports_after_shift

This test checks that exports in dyld_info are shifted correctly.

* Add macho/test_chained_exports_after_shift

This test checks that exports in dyld_exports_trie
are shifted correctly.

---------

Co-authored-by: Peteris Ledins <[email protected]>
Co-authored-by: Javier Lopez-Gomez <[email protected]>
  • Loading branch information
3 people authored Dec 21, 2024
1 parent 1c46aed commit 1e425fc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/MachO/Binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ void Binary::shift_command(size_t width, uint64_t from_offset) {
// Shift Export Info
// -----------------
for (ExportInfo& info : dyld->exports()) {
if (info.address() > virtual_address) {
if (info.address() > from_offset) {
info.address(info.address() + width);
}
}
Expand Down Expand Up @@ -816,7 +816,7 @@ void Binary::shift_command(size_t width, uint64_t from_offset) {

if (DyldExportsTrie* exports = dyld_exports_trie()) {
for (ExportInfo& info : exports->exports()) {
if (virtual_address >= info.address()) {
if (info.address() > from_offset) {
info.address(info.address() + width);
}
}
Expand Down
38 changes: 37 additions & 1 deletion tests/macho/test_symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import lief
import pathlib
import re
from utils import is_osx, get_sample
from utils import is_aarch64, is_osx, get_sample

from .test_builder import run_program

Expand Down Expand Up @@ -148,3 +148,39 @@ def get_shifted_symbol(sym):
shifted_symbols = {(sym.name, sym.value) for sym in macho.symbols if sym.raw_type & 0x0E == lief.MachO.Symbol.TYPE.SECTION}

assert shifted_symbols == check_symbols

def test_exports_after_shift(tmp_path):
bin_path = pathlib.Path(get_sample("MachO/MachO64_AArch64_weak-sym.bin"))
macho = lief.MachO.parse(bin_path.as_posix()).at(0)
assert macho.dyld_info

shift = 0x10000
loadcommands_end = 32 + macho.header.sizeof_cmds # sizeof(mach_header_64) + size of load command table
def get_shifted_export(e):
address = e.address
if address > loadcommands_end:
address += shift
return address

expected_exports_addrs = [get_shifted_export(e) for e in macho.dyld_info.exports]
macho.shift(shift)
new_exports_addrs = [e.address for e in macho.dyld_info.exports]
assert new_exports_addrs == expected_exports_addrs

def test_chained_exports_after_shift(tmp_path):
bin_path = pathlib.Path(get_sample("MachO/MachO64_AArch64_weak-sym-fc.bin"))
macho = lief.MachO.parse(bin_path.as_posix()).at(0)
assert macho.dyld_exports_trie

shift = 0x10000
loadcommands_end = 32 + macho.header.sizeof_cmds # sizeof(mach_header_64) + size of load command table
def get_shifted_export(e):
address = e.address
if address > loadcommands_end:
address += shift
return address

expected_exports_addrs = [get_shifted_export(e) for e in macho.dyld_exports_trie.exports]
macho.shift(shift)
new_exports_addrs = [e.address for e in macho.dyld_exports_trie.exports]
assert new_exports_addrs == expected_exports_addrs

0 comments on commit 1e425fc

Please sign in to comment.