smallworld-re 1.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/__init__.py +35 -0
- smallworld/analyses/__init__.py +14 -0
- smallworld/analyses/analysis.py +88 -0
- smallworld/analyses/code_coverage.py +31 -0
- smallworld/analyses/colorizer.py +682 -0
- smallworld/analyses/colorizer_summary.py +100 -0
- smallworld/analyses/field_detection/__init__.py +14 -0
- smallworld/analyses/field_detection/field_analysis.py +536 -0
- smallworld/analyses/field_detection/guards.py +26 -0
- smallworld/analyses/field_detection/hints.py +133 -0
- smallworld/analyses/field_detection/malloc.py +211 -0
- smallworld/analyses/forced_exec/__init__.py +3 -0
- smallworld/analyses/forced_exec/forced_exec.py +87 -0
- smallworld/analyses/underlays/__init__.py +4 -0
- smallworld/analyses/underlays/basic.py +13 -0
- smallworld/analyses/underlays/underlay.py +31 -0
- smallworld/analyses/unstable/__init__.py +4 -0
- smallworld/analyses/unstable/angr/__init__.py +0 -0
- smallworld/analyses/unstable/angr/base.py +12 -0
- smallworld/analyses/unstable/angr/divergence.py +274 -0
- smallworld/analyses/unstable/angr/model.py +383 -0
- smallworld/analyses/unstable/angr/nwbt.py +63 -0
- smallworld/analyses/unstable/angr/typedefs.py +170 -0
- smallworld/analyses/unstable/angr/utils.py +25 -0
- smallworld/analyses/unstable/angr/visitor.py +315 -0
- smallworld/analyses/unstable/angr_nwbt.py +106 -0
- smallworld/analyses/unstable/code_coverage.py +54 -0
- smallworld/analyses/unstable/code_reachable.py +44 -0
- smallworld/analyses/unstable/control_flow_tracer.py +71 -0
- smallworld/analyses/unstable/pointer_finder.py +90 -0
- smallworld/arch/__init__.py +0 -0
- smallworld/arch/aarch64_arch.py +286 -0
- smallworld/arch/amd64_arch.py +86 -0
- smallworld/arch/i386_arch.py +44 -0
- smallworld/emulators/__init__.py +14 -0
- smallworld/emulators/angr/__init__.py +7 -0
- smallworld/emulators/angr/angr.py +1652 -0
- smallworld/emulators/angr/default.py +15 -0
- smallworld/emulators/angr/exceptions.py +7 -0
- smallworld/emulators/angr/exploration/__init__.py +9 -0
- smallworld/emulators/angr/exploration/bounds.py +27 -0
- smallworld/emulators/angr/exploration/default.py +17 -0
- smallworld/emulators/angr/exploration/terminate.py +22 -0
- smallworld/emulators/angr/factory.py +55 -0
- smallworld/emulators/angr/machdefs/__init__.py +35 -0
- smallworld/emulators/angr/machdefs/aarch64.py +292 -0
- smallworld/emulators/angr/machdefs/amd64.py +192 -0
- smallworld/emulators/angr/machdefs/arm.py +387 -0
- smallworld/emulators/angr/machdefs/i386.py +221 -0
- smallworld/emulators/angr/machdefs/machdef.py +138 -0
- smallworld/emulators/angr/machdefs/mips.py +184 -0
- smallworld/emulators/angr/machdefs/mips64.py +189 -0
- smallworld/emulators/angr/machdefs/ppc.py +101 -0
- smallworld/emulators/angr/machdefs/riscv.py +261 -0
- smallworld/emulators/angr/machdefs/xtensa.py +255 -0
- smallworld/emulators/angr/memory/__init__.py +7 -0
- smallworld/emulators/angr/memory/default.py +10 -0
- smallworld/emulators/angr/memory/fixups.py +43 -0
- smallworld/emulators/angr/memory/memtrack.py +105 -0
- smallworld/emulators/angr/scratch.py +43 -0
- smallworld/emulators/angr/simos.py +53 -0
- smallworld/emulators/angr/utils.py +70 -0
- smallworld/emulators/emulator.py +1013 -0
- smallworld/emulators/hookable.py +252 -0
- smallworld/emulators/panda/__init__.py +5 -0
- smallworld/emulators/panda/machdefs/__init__.py +28 -0
- smallworld/emulators/panda/machdefs/aarch64.py +93 -0
- smallworld/emulators/panda/machdefs/amd64.py +71 -0
- smallworld/emulators/panda/machdefs/arm.py +89 -0
- smallworld/emulators/panda/machdefs/i386.py +36 -0
- smallworld/emulators/panda/machdefs/machdef.py +86 -0
- smallworld/emulators/panda/machdefs/mips.py +94 -0
- smallworld/emulators/panda/machdefs/mips64.py +91 -0
- smallworld/emulators/panda/machdefs/ppc.py +79 -0
- smallworld/emulators/panda/panda.py +575 -0
- smallworld/emulators/unicorn/__init__.py +13 -0
- smallworld/emulators/unicorn/machdefs/__init__.py +28 -0
- smallworld/emulators/unicorn/machdefs/aarch64.py +310 -0
- smallworld/emulators/unicorn/machdefs/amd64.py +326 -0
- smallworld/emulators/unicorn/machdefs/arm.py +321 -0
- smallworld/emulators/unicorn/machdefs/i386.py +137 -0
- smallworld/emulators/unicorn/machdefs/machdef.py +117 -0
- smallworld/emulators/unicorn/machdefs/mips.py +202 -0
- smallworld/emulators/unicorn/unicorn.py +684 -0
- smallworld/exceptions/__init__.py +5 -0
- smallworld/exceptions/exceptions.py +85 -0
- smallworld/exceptions/unstable/__init__.py +1 -0
- smallworld/exceptions/unstable/exceptions.py +25 -0
- smallworld/extern/__init__.py +4 -0
- smallworld/extern/ctypes.py +94 -0
- smallworld/extern/unstable/__init__.py +1 -0
- smallworld/extern/unstable/ghidra.py +129 -0
- smallworld/helpers.py +107 -0
- smallworld/hinting/__init__.py +8 -0
- smallworld/hinting/hinting.py +214 -0
- smallworld/hinting/hints.py +427 -0
- smallworld/hinting/unstable/__init__.py +2 -0
- smallworld/hinting/utils.py +19 -0
- smallworld/instructions/__init__.py +18 -0
- smallworld/instructions/aarch64.py +20 -0
- smallworld/instructions/arm.py +18 -0
- smallworld/instructions/bsid.py +67 -0
- smallworld/instructions/instructions.py +258 -0
- smallworld/instructions/mips.py +21 -0
- smallworld/instructions/x86.py +100 -0
- smallworld/logging.py +90 -0
- smallworld/platforms.py +95 -0
- smallworld/py.typed +0 -0
- smallworld/state/__init__.py +6 -0
- smallworld/state/cpus/__init__.py +32 -0
- smallworld/state/cpus/aarch64.py +563 -0
- smallworld/state/cpus/amd64.py +676 -0
- smallworld/state/cpus/arm.py +630 -0
- smallworld/state/cpus/cpu.py +71 -0
- smallworld/state/cpus/i386.py +239 -0
- smallworld/state/cpus/mips.py +374 -0
- smallworld/state/cpus/mips64.py +372 -0
- smallworld/state/cpus/powerpc.py +229 -0
- smallworld/state/cpus/riscv.py +357 -0
- smallworld/state/cpus/xtensa.py +80 -0
- smallworld/state/memory/__init__.py +7 -0
- smallworld/state/memory/code.py +70 -0
- smallworld/state/memory/elf/__init__.py +3 -0
- smallworld/state/memory/elf/elf.py +564 -0
- smallworld/state/memory/elf/rela/__init__.py +32 -0
- smallworld/state/memory/elf/rela/aarch64.py +27 -0
- smallworld/state/memory/elf/rela/amd64.py +32 -0
- smallworld/state/memory/elf/rela/arm.py +51 -0
- smallworld/state/memory/elf/rela/i386.py +32 -0
- smallworld/state/memory/elf/rela/mips.py +45 -0
- smallworld/state/memory/elf/rela/ppc.py +45 -0
- smallworld/state/memory/elf/rela/rela.py +63 -0
- smallworld/state/memory/elf/rela/riscv64.py +27 -0
- smallworld/state/memory/elf/rela/xtensa.py +15 -0
- smallworld/state/memory/elf/structs.py +55 -0
- smallworld/state/memory/heap.py +85 -0
- smallworld/state/memory/memory.py +181 -0
- smallworld/state/memory/stack/__init__.py +31 -0
- smallworld/state/memory/stack/aarch64.py +22 -0
- smallworld/state/memory/stack/amd64.py +42 -0
- smallworld/state/memory/stack/arm.py +66 -0
- smallworld/state/memory/stack/i386.py +22 -0
- smallworld/state/memory/stack/mips.py +34 -0
- smallworld/state/memory/stack/mips64.py +34 -0
- smallworld/state/memory/stack/ppc.py +34 -0
- smallworld/state/memory/stack/riscv.py +22 -0
- smallworld/state/memory/stack/stack.py +127 -0
- smallworld/state/memory/stack/xtensa.py +34 -0
- smallworld/state/models/__init__.py +6 -0
- smallworld/state/models/mmio.py +186 -0
- smallworld/state/models/model.py +163 -0
- smallworld/state/models/posix.py +455 -0
- smallworld/state/models/x86/__init__.py +2 -0
- smallworld/state/models/x86/microsoftcdecl.py +35 -0
- smallworld/state/models/x86/systemv.py +240 -0
- smallworld/state/state.py +962 -0
- smallworld/state/unstable/__init__.py +0 -0
- smallworld/state/unstable/elf.py +393 -0
- smallworld/state/x86_registers.py +30 -0
- smallworld/utils.py +935 -0
- smallworld_re-1.0.0.dist-info/LICENSE.txt +21 -0
- smallworld_re-1.0.0.dist-info/METADATA +189 -0
- smallworld_re-1.0.0.dist-info/RECORD +166 -0
- smallworld_re-1.0.0.dist-info/WHEEL +5 -0
- smallworld_re-1.0.0.dist-info/entry_points.txt +2 -0
- smallworld_re-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
import abc
|
2
|
+
import code
|
3
|
+
import logging
|
4
|
+
import pdb
|
5
|
+
import typing
|
6
|
+
|
7
|
+
from ... import emulators, exceptions, platforms, utils
|
8
|
+
from .. import state
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class Hook(state.Stateful):
|
14
|
+
"""Hook a particular instruction with a function.
|
15
|
+
|
16
|
+
Runs the function provided when the emulator reaches (but has not
|
17
|
+
yet executed) the instruction at a particular address.
|
18
|
+
|
19
|
+
Arguments:
|
20
|
+
address: The address of the instruction.
|
21
|
+
function: The function to run.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(
|
25
|
+
self, address: int, function: typing.Callable[[emulators.Emulator], None]
|
26
|
+
):
|
27
|
+
self._address = address
|
28
|
+
self._function = function
|
29
|
+
|
30
|
+
def extract(self, emulator: emulators.Emulator) -> None:
|
31
|
+
# Hooks have no state to extract;
|
32
|
+
# Just as we assume the memory layout is the same,
|
33
|
+
# we have to assume the hook layout is the same.
|
34
|
+
pass
|
35
|
+
|
36
|
+
def apply(self, emulator: emulators.Emulator) -> None:
|
37
|
+
if not isinstance(emulator, emulators.InstructionHookable):
|
38
|
+
raise exceptions.ConfigurationError("Emulator cannot hook instructions")
|
39
|
+
emulator.hook_instruction(self._address, self._function)
|
40
|
+
|
41
|
+
|
42
|
+
class Breakpoint(Hook):
|
43
|
+
|
44
|
+
"""An interactive breakpoint.
|
45
|
+
|
46
|
+
Stops execution at the specified address and opens an interactive
|
47
|
+
shell, as specified in the self.interact method.
|
48
|
+
|
49
|
+
Arguments:
|
50
|
+
address: The address of the breakpoint.
|
51
|
+
|
52
|
+
"""
|
53
|
+
|
54
|
+
def __init__(self, address: int):
|
55
|
+
super().__init__(address=address, function=self.interact)
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
@abc.abstractmethod
|
59
|
+
def interact(emulator: emulators.Emulator) -> None:
|
60
|
+
pass
|
61
|
+
|
62
|
+
|
63
|
+
class PDBBreakpoint(Breakpoint):
|
64
|
+
"""A PDB interactive breakpoint."""
|
65
|
+
|
66
|
+
@staticmethod
|
67
|
+
def interact(emulator: emulators.Emulator) -> None:
|
68
|
+
pdb.set_trace()
|
69
|
+
|
70
|
+
|
71
|
+
class PythonShellBreakpoint(Breakpoint):
|
72
|
+
"""A Python shell interactive breakpoint."""
|
73
|
+
|
74
|
+
@staticmethod
|
75
|
+
def interact(emulator: emulators.Emulator) -> None:
|
76
|
+
code.interact(local={"emulator": emulator})
|
77
|
+
|
78
|
+
|
79
|
+
class Model(Hook):
|
80
|
+
"""A runtime function model implemented in Python.
|
81
|
+
|
82
|
+
If execution reaches the given address, call the function assigned
|
83
|
+
to self.model, instead of any code at that address in the
|
84
|
+
emulator, and return. This is most often used to model an external
|
85
|
+
function, e.g., libc `fread`. It is the responsibility of the
|
86
|
+
model to read arguments and generate reasonable return values.
|
87
|
+
|
88
|
+
Arguments:
|
89
|
+
address: The address to model.
|
90
|
+
|
91
|
+
"""
|
92
|
+
|
93
|
+
def __init__(self, address: int):
|
94
|
+
super().__init__(address=address, function=self.model)
|
95
|
+
|
96
|
+
@property
|
97
|
+
@abc.abstractmethod
|
98
|
+
def name(self) -> str:
|
99
|
+
"""A name for this model, e.g., fread or ioctl."""
|
100
|
+
return ""
|
101
|
+
|
102
|
+
@property
|
103
|
+
@abc.abstractmethod
|
104
|
+
def platform(self) -> platforms.Platform:
|
105
|
+
"""The platform for which this model is defined."""
|
106
|
+
pass
|
107
|
+
|
108
|
+
@property
|
109
|
+
@abc.abstractmethod
|
110
|
+
def abi(self) -> platforms.ABI:
|
111
|
+
"""The ABI according to which this model works."""
|
112
|
+
pass
|
113
|
+
|
114
|
+
@classmethod
|
115
|
+
def lookup(
|
116
|
+
cls, name: str, platform: platforms.Platform, abi: platforms.ABI, address: int
|
117
|
+
):
|
118
|
+
"""Instantiate a model by name, platform, and ABI.
|
119
|
+
|
120
|
+
Arguments:
|
121
|
+
name: The name of the model.
|
122
|
+
platform: The platform for which this model is defined.
|
123
|
+
abi: The ABI according to which this model works.
|
124
|
+
address: The instruction address which the model will hook.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
The fully instantiated model.
|
128
|
+
"""
|
129
|
+
try:
|
130
|
+
return utils.find_subclass(
|
131
|
+
cls,
|
132
|
+
lambda x: x.name == name and x.platform == platform and x.abi == abi,
|
133
|
+
address,
|
134
|
+
)
|
135
|
+
except ValueError:
|
136
|
+
raise ValueError(f"no model for '{name}' on {platform} with ABI '{abi}'")
|
137
|
+
|
138
|
+
def apply(self, emulator: emulators.Emulator) -> None:
|
139
|
+
logger.debug(f"Hooking Model {self} {self._address:x}")
|
140
|
+
emulator.map_memory(self._address, 16)
|
141
|
+
if not isinstance(emulator, emulators.FunctionHookable):
|
142
|
+
raise exceptions.ConfigurationError("Emulator cannot hook functions")
|
143
|
+
emulator.hook_function(self._address, self._function)
|
144
|
+
|
145
|
+
@abc.abstractmethod
|
146
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
147
|
+
"""This is the implementation of the model for the named function.
|
148
|
+
|
149
|
+
Note that implementation will have to make use of knowledge of
|
150
|
+
the ABI to obtain arguments and return results, as well as
|
151
|
+
modeling the semantics of the modeled functions appropriately.
|
152
|
+
|
153
|
+
"""
|
154
|
+
pass
|
155
|
+
|
156
|
+
|
157
|
+
__all__ = [
|
158
|
+
"Hook",
|
159
|
+
"Breakpoint",
|
160
|
+
"PDBBreakpoint",
|
161
|
+
"PythonShellBreakpoint",
|
162
|
+
"Model",
|
163
|
+
]
|
@@ -0,0 +1,455 @@
|
|
1
|
+
import abc
|
2
|
+
import logging
|
3
|
+
import random
|
4
|
+
|
5
|
+
from ... import emulators
|
6
|
+
from .model import Model
|
7
|
+
|
8
|
+
logger = logging.getLogger(__name__)
|
9
|
+
|
10
|
+
######################################################
|
11
|
+
# This stuff is private. Dont' add it to __all__ #
|
12
|
+
######################################################
|
13
|
+
|
14
|
+
|
15
|
+
MAX_STRLEN = 0x10000
|
16
|
+
|
17
|
+
|
18
|
+
# obtain addr of emulator heap memory of this size
|
19
|
+
# NB: this will map new pages into emulator as needed
|
20
|
+
def _emu_alloc(emulator: emulators.Emulator, size: int) -> int:
|
21
|
+
address = 0x10000
|
22
|
+
memory_map = emulator.get_memory_map()
|
23
|
+
if len(memory_map) > 0:
|
24
|
+
address = memory_map[-1][1]
|
25
|
+
emulator.map_memory(address, size)
|
26
|
+
return address
|
27
|
+
|
28
|
+
|
29
|
+
def _emu_calloc(emulator: emulators.Emulator, size: int) -> int:
|
30
|
+
addr = _emu_alloc(emulator, size)
|
31
|
+
emulator.write_memory(addr, b"\0" * size)
|
32
|
+
return addr
|
33
|
+
|
34
|
+
|
35
|
+
def _emu_strlen_n(emulator: emulators.Emulator, addr: int, n: int) -> int:
|
36
|
+
sl = 0
|
37
|
+
while sl <= n:
|
38
|
+
b_opt = emulator.read_memory(addr + sl, 1)
|
39
|
+
if b_opt is not None:
|
40
|
+
b = b_opt[0]
|
41
|
+
if b == 0:
|
42
|
+
break
|
43
|
+
sl += 1
|
44
|
+
else:
|
45
|
+
assert b_opt is not None
|
46
|
+
return sl
|
47
|
+
|
48
|
+
|
49
|
+
def _emu_strlen(emulator: emulators.Emulator, addr: int) -> int:
|
50
|
+
return _emu_strlen_n(emulator, addr, MAX_STRLEN)
|
51
|
+
|
52
|
+
|
53
|
+
def _emu_memcpy(emulator: emulators.Emulator, dst: int, src: int, n: int) -> None:
|
54
|
+
src_bytes = emulator.read_memory(src, n)
|
55
|
+
emulator.write_memory(dst, src_bytes)
|
56
|
+
|
57
|
+
|
58
|
+
def _emu_strncpy(
|
59
|
+
emulator: emulators.Emulator, dst: int, src: int, n: int, is_strncpy: bool
|
60
|
+
) -> None:
|
61
|
+
if n == 0:
|
62
|
+
return
|
63
|
+
if emulator.read_memory(src, 1) is None:
|
64
|
+
logger.debug("MEM not available in strncpy read @ {src:x}")
|
65
|
+
elif emulator.read_memory(dst, 1) is None:
|
66
|
+
logger.debug("MEM not available in strncpy write @ {dst:x}")
|
67
|
+
else:
|
68
|
+
# at least a byte is available at both src and dst
|
69
|
+
# find length of src (not to exceed l)
|
70
|
+
l2 = _emu_strlen_n(emulator, src, n)
|
71
|
+
l3 = min(n, l2)
|
72
|
+
if l3 > 0:
|
73
|
+
# read the src string and copy to dst
|
74
|
+
src_bytes = emulator.read_memory(src, l3)
|
75
|
+
emulator.write_memory(dst, src_bytes)
|
76
|
+
if is_strncpy and l3 < n:
|
77
|
+
# if src string is less than n bytes then, according to man page
|
78
|
+
# strncpy copies 0s to get to n bytes
|
79
|
+
emulator.write_memory(dst + l3, b"\0" * (n - l3))
|
80
|
+
|
81
|
+
|
82
|
+
def _emu_strncat(emulator: emulators.Emulator, dst: int, src: int, n: int) -> None:
|
83
|
+
if n == 0:
|
84
|
+
return
|
85
|
+
if emulator.read_memory(src, 1) is None:
|
86
|
+
logger.debug("MEM not available in strncpy read @ {src:x}")
|
87
|
+
elif emulator.read_memory(dst, 1) is None:
|
88
|
+
logger.debug("MEM not available in strncpy write @ {dst:x}")
|
89
|
+
else:
|
90
|
+
# at least a byte is available at both src and dst
|
91
|
+
ld = _emu_strlen_n(emulator, dst, MAX_STRLEN)
|
92
|
+
ls = _emu_strlen_n(emulator, src, MAX_STRLEN)
|
93
|
+
lsn = min(ls, n)
|
94
|
+
b_opt = emulator.read_memory(src, lsn)
|
95
|
+
if b_opt is not None:
|
96
|
+
src_bytes = b_opt + b"\0"
|
97
|
+
emulator.write_memory(dst + ld, src_bytes)
|
98
|
+
else:
|
99
|
+
assert b_opt is not None
|
100
|
+
|
101
|
+
|
102
|
+
######################################################
|
103
|
+
# End private stuff #
|
104
|
+
######################################################
|
105
|
+
|
106
|
+
|
107
|
+
class PosixModel(Model):
|
108
|
+
# Base class for POSIX models.
|
109
|
+
#
|
110
|
+
# Most POSIX ABIS use a register-based calling convention.
|
111
|
+
# Rather than tailor each model for each ABI, this base class
|
112
|
+
# lets us play madlibs with the argument and return registers.
|
113
|
+
#
|
114
|
+
# TODO: i386 and mips32 also have stack-passed arguments.
|
115
|
+
|
116
|
+
@property
|
117
|
+
@abc.abstractmethod
|
118
|
+
def argument1(self) -> str:
|
119
|
+
return ""
|
120
|
+
|
121
|
+
@property
|
122
|
+
@abc.abstractmethod
|
123
|
+
def argument2(self) -> str:
|
124
|
+
return ""
|
125
|
+
|
126
|
+
@property
|
127
|
+
@abc.abstractmethod
|
128
|
+
def argument3(self) -> str:
|
129
|
+
return ""
|
130
|
+
|
131
|
+
@property
|
132
|
+
@abc.abstractmethod
|
133
|
+
def argument4(self) -> str:
|
134
|
+
return ""
|
135
|
+
|
136
|
+
@property
|
137
|
+
@abc.abstractmethod
|
138
|
+
def argument5(self) -> str:
|
139
|
+
return ""
|
140
|
+
|
141
|
+
@property
|
142
|
+
@abc.abstractmethod
|
143
|
+
def argument6(self) -> str:
|
144
|
+
return ""
|
145
|
+
|
146
|
+
@property
|
147
|
+
@abc.abstractmethod
|
148
|
+
def return_val(self) -> str:
|
149
|
+
return ""
|
150
|
+
|
151
|
+
|
152
|
+
class BasenameModel(PosixModel):
|
153
|
+
name = "basename"
|
154
|
+
|
155
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
156
|
+
# char *basename(char "path)
|
157
|
+
# returns final component (after last '/') of filename
|
158
|
+
# if path ends with '/' return a ptr to an empty string
|
159
|
+
path = emulator.read_register(self.argument1)
|
160
|
+
sl = _emu_strlen_n(emulator, path, MAX_STRLEN)
|
161
|
+
bn = None
|
162
|
+
while True:
|
163
|
+
b_opt = emulator.read_memory(path + sl, 1)
|
164
|
+
if b_opt is not None:
|
165
|
+
b = b_opt[0]
|
166
|
+
if chr(b) == "/":
|
167
|
+
bn = path + sl + 1
|
168
|
+
break
|
169
|
+
if sl == 0:
|
170
|
+
bn = path
|
171
|
+
break
|
172
|
+
sl = sl - 1
|
173
|
+
else:
|
174
|
+
assert b_opt is not None
|
175
|
+
assert not (bn is None)
|
176
|
+
emulator.write_register(self.return_val, bn)
|
177
|
+
|
178
|
+
|
179
|
+
class CallocModel(PosixModel):
|
180
|
+
name = "calloc"
|
181
|
+
|
182
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
183
|
+
# void *calloc(size_t count, size_t size);
|
184
|
+
count = emulator.read_register(self.argument1)
|
185
|
+
size = emulator.read_register(self.argument2)
|
186
|
+
num_bytes = count * size
|
187
|
+
addr = _emu_calloc(emulator, num_bytes)
|
188
|
+
emulator.write_register(self.return_val, addr)
|
189
|
+
|
190
|
+
|
191
|
+
class ReturnsNothingModel(PosixModel):
|
192
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
193
|
+
# so just do nothing
|
194
|
+
pass
|
195
|
+
|
196
|
+
|
197
|
+
class Returns0Model(PosixModel):
|
198
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
199
|
+
# just return 0
|
200
|
+
emulator.write_register(self.return_val, 0)
|
201
|
+
|
202
|
+
|
203
|
+
class DaemonModel(Returns0Model):
|
204
|
+
name = "daemon"
|
205
|
+
|
206
|
+
|
207
|
+
class FlockModel(Returns0Model):
|
208
|
+
name = "flock"
|
209
|
+
|
210
|
+
|
211
|
+
class Getopt_longModel(PosixModel):
|
212
|
+
name = "getopt_long"
|
213
|
+
|
214
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
215
|
+
# int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
|
216
|
+
# return -1 if no more args
|
217
|
+
emulator.write_register(self.return_val, -1)
|
218
|
+
|
219
|
+
|
220
|
+
class GetpagesizeModel(PosixModel):
|
221
|
+
name = "getpagesize"
|
222
|
+
|
223
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
224
|
+
# int getpagesize(void);
|
225
|
+
emulator.write_register(self.return_val, 0x1000)
|
226
|
+
|
227
|
+
|
228
|
+
class GetppidModel(Returns0Model):
|
229
|
+
name = "getppid"
|
230
|
+
|
231
|
+
|
232
|
+
class GetsModel(PosixModel):
|
233
|
+
name = "gets"
|
234
|
+
|
235
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
236
|
+
# char *gets(char *str);
|
237
|
+
s = emulator.read_register(self.argument1)
|
238
|
+
value = input()
|
239
|
+
emulator.write_memory(s, value.encode("utf-8"))
|
240
|
+
emulator.write_register(self.return_val, s)
|
241
|
+
|
242
|
+
|
243
|
+
class MallocModel(CallocModel):
|
244
|
+
name = "malloc"
|
245
|
+
|
246
|
+
|
247
|
+
class MemcpyModel(PosixModel):
|
248
|
+
name = "memcpy"
|
249
|
+
|
250
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
251
|
+
# void *memcpy(void *restrict dst, const void *restrict src, size_t n);
|
252
|
+
dst = emulator.read_register(self.argument1)
|
253
|
+
src = emulator.read_register(self.argument2)
|
254
|
+
n = emulator.read_register(self.argument3)
|
255
|
+
_emu_memcpy(emulator, dst, src, n)
|
256
|
+
emulator.write_register(self.return_val, dst)
|
257
|
+
|
258
|
+
|
259
|
+
class OpenModel(PosixModel):
|
260
|
+
name = "open"
|
261
|
+
|
262
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
263
|
+
# int open64(const char *pathname, int oflag,...);
|
264
|
+
# just return a fd that's not stdin/stdout/stderr
|
265
|
+
emulator.write_register(self.return_val, 3)
|
266
|
+
|
267
|
+
|
268
|
+
class Open64Model(OpenModel):
|
269
|
+
name = "open64"
|
270
|
+
|
271
|
+
|
272
|
+
class PutsModel(PosixModel):
|
273
|
+
name = "puts"
|
274
|
+
|
275
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
276
|
+
# int fputs(const char *restrict s, FILE *restrict stream);
|
277
|
+
addr = emulator.read_register_content(self.argument1)
|
278
|
+
sl = _emu_strlen(emulator, addr)
|
279
|
+
b_opt = emulator.read_memory(addr, sl)
|
280
|
+
if b_opt is not None:
|
281
|
+
logger.debug(f"puts stream={self.argument2:x} s=[{b_opt!r}]")
|
282
|
+
emulator.write_register(self.return_val, 0)
|
283
|
+
|
284
|
+
|
285
|
+
class PthreadCondInitModel(Returns0Model):
|
286
|
+
name = "pthread_cond_init"
|
287
|
+
|
288
|
+
|
289
|
+
class PthreadCondSignalModel(Returns0Model):
|
290
|
+
name = "pthread_cond_signal_model"
|
291
|
+
|
292
|
+
|
293
|
+
class PthreadCondWaitModel(Returns0Model):
|
294
|
+
name = "pthread_cond_wait"
|
295
|
+
|
296
|
+
|
297
|
+
class PthreadCreateModel(Returns0Model):
|
298
|
+
name = "pthread_create"
|
299
|
+
|
300
|
+
|
301
|
+
class PthreadMutexInitModel(Returns0Model):
|
302
|
+
name = "pthread_mutex_init"
|
303
|
+
|
304
|
+
|
305
|
+
class PthreadMutexLockModel(Returns0Model):
|
306
|
+
name = "ptherad_mutex_lock"
|
307
|
+
|
308
|
+
|
309
|
+
class PthreadMutexUnlockModel(Returns0Model):
|
310
|
+
name = "pthread_mutex_unlock"
|
311
|
+
|
312
|
+
|
313
|
+
class PtraceModel(Returns0Model):
|
314
|
+
name = "ptrace"
|
315
|
+
|
316
|
+
|
317
|
+
class RandModel(PosixModel):
|
318
|
+
name = "rand"
|
319
|
+
|
320
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
321
|
+
# int rand(void);
|
322
|
+
emulator.write_register(self.return_val, random.randint(0, 0x7FFFFFFF))
|
323
|
+
|
324
|
+
|
325
|
+
class RandomModel(PosixModel):
|
326
|
+
name = "random"
|
327
|
+
|
328
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
329
|
+
# long random(void);
|
330
|
+
emulator.write_register(self.return_val, random.randint(0, 0xFFFFFFFF))
|
331
|
+
|
332
|
+
|
333
|
+
class SleepModel(Returns0Model):
|
334
|
+
name = "sleep"
|
335
|
+
|
336
|
+
|
337
|
+
class SrandModel(ReturnsNothingModel):
|
338
|
+
name = "srand"
|
339
|
+
|
340
|
+
|
341
|
+
class SrandomModel(ReturnsNothingModel):
|
342
|
+
name = "srandom"
|
343
|
+
|
344
|
+
|
345
|
+
class StrcatModel(PosixModel):
|
346
|
+
name = "strcat"
|
347
|
+
|
348
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
349
|
+
# char *strcat(char *restrict s1, const char *restrict s2);
|
350
|
+
dst = emulator.read_register(self.argument1)
|
351
|
+
src = emulator.read_register(self.argument2)
|
352
|
+
_emu_strncat(emulator, dst, src, MAX_STRLEN)
|
353
|
+
|
354
|
+
|
355
|
+
class StrncatModel(PosixModel):
|
356
|
+
name = "strncat"
|
357
|
+
|
358
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
359
|
+
# char *strncat(char *restrict s1, const char *restrict s2, size_t n);
|
360
|
+
dst = emulator.read_register(self.argument1)
|
361
|
+
src = emulator.read_register(self.argument2)
|
362
|
+
msl = emulator.read_register(self.argument3)
|
363
|
+
_emu_strncat(emulator, dst, src, msl)
|
364
|
+
|
365
|
+
|
366
|
+
class StrcpyModel(PosixModel):
|
367
|
+
name = "strcpy"
|
368
|
+
|
369
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
370
|
+
# char *strcpy(char * dst, const char * src);
|
371
|
+
dst = emulator.read_register(self.argument1)
|
372
|
+
src = emulator.read_register(self.argument2)
|
373
|
+
_emu_strncpy(emulator, dst, src, MAX_STRLEN, is_strncpy=False)
|
374
|
+
|
375
|
+
|
376
|
+
class StrncpyModel(PosixModel):
|
377
|
+
name = "strncpy"
|
378
|
+
|
379
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
380
|
+
# char *strncpy(char * dst, const char * src, size_t len);
|
381
|
+
dst = emulator.read_register(self.argument1)
|
382
|
+
src = emulator.read_register(self.argument2)
|
383
|
+
sl = emulator.read_register(self.argument3)
|
384
|
+
_emu_strncpy(emulator, dst, src, sl, is_strncpy=True)
|
385
|
+
|
386
|
+
|
387
|
+
class StrdupModel(PosixModel):
|
388
|
+
name = "strdup"
|
389
|
+
|
390
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
391
|
+
# char *strdup(const char *s1);
|
392
|
+
src = emulator.read_register(self.argument1)
|
393
|
+
sl = _emu_strlen_n(emulator, src, MAX_STRLEN)
|
394
|
+
dst = _emu_calloc(emulator, sl)
|
395
|
+
_emu_memcpy(emulator, dst, src, sl)
|
396
|
+
emulator.write_register(self.return_val, dst)
|
397
|
+
|
398
|
+
|
399
|
+
class StrlenModel(PosixModel):
|
400
|
+
name = "strlen"
|
401
|
+
|
402
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
403
|
+
# size_t strlen(const char *s)
|
404
|
+
ptr = emulator.read_register(self.argument1)
|
405
|
+
emulator.write_register(
|
406
|
+
self.return_val, _emu_strlen_n(emulator, ptr, MAX_STRLEN)
|
407
|
+
)
|
408
|
+
|
409
|
+
|
410
|
+
class StrnlenModel(PosixModel):
|
411
|
+
name = "strnlen"
|
412
|
+
|
413
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
414
|
+
# size_t strnlen(const char *s, size_t maxlen);
|
415
|
+
ptr = emulator.read_register(self.argument1)
|
416
|
+
n = emulator.read_register(self.argument2)
|
417
|
+
emulator.write_register(self.return_val, _emu_strlen_n(emulator, ptr, n))
|
418
|
+
|
419
|
+
|
420
|
+
class SysconfModel(PosixModel):
|
421
|
+
name = "sysconf"
|
422
|
+
|
423
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
424
|
+
# long sysconf(int name);
|
425
|
+
arg1 = emulator.read_register(self.argument1)
|
426
|
+
if arg1 == 0x54:
|
427
|
+
# this is the one case we know about so far
|
428
|
+
# it's asking for the number of cores
|
429
|
+
emulator.write_register(self.return_val, 1)
|
430
|
+
|
431
|
+
|
432
|
+
class TimeModel(PosixModel):
|
433
|
+
name = "time"
|
434
|
+
|
435
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
436
|
+
# time_t time(time_t *tloc);
|
437
|
+
# just return something
|
438
|
+
emulator.write_register(self.return_val, 0x1234)
|
439
|
+
|
440
|
+
|
441
|
+
class UnlinkModel(Returns0Model):
|
442
|
+
name = "unlink"
|
443
|
+
|
444
|
+
|
445
|
+
class WriteModel(PosixModel):
|
446
|
+
name = "write"
|
447
|
+
|
448
|
+
def model(self, emulator: emulators.Emulator) -> None:
|
449
|
+
# ssize_t write(int fildes, const void *buf, size_t nbyte);
|
450
|
+
addr = emulator.read_register_content(self.argument2)
|
451
|
+
size = emulator.read_register_content(self.argument3)
|
452
|
+
b_opt = emulator.read_memory(addr, size)
|
453
|
+
if b_opt is not None:
|
454
|
+
logger.debug(f"write fd={self.argument1} buf=[{b_opt!r}]")
|
455
|
+
emulator.write_register(self.return_val, 0)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from ..model import Model
|
5
|
+
from ..posix import GetsModel
|
6
|
+
|
7
|
+
|
8
|
+
class AMD64Win32Model(Model):
|
9
|
+
platform = platforms.Platform(
|
10
|
+
platforms.Architecture.X86_64, platforms.Byteorder.LITTLE
|
11
|
+
)
|
12
|
+
abi = platforms.ABI.CDECL
|
13
|
+
|
14
|
+
# NOTE: according to Wikipedia, win32 only allows 4 register-passed arguments.
|
15
|
+
argument1 = "rcx"
|
16
|
+
argument2 = "rdx"
|
17
|
+
argument3 = "r8"
|
18
|
+
argument4 = "r9"
|
19
|
+
|
20
|
+
@property
|
21
|
+
def argument5(self) -> str:
|
22
|
+
raise ValueError("win32 has no argument 5 register")
|
23
|
+
|
24
|
+
@property
|
25
|
+
def argument6(self) -> str:
|
26
|
+
raise ValueError("win32 has no argument 6 register")
|
27
|
+
|
28
|
+
return_val = "rax"
|
29
|
+
|
30
|
+
|
31
|
+
class AMD64MicrosoftGetsModel(AMD64Win32Model, GetsModel):
|
32
|
+
pass
|
33
|
+
|
34
|
+
|
35
|
+
__all__: typing.List[str] = []
|