angr 9.2.115__py3-none-manylinux2014_aarch64.whl → 9.2.117__py3-none-manylinux2014_aarch64.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.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/__main__.py +1 -1
- angr/analyses/cfg/cfg_emulated.py +4 -4
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +7 -7
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +3 -2
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +5 -1
- angr/analyses/decompiler/structured_codegen/c.py +10 -13
- angr/analyses/decompiler/structuring/dream.py +3 -4
- angr/analyses/decompiler/structuring/phoenix.py +4 -5
- angr/analyses/decompiler/structuring/structurer_base.py +2 -3
- angr/analyses/decompiler/structuring/structurer_nodes.py +3 -3
- angr/analyses/identifier/functions/free.py +3 -1
- angr/analyses/identifier/identify.py +13 -15
- angr/analyses/identifier/runner.py +2 -2
- angr/analyses/reaching_definitions/dep_graph.py +62 -5
- angr/analyses/reaching_definitions/function_handler_library/__init__.py +11 -0
- angr/analyses/reaching_definitions/function_handler_library/stdio.py +15 -13
- angr/analyses/reaching_definitions/function_handler_library/stdlib.py +17 -11
- angr/analyses/reaching_definitions/function_handler_library/string.py +1 -1
- angr/analyses/reaching_definitions/function_handler_library/unistd.py +2 -2
- angr/analyses/reaching_definitions/rd_state.py +26 -29
- angr/analyses/variable_recovery/engine_vex.py +0 -9
- angr/analyses/vfg.py +4 -4
- angr/calling_conventions.py +4 -2
- angr/concretization_strategies/any_named.py +3 -1
- angr/concretization_strategies/controlled_data.py +4 -2
- angr/concretization_strategies/signed_add.py +3 -1
- angr/engines/concrete.py +3 -1
- angr/engines/pcode/behavior.py +2 -0
- angr/engines/pcode/cc.py +2 -0
- angr/engines/pcode/emulate.py +4 -4
- angr/engines/pcode/engine.py +3 -7
- angr/engines/soot/engine.py +7 -6
- angr/engines/soot/expressions/constants.py +6 -5
- angr/engines/soot/expressions/newArray.py +3 -1
- angr/engines/soot/expressions/newMultiArray.py +3 -1
- angr/engines/soot/statements/goto.py +3 -1
- angr/engines/soot/statements/if_.py +3 -1
- angr/engines/soot/statements/switch.py +3 -1
- angr/engines/soot/statements/throw.py +4 -2
- angr/engines/soot/values/arrayref.py +5 -5
- angr/engines/unicorn.py +8 -7
- angr/engines/vex/heavy/concretizers.py +6 -6
- angr/engines/vex/heavy/dirty.py +20 -22
- angr/engines/vex/heavy/heavy.py +4 -8
- angr/exploration_techniques/director.py +1 -1
- angr/exploration_techniques/driller_core.py +3 -1
- angr/exploration_techniques/tracer.py +2 -1
- angr/knowledge_plugins/key_definitions/live_definitions.py +12 -13
- angr/procedures/cgc/allocate.py +8 -10
- angr/procedures/cgc/deallocate.py +10 -3
- angr/procedures/cgc/fdwait.py +15 -13
- angr/procedures/cgc/random.py +11 -5
- angr/procedures/cgc/receive.py +5 -3
- angr/procedures/cgc/transmit.py +5 -4
- angr/procedures/glibc/__libc_start_main.py +5 -4
- angr/procedures/java_jni/__init__.py +4 -4
- angr/procedures/java_jni/array_operations.py +3 -1
- angr/procedures/java_lang/string.py +1 -1
- angr/procedures/java_util/random.py +3 -1
- angr/procedures/libc/access.py +4 -2
- angr/procedures/libc/feof.py +4 -3
- angr/procedures/libc/fgetc.py +3 -1
- angr/procedures/libc/fgets.py +5 -5
- angr/procedures/libc/fopen.py +5 -4
- angr/procedures/libc/fread.py +4 -3
- angr/procedures/libc/fseek.py +4 -3
- angr/procedures/libc/getdelim.py +7 -4
- angr/procedures/libc/gets.py +4 -2
- angr/procedures/libc/memcmp.py +18 -15
- angr/procedures/libc/memset.py +9 -7
- angr/procedures/libc/puts.py +3 -1
- angr/procedures/libc/snprintf.py +4 -2
- angr/procedures/libc/sprintf.py +3 -1
- angr/procedures/libc/strchr.py +6 -3
- angr/procedures/libc/strcmp.py +5 -3
- angr/procedures/libc/strlen.py +3 -3
- angr/procedures/libc/strncmp.py +28 -28
- angr/procedures/libc/strncpy.py +5 -2
- angr/procedures/libc/strstr.py +10 -7
- angr/procedures/libc/strtol.py +32 -34
- angr/procedures/libc/tolower.py +3 -1
- angr/procedures/libc/toupper.py +3 -1
- angr/procedures/linux_kernel/fstat.py +13 -13
- angr/procedures/linux_kernel/fstat64.py +15 -15
- angr/procedures/linux_kernel/lseek.py +5 -3
- angr/procedures/linux_kernel/sigaction.py +4 -2
- angr/procedures/linux_kernel/sigprocmask.py +5 -3
- angr/procedures/linux_kernel/tgkill.py +3 -1
- angr/procedures/linux_kernel/time.py +7 -4
- angr/procedures/msvcr/fmode.py +3 -1
- angr/procedures/ntdll/exceptions.py +3 -1
- angr/procedures/posix/bzero.py +3 -1
- angr/procedures/posix/fdopen.py +6 -4
- angr/procedures/posix/fork.py +6 -4
- angr/procedures/posix/mmap.py +6 -3
- angr/procedures/posix/poll.py +6 -5
- angr/procedures/posix/readdir.py +10 -7
- angr/procedures/posix/select.py +4 -2
- angr/procedures/posix/send.py +4 -3
- angr/procedures/posix/sigaction.py +4 -2
- angr/procedures/posix/sim_time.py +3 -1
- angr/procedures/posix/strcasecmp.py +3 -1
- angr/procedures/posix/strtok_r.py +10 -7
- angr/procedures/stubs/Redirect.py +3 -1
- angr/procedures/stubs/ReturnChar.py +3 -3
- angr/procedures/stubs/UserHook.py +3 -1
- angr/procedures/stubs/b64_decode.py +3 -1
- angr/procedures/stubs/crazy_scanf.py +6 -4
- angr/procedures/stubs/format_parser.py +13 -15
- angr/procedures/tracer/receive.py +3 -1
- angr/procedures/tracer/transmit.py +3 -1
- angr/procedures/win32/GetLastInputInfo.py +4 -2
- angr/procedures/win32/GetProcessAffinityMask.py +4 -2
- angr/procedures/win32/gethostbyname.py +3 -1
- angr/procedures/win32/heap.py +3 -1
- angr/procedures/win32/local_storage.py +4 -2
- angr/procedures/win32/sim_time.py +7 -4
- angr/procedures/win_user32/chars.py +4 -2
- angr/procedures/win_user32/messagebox.py +3 -1
- angr/sim_procedure.py +7 -7
- angr/sim_state.py +10 -7
- angr/sim_type.py +3 -3
- angr/simos/cgc.py +2 -2
- angr/simos/simos.py +5 -4
- angr/simos/windows.py +5 -5
- angr/state_plugins/heap/heap_brk.py +5 -3
- angr/state_plugins/heap/heap_ptmalloc.py +5 -4
- angr/state_plugins/history.py +7 -5
- angr/state_plugins/light_registers.py +2 -2
- angr/state_plugins/plugin.py +2 -2
- angr/state_plugins/posix.py +28 -26
- angr/state_plugins/preconstrainer.py +2 -1
- angr/state_plugins/solver.py +11 -27
- angr/state_plugins/trace_additions.py +9 -13
- angr/state_plugins/uc_manager.py +4 -2
- angr/state_plugins/unicorn_engine.py +1 -1
- angr/state_plugins/view.py +1 -1
- angr/storage/file.py +21 -26
- angr/storage/memory_mixins/actions_mixin.py +4 -2
- angr/storage/memory_mixins/address_concretization_mixin.py +3 -3
- angr/storage/memory_mixins/default_filler_mixin.py +6 -4
- angr/storage/memory_mixins/javavm_memory/javavm_memory_mixin.py +7 -5
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +2 -1
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/region_data.py +3 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +5 -4
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
- angr/storage/memory_mixins/size_resolution_mixin.py +3 -1
- angr/storage/memory_mixins/slotted_memory.py +1 -1
- angr/storage/memory_mixins/smart_find_mixin.py +2 -2
- angr/storage/memory_mixins/symbolic_merger_mixin.py +5 -3
- angr/tablespecs.py +3 -3
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/METADATA +7 -7
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/RECORD +161 -161
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/WHEEL +1 -1
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/LICENSE +0 -0
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/entry_points.txt +0 -0
- {angr-9.2.115.dist-info → angr-9.2.117.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
import claripy
|
|
4
|
+
|
|
3
5
|
from .base import SimSootStmt
|
|
4
6
|
|
|
5
7
|
l = logging.getLogger("angr.engines.soot.statements.goto")
|
|
@@ -8,4 +10,4 @@ l = logging.getLogger("angr.engines.soot.statements.goto")
|
|
|
8
10
|
class SimSootStmt_Goto(SimSootStmt):
|
|
9
11
|
def _execute(self):
|
|
10
12
|
jmp_target = self._get_bb_addr_from_instr(instr=self.stmt.target)
|
|
11
|
-
self._add_jmp_target(target=jmp_target, condition=
|
|
13
|
+
self._add_jmp_target(target=jmp_target, condition=claripy.true)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
import claripy
|
|
4
|
+
|
|
3
5
|
from .base import SimSootStmt
|
|
4
6
|
|
|
5
7
|
l = logging.getLogger("angr.engines.soot.statements.if")
|
|
@@ -12,5 +14,5 @@ class SimSootStmt_If(SimSootStmt):
|
|
|
12
14
|
self._add_jmp_target(target=jmp_target, condition=jmp_condition)
|
|
13
15
|
self._add_jmp_target(
|
|
14
16
|
target=None, # if target is None, engine goes on linearly
|
|
15
|
-
condition=(jmp_condition ==
|
|
17
|
+
condition=(jmp_condition == claripy.false),
|
|
16
18
|
)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
import claripy
|
|
4
|
+
|
|
3
5
|
from .base import SimSootStmt
|
|
4
6
|
|
|
5
7
|
l = logging.getLogger("angr.engines.soot.statements.switch")
|
|
@@ -26,7 +28,7 @@ class SwitchBase(SimSootStmt):
|
|
|
26
28
|
|
|
27
29
|
# add default target
|
|
28
30
|
default_jmp_target = self._get_bb_addr_from_instr(self.stmt.default_target)
|
|
29
|
-
default_jmp_cond =
|
|
31
|
+
default_jmp_cond = claripy.And(*default_jmp_conditions)
|
|
30
32
|
self._add_jmp_target(default_jmp_target, default_jmp_cond)
|
|
31
33
|
|
|
32
34
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import claripy
|
|
4
4
|
from archinfo.arch_soot import SootAddressTerminator
|
|
5
5
|
|
|
6
|
+
from .base import SimSootStmt
|
|
7
|
+
|
|
6
8
|
l = logging.getLogger(name=__name__)
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class SimSootStmt_Throw(SimSootStmt):
|
|
10
12
|
def _execute(self):
|
|
11
13
|
# TODO: implement simprocedure to throw exception
|
|
12
|
-
self._add_jmp_target(target=SootAddressTerminator(), condition=
|
|
14
|
+
self._add_jmp_target(target=SootAddressTerminator(), condition=claripy.true)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import claripy
|
|
4
4
|
|
|
5
5
|
from . import translate_value
|
|
6
6
|
from ....errors import SimEngineError
|
|
@@ -38,7 +38,7 @@ class SimSootValue_ArrayBaseRef(SimSootValue):
|
|
|
38
38
|
|
|
39
39
|
:param function generator: Function that given the state, returns a
|
|
40
40
|
default value for array elements, e.g.
|
|
41
|
-
`generator = lambda state:
|
|
41
|
+
`generator = lambda state: claripy.BVV(0, 32)`
|
|
42
42
|
"""
|
|
43
43
|
self._default_value_generator = generator
|
|
44
44
|
|
|
@@ -81,9 +81,9 @@ class SimSootValue_ArrayRef(SimSootValue):
|
|
|
81
81
|
def check_array_bounds(idx, array, state):
|
|
82
82
|
# a valid idx fullfills the constraint
|
|
83
83
|
# 0 <= idx < length
|
|
84
|
-
zero =
|
|
84
|
+
zero = claripy.BVV(0, 32)
|
|
85
85
|
length = array.size
|
|
86
|
-
bound_constraint =
|
|
86
|
+
bound_constraint = claripy.And(
|
|
87
87
|
length.SGT(idx),
|
|
88
88
|
zero.SLE(idx),
|
|
89
89
|
)
|
|
@@ -121,4 +121,4 @@ class SimSootValue_ArrayRef(SimSootValue):
|
|
|
121
121
|
idx,
|
|
122
122
|
length,
|
|
123
123
|
)
|
|
124
|
-
state.solver.add(And(length.SGT(idx), zero.SLE(idx)))
|
|
124
|
+
state.solver.add(claripy.And(length.SGT(idx), zero.SLE(idx)))
|
angr/engines/unicorn.py
CHANGED
|
@@ -3,6 +3,7 @@ import functools
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
import archinfo
|
|
6
|
+
import claripy
|
|
6
7
|
|
|
7
8
|
from ..errors import SimIRSBError, SimIRSBNoDecodeError, SimValueError
|
|
8
9
|
from .engine import SuccessorsMixin
|
|
@@ -178,7 +179,7 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
178
179
|
|
|
179
180
|
self._instr_mem_write_addrs = set() # pylint:disable=attribute-defined-outside-init
|
|
180
181
|
for block_details in self.state.unicorn._get_details_of_blocks_with_symbolic_vex_stmts():
|
|
181
|
-
self.state.scratch.guard =
|
|
182
|
+
self.state.scratch.guard = claripy.true
|
|
182
183
|
try:
|
|
183
184
|
if self.state.os_name == "CGC" and block_details["block_addr"] in {
|
|
184
185
|
self.state.unicorn.cgc_random_addr,
|
|
@@ -314,7 +315,7 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
314
315
|
mem_read_val += next_val["value"]
|
|
315
316
|
|
|
316
317
|
assert state.inspect.mem_read_length == mem_read_size
|
|
317
|
-
state.inspect.mem_read_address =
|
|
318
|
+
state.inspect.mem_read_address = claripy.BVV(mem_read_address, state.inspect.mem_read_address.size())
|
|
318
319
|
if mem_read_taint_map.count(-1) != mem_read_size:
|
|
319
320
|
# Since read is might need bitmap adjustment, insert breakpoint to return the correct concrete value
|
|
320
321
|
self.state.inspect.b(
|
|
@@ -330,9 +331,9 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
330
331
|
if taint_map.count(0) == state.inspect.mem_read_length:
|
|
331
332
|
# The value is completely concrete
|
|
332
333
|
if state.arch.memory_endness == archinfo.Endness.LE:
|
|
333
|
-
state.inspect.mem_read_expr =
|
|
334
|
+
state.inspect.mem_read_expr = claripy.BVV(value[::-1])
|
|
334
335
|
else:
|
|
335
|
-
state.inspect.mem_read_expr =
|
|
336
|
+
state.inspect.mem_read_expr = claripy.BVV(value)
|
|
336
337
|
else:
|
|
337
338
|
# The value may be partially concrete. Set the symbolic bitmap to read correct value and restore it
|
|
338
339
|
mem_read_addr = state.solver.eval(state.inspect.mem_read_address)
|
|
@@ -370,12 +371,12 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
370
371
|
|
|
371
372
|
for offset, expected_taint in enumerate(taint_map):
|
|
372
373
|
if expected_taint == 0:
|
|
373
|
-
curr_value_bytes[offset] =
|
|
374
|
+
curr_value_bytes[offset] = claripy.BVV(value[offset], 8)
|
|
374
375
|
|
|
375
376
|
if state.arch.memory_endness == archinfo.Endness.LE:
|
|
376
377
|
curr_value_bytes = reversed(curr_value_bytes)
|
|
377
378
|
|
|
378
|
-
curr_value =
|
|
379
|
+
curr_value = claripy.Concat(*curr_value_bytes)
|
|
379
380
|
|
|
380
381
|
state.inspect.mem_read_expr = curr_value
|
|
381
382
|
|
|
@@ -475,7 +476,7 @@ class SimEngineUnicorn(SuccessorsMixin):
|
|
|
475
476
|
|
|
476
477
|
if state.unicorn.jumpkind.startswith("Ijk_Sys"):
|
|
477
478
|
state.ip = state.unicorn._syscall_pc
|
|
478
|
-
successors.add_successor(state, state.ip,
|
|
479
|
+
successors.add_successor(state, state.ip, claripy.true, state.unicorn.jumpkind)
|
|
479
480
|
|
|
480
481
|
successors.description = description
|
|
481
482
|
successors.processed = True
|
|
@@ -57,13 +57,13 @@ def concretize_cmpf64(state, args):
|
|
|
57
57
|
fp_arg0 = state.solver.eval(args[0])
|
|
58
58
|
fp_arg1 = state.solver.eval(args[1])
|
|
59
59
|
if fp_arg0 < fp_arg1:
|
|
60
|
-
return
|
|
60
|
+
return claripy.BVV(1, 32)
|
|
61
61
|
if fp_arg0 > fp_arg1:
|
|
62
|
-
return
|
|
62
|
+
return claripy.BVV(0, 32)
|
|
63
63
|
if fp_arg0 == fp_arg1:
|
|
64
|
-
return
|
|
64
|
+
return claripy.BVV(0x40, 32)
|
|
65
65
|
|
|
66
|
-
return
|
|
66
|
+
return claripy.BVV(0x45, 32)
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
def concretize_divf64(state, args):
|
|
@@ -113,13 +113,13 @@ def concretize_float64_to_int64s(state, args):
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def concretize_int32s_to_float64(state, args):
|
|
116
|
-
arg =
|
|
116
|
+
arg = claripy.BVV(state.solver.eval(args[0]), args[0].size())
|
|
117
117
|
return arg.val_to_fp(claripy.fp.FSort.from_size(64), signed=True, rm=fp_rm_map[0])
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
def concretize_int64s_to_float64(state, args):
|
|
121
121
|
rm = translate_rm(args[0])
|
|
122
|
-
arg =
|
|
122
|
+
arg = claripy.BVV(state.solver.eval(args[1]), args[1].size())
|
|
123
123
|
return arg.val_to_fp(claripy.fp.FSort.from_size(64), signed=True, rm=rm)
|
|
124
124
|
|
|
125
125
|
|
angr/engines/vex/heavy/dirty.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import claripy
|
|
2
|
-
|
|
3
1
|
import logging
|
|
4
2
|
import time
|
|
5
3
|
|
|
4
|
+
import claripy
|
|
5
|
+
|
|
6
6
|
from angr import sim_options as o, errors
|
|
7
7
|
|
|
8
8
|
l = logging.getLogger(name=__name__)
|
|
@@ -20,16 +20,16 @@ l = logging.getLogger(name=__name__)
|
|
|
20
20
|
# http://www.cap-lore.com/code/TB/
|
|
21
21
|
def ppcg_dirtyhelper_MFTB(state):
|
|
22
22
|
# TODO: This is an incorrect implementation. Fix it later!
|
|
23
|
-
return
|
|
23
|
+
return claripy.BVV(0x200, 64), []
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def ppc32g_dirtyhelper_MFSPR_287(state):
|
|
27
|
-
return
|
|
27
|
+
return claripy.BVV(0x200, 32), []
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def amd64g_dirtyhelper_RDTSC(state):
|
|
31
31
|
if o.USE_SYSTEM_TIMES in state.options:
|
|
32
|
-
val =
|
|
32
|
+
val = claripy.BVV(int(time.process_time() * 1000000) + 12345678, 64)
|
|
33
33
|
else:
|
|
34
34
|
val = state.solver.BVS("RDTSC", 64, key=("hardware", "rdtsc"))
|
|
35
35
|
return val, []
|
|
@@ -121,15 +121,13 @@ EmWarn_S390X_invalid_rounding = 11
|
|
|
121
121
|
def amd64g_check_ldmxcsr(state, mxcsr):
|
|
122
122
|
rmode = state.solver.LShR(mxcsr, 13) & 3
|
|
123
123
|
|
|
124
|
-
ew =
|
|
124
|
+
ew = claripy.If(
|
|
125
125
|
(mxcsr & 0x1F80) != 0x1F80,
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
claripy.BVV(EmWarn_X86_sseExns, 64),
|
|
127
|
+
claripy.If(
|
|
128
128
|
mxcsr & (1 << 15) != 0,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
mxcsr & (1 << 6) != 0, state.solver.BVV(EmWarn_X86_daz, 64), state.solver.BVV(EmNote_NONE, 64)
|
|
132
|
-
),
|
|
129
|
+
claripy.BVV(EmWarn_X86_fz, 64),
|
|
130
|
+
claripy.If(mxcsr & (1 << 6) != 0, claripy.BVV(EmWarn_X86_daz, 64), claripy.BVV(EmNote_NONE, 64)),
|
|
133
131
|
),
|
|
134
132
|
)
|
|
135
133
|
|
|
@@ -138,7 +136,7 @@ def amd64g_check_ldmxcsr(state, mxcsr):
|
|
|
138
136
|
|
|
139
137
|
# see canonical implementation of this in guest_amd64_helpers.c
|
|
140
138
|
def amd64g_dirtyhelper_XRSTOR_COMPONENT_1_EXCLUDING_XMMREGS(state, _, addr):
|
|
141
|
-
w32 =
|
|
139
|
+
w32 = claripy.BVV(
|
|
142
140
|
(state.mem[state.solver.eval(addr) + 12 * 2].short.concrete & 0xFFFF)
|
|
143
141
|
| ((state.mem[state.solver.eval(addr) + 13 * 2].short.concrete & 0xFFFF) << 16),
|
|
144
142
|
64,
|
|
@@ -365,7 +363,7 @@ def x86g_dirtyhelper_LGDT_LIDT(state, addr, op):
|
|
|
365
363
|
base = state.memory.load(addr + 2, 4, endness="Iend_LE")
|
|
366
364
|
|
|
367
365
|
if op.concrete_value == 2:
|
|
368
|
-
state.regs.gdt =
|
|
366
|
+
state.regs.gdt = claripy.Concat(base, limit).zero_extend(16)
|
|
369
367
|
elif op.concrete_value == 3:
|
|
370
368
|
# LIDT is a nop
|
|
371
369
|
pass
|
|
@@ -398,8 +396,8 @@ def x86g_dirtyhelper_loadF80le(state, addr):
|
|
|
398
396
|
mantissa = tbyte[62:0]
|
|
399
397
|
|
|
400
398
|
normalized_exponent = exponent[10:0] - 16383 + 1023
|
|
401
|
-
zero_exponent =
|
|
402
|
-
inf_exponent =
|
|
399
|
+
zero_exponent = claripy.BVV(0, 11)
|
|
400
|
+
inf_exponent = claripy.BVV(-1, 11)
|
|
403
401
|
final_exponent = claripy.If(
|
|
404
402
|
exponent == 0, zero_exponent, claripy.If(exponent == -1, inf_exponent, normalized_exponent)
|
|
405
403
|
)
|
|
@@ -424,8 +422,8 @@ def x86g_dirtyhelper_storeF80le(state, addr, qword):
|
|
|
424
422
|
mantissa = qword[51:0]
|
|
425
423
|
|
|
426
424
|
normalized_exponent = exponent.zero_extend(4) - 1023 + 16383
|
|
427
|
-
zero_exponent =
|
|
428
|
-
inf_exponent =
|
|
425
|
+
zero_exponent = claripy.BVV(0, 15)
|
|
426
|
+
inf_exponent = claripy.BVV(-1, 15)
|
|
429
427
|
final_exponent = claripy.If(
|
|
430
428
|
exponent == 0, zero_exponent, claripy.If(exponent == -1, inf_exponent, normalized_exponent)
|
|
431
429
|
)
|
|
@@ -449,18 +447,18 @@ def x86g_dirtyhelper_RDMSR(state, msr):
|
|
|
449
447
|
try:
|
|
450
448
|
msr_conc = state.solver.eval_one(msr)
|
|
451
449
|
except errors.SimSolverError:
|
|
452
|
-
return
|
|
450
|
+
return claripy.BVS("rdmsr_?", 64, key=("cpu", "rdmsr", "?")), []
|
|
453
451
|
else:
|
|
454
|
-
return
|
|
452
|
+
return claripy.BVS("rdmsr_%#x" % msr_conc, 64, key=("cpu", "rdmsr", msr_conc), eternal=True), []
|
|
455
453
|
|
|
456
454
|
|
|
457
455
|
def x86g_dirtyhelper_XGETBV(state, reg):
|
|
458
456
|
try:
|
|
459
457
|
reg_conc = state.solver.eval_one(reg)
|
|
460
458
|
except errors.SimSolverError:
|
|
461
|
-
return
|
|
459
|
+
return claripy.BVS("xgetbv_?", 64, key=("cpu", "xgetbv", "?")), []
|
|
462
460
|
else:
|
|
463
|
-
return
|
|
461
|
+
return claripy.BVS("xgetbv_%#x" % reg_conc, 64, key=("cpu", "xgetbv", reg_conc), eternal=True), []
|
|
464
462
|
|
|
465
463
|
|
|
466
464
|
amd64g_dirtyhelper_RDMSR = x86g_dirtyhelper_RDMSR
|
angr/engines/vex/heavy/heavy.py
CHANGED
|
@@ -203,7 +203,7 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
203
203
|
exit_state.registers.store(
|
|
204
204
|
exit_state.arch.ret_offset, exit_state.solver.Unconstrained("fake_ret_value", exit_state.arch.bits)
|
|
205
205
|
)
|
|
206
|
-
exit_state.scratch.target =
|
|
206
|
+
exit_state.scratch.target = claripy.BVV(successors.addr + irsb.size, exit_state.arch.bits)
|
|
207
207
|
exit_state.history.jumpkind = "Ijk_Ret"
|
|
208
208
|
exit_state.regs.ip = exit_state.scratch.target
|
|
209
209
|
if exit_state.arch.call_pushes_ret:
|
|
@@ -215,12 +215,8 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
215
215
|
l.debug("%s adding postcall exit.", self)
|
|
216
216
|
|
|
217
217
|
ret_state = exit_state.copy()
|
|
218
|
-
guard =
|
|
219
|
-
|
|
220
|
-
if o.TRUE_RET_EMULATION_GUARD in self.state.options
|
|
221
|
-
else ret_state.solver.false
|
|
222
|
-
)
|
|
223
|
-
ret_target = ret_state.solver.BVV(successors.addr + irsb.size, ret_state.arch.bits)
|
|
218
|
+
guard = claripy.true if o.TRUE_RET_EMULATION_GUARD in self.state.options else claripy.false
|
|
219
|
+
ret_target = claripy.BVV(successors.addr + irsb.size, ret_state.arch.bits)
|
|
224
220
|
ret_state.registers.store(
|
|
225
221
|
ret_state.arch.ret_offset, ret_state.solver.Unconstrained("fake_ret_value", ret_state.arch.bits)
|
|
226
222
|
)
|
|
@@ -340,7 +336,7 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
340
336
|
result = self.state.solver.simplify(result)
|
|
341
337
|
|
|
342
338
|
if self.state.solver.symbolic(result) and o.CONCRETIZE in self.state.options:
|
|
343
|
-
concrete_value =
|
|
339
|
+
concrete_value = claripy.BVV(self.state.solver.eval(result), len(result))
|
|
344
340
|
self.state.add_constraints(result == concrete_value)
|
|
345
341
|
result = concrete_value
|
|
346
342
|
|
|
@@ -330,7 +330,7 @@ class CallFunctionGoal(BaseGoal):
|
|
|
330
330
|
def _compare_pointer_content(state, ptr, expected):
|
|
331
331
|
if isinstance(expected, str):
|
|
332
332
|
# convert it to an AST
|
|
333
|
-
expected =
|
|
333
|
+
expected = claripy.BVV(expected)
|
|
334
334
|
length = expected.size() // 8
|
|
335
335
|
real_string = state.memory.load(ptr, length, endness="Iend_BE")
|
|
336
336
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from itertools import islice
|
|
3
3
|
|
|
4
|
+
import claripy
|
|
5
|
+
|
|
4
6
|
from . import ExplorationTechnique
|
|
5
7
|
|
|
6
8
|
|
|
@@ -91,7 +93,7 @@ class DrillerCore(ExplorationTechnique):
|
|
|
91
93
|
@staticmethod
|
|
92
94
|
def _has_false(state):
|
|
93
95
|
# Check if the state is unsat even if we remove preconstraints.
|
|
94
|
-
claripy_false =
|
|
96
|
+
claripy_false = claripy.false
|
|
95
97
|
if state.scratch.guard.cache_key == claripy_false.cache_key:
|
|
96
98
|
return True
|
|
97
99
|
|
|
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING
|
|
|
2
2
|
import logging
|
|
3
3
|
import cle
|
|
4
4
|
|
|
5
|
+
import claripy
|
|
5
6
|
from capstone import CS_GRP_CALL, CS_GRP_IRET, CS_GRP_JUMP, CS_GRP_RET
|
|
6
7
|
|
|
7
8
|
from . import ExplorationTechnique
|
|
@@ -53,7 +54,7 @@ class RepHook:
|
|
|
53
54
|
|
|
54
55
|
@staticmethod
|
|
55
56
|
def _inline_call(state, procedure, *arguments, **kwargs):
|
|
56
|
-
e_args = [
|
|
57
|
+
e_args = [claripy.BVV(a, state.arch.bits) if isinstance(a, int) else a for a in arguments]
|
|
57
58
|
p = procedure(project=state.project, **kwargs)
|
|
58
59
|
return p.execute(state, None, arguments=e_args)
|
|
59
60
|
|
|
@@ -14,6 +14,7 @@ from angr.misc.ux import deprecated
|
|
|
14
14
|
from angr.errors import SimMemoryMissingError, SimMemoryError
|
|
15
15
|
from angr.storage.memory_mixins import MultiValuedMemory
|
|
16
16
|
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
17
|
+
from angr.knowledge_plugins.key_definitions.definition import A
|
|
17
18
|
from angr.engines.light import SpOffset
|
|
18
19
|
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
19
20
|
from .atoms import Atom, Register, MemoryLocation, Tmp, ConstantSrc
|
|
@@ -660,7 +661,7 @@ class LiveDefinitions:
|
|
|
660
661
|
self.other_uses.add_use(definition, code_loc, expr)
|
|
661
662
|
|
|
662
663
|
def get_definitions(
|
|
663
|
-
self, thing:
|
|
664
|
+
self, thing: A | Definition[A] | Iterable[A] | Iterable[Definition[A]] | MultiValues
|
|
664
665
|
) -> set[Definition[Atom]]:
|
|
665
666
|
if isinstance(thing, MultiValues):
|
|
666
667
|
defs = set()
|
|
@@ -693,9 +694,9 @@ class LiveDefinitions:
|
|
|
693
694
|
return self.get_tmp_definitions(thing.tmp_idx)
|
|
694
695
|
else:
|
|
695
696
|
defs = set()
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
697
|
+
mv = self.others.get(thing, None)
|
|
698
|
+
if mv is not None:
|
|
699
|
+
defs |= self.get_definitions(mv)
|
|
699
700
|
return defs
|
|
700
701
|
|
|
701
702
|
def get_tmp_definitions(self, tmp_idx: int) -> set[Definition]:
|
|
@@ -749,7 +750,7 @@ class LiveDefinitions:
|
|
|
749
750
|
return LiveDefinitions.extract_defs_from_annotations(annotations)
|
|
750
751
|
|
|
751
752
|
@deprecated("get_definitions")
|
|
752
|
-
def get_definitions_from_atoms(self, atoms: Iterable[
|
|
753
|
+
def get_definitions_from_atoms(self, atoms: Iterable[A]) -> Iterable[Definition]:
|
|
753
754
|
result = set()
|
|
754
755
|
for atom in atoms:
|
|
755
756
|
result |= self.get_definitions(atom)
|
|
@@ -813,9 +814,7 @@ class LiveDefinitions:
|
|
|
813
814
|
return None
|
|
814
815
|
return r.concrete_value
|
|
815
816
|
|
|
816
|
-
def get_values(
|
|
817
|
-
self, spec: Atom | Definition[Atom] | Iterable[Atom] | Iterable[Definition[Atom]]
|
|
818
|
-
) -> MultiValues | None:
|
|
817
|
+
def get_values(self, spec: A | Definition[A] | Iterable[A] | Iterable[Definition[A]]) -> MultiValues | None:
|
|
819
818
|
if isinstance(spec, Definition):
|
|
820
819
|
atom = spec.atom
|
|
821
820
|
elif isinstance(spec, Atom):
|
|
@@ -874,7 +873,7 @@ class LiveDefinitions:
|
|
|
874
873
|
|
|
875
874
|
def get_one_value(
|
|
876
875
|
self,
|
|
877
|
-
spec:
|
|
876
|
+
spec: A | Definition[A] | Iterable[A] | Iterable[Definition[A]],
|
|
878
877
|
strip_annotations: bool = False,
|
|
879
878
|
) -> claripy.ast.bv.BV | None:
|
|
880
879
|
r = self.get_values(spec)
|
|
@@ -884,19 +883,19 @@ class LiveDefinitions:
|
|
|
884
883
|
|
|
885
884
|
@overload
|
|
886
885
|
def get_concrete_value(
|
|
887
|
-
self, spec:
|
|
886
|
+
self, spec: A | Definition[A] | Iterable[A] | Iterable[Definition[A]], cast_to: type[int] = ...
|
|
888
887
|
) -> int | None: ...
|
|
889
888
|
|
|
890
889
|
@overload
|
|
891
890
|
def get_concrete_value(
|
|
892
891
|
self,
|
|
893
|
-
spec:
|
|
892
|
+
spec: A | Definition[A] | Iterable[A] | Iterable[Definition[A]],
|
|
894
893
|
cast_to: type[bytes] = ...,
|
|
895
894
|
) -> bytes | None: ...
|
|
896
895
|
|
|
897
896
|
def get_concrete_value(
|
|
898
897
|
self,
|
|
899
|
-
spec:
|
|
898
|
+
spec: A | Definition[A] | Iterable[A] | Iterable[Definition[A]],
|
|
900
899
|
cast_to: type[int] | type[bytes] = int,
|
|
901
900
|
) -> int | bytes | None:
|
|
902
901
|
r = self.get_one_value(spec, strip_annotations=True)
|
|
@@ -983,7 +982,7 @@ class LiveDefinitions:
|
|
|
983
982
|
@overload
|
|
984
983
|
def deref(
|
|
985
984
|
self,
|
|
986
|
-
pointer: MultiValues |
|
|
985
|
+
pointer: MultiValues | A | Definition[A] | Iterable[A] | Iterable[Definition[A]],
|
|
987
986
|
size: int | DerefSize,
|
|
988
987
|
endness: archinfo.Endness = ...,
|
|
989
988
|
) -> set[MemoryLocation]: ...
|
angr/procedures/cgc/allocate.py
CHANGED
|
@@ -18,13 +18,13 @@ class allocate(angr.SimProcedure):
|
|
|
18
18
|
length = self.state.solver.max_int(length)
|
|
19
19
|
|
|
20
20
|
# return code (see allocate() docs)
|
|
21
|
-
r =
|
|
21
|
+
r = claripy.ite_cases(
|
|
22
22
|
(
|
|
23
23
|
(length == 0, self.state.cgc.EINVAL),
|
|
24
24
|
(length > self.state.cgc.max_allocation, self.state.cgc.EINVAL),
|
|
25
25
|
(self.state.cgc.addr_invalid(addr), self.state.cgc.EFAULT),
|
|
26
26
|
),
|
|
27
|
-
|
|
27
|
+
claripy.BVV(0, self.state.arch.bits),
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
if self.state.solver.max_int(r) != 0:
|
|
@@ -34,7 +34,7 @@ class allocate(angr.SimProcedure):
|
|
|
34
34
|
aligned_length = ((length + 0xFFF) // 0x1000) * 0x1000
|
|
35
35
|
|
|
36
36
|
if isinstance(self.state.cgc.allocation_base, int):
|
|
37
|
-
self.state.cgc.allocation_base =
|
|
37
|
+
self.state.cgc.allocation_base = claripy.BVV(self.state.cgc.allocation_base, self.state.arch.bits)
|
|
38
38
|
|
|
39
39
|
chosen = self.state.cgc.get_max_sinkhole(aligned_length)
|
|
40
40
|
if chosen is None:
|
|
@@ -49,26 +49,24 @@ class allocate(angr.SimProcedure):
|
|
|
49
49
|
if sinkhole_size != 0:
|
|
50
50
|
self.state.cgc.add_sinkhole(cgc_flag_page_start_addr + 0x1000, sinkhole_size)
|
|
51
51
|
|
|
52
|
-
chosen =
|
|
52
|
+
chosen = claripy.BVV(cgc_flag_page_start_addr - aligned_length, self.state.arch.bits)
|
|
53
53
|
elif chosen_conc <= self.state.project.loader.max_addr < allocation_base_conc:
|
|
54
54
|
# Chosen memory overlaps with some loaded object
|
|
55
55
|
sinkhole_size = allocation_base_conc - self.state.project.loader.max_addr
|
|
56
56
|
if sinkhole_size != 0:
|
|
57
57
|
self.state.cgc.add_sinkhole(self.state.project.loader.max_addr, sinkhole_size)
|
|
58
58
|
|
|
59
|
-
chosen = self.state.
|
|
60
|
-
self.state.project.loader.min_addr - aligned_length, self.state.arch.bits
|
|
61
|
-
)
|
|
59
|
+
chosen = claripy.BVV(self.state.project.loader.min_addr - aligned_length, self.state.arch.bits)
|
|
62
60
|
|
|
63
61
|
self.state.cgc.allocation_base = chosen
|
|
64
62
|
|
|
65
63
|
self.state.memory.store(
|
|
66
|
-
addr, chosen, size=self.state.arch.bytes, condition=
|
|
64
|
+
addr, chosen, size=self.state.arch.bytes, condition=claripy.And(addr != 0), endness="Iend_LE"
|
|
67
65
|
)
|
|
68
66
|
|
|
69
67
|
# PROT_READ | PROT_WRITE default
|
|
70
|
-
permissions =
|
|
71
|
-
permissions |=
|
|
68
|
+
permissions = claripy.BVV(1 | 2, 3)
|
|
69
|
+
permissions |= claripy.If(is_x != 0, claripy.BVV(4, 3), claripy.BVV(0, 3))
|
|
72
70
|
|
|
73
71
|
chosen_conc = self.state.solver.eval(chosen)
|
|
74
72
|
l.debug("Allocating [%#x, %#x]", chosen_conc, chosen_conc + aligned_length - 1)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
import claripy
|
|
3
4
|
from unique_log_filter import UniqueLogFilter
|
|
4
5
|
|
|
5
6
|
import angr
|
|
7
|
+
from angr.state_plugins.sim_action_object import SimActionObject
|
|
6
8
|
|
|
7
9
|
l = logging.getLogger(name=__name__)
|
|
8
10
|
l.addFilter(UniqueLogFilter())
|
|
@@ -11,16 +13,21 @@ l.addFilter(UniqueLogFilter())
|
|
|
11
13
|
class deallocate(angr.SimProcedure):
|
|
12
14
|
# pylint:disable=arguments-differ
|
|
13
15
|
|
|
14
|
-
def run(self, addr, length):
|
|
16
|
+
def run(self, addr, length):
|
|
17
|
+
if isinstance(addr, SimActionObject):
|
|
18
|
+
addr = addr.ast
|
|
19
|
+
if isinstance(length, SimActionObject):
|
|
20
|
+
length = length.ast
|
|
21
|
+
|
|
15
22
|
# return code (see deallocate() docs)
|
|
16
|
-
r =
|
|
23
|
+
r = claripy.ite_cases(
|
|
17
24
|
(
|
|
18
25
|
(addr % 0x1000 != 0, self.state.cgc.EINVAL),
|
|
19
26
|
(length == 0, self.state.cgc.EINVAL),
|
|
20
27
|
(self.state.cgc.addr_invalid(addr), self.state.cgc.EINVAL),
|
|
21
28
|
(self.state.cgc.addr_invalid(addr + length), self.state.cgc.EINVAL),
|
|
22
29
|
),
|
|
23
|
-
|
|
30
|
+
claripy.BVV(0, self.state.arch.bits),
|
|
24
31
|
)
|
|
25
32
|
|
|
26
33
|
if self.state.solver.symbolic(addr):
|
angr/procedures/cgc/fdwait.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import angr
|
|
2
|
-
|
|
3
1
|
import itertools
|
|
4
2
|
|
|
3
|
+
import claripy
|
|
4
|
+
|
|
5
|
+
import angr
|
|
6
|
+
|
|
5
7
|
fdcount = itertools.count()
|
|
6
8
|
|
|
7
9
|
|
|
@@ -10,42 +12,42 @@ class fdwait(angr.SimProcedure):
|
|
|
10
12
|
|
|
11
13
|
def run(self, nfds, readfds, writefds, timeout, readyfds):
|
|
12
14
|
run_count = next(fdcount)
|
|
13
|
-
total_ready =
|
|
15
|
+
total_ready = claripy.BVV(0, self.state.arch.bits)
|
|
14
16
|
|
|
15
17
|
read_fds = []
|
|
16
18
|
for fd_set in range(0, 32, 8):
|
|
17
19
|
sym_newbits = []
|
|
18
20
|
for fd in range(fd_set, fd_set + 8):
|
|
19
21
|
if angr.options.CGC_NON_BLOCKING_FDS in self.state.options:
|
|
20
|
-
sym_bit =
|
|
22
|
+
sym_bit = claripy.BVV(1, 1)
|
|
21
23
|
else:
|
|
22
24
|
sym_bit = self.state.solver.Unconstrained(
|
|
23
25
|
"fdwait_read_%d_%d" % (run_count, fd), 1, key=("syscall", "fdwait", fd, "read_ready")
|
|
24
26
|
)
|
|
25
|
-
fd =
|
|
26
|
-
sym_newbit =
|
|
27
|
+
fd = claripy.BVV(fd, self.state.arch.bits)
|
|
28
|
+
sym_newbit = claripy.If(claripy.ULT(fd, nfds), sym_bit, 0)
|
|
27
29
|
total_ready += sym_newbit.zero_extend(self.state.arch.bits - 1)
|
|
28
30
|
sym_newbits.append(sym_newbit)
|
|
29
31
|
read_fds.extend(reversed(sym_newbits))
|
|
30
|
-
self.state.memory.store(readfds,
|
|
32
|
+
self.state.memory.store(readfds, claripy.Concat(*read_fds), condition=readfds != 0)
|
|
31
33
|
|
|
32
34
|
write_fds = []
|
|
33
35
|
for fd_set in range(0, 32, 8):
|
|
34
36
|
sym_newbits = []
|
|
35
37
|
for fd in range(fd_set, fd_set + 8):
|
|
36
38
|
if angr.options.CGC_NON_BLOCKING_FDS in self.state.options:
|
|
37
|
-
sym_bit =
|
|
39
|
+
sym_bit = claripy.BVV(1, 1)
|
|
38
40
|
else:
|
|
39
41
|
sym_bit = self.state.solver.Unconstrained(
|
|
40
42
|
"fdwait_write_%d_%d" % (run_count, fd), 1, key=("syscall", "fdwait", fd, "write_ready")
|
|
41
43
|
)
|
|
42
44
|
|
|
43
|
-
fd =
|
|
44
|
-
sym_newbit =
|
|
45
|
+
fd = claripy.BVV(fd, self.state.arch.bits)
|
|
46
|
+
sym_newbit = claripy.If(claripy.ULT(fd, nfds), sym_bit, 0)
|
|
45
47
|
total_ready += sym_newbit.zero_extend(self.state.arch.bits - 1)
|
|
46
48
|
sym_newbits.append(sym_newbit)
|
|
47
49
|
write_fds.extend(reversed(sym_newbits))
|
|
48
|
-
self.state.memory.store(writefds,
|
|
50
|
+
self.state.memory.store(writefds, claripy.Concat(*write_fds), condition=writefds != 0)
|
|
49
51
|
|
|
50
52
|
self.state.memory.store(readyfds, total_ready, endness="Iend_LE", condition=readyfds != 0)
|
|
51
53
|
|
|
@@ -56,7 +58,7 @@ class fdwait(angr.SimProcedure):
|
|
|
56
58
|
timeout + 4, 4, endness=self.state.arch.memory_endness, condition=timeout != 0, fallback=0
|
|
57
59
|
)
|
|
58
60
|
total_time = tv_sec * 1000000 + tv_usec
|
|
59
|
-
self.state.cgc.time +=
|
|
61
|
+
self.state.cgc.time += claripy.If(total_ready == 0, total_time, 0)
|
|
60
62
|
|
|
61
63
|
# TODO: errors
|
|
62
|
-
return
|
|
64
|
+
return claripy.BVV(0, self.state.arch.bits)
|