cle 9.3.2__tar.gz → 9.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cle-9.3.2/cle.egg-info → cle-9.3.3}/PKG-INFO +3 -3
- {cle-9.3.2 → cle-9.3.3}/cle/__init__.py +9 -1
- {cle-9.3.2 → cle-9.3.3}/cle/backends/__init__.py +6 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/coff.py +15 -8
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/elf.py +17 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/arm64.py +2 -1
- cle-9.3.3/cle/backends/gopclntab.py +313 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/macho.py +11 -4
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/macho_enums.py +62 -1
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/section.py +16 -4
- {cle-9.3.2 → cle-9.3.3}/cle/backends/stm32.py +45 -34
- {cle-9.3.2 → cle-9.3.3}/cle/backends/te.py +53 -16
- {cle-9.3.2 → cle-9.3.3}/cle/loader.py +37 -20
- {cle-9.3.2 → cle-9.3.3/cle.egg-info}/PKG-INFO +3 -3
- {cle-9.3.2 → cle-9.3.3}/cle.egg-info/SOURCES.txt +5 -0
- {cle-9.3.2 → cle-9.3.3}/cle.egg-info/requires.txt +2 -2
- {cle-9.3.2 → cle-9.3.3}/pyproject.toml +2 -2
- cle-9.3.3/tests/test_aarch64_relocations.py +119 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_arm_firmware.py +14 -0
- cle-9.3.3/tests/test_coff.py +79 -0
- cle-9.3.3/tests/test_gopclntab.py +151 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho.py +158 -0
- cle-9.3.3/tests/test_rebase.py +75 -0
- cle-9.3.3/tests/test_stm32.py +148 -0
- cle-9.3.3/tests/test_te.py +103 -0
- cle-9.3.2/tests/test_aarch64_relocations.py +0 -44
- cle-9.3.2/tests/test_coff.py +0 -37
- {cle-9.3.2 → cle-9.3.3}/LICENSE +0 -0
- {cle-9.3.2 → cle-9.3.3}/MANIFEST.in +0 -0
- {cle-9.3.2 → cle-9.3.3}/README.md +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/address_translator.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/backend.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/binja.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/blob.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/cartfile.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/cgc/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/cgc/backedcgc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/cgc/cgc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/compilation_unit.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/elfcore.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/hashtable.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/lsda.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/metaelf.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/amd64.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/arm.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/elfreloc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/generic.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/i386.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/mips.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/ppc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/ppc64.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/s390x.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/relocation/sparc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/subprogram.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/symbol.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/symbol_type.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/variable.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/elf/variable_type.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/simdata/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/simdata/common.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/simdata/glibc_startup.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/simdata/io_file.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/externs/simdata/simdata.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/ihex.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/inlined_function.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/java/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/java/android_lifecycle.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/java/apk.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/java/jar.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/java/soot.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/binding.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/encrypted_sentinel_backer.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/segment.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/structs.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/macho/symbol.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/minidump/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/named_region.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/pe.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/arm.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/generic.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/mips.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/pereloc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/relocation/riscv.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/stubs.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/symbol.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/pe/symbolserver.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/region.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/relocation.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/srec.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/static_archive.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/symbol.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/elf_tls.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/elfcore_tls.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/minidump_tls.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/pe_tls.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/tls/tls_object.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/uefi_firmware.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/universal2.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/backends/xbe.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/errors.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/gdb.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/memory.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/patched_stream.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/py.typed +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/structs/__init__.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/structs/mem_regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle/utils.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle.egg-info/dependency_links.txt +0 -0
- {cle-9.3.2 → cle-9.3.3}/cle.egg-info/top_level.txt +0 -0
- {cle-9.3.2 → cle-9.3.3}/setup.cfg +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_address_translator.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_amd64_relocations.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_arch_detect.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_blob.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_cart.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_clemory.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_compiler_detection.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_dwarf.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_dwarf_resiliency.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_elfcore.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_exceptions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_extern.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_gdb.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_got.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_hex.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho_bindinghelper.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho_dyld.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho_dyld_structs.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho_libs.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_macho_reloc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_minidump.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_mips_relocations.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_namedregion.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_optional_backends.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_overlap.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_patched_stream.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_pe.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_pe_coff_symbols.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_pe_delay_imports.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_pe_meta_regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_plt.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_ppc64_initial_rtoc.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_ppc_relocations.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_preload.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_regions.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_relocated.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_runpath.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_simdata.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_stream.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_symbolserver.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_tls_resiliency.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_universal2.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_unpackword.py +0 -0
- {cle-9.3.2 → cle-9.3.3}/tests/test_xbe.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cle
|
|
3
|
-
Version: 9.3.
|
|
3
|
+
Version: 9.3.3
|
|
4
4
|
Summary: CLE Loads Everything (at least, many binary formats!) and provides a pythonic interface to analyze what they are and what they would look like in memory.
|
|
5
5
|
License-Expression: BSD-2-Clause
|
|
6
6
|
Project-URL: Homepage, https://api.angr.io/projects/cle/en/latest/
|
|
@@ -13,13 +13,13 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
13
13
|
Requires-Python: >=3.12
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: archinfo==9.3.
|
|
16
|
+
Requires-Dist: archinfo==9.3.3
|
|
17
17
|
Requires-Dist: arpy==1.1.1
|
|
18
18
|
Requires-Dist: cart
|
|
19
19
|
Requires-Dist: minidump>=0.0.10
|
|
20
20
|
Requires-Dist: pefile==2024.8.26
|
|
21
21
|
Requires-Dist: pyelftools>=0.29
|
|
22
|
-
Requires-Dist: pyvex==9.3.
|
|
22
|
+
Requires-Dist: pyvex==9.3.3
|
|
23
23
|
Requires-Dist: pyxbe~=1.0.3
|
|
24
24
|
Requires-Dist: pyxdia~=0.1; sys_platform != "emscripten"
|
|
25
25
|
Requires-Dist: sortedcontainers>=2.0
|
|
@@ -7,7 +7,7 @@ The primary interface to CLE is the Loader class.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
__version__ = "9.3.
|
|
10
|
+
__version__ = "9.3.3"
|
|
11
11
|
|
|
12
12
|
from .address_translator import AT, AddressTranslator
|
|
13
13
|
from .backends import (
|
|
@@ -26,6 +26,9 @@ from .backends import (
|
|
|
26
26
|
ExceptionHandling,
|
|
27
27
|
FunctionHint,
|
|
28
28
|
FunctionHintSource,
|
|
29
|
+
GoFunction,
|
|
30
|
+
GoPclntab,
|
|
31
|
+
GoSymbol,
|
|
29
32
|
Hex,
|
|
30
33
|
Jar,
|
|
31
34
|
MachO,
|
|
@@ -40,6 +43,7 @@ from .backends import (
|
|
|
40
43
|
Soot,
|
|
41
44
|
SRec,
|
|
42
45
|
StaticArchive,
|
|
46
|
+
STM32Backend,
|
|
43
47
|
Symbol,
|
|
44
48
|
SymbolSubType,
|
|
45
49
|
SymbolType,
|
|
@@ -95,6 +99,9 @@ __all__ = [
|
|
|
95
99
|
"ExceptionHandling",
|
|
96
100
|
"FunctionHint",
|
|
97
101
|
"FunctionHintSource",
|
|
102
|
+
"GoFunction",
|
|
103
|
+
"GoPclntab",
|
|
104
|
+
"GoSymbol",
|
|
98
105
|
"Hex",
|
|
99
106
|
"SRec",
|
|
100
107
|
"Jar",
|
|
@@ -108,6 +115,7 @@ __all__ = [
|
|
|
108
115
|
"Segment",
|
|
109
116
|
"Soot",
|
|
110
117
|
"StaticArchive",
|
|
118
|
+
"STM32Backend",
|
|
111
119
|
"Universal2",
|
|
112
120
|
"register_backend",
|
|
113
121
|
"ExternObject",
|
|
@@ -6,6 +6,7 @@ from .cartfile import CARTFile
|
|
|
6
6
|
from .cgc import CGC, BackedCGC
|
|
7
7
|
from .coff import Coff
|
|
8
8
|
from .elf import ELF, ELFCore, MetaELF
|
|
9
|
+
from .gopclntab import GoFunction, GoPclntab, GoSymbol
|
|
9
10
|
from .ihex import Hex
|
|
10
11
|
from .java.apk import Apk
|
|
11
12
|
from .java.jar import Jar
|
|
@@ -18,6 +19,7 @@ from .region import Region, Section, Segment
|
|
|
18
19
|
from .regions import Regions
|
|
19
20
|
from .srec import SRec
|
|
20
21
|
from .static_archive import StaticArchive
|
|
22
|
+
from .stm32 import STM32Backend
|
|
21
23
|
from .symbol import Symbol, SymbolSubType, SymbolType
|
|
22
24
|
from .te import TE
|
|
23
25
|
from .uefi_firmware import UefiFirmware
|
|
@@ -53,6 +55,7 @@ __all__ = [
|
|
|
53
55
|
"Soot",
|
|
54
56
|
"XBE",
|
|
55
57
|
"StaticArchive",
|
|
58
|
+
"STM32Backend",
|
|
56
59
|
"Region",
|
|
57
60
|
"Segment",
|
|
58
61
|
"Section",
|
|
@@ -60,6 +63,9 @@ __all__ = [
|
|
|
60
63
|
"Symbol",
|
|
61
64
|
"SymbolType",
|
|
62
65
|
"SymbolSubType",
|
|
66
|
+
"GoFunction",
|
|
67
|
+
"GoPclntab",
|
|
68
|
+
"GoSymbol",
|
|
63
69
|
"UefiFirmware",
|
|
64
70
|
"TE",
|
|
65
71
|
"Universal2",
|
|
@@ -53,6 +53,7 @@ class IMAGE_SCN(IntFlag):
|
|
|
53
53
|
Section Flags (Characteristics field)
|
|
54
54
|
"""
|
|
55
55
|
|
|
56
|
+
MEM_DISCARDABLE = 0x02000000
|
|
56
57
|
MEM_EXECUTE = 0x20000000
|
|
57
58
|
MEM_READ = 0x40000000
|
|
58
59
|
MEM_WRITE = 0x80000000
|
|
@@ -236,13 +237,19 @@ class CoffParser:
|
|
|
236
237
|
name_encoded = bytes(self.symbols[symbol_idx].Name)
|
|
237
238
|
name_as_dwords = struct.unpack("<II", name_encoded)
|
|
238
239
|
if name_as_dwords[0] == 0:
|
|
239
|
-
|
|
240
|
+
return self.get_string(name_as_dwords[1])
|
|
240
241
|
return name_encoded.rstrip(b"\x00").decode("ascii")
|
|
241
242
|
|
|
243
|
+
def get_string(self, offset: int) -> str:
|
|
244
|
+
"""
|
|
245
|
+
Read the string table entry at `offset`, counted from the start of the table.
|
|
246
|
+
"""
|
|
247
|
+
return extract_null_terminated_bytestr(self.strings, offset=offset).decode("ascii")
|
|
248
|
+
|
|
242
249
|
def get_section_name(self, section_idx: int) -> str:
|
|
243
250
|
name = bytes(self.sections[section_idx].Name).rstrip(b"\x00").decode("ascii")
|
|
244
251
|
if name.startswith("/"):
|
|
245
|
-
return self.
|
|
252
|
+
return self.get_string(int(name[1:]))
|
|
246
253
|
return name
|
|
247
254
|
|
|
248
255
|
|
|
@@ -288,13 +295,16 @@ class CoffRelocation(Relocation):
|
|
|
288
295
|
|
|
289
296
|
__slots__ = ()
|
|
290
297
|
|
|
291
|
-
PACK_FORMAT = "<
|
|
298
|
+
PACK_FORMAT = "<I"
|
|
292
299
|
|
|
293
300
|
def relocate(self):
|
|
294
301
|
value = self.value
|
|
295
302
|
if value is None:
|
|
296
303
|
log.debug("Unresolved relocation with no symbol.")
|
|
297
304
|
return False
|
|
305
|
+
# The field holds a fixed-width bit pattern, so the value is truncated to that width
|
|
306
|
+
# rather than required to fit in it.
|
|
307
|
+
value &= (1 << (struct.calcsize(self.PACK_FORMAT) * 8)) - 1
|
|
298
308
|
self.owner.memory.store(self.relative_addr, struct.pack(self.PACK_FORMAT, value))
|
|
299
309
|
return True
|
|
300
310
|
|
|
@@ -310,7 +320,8 @@ class CoffRelocationREL32(CoffRelocation):
|
|
|
310
320
|
def value(self):
|
|
311
321
|
assert self.resolvedby is not None
|
|
312
322
|
org_bytes = self.owner.memory.load(self.relative_addr, 4)
|
|
313
|
-
|
|
323
|
+
# The field is a signed displacement, so its addend is too.
|
|
324
|
+
org_value = struct.unpack("<i", org_bytes)[0]
|
|
314
325
|
return org_value + self.resolvedby.rebased_addr - (self.rebased_addr + 4)
|
|
315
326
|
|
|
316
327
|
|
|
@@ -351,8 +362,6 @@ class CoffRelocationADDR32NB(CoffRelocation):
|
|
|
351
362
|
|
|
352
363
|
__slots__ = ()
|
|
353
364
|
|
|
354
|
-
PACK_FORMAT = "<I"
|
|
355
|
-
|
|
356
365
|
@property
|
|
357
366
|
def value(self) -> int:
|
|
358
367
|
assert self.resolvedby is not None
|
|
@@ -397,8 +406,6 @@ class CoffRelocationSECREL(CoffRelocation):
|
|
|
397
406
|
|
|
398
407
|
__slots__ = ()
|
|
399
408
|
|
|
400
|
-
PACK_FORMAT = "<I"
|
|
401
|
-
|
|
402
409
|
@property
|
|
403
410
|
def value(self):
|
|
404
411
|
assert isinstance(self.owner, Coff)
|
|
@@ -24,6 +24,7 @@ from sortedcontainers import SortedDict
|
|
|
24
24
|
|
|
25
25
|
from cle.address_translator import AT
|
|
26
26
|
from cle.backends.backend import ExceptionHandling, FunctionHint, FunctionHintSource, register_backend
|
|
27
|
+
from cle.backends.gopclntab import GoPclntab, register_gopclntab_symbols
|
|
27
28
|
from cle.backends.inlined_function import InlinedFunction
|
|
28
29
|
from cle.errors import CLECompatibilityError, CLEError, CLEInvalidBinaryError
|
|
29
30
|
from cle.patched_stream import PatchedStream
|
|
@@ -171,6 +172,9 @@ class ELF(MetaELF):
|
|
|
171
172
|
self.compilation_units: list[CompilationUnit] | None = None
|
|
172
173
|
self.functions_debug_info: dict[int, Subprogram] = {}
|
|
173
174
|
|
|
175
|
+
# Go
|
|
176
|
+
self.gopclntab: GoPclntab | None = None
|
|
177
|
+
|
|
174
178
|
# misc
|
|
175
179
|
self._entry = self._reader.header.e_entry
|
|
176
180
|
self.is_relocatable = self._reader.header.e_type == "ET_REL"
|
|
@@ -238,6 +242,9 @@ class ELF(MetaELF):
|
|
|
238
242
|
if os.path.isfile(debug_filename):
|
|
239
243
|
self.__process_debug_file(debug_filename)
|
|
240
244
|
|
|
245
|
+
# Go binaries keep a full function table even when stripped
|
|
246
|
+
self.gopclntab = register_gopclntab_symbols(self)
|
|
247
|
+
|
|
241
248
|
# call the methods defined by MetaELF
|
|
242
249
|
self._ppc64_abiv1_entry_fix()
|
|
243
250
|
self._load_plt()
|
|
@@ -1289,6 +1296,16 @@ class ELF(MetaELF):
|
|
|
1289
1296
|
if isinstance(symtab, sections.NullSection):
|
|
1290
1297
|
# Oh my god Atmel please stop
|
|
1291
1298
|
symtab = self._reader.get_section_by_name(".symtab")
|
|
1299
|
+
if symtab is None and section.header.get("sh_type") != "SHT_RELR":
|
|
1300
|
+
# A stripped object can still carry a relocation section whose linked symbol table was stripped away.
|
|
1301
|
+
# Without the table there is nothing that can be registered.
|
|
1302
|
+
# RELR sections are exempt: their entries carry no symbol index.
|
|
1303
|
+
log.warning(
|
|
1304
|
+
"%s: relocation section %s has no symbol table to resolve its entries against; skipping it.",
|
|
1305
|
+
self.binary,
|
|
1306
|
+
section.name,
|
|
1307
|
+
)
|
|
1308
|
+
return
|
|
1292
1309
|
relocs = []
|
|
1293
1310
|
for readelf_reloc in section.iter_relocations():
|
|
1294
1311
|
# Handle packed RELR relocations specially
|
|
@@ -19,6 +19,7 @@ from .generic import (
|
|
|
19
19
|
GenericTLSDoffsetReloc,
|
|
20
20
|
GenericTLSModIdReloc,
|
|
21
21
|
GenericTLSOffsetReloc,
|
|
22
|
+
RelocTruncate32Mixin,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
log = logging.getLogger(name=__name__)
|
|
@@ -66,7 +67,7 @@ class R_AARCH64_TLSDESC(GenericTLSDescriptorReloc):
|
|
|
66
67
|
RESOLVER_ADDR = 0xFFFF_FFFF_FFFF_FE00
|
|
67
68
|
|
|
68
69
|
|
|
69
|
-
class R_AARCH64_PREL32(GenericPCRelativeAddendReloc):
|
|
70
|
+
class R_AARCH64_PREL32(RelocTruncate32Mixin, GenericPCRelativeAddendReloc):
|
|
70
71
|
"""
|
|
71
72
|
Relocation Type: 261
|
|
72
73
|
Calculation: (S + A - P)
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Recovery of Go function symbols from the Go runtime's ``pclntab``.
|
|
3
|
+
|
|
4
|
+
Every binary produced by the Go linker carries this table (``.gopclntab`` on ELF,
|
|
5
|
+
``__gopclntab`` on Mach-O, embedded in ``.rdata`` on PE). It lists the entry point and the
|
|
6
|
+
name of every function in the image, which makes it the only reliable source of function
|
|
7
|
+
starts for stripped Go binaries.
|
|
8
|
+
|
|
9
|
+
Only the Go 1.18+ layouts (magic ``0xfffffff0`` and ``0xfffffff1``) are supported. The
|
|
10
|
+
header magic and the ``textStart`` field are deliberately not trusted: obfuscated binaries
|
|
11
|
+
clobber them, so the table is instead accepted or rejected on structural grounds.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import struct
|
|
18
|
+
from typing import TYPE_CHECKING, NamedTuple
|
|
19
|
+
|
|
20
|
+
from cle.address_translator import AT
|
|
21
|
+
|
|
22
|
+
from .symbol import Symbol, SymbolType
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from collections.abc import Callable
|
|
26
|
+
|
|
27
|
+
from .backend import Backend
|
|
28
|
+
|
|
29
|
+
log = logging.getLogger(name=__name__)
|
|
30
|
+
|
|
31
|
+
__all__ = ["GoFunction", "GoPclntab", "GoSymbol", "load_gopclntab", "register_gopclntab_symbols"]
|
|
32
|
+
|
|
33
|
+
# magic -> minimum Go version that emits it
|
|
34
|
+
GO_PCLNTAB_MAGICS = {
|
|
35
|
+
0xFFFFFFF1: (1, 20),
|
|
36
|
+
0xFFFFFFF0: (1, 18),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Section names that hold nothing but a pclntab.
|
|
40
|
+
PCLNTAB_SECTION_NAMES = frozenset({".gopclntab", "__gopclntab", ".go.pclntab", "__go_pclntab"})
|
|
41
|
+
|
|
42
|
+
# Sections a pclntab may be embedded in, searched by magic as a fallback.
|
|
43
|
+
_EMBEDDING_SECTION_NAMES = frozenset({".rdata", ".rodata", "__rodata", "__const", "__DATA_CONST"})
|
|
44
|
+
|
|
45
|
+
# Sections whose presence means "this was built by the Go toolchain".
|
|
46
|
+
_GO_MARKER_SECTION_NAMES = frozenset({".gosymtab", ".typelink", ".itablink", ".noptrdata", ".noptrbss"})
|
|
47
|
+
|
|
48
|
+
_VALID_PTR_SIZES = (4, 8)
|
|
49
|
+
_VALID_MIN_LC = (1, 2, 4)
|
|
50
|
+
_MAX_NAME_LEN = 4096
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class GoFunction(NamedTuple):
|
|
54
|
+
"""
|
|
55
|
+
One entry of the pclntab's function table.
|
|
56
|
+
|
|
57
|
+
:ivar addr: Entry point of the function, as a linked virtual address.
|
|
58
|
+
:ivar size: Distance to the next function; includes inter-function padding.
|
|
59
|
+
:ivar name: Fully qualified Go name, e.g. ``net/http.(*Server).Serve``.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
addr: int
|
|
63
|
+
size: int
|
|
64
|
+
name: str
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class GoSymbol(Symbol):
|
|
68
|
+
"""
|
|
69
|
+
A function symbol recovered from a Go pclntab.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, owner: Backend, name: str, relative_addr: int, size: int):
|
|
73
|
+
super().__init__(owner, name, relative_addr, size, SymbolType.TYPE_FUNCTION)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class GoPclntab:
|
|
77
|
+
"""
|
|
78
|
+
A parsed Go pclntab.
|
|
79
|
+
|
|
80
|
+
:ivar magic: The raw magic word. May be garbage: it is not used for validation.
|
|
81
|
+
:ivar min_lc: Minimum instruction length of the target architecture.
|
|
82
|
+
:ivar ptr_size: Pointer size, in bytes.
|
|
83
|
+
:ivar text_start: The base the function entry offsets are relative to, after recovery.
|
|
84
|
+
:ivar functions: The function table, sorted by address.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
__slots__ = ("magic", "min_lc", "ptr_size", "text_start", "functions")
|
|
88
|
+
|
|
89
|
+
def __init__(self, magic: int, min_lc: int, ptr_size: int, text_start: int, functions: list[GoFunction]):
|
|
90
|
+
self.magic = magic
|
|
91
|
+
self.min_lc = min_lc
|
|
92
|
+
self.ptr_size = ptr_size
|
|
93
|
+
self.text_start = text_start
|
|
94
|
+
self.functions = functions
|
|
95
|
+
|
|
96
|
+
def __repr__(self):
|
|
97
|
+
return f"<GoPclntab: {len(self.functions)} functions, text at {self.text_start:#x}>"
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def go_version(self) -> tuple[int, int] | None:
|
|
101
|
+
return GO_PCLNTAB_MAGICS.get(self.magic)
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def parse(
|
|
105
|
+
cls,
|
|
106
|
+
data: bytes,
|
|
107
|
+
endness: str = "<",
|
|
108
|
+
text_start_fallback: int | None = None,
|
|
109
|
+
is_text_addr: Callable[[int], bool] | None = None,
|
|
110
|
+
) -> GoPclntab | None:
|
|
111
|
+
"""
|
|
112
|
+
Parse a pclntab out of ``data``, which must start at the table header.
|
|
113
|
+
|
|
114
|
+
Returns None if ``data`` does not structurally look like a pclntab.
|
|
115
|
+
|
|
116
|
+
:param data: The bytes of the table.
|
|
117
|
+
:param endness: ``<`` or ``>``.
|
|
118
|
+
:param text_start_fallback: Address to use when the header's ``textStart`` is unusable.
|
|
119
|
+
:param is_text_addr: Predicate deciding whether ``textStart`` points at code.
|
|
120
|
+
"""
|
|
121
|
+
header = _parse_header(data, endness)
|
|
122
|
+
if header is None:
|
|
123
|
+
return None
|
|
124
|
+
magic, min_lc, ptr_size, nfunc, text_start, funcname_off, pcln_off = header
|
|
125
|
+
|
|
126
|
+
if text_start == 0 or (is_text_addr is not None and not is_text_addr(text_start)):
|
|
127
|
+
if text_start_fallback is None:
|
|
128
|
+
log.warning("gopclntab: textStart %#x is not code and there is no fallback", text_start)
|
|
129
|
+
return None
|
|
130
|
+
log.debug("gopclntab: textStart %#x is not code, using %#x instead", text_start, text_start_fallback)
|
|
131
|
+
text_start = text_start_fallback
|
|
132
|
+
|
|
133
|
+
# nfunc pairs of (entryoff, funcoff), then one final entryoff marking the end of the last function
|
|
134
|
+
entries = struct.unpack_from(f"{endness}{2 * nfunc + 1}I", data, pcln_off)
|
|
135
|
+
entry_offs = entries[0::2]
|
|
136
|
+
func_offs = entries[1::2]
|
|
137
|
+
if any(a >= b for a, b in zip(entry_offs, entry_offs[1:])):
|
|
138
|
+
log.debug("gopclntab: function entry offsets are not monotonically increasing")
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
functions = []
|
|
142
|
+
for i, func_off in enumerate(func_offs):
|
|
143
|
+
# the _func struct is entryOff uint32 followed by nameOff int32
|
|
144
|
+
name_ptr = pcln_off + func_off + 4
|
|
145
|
+
if name_ptr + 4 > len(data):
|
|
146
|
+
log.debug("gopclntab: _func %d lies outside the table", i)
|
|
147
|
+
return None
|
|
148
|
+
name_off = funcname_off + struct.unpack_from(endness + "i", data, name_ptr)[0]
|
|
149
|
+
if not funcname_off <= name_off < len(data):
|
|
150
|
+
log.debug("gopclntab: name of function %d lies outside the table", i)
|
|
151
|
+
return None
|
|
152
|
+
end = data.find(b"\0", name_off, name_off + _MAX_NAME_LEN)
|
|
153
|
+
if end == -1:
|
|
154
|
+
log.debug("gopclntab: name of function %d is unterminated", i)
|
|
155
|
+
return None
|
|
156
|
+
name = data[name_off:end].decode("utf-8", "replace")
|
|
157
|
+
functions.append(GoFunction(text_start + entry_offs[i], entry_offs[i + 1] - entry_offs[i], name))
|
|
158
|
+
|
|
159
|
+
return cls(magic, min_lc, ptr_size, text_start, functions)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _parse_header(data: bytes, endness: str) -> tuple[int, int, int, int, int, int, int] | None:
|
|
163
|
+
"""
|
|
164
|
+
Validate and decode a pclntab header. Returns
|
|
165
|
+
``(magic, min_lc, ptr_size, nfunc, text_start, funcname_off, pcln_off)`` or None.
|
|
166
|
+
|
|
167
|
+
The magic is decoded but never checked, so that binaries with a clobbered one still load.
|
|
168
|
+
"""
|
|
169
|
+
if len(data) < 16:
|
|
170
|
+
return None
|
|
171
|
+
magic, _pad, min_lc, ptr_size = struct.unpack_from(endness + "IHBB", data, 0)
|
|
172
|
+
if ptr_size not in _VALID_PTR_SIZES or min_lc not in _VALID_MIN_LC or _pad != 0:
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
header_size = 8 + 8 * ptr_size
|
|
176
|
+
if len(data) < header_size:
|
|
177
|
+
return None
|
|
178
|
+
word = endness + ("Q" if ptr_size == 8 else "I")
|
|
179
|
+
nfunc, nfiles, text_start, funcname_off, cu_off, filetab_off, pctab_off, pcln_off = (
|
|
180
|
+
struct.unpack_from(word, data, 8 + i * ptr_size)[0] for i in range(8)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
size = len(data)
|
|
184
|
+
# the five sub-tables follow the header in a fixed order and all live inside the table
|
|
185
|
+
offsets = (funcname_off, cu_off, filetab_off, pctab_off, pcln_off)
|
|
186
|
+
if offsets[0] < header_size or offsets[-1] >= size:
|
|
187
|
+
return None
|
|
188
|
+
if any(a > b for a, b in zip(offsets, offsets[1:])):
|
|
189
|
+
return None
|
|
190
|
+
# a function costs 8 bytes of functab plus a _func struct, a file name at least 2 bytes
|
|
191
|
+
if nfunc <= 0 or pcln_off + (2 * nfunc + 1) * 4 > size:
|
|
192
|
+
return None
|
|
193
|
+
if nfiles * 2 > size:
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
return magic, min_lc, ptr_size, nfunc, text_start, funcname_off, pcln_off
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
#
|
|
200
|
+
# Backend integration
|
|
201
|
+
#
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _read_section(backend: Backend, section) -> bytes | None:
|
|
205
|
+
try:
|
|
206
|
+
if section.memsize == 0 or section.only_contains_uninitialized_data:
|
|
207
|
+
return None
|
|
208
|
+
return backend.memory.load(AT.from_lva(section.vaddr, backend).to_rva(), section.memsize)
|
|
209
|
+
except Exception: # pylint: disable=broad-except
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _executable_sections(backend: Backend):
|
|
214
|
+
return [sec for sec in backend.sections if sec.is_executable and sec.memsize > 0]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _text_start_fallback(execs) -> int | None:
|
|
218
|
+
"""
|
|
219
|
+
The vaddr of the section holding the executable code, used when ``textStart`` is unusable.
|
|
220
|
+
"""
|
|
221
|
+
if not execs:
|
|
222
|
+
return None
|
|
223
|
+
for sec in execs:
|
|
224
|
+
if sec.name in (".text", "__text"):
|
|
225
|
+
return sec.vaddr
|
|
226
|
+
return min(sec.vaddr for sec in execs)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _looks_like_go(backend: Backend) -> bool:
|
|
230
|
+
return any(sec.name in _GO_MARKER_SECTION_NAMES or sec.name.startswith(".go.") for sec in backend.sections)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _find_pclntab_data(backend: Backend, endness: str):
|
|
234
|
+
"""
|
|
235
|
+
Yield candidate ``bytes`` objects, each starting at a possible pclntab header.
|
|
236
|
+
"""
|
|
237
|
+
embedding = []
|
|
238
|
+
for section in backend.sections:
|
|
239
|
+
if section.name in PCLNTAB_SECTION_NAMES:
|
|
240
|
+
data = _read_section(backend, section)
|
|
241
|
+
if data is not None:
|
|
242
|
+
yield data
|
|
243
|
+
elif section.name in _EMBEDDING_SECTION_NAMES and not section.is_executable:
|
|
244
|
+
embedding.append(section)
|
|
245
|
+
|
|
246
|
+
# PE and Mach-O bury the table in a generic read-only section; find it by magic. Only worth
|
|
247
|
+
# doing when something else already says this is a Go binary.
|
|
248
|
+
if not embedding or not _looks_like_go(backend):
|
|
249
|
+
return
|
|
250
|
+
magics = [struct.pack(endness + "I", magic) for magic in GO_PCLNTAB_MAGICS]
|
|
251
|
+
for section in embedding:
|
|
252
|
+
data = _read_section(backend, section)
|
|
253
|
+
if data is None:
|
|
254
|
+
continue
|
|
255
|
+
for magic in magics:
|
|
256
|
+
pos = data.find(magic)
|
|
257
|
+
while pos != -1:
|
|
258
|
+
yield data[pos:]
|
|
259
|
+
pos = data.find(magic, pos + 4)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def load_gopclntab(backend: Backend) -> GoPclntab | None:
|
|
263
|
+
"""
|
|
264
|
+
Find and parse the Go pclntab of an already-loaded object. Returns None if there is none.
|
|
265
|
+
"""
|
|
266
|
+
if not backend.sections:
|
|
267
|
+
return None
|
|
268
|
+
endness = ">" if backend.arch is not None and backend.arch.memory_endness == "Iend_BE" else "<"
|
|
269
|
+
|
|
270
|
+
execs: list = []
|
|
271
|
+
|
|
272
|
+
def is_text_addr(addr: int) -> bool:
|
|
273
|
+
return any(sec.contains_addr(addr) for sec in execs)
|
|
274
|
+
|
|
275
|
+
fallback = None
|
|
276
|
+
for i, data in enumerate(_find_pclntab_data(backend, endness)):
|
|
277
|
+
if i == 0:
|
|
278
|
+
execs = _executable_sections(backend)
|
|
279
|
+
fallback = _text_start_fallback(execs)
|
|
280
|
+
tab = GoPclntab.parse(data, endness, text_start_fallback=fallback, is_text_addr=is_text_addr)
|
|
281
|
+
if tab is not None:
|
|
282
|
+
return tab
|
|
283
|
+
return None
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def register_gopclntab_symbols(backend: Backend) -> GoPclntab | None:
|
|
287
|
+
"""
|
|
288
|
+
Parse the object's Go pclntab, if it has one, and add a function symbol for every Go
|
|
289
|
+
function that is not already covered by a symbol table.
|
|
290
|
+
"""
|
|
291
|
+
try:
|
|
292
|
+
tab = load_gopclntab(backend)
|
|
293
|
+
except (struct.error, ValueError):
|
|
294
|
+
log.warning("Failed to parse the Go pclntab of %s", backend.binary_basename, exc_info=True)
|
|
295
|
+
return None
|
|
296
|
+
if tab is None:
|
|
297
|
+
return None
|
|
298
|
+
|
|
299
|
+
covered = {sym.relative_addr for sym in backend.symbols if sym.size and sym.is_function}
|
|
300
|
+
by_name = getattr(backend, "_symbols_by_name", None)
|
|
301
|
+
added = 0
|
|
302
|
+
for func in tab.functions:
|
|
303
|
+
relative_addr = AT.from_lva(func.addr, backend).to_rva()
|
|
304
|
+
if relative_addr in covered:
|
|
305
|
+
continue
|
|
306
|
+
symbol = GoSymbol(backend, func.name, relative_addr, func.size)
|
|
307
|
+
backend.symbols.add(symbol)
|
|
308
|
+
if by_name is not None and func.name and func.name not in by_name:
|
|
309
|
+
by_name[func.name] = symbol
|
|
310
|
+
added += 1
|
|
311
|
+
|
|
312
|
+
log.info("Recovered %d Go functions from the pclntab of %s (%d new)", len(tab.functions), backend, added)
|
|
313
|
+
return tab
|
|
@@ -1041,11 +1041,18 @@ class MachO(Backend):
|
|
|
1041
1041
|
# It would allocate 4GB of unneeded memory and also break rebasing
|
|
1042
1042
|
# because now there is a segment that must be at address 0, while the other segments should be slid
|
|
1043
1043
|
log.info("Found PAGEZERO, skipping backer for memory conservation")
|
|
1044
|
+
elif seg.memsize == 0:
|
|
1045
|
+
# A segment with vmsize 0 occupies no address space, so it must not be backed no matter how much file
|
|
1046
|
+
# content it has. Debug info kept in the executable rather than a .dSYM is emitted like this: __DWARF has
|
|
1047
|
+
# vmsize 0 and shares its vmaddr with the segment that follows it, so backing it would map the debug info
|
|
1048
|
+
# over that segment.
|
|
1049
|
+
log.info("Segment %r is not mapped at runtime, skipping backer", segname)
|
|
1044
1050
|
elif seg.filesize > 0:
|
|
1045
|
-
# Append segment data to memory
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1051
|
+
# Append segment data to memory. A segment maps memsize bytes and the file contributes at most that many
|
|
1052
|
+
# of them, so anything the file has beyond memsize is not part of the mapping.
|
|
1053
|
+
blob = self._read(f, seg.offset, min(seg.filesize, seg.memsize))
|
|
1054
|
+
if len(blob) < seg.memsize:
|
|
1055
|
+
blob += b"\0" * (seg.memsize - len(blob)) # padding
|
|
1049
1056
|
|
|
1050
1057
|
# The memory of the Backend itself should start at 0, where 0 is the lowest meaningful address
|
|
1051
1058
|
# In our case this would be the Mach header magic
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from enum import IntEnum
|
|
3
|
+
from enum import IntEnum, IntFlag
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class LoadCommands(IntEnum):
|
|
@@ -70,6 +70,67 @@ class LoadCommands(IntEnum):
|
|
|
70
70
|
LC_DYLD_CHAINED_FIXUPS = 0x34 | LC_REQ_DYLD
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
class SectionType(IntEnum):
|
|
74
|
+
"""
|
|
75
|
+
from mach-o/loader.h
|
|
76
|
+
|
|
77
|
+
Constants for the low byte of a section's flags field, which says what the section holds.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
S_REGULAR = 0x0
|
|
81
|
+
S_ZEROFILL = 0x1
|
|
82
|
+
S_CSTRING_LITERALS = 0x2
|
|
83
|
+
S_4BYTE_LITERALS = 0x3
|
|
84
|
+
S_8BYTE_LITERALS = 0x4
|
|
85
|
+
S_LITERAL_POINTERS = 0x5
|
|
86
|
+
S_NON_LAZY_SYMBOL_POINTERS = 0x6
|
|
87
|
+
S_LAZY_SYMBOL_POINTERS = 0x7
|
|
88
|
+
S_SYMBOL_STUBS = 0x8
|
|
89
|
+
S_MOD_INIT_FUNC_POINTERS = 0x9
|
|
90
|
+
S_MOD_TERM_FUNC_POINTERS = 0xA
|
|
91
|
+
S_COALESCED = 0xB
|
|
92
|
+
S_GB_ZEROFILL = 0xC
|
|
93
|
+
S_INTERPOSING = 0xD
|
|
94
|
+
S_16BYTE_LITERALS = 0xE
|
|
95
|
+
S_DTRACE_DOF = 0xF
|
|
96
|
+
S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10
|
|
97
|
+
S_THREAD_LOCAL_REGULAR = 0x11
|
|
98
|
+
S_THREAD_LOCAL_ZEROFILL = 0x12
|
|
99
|
+
S_THREAD_LOCAL_VARIABLES = 0x13
|
|
100
|
+
S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14
|
|
101
|
+
S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15
|
|
102
|
+
S_INIT_FUNC_OFFSETS = 0x16
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class SectionAttributes(IntFlag):
|
|
106
|
+
"""
|
|
107
|
+
from mach-o/loader.h
|
|
108
|
+
|
|
109
|
+
Constants for the section attributes, which occupy the high three bytes of a section's flags field.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
# section contains only true machine instructions
|
|
113
|
+
S_ATTR_PURE_INSTRUCTIONS = 0x80000000
|
|
114
|
+
# section contains coalesced symbols that are not to be in a ranlib table of contents
|
|
115
|
+
S_ATTR_NO_TOC = 0x40000000
|
|
116
|
+
# ok to strip static symbols in this section in files with the MH_DYLDLINK flag
|
|
117
|
+
S_ATTR_STRIP_STATIC_SYMS = 0x20000000
|
|
118
|
+
# no dead stripping
|
|
119
|
+
S_ATTR_NO_DEAD_STRIP = 0x10000000
|
|
120
|
+
# blocks are live if they reference live blocks
|
|
121
|
+
S_ATTR_LIVE_SUPPORT = 0x08000000
|
|
122
|
+
# used in code generated by the UNIX C++ compiler for virtual function tables
|
|
123
|
+
S_ATTR_SELF_MODIFYING_CODE = 0x04000000
|
|
124
|
+
# a debug section
|
|
125
|
+
S_ATTR_DEBUG = 0x02000000
|
|
126
|
+
# section contains some machine instructions
|
|
127
|
+
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
|
|
128
|
+
# section has external relocation entries
|
|
129
|
+
S_ATTR_EXT_RELOC = 0x00000200
|
|
130
|
+
# section has local relocation entries
|
|
131
|
+
S_ATTR_LOC_RELOC = 0x00000100
|
|
132
|
+
|
|
133
|
+
|
|
73
134
|
class MachoFiletype(IntEnum):
|
|
74
135
|
"""
|
|
75
136
|
from mach-o/loader.h
|