MachOSymbol.is_function is always False, so CFGFast never seeds from a Mach-O symbol table
- 主要言語
- Python
- スター
- 485
- フォーク
- 135
- 平均マージ
- 2日 2時間
- マージ済み PR(30日)
- 15
説明
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
`MachOSymbol.is_function` returns `False` for every symbol, unconditionally:
```python
@property
def is_function(self):
# Incompatibility to CLE
log.debug("It is not possible to decide wether a symbol is a function or not for MachOSymbols")
return False
```
That contradicts the type the same class assigns. `SymbolTableSymbol.__init__` sets `self._type = SymbolType.TYPE_FUNCTION_OR_OBJECT` for exported, stab and local symbols, and `Symbol.is_function` on the base class answers `True` for exactly that type — but the override wins, so a symbol reports `TYPE_FUNCTION_OR_OBJECT` and `is_function == False` at the same time.
It is visible on this project's own fixtures:
```python
import cle
mo = cle.Loader("angr/binaries/tests/aarch64/macho_lib_loading/FrameWorkApp.app_15/FrameWorkApp",
auto_load_libs=False).main_object
sum(1 for s in mo.symbols if str(s.type).endswith("TYPE_FUNCTION_OR_OBJECT")) # 143
sum(1 for s in mo.symbols if s.is_function) # 0
```
Every Mach-O fixture I checked behaves the same way — `dyld_ios15.macho`, `macho_nop_stub`, both `FrameWorkApp` variants and their `dynamicLibrary` frameworks — typed symbols on one side, zero on the other.
The consequence is downstream: `CFGFast` seeds functions from `symbol.is_function`, so **no Mach-O binary is ever seeded from its symbol table**. On one aarch64 Mach-O shared library I measured — digest `a1fcc20929f610de966b4667bdf5dcaf437275b0a43d6388ad5682996b1cffc8`, a Homebrew-installed dylib — the file records 1,311 function starts and angr recovers 638. Of the 673 it misses, **629 are never decoded at all**: no block covers them, because with `force_complete_scan=False` nothing reaches them and nothing seeds them. That object carries no `LC_FUNCTION_STARTS` table and no `.eh_frame`, so its symbol table is the only thing that records where its code begins.
The comment is fair as far as it goes — Mach-O's `nlist` does not separate code from data the way ELF's `STT_FUNC` does. But the decision is not undecidable: a symbol whose `n_type` says `N_SECT` and whose section is executable is a function to a useful approximation, and it can be checked against the bytes. angr/cle#754 and angr/angr#6861 already take that route for `LC_FUNCTION_STARTS`, with a byte-level code test on the angr side, so the machinery for doing this carefully exists. What they do not cover is an object with no function-starts table, which is where the symbol table is all there is.
Worth pairing with a real caution rather than seeding naively: GHC emits `_dsp_`-prefixed info tables into `__TEXT,__text` in a section carrying `S_ATTR_PURE_INSTRUCTIONS`, so "in an executable section" alone will seed data as functions. Any fix here needs the same code test.
Happy to open a pull request if you would like this pursued, and to say which direction you prefer.
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
評価
この issue はまだ評価されていません。