smallworld-re 1.0.2__py3-none-any.whl → 2.0.0__py3-none-any.whl
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.
- smallworld/analyses/__init__.py +8 -0
- smallworld/analyses/analysis.py +8 -67
- smallworld/analyses/code_coverage.py +1 -2
- smallworld/analyses/colorizer.py +301 -534
- smallworld/analyses/colorizer_def_use.py +217 -0
- smallworld/analyses/colorizer_summary.py +173 -83
- smallworld/analyses/field_detection/field_analysis.py +7 -8
- smallworld/analyses/field_detection/hints.py +1 -1
- smallworld/analyses/field_detection/malloc.py +2 -2
- smallworld/analyses/trace_execution.py +160 -0
- smallworld/analyses/trace_execution_types.py +42 -0
- smallworld/analyses/unstable/angr/divergence.py +1 -2
- smallworld/analyses/unstable/angr/model.py +5 -6
- smallworld/analyses/unstable/angr_nwbt.py +3 -4
- smallworld/analyses/unstable/code_coverage.py +2 -3
- smallworld/analyses/unstable/code_reachable.py +2 -3
- smallworld/analyses/unstable/control_flow_tracer.py +2 -3
- smallworld/analyses/unstable/pointer_finder.py +2 -3
- smallworld/analyses/unstable/utils/tui.py +71 -0
- smallworld/emulators/__init__.py +3 -1
- smallworld/emulators/angr/angr.py +30 -9
- smallworld/emulators/angr/machdefs/__init__.py +2 -0
- smallworld/emulators/angr/machdefs/aarch64.py +1 -1
- smallworld/emulators/angr/machdefs/amd64.py +0 -4
- smallworld/emulators/angr/machdefs/arm.py +0 -2
- smallworld/emulators/angr/machdefs/i386.py +0 -2
- smallworld/emulators/angr/machdefs/loongarch.py +340 -0
- smallworld/emulators/angr/machdefs/machdef.py +1 -8
- smallworld/emulators/angr/machdefs/mips.py +0 -2
- smallworld/emulators/angr/machdefs/mips64.py +0 -2
- smallworld/emulators/angr/machdefs/ppc.py +1 -2
- smallworld/emulators/angr/machdefs/riscv.py +8 -10
- smallworld/emulators/angr/machdefs/xtensa.py +7 -4
- smallworld/emulators/emulator.py +22 -0
- smallworld/emulators/ghidra/__init__.py +37 -0
- smallworld/emulators/ghidra/ghidra.py +513 -0
- smallworld/emulators/ghidra/machdefs/__init__.py +31 -0
- smallworld/emulators/ghidra/machdefs/aarch64.py +289 -0
- smallworld/emulators/ghidra/machdefs/amd64.py +185 -0
- smallworld/emulators/ghidra/machdefs/arm.py +370 -0
- smallworld/emulators/ghidra/machdefs/i386.py +109 -0
- smallworld/emulators/ghidra/machdefs/loongarch.py +162 -0
- smallworld/emulators/ghidra/machdefs/machdef.py +81 -0
- smallworld/emulators/ghidra/machdefs/mips.py +163 -0
- smallworld/emulators/ghidra/machdefs/mips64.py +186 -0
- smallworld/emulators/ghidra/machdefs/ppc.py +98 -0
- smallworld/emulators/ghidra/machdefs/riscv.py +208 -0
- smallworld/emulators/ghidra/machdefs/xtensa.py +21 -0
- smallworld/emulators/ghidra/typing.py +28 -0
- smallworld/emulators/hookable.py +18 -4
- smallworld/emulators/panda/machdefs/__init__.py +2 -2
- smallworld/emulators/panda/machdefs/aarch64.py +186 -11
- smallworld/emulators/panda/machdefs/amd64.py +103 -11
- smallworld/emulators/panda/machdefs/arm.py +216 -20
- smallworld/emulators/panda/machdefs/i386.py +30 -7
- smallworld/emulators/panda/machdefs/machdef.py +9 -16
- smallworld/emulators/panda/machdefs/mips.py +49 -5
- smallworld/emulators/panda/machdefs/mips64.py +57 -5
- smallworld/emulators/panda/machdefs/ppc.py +38 -13
- smallworld/emulators/panda/panda.py +146 -44
- smallworld/emulators/unicorn/__init__.py +2 -0
- smallworld/emulators/unicorn/machdefs/aarch64.py +253 -264
- smallworld/emulators/unicorn/machdefs/amd64.py +254 -259
- smallworld/emulators/unicorn/machdefs/arm.py +200 -212
- smallworld/emulators/unicorn/machdefs/i386.py +84 -90
- smallworld/emulators/unicorn/machdefs/machdef.py +2 -23
- smallworld/emulators/unicorn/machdefs/mips.py +127 -135
- smallworld/emulators/unicorn/unicorn.py +52 -13
- smallworld/helpers.py +4 -19
- smallworld/hinting/hinting.py +22 -192
- smallworld/hinting/hints.py +50 -18
- smallworld/instructions/bsid.py +8 -8
- smallworld/logging.py +4 -2
- smallworld/platforms/__init__.py +12 -0
- smallworld/platforms/defs/__init__.py +36 -0
- smallworld/platforms/defs/aarch64.py +450 -0
- smallworld/platforms/defs/amd64.py +463 -0
- smallworld/platforms/defs/arm.py +519 -0
- smallworld/platforms/defs/i386.py +258 -0
- smallworld/platforms/defs/loongarch.py +270 -0
- smallworld/platforms/defs/mips.py +321 -0
- smallworld/platforms/defs/mips64.py +313 -0
- smallworld/platforms/defs/platformdef.py +97 -0
- smallworld/platforms/defs/powerpc.py +259 -0
- smallworld/platforms/defs/riscv.py +257 -0
- smallworld/platforms/defs/xtensa.py +96 -0
- smallworld/{platforms.py → platforms/platforms.py} +3 -0
- smallworld/state/cpus/__init__.py +2 -0
- smallworld/state/cpus/aarch64.py +0 -9
- smallworld/state/cpus/amd64.py +6 -28
- smallworld/state/cpus/arm.py +0 -11
- smallworld/state/cpus/cpu.py +0 -11
- smallworld/state/cpus/i386.py +0 -7
- smallworld/state/cpus/loongarch.py +299 -0
- smallworld/state/cpus/mips.py +4 -47
- smallworld/state/cpus/mips64.py +18 -58
- smallworld/state/cpus/powerpc.py +2 -9
- smallworld/state/cpus/riscv.py +1 -11
- smallworld/state/cpus/xtensa.py +0 -5
- smallworld/state/memory/code.py +44 -2
- smallworld/state/memory/elf/__init__.py +5 -1
- smallworld/state/memory/elf/coredump/__init__.py +3 -0
- smallworld/state/memory/elf/coredump/coredump.py +46 -0
- smallworld/state/memory/elf/coredump/prstatus/__init__.py +27 -0
- smallworld/state/memory/elf/coredump/prstatus/aarch64.py +46 -0
- smallworld/state/memory/elf/coredump/prstatus/amd64.py +40 -0
- smallworld/state/memory/elf/coredump/prstatus/arm.py +53 -0
- smallworld/state/memory/elf/coredump/prstatus/i386.py +30 -0
- smallworld/state/memory/elf/coredump/prstatus/mips.py +55 -0
- smallworld/state/memory/elf/coredump/prstatus/mips64.py +57 -0
- smallworld/state/memory/elf/coredump/prstatus/ppc.py +82 -0
- smallworld/state/memory/elf/coredump/prstatus/prstatus.py +129 -0
- smallworld/state/memory/elf/elf.py +225 -61
- smallworld/state/memory/elf/register_state.py +36 -0
- smallworld/state/memory/elf/rela/__init__.py +2 -0
- smallworld/state/memory/elf/rela/aarch64.py +3 -1
- smallworld/state/memory/elf/rela/amd64.py +4 -2
- smallworld/state/memory/elf/rela/arm.py +4 -2
- smallworld/state/memory/elf/rela/i386.py +4 -2
- smallworld/state/memory/elf/rela/loongarch.py +32 -0
- smallworld/state/memory/elf/rela/mips.py +39 -18
- smallworld/state/memory/elf/rela/ppc.py +31 -14
- smallworld/state/memory/elf/structs.py +3 -0
- smallworld/state/memory/heap.py +2 -2
- smallworld/state/memory/memory.py +18 -0
- smallworld/state/memory/pe/__init__.py +3 -0
- smallworld/state/memory/pe/pe.py +361 -0
- smallworld/state/memory/pe/structs.py +60 -0
- smallworld/state/memory/stack/__init__.py +2 -0
- smallworld/state/memory/stack/loongarch.py +26 -0
- smallworld/state/models/__init__.py +29 -2
- smallworld/state/models/aarch64/__init__.py +1 -0
- smallworld/state/models/aarch64/systemv/__init__.py +6 -0
- smallworld/state/models/aarch64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/aarch64/systemv/c99/signal.py +16 -0
- smallworld/state/models/aarch64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/aarch64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/aarch64/systemv/c99/string.py +139 -0
- smallworld/state/models/aarch64/systemv/c99/time.py +61 -0
- smallworld/state/models/aarch64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/aarch64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/aarch64/systemv/posix/signal.py +157 -0
- smallworld/state/models/aarch64/systemv/systemv.py +80 -0
- smallworld/state/models/amd64/__init__.py +1 -0
- smallworld/state/models/amd64/systemv/__init__.py +6 -0
- smallworld/state/models/amd64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/amd64/systemv/c99/signal.py +16 -0
- smallworld/state/models/amd64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/amd64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/amd64/systemv/c99/string.py +139 -0
- smallworld/state/models/amd64/systemv/c99/time.py +61 -0
- smallworld/state/models/amd64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/amd64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/amd64/systemv/posix/signal.py +157 -0
- smallworld/state/models/amd64/systemv/systemv.py +78 -0
- smallworld/state/models/armel/__init__.py +1 -0
- smallworld/state/models/armel/systemv/__init__.py +6 -0
- smallworld/state/models/armel/systemv/c99/__init__.py +12 -0
- smallworld/state/models/armel/systemv/c99/signal.py +16 -0
- smallworld/state/models/armel/systemv/c99/stdio.py +265 -0
- smallworld/state/models/armel/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/armel/systemv/c99/string.py +139 -0
- smallworld/state/models/armel/systemv/c99/time.py +61 -0
- smallworld/state/models/armel/systemv/posix/__init__.py +6 -0
- smallworld/state/models/armel/systemv/posix/libgen.py +16 -0
- smallworld/state/models/armel/systemv/posix/signal.py +157 -0
- smallworld/state/models/armel/systemv/systemv.py +82 -0
- smallworld/state/models/armhf/__init__.py +1 -0
- smallworld/state/models/armhf/systemv/__init__.py +6 -0
- smallworld/state/models/armhf/systemv/c99/__init__.py +12 -0
- smallworld/state/models/armhf/systemv/c99/signal.py +16 -0
- smallworld/state/models/armhf/systemv/c99/stdio.py +265 -0
- smallworld/state/models/armhf/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/armhf/systemv/c99/string.py +139 -0
- smallworld/state/models/armhf/systemv/c99/time.py +61 -0
- smallworld/state/models/armhf/systemv/posix/__init__.py +6 -0
- smallworld/state/models/armhf/systemv/posix/libgen.py +16 -0
- smallworld/state/models/armhf/systemv/posix/signal.py +157 -0
- smallworld/state/models/armhf/systemv/systemv.py +77 -0
- smallworld/state/models/c99/__init__.py +12 -0
- smallworld/state/models/c99/fmt_print.py +915 -0
- smallworld/state/models/c99/fmt_scan.py +864 -0
- smallworld/state/models/c99/math.py +362 -0
- smallworld/state/models/c99/signal.py +71 -0
- smallworld/state/models/c99/stdio.py +1305 -0
- smallworld/state/models/c99/stdlib.py +595 -0
- smallworld/state/models/c99/string.py +674 -0
- smallworld/state/models/c99/time.py +340 -0
- smallworld/state/models/c99/utils.py +89 -0
- smallworld/state/models/cstd.py +759 -0
- smallworld/state/models/errno.py +581 -0
- smallworld/state/models/filedesc.py +515 -0
- smallworld/state/models/i386/__init__.py +1 -0
- smallworld/state/models/i386/systemv/__init__.py +6 -0
- smallworld/state/models/i386/systemv/c99/__init__.py +12 -0
- smallworld/state/models/i386/systemv/c99/signal.py +16 -0
- smallworld/state/models/i386/systemv/c99/stdio.py +265 -0
- smallworld/state/models/i386/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/i386/systemv/c99/string.py +139 -0
- smallworld/state/models/i386/systemv/c99/time.py +61 -0
- smallworld/state/models/i386/systemv/posix/__init__.py +6 -0
- smallworld/state/models/i386/systemv/posix/libgen.py +16 -0
- smallworld/state/models/i386/systemv/posix/signal.py +157 -0
- smallworld/state/models/i386/systemv/systemv.py +71 -0
- smallworld/state/models/loongarch64/__init__.py +1 -0
- smallworld/state/models/loongarch64/systemv/__init__.py +6 -0
- smallworld/state/models/loongarch64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/loongarch64/systemv/c99/signal.py +16 -0
- smallworld/state/models/loongarch64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/loongarch64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/loongarch64/systemv/c99/string.py +139 -0
- smallworld/state/models/loongarch64/systemv/c99/time.py +61 -0
- smallworld/state/models/loongarch64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/loongarch64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/loongarch64/systemv/posix/signal.py +157 -0
- smallworld/state/models/loongarch64/systemv/systemv.py +83 -0
- smallworld/state/models/mips/__init__.py +1 -0
- smallworld/state/models/mips/systemv/__init__.py +6 -0
- smallworld/state/models/mips/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips/systemv/c99/string.py +139 -0
- smallworld/state/models/mips/systemv/c99/time.py +61 -0
- smallworld/state/models/mips/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips/systemv/systemv.py +78 -0
- smallworld/state/models/mips64/__init__.py +1 -0
- smallworld/state/models/mips64/systemv/__init__.py +6 -0
- smallworld/state/models/mips64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips64/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips64/systemv/c99/string.py +139 -0
- smallworld/state/models/mips64/systemv/c99/time.py +61 -0
- smallworld/state/models/mips64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips64/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips64/systemv/systemv.py +98 -0
- smallworld/state/models/mips64el/__init__.py +1 -0
- smallworld/state/models/mips64el/systemv/__init__.py +6 -0
- smallworld/state/models/mips64el/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mips64el/systemv/c99/signal.py +16 -0
- smallworld/state/models/mips64el/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mips64el/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mips64el/systemv/c99/string.py +139 -0
- smallworld/state/models/mips64el/systemv/c99/time.py +61 -0
- smallworld/state/models/mips64el/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mips64el/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mips64el/systemv/posix/signal.py +157 -0
- smallworld/state/models/mips64el/systemv/systemv.py +96 -0
- smallworld/state/models/mipsel/__init__.py +1 -0
- smallworld/state/models/mipsel/systemv/__init__.py +6 -0
- smallworld/state/models/mipsel/systemv/c99/__init__.py +12 -0
- smallworld/state/models/mipsel/systemv/c99/signal.py +16 -0
- smallworld/state/models/mipsel/systemv/c99/stdio.py +265 -0
- smallworld/state/models/mipsel/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/mipsel/systemv/c99/string.py +139 -0
- smallworld/state/models/mipsel/systemv/c99/time.py +61 -0
- smallworld/state/models/mipsel/systemv/posix/__init__.py +6 -0
- smallworld/state/models/mipsel/systemv/posix/libgen.py +16 -0
- smallworld/state/models/mipsel/systemv/posix/signal.py +157 -0
- smallworld/state/models/mipsel/systemv/systemv.py +78 -0
- smallworld/state/models/model.py +27 -2
- smallworld/state/models/posix/__init__.py +6 -0
- smallworld/state/models/posix/libgen.py +123 -0
- smallworld/state/models/posix/signal.py +690 -0
- smallworld/state/models/powerpc/__init__.py +1 -0
- smallworld/state/models/powerpc/systemv/__init__.py +6 -0
- smallworld/state/models/powerpc/systemv/c99/__init__.py +12 -0
- smallworld/state/models/powerpc/systemv/c99/signal.py +16 -0
- smallworld/state/models/powerpc/systemv/c99/stdio.py +265 -0
- smallworld/state/models/powerpc/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/powerpc/systemv/c99/string.py +139 -0
- smallworld/state/models/powerpc/systemv/c99/time.py +61 -0
- smallworld/state/models/powerpc/systemv/posix/__init__.py +6 -0
- smallworld/state/models/powerpc/systemv/posix/libgen.py +16 -0
- smallworld/state/models/powerpc/systemv/posix/signal.py +157 -0
- smallworld/state/models/powerpc/systemv/systemv.py +93 -0
- smallworld/state/models/riscv64/__init__.py +1 -0
- smallworld/state/models/riscv64/systemv/__init__.py +6 -0
- smallworld/state/models/riscv64/systemv/c99/__init__.py +12 -0
- smallworld/state/models/riscv64/systemv/c99/signal.py +16 -0
- smallworld/state/models/riscv64/systemv/c99/stdio.py +265 -0
- smallworld/state/models/riscv64/systemv/c99/stdlib.py +169 -0
- smallworld/state/models/riscv64/systemv/c99/string.py +139 -0
- smallworld/state/models/riscv64/systemv/c99/time.py +61 -0
- smallworld/state/models/riscv64/systemv/posix/__init__.py +6 -0
- smallworld/state/models/riscv64/systemv/posix/libgen.py +16 -0
- smallworld/state/models/riscv64/systemv/posix/signal.py +157 -0
- smallworld/state/models/riscv64/systemv/systemv.py +85 -0
- smallworld/state/state.py +65 -24
- smallworld/state/unstable/elf.py +16 -31
- smallworld/utils.py +6 -1
- {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/METADATA +76 -43
- smallworld_re-2.0.0.dist-info/RECORD +374 -0
- {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/WHEEL +1 -1
- smallworld/state/models/x86/__init__.py +0 -2
- smallworld/state/models/x86/microsoftcdecl.py +0 -35
- smallworld/state/models/x86/systemv.py +0 -240
- smallworld_re-1.0.2.dist-info/RECORD +0 -166
- /smallworld/state/models/{posix.py → _posix.py} +0 -0
- {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/entry_points.txt +0 -0
- {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
- {smallworld_re-1.0.2.dist-info → smallworld_re-2.0.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,9 @@ from .....exceptions import ConfigurationError
|
|
3
3
|
from ..structs import ElfRela
|
4
4
|
from .rela import ElfRelocator
|
5
5
|
|
6
|
+
R_MIPS_NONE = 0
|
6
7
|
R_MIPS_32 = 2 # 32-bit direct
|
8
|
+
R_MIPS_REL32 = 3
|
7
9
|
R_MIPS_64 = 18 # 64-bit direct
|
8
10
|
|
9
11
|
|
@@ -12,24 +14,43 @@ class MIPSElfRelocator(ElfRelocator):
|
|
12
14
|
byteorder = platforms.Byteorder.BIG
|
13
15
|
|
14
16
|
def _compute_value(self, rela: ElfRela):
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
17
|
+
# Unpack a MIPS64 relocation.
|
18
|
+
#
|
19
|
+
# It's not possible to build a 64-bit address in one instruction in MIPS64.
|
20
|
+
# Rather than tell the linker to live with it,
|
21
|
+
# MIPS64 relocation entries can define up to three nested relocations,
|
22
|
+
# with relocations 2 and 3 acting as if the symbol value were the result
|
23
|
+
# of the previous relocation.
|
24
|
+
#
|
25
|
+
# There's a fourth argument, which is a parameter to relocation 2, I think.
|
26
|
+
# Don't want to waste those bytes...
|
27
|
+
rela_types = []
|
28
|
+
# rela_special = (rela.type >> 24) & 0xFF
|
29
|
+
for i in range(0, 3):
|
30
|
+
rela_types.append((rela.type >> (i * 8)) & 0xFF)
|
31
|
+
|
32
|
+
val = rela.symbol.value + rela.symbol.baseaddr
|
33
|
+
is_64 = False
|
34
|
+
for i in range(0, 3):
|
35
|
+
rela_type = rela_types[i]
|
36
|
+
if rela_type == R_MIPS_NONE:
|
37
|
+
break
|
38
|
+
elif rela_type == R_MIPS_32 or rela_type == R_MIPS_REL32:
|
39
|
+
# 32-bit direct
|
40
|
+
val = val + rela.addend
|
41
|
+
elif rela_type == R_MIPS_64:
|
42
|
+
# 64-bit direct
|
43
|
+
val = val + rela.addend
|
44
|
+
is_64 = True
|
45
|
+
else:
|
46
|
+
raise ConfigurationError(
|
47
|
+
f"Invalid relocation type {i} for {rela.symbol.name}: {rela_type}"
|
48
|
+
)
|
49
|
+
|
50
|
+
return val.to_bytes(
|
51
|
+
8 if is_64 else 4,
|
52
|
+
"big" if self.byteorder == platforms.Byteorder.BIG else "little",
|
53
|
+
)
|
33
54
|
|
34
55
|
|
35
56
|
class MIPSELElfRelocator(MIPSElfRelocator):
|
@@ -3,6 +3,7 @@ from .....exceptions import ConfigurationError
|
|
3
3
|
from ..structs import ElfRela
|
4
4
|
from .rela import ElfRelocator
|
5
5
|
|
6
|
+
R_PPC_ABS32 = 1 # Direct 32-bit
|
6
7
|
R_PPC_GLOB_DAT = 20 # Create GOT entry
|
7
8
|
R_PPC_JUMP_SLOT = 21 # Create PLT entry
|
8
9
|
R_PPC_RELATIVE = 22 # Adjust by program base
|
@@ -14,7 +15,10 @@ class PowerPCElfRelocator(ElfRelocator):
|
|
14
15
|
addrsz = 4
|
15
16
|
|
16
17
|
def _compute_value(self, rela: ElfRela):
|
17
|
-
if
|
18
|
+
if rela.type == R_PPC_ABS32:
|
19
|
+
val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
|
20
|
+
return val.to_bytes(4, "big")
|
21
|
+
elif (
|
18
22
|
rela.type == R_PPC_GLOB_DAT
|
19
23
|
or rela.type == R_PPC_JUMP_SLOT
|
20
24
|
or rela.type == R_PPC_RELATIVE
|
@@ -24,22 +28,35 @@ class PowerPCElfRelocator(ElfRelocator):
|
|
24
28
|
return val.to_bytes(self.addrsz, "big")
|
25
29
|
else:
|
26
30
|
raise ConfigurationError(
|
27
|
-
"Invalid relocation type for {rela.symbol.name}: {rela.type}"
|
31
|
+
f"Invalid relocation type for {rela.symbol.name}: {rela.type}"
|
28
32
|
)
|
29
33
|
|
30
34
|
|
35
|
+
R_PPC64_ADDR64 = 38 # Adjust by program base, I think...
|
36
|
+
|
37
|
+
|
31
38
|
class PowerPC64ElfRelocator(PowerPCElfRelocator):
|
32
39
|
arch = platforms.Architecture.POWERPC64
|
40
|
+
byteorder = platforms.Byteorder.BIG
|
33
41
|
addrsz = 8
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
|
43
|
+
def _compute_value(self, rela: ElfRela):
|
44
|
+
if rela.type == R_PPC64_ADDR64:
|
45
|
+
val = rela.symbol.value + rela.symbol.baseaddr + rela.addend
|
46
|
+
return val.to_bytes(self.addrsz, "big")
|
47
|
+
elif rela.type == R_PPC_JUMP_SLOT:
|
48
|
+
# The PowerPC64 JUMP_SLOT relocation is much more complicated.
|
49
|
+
# It actually fills in three 64-bit values:
|
50
|
+
#
|
51
|
+
# 1. The actual function address
|
52
|
+
# 2. The TOC base address; serves a similar purpose to the Global Pointer in MIPS.
|
53
|
+
# 3. An "environment" pointer, not used by C.
|
54
|
+
#
|
55
|
+
# We're currently correctly filling in 1.
|
56
|
+
# Entry 2. is the address of the GOT section of the containing binary + 0x8000.
|
57
|
+
#
|
58
|
+
# This requires a reference to the containing binary,
|
59
|
+
# which I have no idea how to pass.
|
60
|
+
raise NotImplementedError("R_PPC64_JUMP_SLOT not implemented")
|
61
|
+
else:
|
62
|
+
return super()._compute_value(rela)
|
@@ -24,11 +24,14 @@ class ElfSymbol:
|
|
24
24
|
without a separate dict.
|
25
25
|
"""
|
26
26
|
|
27
|
+
idx: int # Symbol table index
|
28
|
+
dynamic: bool # Is this in the static or dynamic symbol table?
|
27
29
|
name: str # Symbol name
|
28
30
|
type: int # Symbol type
|
29
31
|
bind: int # Symbol binding
|
30
32
|
visibility: int # Symbol visibility
|
31
33
|
shndx: int # Symbol section index, or reserved flags
|
34
|
+
defined: bool # Is this symbol defined?
|
32
35
|
value: int # Symbol value
|
33
36
|
size: int # Symbol size
|
34
37
|
baseaddr: int # Base address for relative symbol values
|
smallworld/state/memory/heap.py
CHANGED
@@ -42,7 +42,7 @@ class Heap(memory.Memory):
|
|
42
42
|
return self.allocate(value)
|
43
43
|
|
44
44
|
def allocate_bytes(
|
45
|
-
self, content: typing.Union[bytes, bytearray], label: str
|
45
|
+
self, content: typing.Union[bytes, bytearray], label: typing.Optional[str]
|
46
46
|
) -> int:
|
47
47
|
"""Allocate space for and write bytes to the heap.
|
48
48
|
|
@@ -79,7 +79,7 @@ class BumpAllocator(Heap):
|
|
79
79
|
return self.address + offset
|
80
80
|
|
81
81
|
def free(self, address: int) -> None:
|
82
|
-
|
82
|
+
pass
|
83
83
|
|
84
84
|
|
85
85
|
__all__ = ["Heap", "BumpAllocator"]
|
@@ -114,6 +114,24 @@ class Memory(state.Stateful, dict):
|
|
114
114
|
self.clear()
|
115
115
|
self[0] = value
|
116
116
|
|
117
|
+
def write_bytes(self, address: int, data: bytes) -> None:
|
118
|
+
"""Overwrite part of this memory region with specific bytes
|
119
|
+
|
120
|
+
This will fail if the data you want to overwrite is in a symbolic sub-region.
|
121
|
+
"""
|
122
|
+
|
123
|
+
for segment_offset, segment in self.items():
|
124
|
+
segment_address = self.address + segment_offset
|
125
|
+
if address >= segment_address and address < segment_address + segment._size:
|
126
|
+
contents = segment.get_content()
|
127
|
+
if not isinstance(contents, bytes):
|
128
|
+
raise exceptions.SymbolicValueError(
|
129
|
+
f"Tried to write {len(data)} bytes at {hex(address)}; data in {segment_address:x} - {segment_address + segment._size:x} is symbolic."
|
130
|
+
)
|
131
|
+
offset = address - segment_address
|
132
|
+
contents = contents[0:offset] + data + contents[offset + len(data) :]
|
133
|
+
segment.set_content(contents)
|
134
|
+
|
117
135
|
def __hash__(self):
|
118
136
|
return super(dict, self).__hash__()
|
119
137
|
|
@@ -0,0 +1,361 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
import lief
|
4
|
+
|
5
|
+
from ....exceptions import ConfigurationError
|
6
|
+
from ....platforms import Architecture, Byteorder, Platform, PlatformDef
|
7
|
+
from ....utils import RangeCollection
|
8
|
+
from ...state import BytesValue
|
9
|
+
from ..code import Executable
|
10
|
+
from .structs import PEExport, PEImport
|
11
|
+
|
12
|
+
# PE32+ machine types
|
13
|
+
# There are a lot more of these, but I can only test on amd64 and i386
|
14
|
+
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
15
|
+
IMAGE_FILE_MACHINE_I386 = 0x14C
|
16
|
+
|
17
|
+
# Section flags
|
18
|
+
# Currently, the only one we care about is "code".
|
19
|
+
# Not sure how the others interact with file loading.
|
20
|
+
IMAGE_SCN_CNT_CODE = 0x20
|
21
|
+
|
22
|
+
# Relocation types
|
23
|
+
# All of these adjust based on the difference between
|
24
|
+
# the requested and actual load addresses
|
25
|
+
IMAGE_REL_BASED_ABSOLUTE = 0x0 # No-op
|
26
|
+
IMAGE_REL_BASED_HIGHLOW = 0x3 # Add 32-bit difference to a 32-bit value
|
27
|
+
IMAGE_REL_BASED_DIR64 = 0xA # Add 64-bit difference to a 64-bit value
|
28
|
+
|
29
|
+
|
30
|
+
class PEExecutable(Executable):
|
31
|
+
"""Executable loaded from a PE32+
|
32
|
+
|
33
|
+
This loads a single PE32+ file into a SmallWorld memory object.
|
34
|
+
It performs no relocation or initialization,
|
35
|
+
just maps the file into memory as the kernel intended.
|
36
|
+
|
37
|
+
Arguments:
|
38
|
+
file: File-like object containing the image
|
39
|
+
platform: Optional platform; used for header verification
|
40
|
+
ignore_platform: Do not try to ID or verify platform from headers
|
41
|
+
user_base: Optional user-specified base address
|
42
|
+
page_size: System page size
|
43
|
+
"""
|
44
|
+
|
45
|
+
def __init__(
|
46
|
+
self,
|
47
|
+
file: typing.BinaryIO,
|
48
|
+
platform: typing.Optional[Platform] = None,
|
49
|
+
ignore_platform: bool = False,
|
50
|
+
user_base: typing.Optional[int] = None,
|
51
|
+
page_size: int = 0x1000,
|
52
|
+
):
|
53
|
+
# Initialize with null address and size;
|
54
|
+
# we will update these later
|
55
|
+
super().__init__(0, 0)
|
56
|
+
|
57
|
+
self.platform = platform
|
58
|
+
self.platdef: typing.Optional[PlatformDef] = None
|
59
|
+
self.bounds: RangeCollection = RangeCollection()
|
60
|
+
|
61
|
+
self._page_size = page_size
|
62
|
+
self._user_base = user_base
|
63
|
+
self._file_base = 0
|
64
|
+
|
65
|
+
self._exports: typing.List[PEExport] = list()
|
66
|
+
self._exports_by_name: typing.Dict[typing.Tuple[str, str], PEExport] = dict()
|
67
|
+
self._exports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEExport] = dict()
|
68
|
+
|
69
|
+
self._imports: typing.List[PEImport] = list()
|
70
|
+
self._imports_by_name: typing.Dict[typing.Tuple[str, str], PEImport] = dict()
|
71
|
+
self._imports_by_ordinal: typing.Dict[typing.Tuple[str, int], PEImport] = dict()
|
72
|
+
|
73
|
+
# Read the entire image out of the file
|
74
|
+
image = file.read()
|
75
|
+
|
76
|
+
# Use lief to check if this is a PE
|
77
|
+
# NOTE: For some reason, this takes list(int), not bytes
|
78
|
+
if not lief.is_pe(list(image)):
|
79
|
+
raise ConfigurationError("Image is not a PE")
|
80
|
+
|
81
|
+
# Use lief to parse the PE
|
82
|
+
# NOTE: For some reason, this takes list(int), not bytes
|
83
|
+
# NOTE: lief objects aren't deep-copyable.
|
84
|
+
# I'd love to keep `pe` around for later use, but I can't.
|
85
|
+
pe = lief.PE.parse(list(image))
|
86
|
+
if pe is None:
|
87
|
+
raise ConfigurationError("Failed parsing PE image")
|
88
|
+
|
89
|
+
# Check machine compatibility
|
90
|
+
if not ignore_platform:
|
91
|
+
hdr_platform = self._platform_for_chdr(pe)
|
92
|
+
if self.platform is not None:
|
93
|
+
if self.platform != hdr_platform:
|
94
|
+
raise ConfigurationError(
|
95
|
+
"Platform mismatch: "
|
96
|
+
f"specified {self.platform}, but got {hdr_platform} from header"
|
97
|
+
)
|
98
|
+
else:
|
99
|
+
self.platform = hdr_platform
|
100
|
+
self.platdef = PlatformDef.for_platform(hdr_platform)
|
101
|
+
|
102
|
+
# Determine the file base address
|
103
|
+
self._file_base = pe.imagebase
|
104
|
+
self._determine_base()
|
105
|
+
|
106
|
+
for section in pe.sections:
|
107
|
+
# TODO: How do PE32+ files distinguish loadable segments?
|
108
|
+
# mingw objdump has some notion of allocated segments,
|
109
|
+
# but it doesn't map to anything in any of the flags.
|
110
|
+
self._map_section(section, image)
|
111
|
+
|
112
|
+
# Fix up the memory image to account for changes in the base address
|
113
|
+
self._apply_base_relocations(pe)
|
114
|
+
|
115
|
+
# Compute the final total capacity
|
116
|
+
for offset, value in self.items():
|
117
|
+
self.size = max(self.size, offset + value.get_size())
|
118
|
+
|
119
|
+
# Extract exports
|
120
|
+
self._extract_exports(pe)
|
121
|
+
|
122
|
+
# Extract imports
|
123
|
+
self._extract_imports(pe)
|
124
|
+
|
125
|
+
def _platform_for_chdr(self, pe):
|
126
|
+
if pe.header.machine.value == IMAGE_FILE_MACHINE_AMD64:
|
127
|
+
return Platform(Architecture.X86_64, Byteorder.LITTLE)
|
128
|
+
elif pe.header.machine.value == IMAGE_FILE_MACHINE_I386:
|
129
|
+
return Platform(Architecture.X86_32, Byteorder.LITTLE)
|
130
|
+
else:
|
131
|
+
raise ConfigurationError(f"Unsupported machine type {pe.header.machine}")
|
132
|
+
|
133
|
+
def _determine_base(self):
|
134
|
+
if self._user_base is None:
|
135
|
+
# No user base requested
|
136
|
+
if self._file_base == 0:
|
137
|
+
# No file base defined (unusal for PE32+)
|
138
|
+
# Need the user to provide one
|
139
|
+
raise ConfigurationError(
|
140
|
+
"No base address provided, and none defined in PE file"
|
141
|
+
)
|
142
|
+
else:
|
143
|
+
self.address = self._file_base
|
144
|
+
else:
|
145
|
+
# PE files are always position-independent;
|
146
|
+
# we'll just have to fix things up later.
|
147
|
+
self.address = self._user_base
|
148
|
+
|
149
|
+
def _rebase_file(self, val: int):
|
150
|
+
# Rebase an offset from file-relative to image-relative
|
151
|
+
res = val + self.address
|
152
|
+
return res
|
153
|
+
|
154
|
+
def _page_align(self, val: int, up: bool = True):
|
155
|
+
if up:
|
156
|
+
val += self._page_size - 1
|
157
|
+
return (val // self._page_size) * self._page_size
|
158
|
+
|
159
|
+
def _map_section(self, sect, image):
|
160
|
+
# NOTE: Unlike ELFs, The physical address of PE sections is not page-aligned.
|
161
|
+
sect_start = sect.offset
|
162
|
+
sect_end = sect.offset + sect.size
|
163
|
+
sect_addr = self._page_align(self._rebase_file(sect.virtual_address), up=False)
|
164
|
+
sect_size = self._page_align(sect.virtual_size)
|
165
|
+
|
166
|
+
sect_data = image[sect_start:sect_end]
|
167
|
+
if len(sect_data) < sect_size:
|
168
|
+
# Section is shorter than what's available in the file;
|
169
|
+
# THis will get zero-padded.
|
170
|
+
pad_size = sect_size - len(sect_data)
|
171
|
+
sect_data += b"\0" * pad_size
|
172
|
+
if len(sect_data) != sect_size:
|
173
|
+
raise ConfigurationError(
|
174
|
+
f"Expected segment of size {sect_size}, but got {len(sect_data)}"
|
175
|
+
)
|
176
|
+
|
177
|
+
if 0 != (sect.characteristics & IMAGE_SCN_CNT_CODE):
|
178
|
+
# This is a code segment; add it to program bounds
|
179
|
+
self.bounds.add_range((sect_addr, sect_addr + sect_size))
|
180
|
+
|
181
|
+
sect_value = BytesValue(sect_data, None)
|
182
|
+
self[sect_addr - self.address] = sect_value
|
183
|
+
|
184
|
+
def _apply_base_relocations(self, pe):
|
185
|
+
# PE32+ files always allow the loader to override
|
186
|
+
# the program's base address.
|
187
|
+
#
|
188
|
+
# The relocation section marks places where
|
189
|
+
# an absolute offset needs fixing
|
190
|
+
# if the loader decides to override
|
191
|
+
if self.address == self._file_base:
|
192
|
+
# This file was not relocated. Nothing to do.
|
193
|
+
return
|
194
|
+
|
195
|
+
if self.platform.byteorder == Byteorder.LITTLE:
|
196
|
+
byteorder = "little"
|
197
|
+
elif self.platform.byteorder == Byteorder.BIG:
|
198
|
+
byteorder = "big"
|
199
|
+
else:
|
200
|
+
raise ConfigurationError(
|
201
|
+
f"Can't encode byteorder {self.platform.byteorder}"
|
202
|
+
)
|
203
|
+
|
204
|
+
for base_reloc in pe.relocations:
|
205
|
+
for entry in base_reloc.entries:
|
206
|
+
if entry.type.value == IMAGE_REL_BASED_ABSOLUTE:
|
207
|
+
# Entry is a no-op; continue
|
208
|
+
continue
|
209
|
+
for off, val in self.items():
|
210
|
+
if entry.address >= off and entry.address <= val.get_size():
|
211
|
+
# Find the section containing this address
|
212
|
+
contents = bytearray(val.get_content())
|
213
|
+
fix_off = entry.address - off
|
214
|
+
|
215
|
+
if entry.type.value == IMAGE_REL_BASED_HIGHLOW:
|
216
|
+
# 4-byte repair
|
217
|
+
tofix = int.from_bytes(
|
218
|
+
contents[fix_off : fix_off + 4], byteorder
|
219
|
+
)
|
220
|
+
tofix += self.address - self._file_base
|
221
|
+
contents[fix_off : fix_off + 4] = tofix.to_bytes(
|
222
|
+
4, byteorder
|
223
|
+
)
|
224
|
+
|
225
|
+
elif entry.type.value == IMAGE_REL_BASED_DIR64:
|
226
|
+
# 8-byte repair
|
227
|
+
tofix = int.from_bytes(
|
228
|
+
contents[fix_off : fix_off + 8], byteorder
|
229
|
+
)
|
230
|
+
tofix += self.address - self._file_base
|
231
|
+
contents[fix_off : fix_off + 8] = tofix.to_bytes(
|
232
|
+
8, byteorder
|
233
|
+
)
|
234
|
+
|
235
|
+
else:
|
236
|
+
raise ConfigurationError(
|
237
|
+
"Unhandled relocation type {entry.type}"
|
238
|
+
)
|
239
|
+
# Reset the data
|
240
|
+
val.set_content(bytes(contents))
|
241
|
+
break
|
242
|
+
|
243
|
+
def _extract_exports(self, pe) -> None:
|
244
|
+
if not pe.has_exports:
|
245
|
+
return
|
246
|
+
|
247
|
+
d = pe.get_export()
|
248
|
+
for e in d.entries:
|
249
|
+
if e.is_forwarded:
|
250
|
+
raise NotImplementedError(
|
251
|
+
"{d.name}.{e.name} is forwarded to {e.forward_information}"
|
252
|
+
)
|
253
|
+
else:
|
254
|
+
exp = PEExport(
|
255
|
+
dll=d.name,
|
256
|
+
name=e.name,
|
257
|
+
ordinal=e.ordinal,
|
258
|
+
forwarder=None,
|
259
|
+
value=e.value + self.address,
|
260
|
+
)
|
261
|
+
self._exports.append(exp)
|
262
|
+
self._exports_by_name[(d.name, e.name)] = exp
|
263
|
+
self._exports_by_ordinal[(d.name, e.ordinal)] = exp
|
264
|
+
|
265
|
+
def _extract_imports(self, pe) -> None:
|
266
|
+
if not pe.has_imports:
|
267
|
+
return
|
268
|
+
|
269
|
+
# Iterate over the import directories
|
270
|
+
# These group imports by the DLL that provides them
|
271
|
+
for d in pe.imports:
|
272
|
+
for e in d.entries:
|
273
|
+
imp = PEImport(
|
274
|
+
dll=d.name,
|
275
|
+
name=e.name if not e.is_ordinal else None,
|
276
|
+
ordinal=e.ordinal if e.is_ordinal else None,
|
277
|
+
iat_address=e.iat_address + self.address,
|
278
|
+
forwarder=None,
|
279
|
+
value=None,
|
280
|
+
)
|
281
|
+
if e.name == "puts":
|
282
|
+
print(f"puts IAT at {e.iat_address:x} or {e.iat_value:x}")
|
283
|
+
self._imports.append(imp)
|
284
|
+
if e.is_ordinal:
|
285
|
+
self._imports_by_ordinal[(d.name, e.ordinal)] = imp
|
286
|
+
else:
|
287
|
+
self._imports_by_name[(d.name, e.name)] = imp
|
288
|
+
|
289
|
+
def update_import(
|
290
|
+
self, dll: str, hint: typing.Union[str, int, PEImport], value: int
|
291
|
+
) -> None:
|
292
|
+
"""Update an imported symbol in this PE file
|
293
|
+
|
294
|
+
Arguments:
|
295
|
+
dll: Name of the DLL where the import is defined
|
296
|
+
hint: Symbol name or ordinal
|
297
|
+
value: New value of the symbol
|
298
|
+
"""
|
299
|
+
# No platform specified
|
300
|
+
if self.platform is None or self.platdef is None:
|
301
|
+
raise ConfigurationError("No platform specified; can't update imports")
|
302
|
+
|
303
|
+
if isinstance(hint, str):
|
304
|
+
# Look up by name
|
305
|
+
if (dll, hint) not in self._imports_by_name:
|
306
|
+
raise ConfigurationError(
|
307
|
+
f"No import for {dll}.{hint}. Try by ordinal?"
|
308
|
+
)
|
309
|
+
imp = self._imports_by_name[(dll, hint)]
|
310
|
+
elif isinstance(hint, int):
|
311
|
+
# Look up by ordinal
|
312
|
+
if (dll, hint) not in self._imports_by_ordinal:
|
313
|
+
raise ConfigurationError(f"No import for {dll}.#{hint}. Try by name?")
|
314
|
+
imp = self._imports_by_ordinal[(dll, hint)]
|
315
|
+
elif isinstance(hint, PEImport):
|
316
|
+
imp = hint
|
317
|
+
else:
|
318
|
+
raise TypeError(f"Unexpected hint {hint} of type {type(hint)}")
|
319
|
+
|
320
|
+
# Save the new value to the import
|
321
|
+
# This marks it as initialized
|
322
|
+
imp.value = value
|
323
|
+
|
324
|
+
# Convert value to bytes
|
325
|
+
if self.platform.byteorder == Byteorder.LITTLE:
|
326
|
+
value_bytes = value.to_bytes(self.platdef.address_size, "little")
|
327
|
+
elif self.platform.byteorder == Byteorder.BIG:
|
328
|
+
value_bytes = value.to_bytes(self.platdef.address_size, "big")
|
329
|
+
else:
|
330
|
+
raise ConfigurationError(
|
331
|
+
f"Can't encode int for byteorder {self.platform.byteorder}"
|
332
|
+
)
|
333
|
+
|
334
|
+
# Rewrite IAT slot
|
335
|
+
# NOTE: PE files can have overlapping segments; check all of them.
|
336
|
+
for off, seg in self.items():
|
337
|
+
start = off + self.address
|
338
|
+
stop = start + seg.get_size()
|
339
|
+
if imp.iat_address >= start and imp.iat_address < stop:
|
340
|
+
start = imp.iat_address - start
|
341
|
+
end = start + len(value_bytes)
|
342
|
+
contents = seg.get_content()
|
343
|
+
contents = contents[0:start] + value_bytes + contents[end:]
|
344
|
+
seg.set_content(contents)
|
345
|
+
|
346
|
+
def link_pe(self, dll: "PEExecutable"):
|
347
|
+
for imp in self._imports:
|
348
|
+
if imp.value is not None:
|
349
|
+
continue
|
350
|
+
|
351
|
+
if imp.name is not None and (imp.dll, imp.name) in dll._exports_by_name:
|
352
|
+
exp = dll._exports_by_name[(imp.dll, imp.name)]
|
353
|
+
elif (
|
354
|
+
imp.ordinal is not None
|
355
|
+
and (imp.dll, imp.ordinal) in dll._exports_by_ordinal
|
356
|
+
):
|
357
|
+
exp = dll._exports_by_ordinal[(imp.dll, imp.ordinal)]
|
358
|
+
else:
|
359
|
+
continue
|
360
|
+
|
361
|
+
self.update_import(imp.dll, imp, exp.value)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import typing
|
2
|
+
from dataclasses import dataclass
|
3
|
+
|
4
|
+
|
5
|
+
@dataclass(frozen=False)
|
6
|
+
class PEExport:
|
7
|
+
"""PE export struct
|
8
|
+
|
9
|
+
Lief parses this data, but I can't keep the objects around.
|
10
|
+
|
11
|
+
An export defines a symbol that can be imported by other images.
|
12
|
+
See 'PEImport' for more on that process.
|
13
|
+
|
14
|
+
This is a mashup of a number of PE32+ structs
|
15
|
+
(export definitions are actually somewhat complicated
|
16
|
+
compared to import definitions).
|
17
|
+
|
18
|
+
Exports can be referenced by name or by ordinal - a numeric key
|
19
|
+
specific to the DLL.
|
20
|
+
|
21
|
+
Exports can provide an actual address, or a "forwarder".
|
22
|
+
This is the name of another export in another DLL that
|
23
|
+
will provide the actual value of the symbol... or possibly forward again.
|
24
|
+
"""
|
25
|
+
|
26
|
+
dll: str
|
27
|
+
ordinal: int
|
28
|
+
name: str
|
29
|
+
forwarder: typing.Optional[str]
|
30
|
+
value: int
|
31
|
+
|
32
|
+
|
33
|
+
@dataclass(frozen=False)
|
34
|
+
class PEImport:
|
35
|
+
"""PE import struct
|
36
|
+
|
37
|
+
Lief parses this data, but I can't keep the objects around.
|
38
|
+
|
39
|
+
An import defines that a specific exported symbol
|
40
|
+
is required from a specific DLL file.
|
41
|
+
|
42
|
+
They are closer to a relocation entry than a symbol;
|
43
|
+
each import defines the export required, and where
|
44
|
+
to write the exported value. There is exactly one
|
45
|
+
relocation mechanism, making this a lot easier to parse than ELF.
|
46
|
+
|
47
|
+
This class actually mashes up two PE32+ structures:
|
48
|
+
an Import Directory Entry, which defines a DLL that the file needs,
|
49
|
+
and an Import Lookup Entry, which defines a specific export it needs.
|
50
|
+
|
51
|
+
Lookup requires two keys, either the DLL name and export name,
|
52
|
+
or the DLL and export ordinal - a numeric key specified wihtin the DLL.
|
53
|
+
"""
|
54
|
+
|
55
|
+
dll: str # Name of the DLL
|
56
|
+
name: typing.Optional[str] # String name of the export
|
57
|
+
ordinal: typing.Optional[int] # Ordinal of the export
|
58
|
+
iat_address: int # Address of the IAT slot for this import
|
59
|
+
forwarder: typing.Optional[str] # Forwarder export, if provided
|
60
|
+
value: typing.Optional[int] # Value imported
|
@@ -2,6 +2,7 @@ from .aarch64 import AArch64Stack
|
|
2
2
|
from .amd64 import AMD64Stack
|
3
3
|
from .arm import ARMv5tStack, ARMv6mStack, ARMv7aStack, ARMv7mStack, ARMv7rStack
|
4
4
|
from .i386 import X86Stack
|
5
|
+
from .loongarch import LoongArch64Stack
|
5
6
|
from .mips import MIPSBEStack, MIPSELStack
|
6
7
|
from .mips64 import MIPS64BEStack, MIPS64ELStack
|
7
8
|
from .ppc import PowerPC32Stack, PowerPC64Stack
|
@@ -19,6 +20,7 @@ __all__ = __stack__ + [
|
|
19
20
|
"ARMv7rStack",
|
20
21
|
"ARMv7aStack",
|
21
22
|
"X86Stack",
|
23
|
+
"LoongArch64Stack",
|
22
24
|
"MIPSBEStack",
|
23
25
|
"MIPSELStack",
|
24
26
|
"MIPS64BEStack",
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class LoongArchStack(stack.DescendingStack):
|
8
|
+
"""A stack for a LoongArch CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 4
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for MIPS64")
|
19
|
+
|
20
|
+
|
21
|
+
class LoongArch64Stack(LoongArchStack):
|
22
|
+
"""A stack for a LoongArch 64-bit CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.LOONGARCH64, platforms.Byteorder.LITTLE
|
26
|
+
)
|