angr 9.2.125__py3-none-win_amd64.whl → 9.2.126__py3-none-win_amd64.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/analyses/__init__.py +4 -0
- angr/analyses/decompiler/ail_simplifier.py +1 -0
- angr/analyses/decompiler/callsite_maker.py +9 -1
- angr/analyses/decompiler/clinic.py +1 -1
- angr/analyses/decompiler/condition_processor.py +104 -66
- angr/analyses/decompiler/decompiler.py +3 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +15 -1
- angr/analyses/decompiler/return_maker.py +1 -0
- angr/analyses/decompiler/ssailification/rewriting.py +4 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +10 -3
- angr/analyses/decompiler/structured_codegen/c.py +18 -2
- angr/analyses/deobfuscator/__init__.py +18 -0
- angr/analyses/deobfuscator/api_obf_finder.py +313 -0
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +51 -0
- angr/analyses/deobfuscator/irsb_reg_collector.py +85 -0
- angr/analyses/deobfuscator/string_obf_finder.py +774 -0
- angr/analyses/deobfuscator/string_obf_opt_passes.py +133 -0
- angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +47 -0
- angr/analyses/reaching_definitions/function_handler_library/stdio.py +8 -1
- angr/analyses/unpacker/__init__.py +6 -0
- angr/analyses/unpacker/obfuscation_detector.py +103 -0
- angr/analyses/unpacker/packing_detector.py +138 -0
- angr/calling_conventions.py +3 -1
- angr/engines/vex/claripy/irop.py +10 -5
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/obfuscations.py +36 -0
- angr/lib/angr_native.dll +0 -0
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/METADATA +6 -6
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/RECORD +34 -23
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/WHEEL +1 -1
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/LICENSE +0 -0
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/entry_points.txt +0 -0
- {angr-9.2.125.dist-info → angr-9.2.126.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/__init__.py
CHANGED
|
@@ -53,6 +53,8 @@ from .codecave import CodeCaveAnalysis
|
|
|
53
53
|
from .patchfinder import PatchFinderAnalysis
|
|
54
54
|
from .pathfinder import Pathfinder
|
|
55
55
|
from .smc import SelfModifyingCodeAnalysis
|
|
56
|
+
from .unpacker import PackingDetector
|
|
57
|
+
from . import deobfuscator
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
__all__ = (
|
|
@@ -109,4 +111,6 @@ __all__ = (
|
|
|
109
111
|
"PatchFinderAnalysis",
|
|
110
112
|
"Pathfinder",
|
|
111
113
|
"SelfModifyingCodeAnalysis",
|
|
114
|
+
"PackingDetector",
|
|
115
|
+
"deobfuscator",
|
|
112
116
|
)
|
|
@@ -872,6 +872,7 @@ class AILSimplifier(Analysis):
|
|
|
872
872
|
Const(None, None, eq.atom0.addr, self.project.arch.bits),
|
|
873
873
|
eq.atom0.size,
|
|
874
874
|
endness=self.project.arch.memory_endness,
|
|
875
|
+
**eq.atom1.tags,
|
|
875
876
|
)
|
|
876
877
|
elif isinstance(eq.atom0, VirtualVariable) and eq.atom0.was_reg:
|
|
877
878
|
if isinstance(eq.atom1, VirtualVariable) and eq.atom1.was_reg:
|
|
@@ -157,7 +157,15 @@ class CallSiteMaker(Analysis):
|
|
|
157
157
|
)
|
|
158
158
|
args.append(vvar_use)
|
|
159
159
|
else:
|
|
160
|
-
|
|
160
|
+
reg = Expr.Register(
|
|
161
|
+
self._atom_idx(),
|
|
162
|
+
None,
|
|
163
|
+
offset,
|
|
164
|
+
size * 8,
|
|
165
|
+
reg_name=arg_loc.reg_name,
|
|
166
|
+
ins_addr=last_stmt.ins_addr,
|
|
167
|
+
)
|
|
168
|
+
args.append(reg)
|
|
161
169
|
elif isinstance(arg_loc, SimStackArg):
|
|
162
170
|
stack_arg_locs.append(arg_loc)
|
|
163
171
|
_, the_arg = self._resolve_stack_argument(call_stmt, arg_loc)
|
|
@@ -1812,7 +1812,7 @@ class Clinic(Analysis):
|
|
|
1812
1812
|
s = self.kb.custom_strings[expr.value]
|
|
1813
1813
|
expr.tags["reference_values"] = {
|
|
1814
1814
|
SimTypePointer(SimTypeChar().with_arch(self.project.arch)).with_arch(self.project.arch): s.decode(
|
|
1815
|
-
"
|
|
1815
|
+
"latin-1"
|
|
1816
1816
|
),
|
|
1817
1817
|
}
|
|
1818
1818
|
else:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from collections import defaultdict, OrderedDict
|
|
3
3
|
from typing import Any
|
|
4
|
+
from collections.abc import Callable
|
|
4
5
|
from collections.abc import Generator
|
|
5
6
|
import operator
|
|
6
7
|
import logging
|
|
@@ -80,17 +81,17 @@ _INVERSE_OPERATIONS = {
|
|
|
80
81
|
#
|
|
81
82
|
|
|
82
83
|
|
|
83
|
-
def _op_with_unified_size(op, conv, operand0, operand1):
|
|
84
|
+
def _op_with_unified_size(op, conv: Callable, operand0, operand1, ins_addr: int):
|
|
84
85
|
# ensure operand1 is of the same size as operand0
|
|
85
86
|
if isinstance(operand1, ailment.Expr.Const):
|
|
86
87
|
# amazing - we do the easy thing here
|
|
87
|
-
return op(conv(operand0, nobool=True), operand1.value)
|
|
88
|
+
return op(conv(operand0, nobool=True, ins_addr=ins_addr), operand1.value)
|
|
88
89
|
if operand1.bits == operand0.bits:
|
|
89
|
-
return op(conv(operand0, nobool=True), conv(operand1))
|
|
90
|
+
return op(conv(operand0, nobool=True, ins_addr=ins_addr), conv(operand1, ins_addr=ins_addr))
|
|
90
91
|
# extension is required
|
|
91
92
|
assert operand1.bits < operand0.bits
|
|
92
93
|
operand1 = ailment.Expr.Convert(None, operand1.bits, operand0.bits, False, operand1)
|
|
93
|
-
return op(conv(operand0, nobool=True), conv(operand1, nobool=True))
|
|
94
|
+
return op(conv(operand0, nobool=True, ins_addr=ins_addr), conv(operand1, nobool=True, ins_addr=ins_addr))
|
|
94
95
|
|
|
95
96
|
|
|
96
97
|
def _dummy_bvs(condition, condition_mapping, name_suffix=""):
|
|
@@ -106,62 +107,94 @@ def _dummy_bools(condition, condition_mapping, name_suffix=""):
|
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
_ail2claripy_op_mapping = {
|
|
109
|
-
"LogicalAnd": lambda expr, conv, _: claripy.And(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
|
|
110
|
+
"LogicalAnd": lambda expr, conv, _, ia: claripy.And(
|
|
111
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
112
|
+
),
|
|
113
|
+
"LogicalOr": lambda expr, conv, _, ia: claripy.Or(
|
|
114
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
115
|
+
),
|
|
116
|
+
"CmpEQ": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) == conv(expr.operands[1], ins_addr=ia),
|
|
117
|
+
"CmpNE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) != conv(expr.operands[1], ins_addr=ia),
|
|
118
|
+
"CmpLE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) <= conv(expr.operands[1], ins_addr=ia),
|
|
119
|
+
"CmpLEs": lambda expr, conv, _, ia: claripy.SLE(
|
|
120
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
121
|
+
),
|
|
122
|
+
"CmpLT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) < conv(expr.operands[1], ins_addr=ia),
|
|
123
|
+
"CmpLTs": lambda expr, conv, _, ia: claripy.SLT(
|
|
124
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
125
|
+
),
|
|
126
|
+
"CmpGE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) >= conv(expr.operands[1], ins_addr=ia),
|
|
127
|
+
"CmpGEs": lambda expr, conv, _, ia: claripy.SGE(
|
|
128
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
129
|
+
),
|
|
130
|
+
"CmpGT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) > conv(expr.operands[1], ins_addr=ia),
|
|
131
|
+
"CmpGTs": lambda expr, conv, _, ia: claripy.SGT(
|
|
132
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
133
|
+
),
|
|
134
|
+
"CasCmpEQ": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) == conv(expr.operands[1], ins_addr=ia),
|
|
135
|
+
"CasCmpNE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) != conv(expr.operands[1], ins_addr=ia),
|
|
136
|
+
"CasCmpLE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) <= conv(expr.operands[1], ins_addr=ia),
|
|
137
|
+
"CasCmpLEs": lambda expr, conv, _, ia: claripy.SLE(
|
|
138
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
139
|
+
),
|
|
140
|
+
"CasCmpLT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) < conv(expr.operands[1], ins_addr=ia),
|
|
141
|
+
"CasCmpLTs": lambda expr, conv, _, ia: claripy.SLT(
|
|
142
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
143
|
+
),
|
|
144
|
+
"CasCmpGE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) >= conv(expr.operands[1], ins_addr=ia),
|
|
145
|
+
"CasCmpGEs": lambda expr, conv, _, ia: claripy.SGE(
|
|
146
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
147
|
+
),
|
|
148
|
+
"CasCmpGT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) > conv(expr.operands[1], ins_addr=ia),
|
|
149
|
+
"CasCmpGTs": lambda expr, conv, _, ia: claripy.SGT(
|
|
150
|
+
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
151
|
+
),
|
|
152
|
+
"Add": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
153
|
+
+ conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
154
|
+
"Sub": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
155
|
+
- conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
156
|
+
"Mul": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
157
|
+
* conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
158
|
+
"Div": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
159
|
+
/ conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
160
|
+
"Mod": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
161
|
+
% conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
162
|
+
"Not": lambda expr, conv, _, ia: claripy.Not(conv(expr.operand, ins_addr=ia)),
|
|
163
|
+
"Neg": lambda expr, conv, _, ia: -conv(expr.operand, ins_addr=ia),
|
|
164
|
+
"BitwiseNeg": lambda expr, conv, _, ia: ~conv(expr.operand, ins_addr=ia),
|
|
165
|
+
"Xor": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
166
|
+
^ conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
167
|
+
"And": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
168
|
+
& conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
169
|
+
"Or": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
170
|
+
| conv(expr.operands[1], nobool=True, ins_addr=ia),
|
|
171
|
+
"Shr": lambda expr, conv, _, ia: _op_with_unified_size(claripy.LShR, conv, expr.operands[0], expr.operands[1], ia),
|
|
172
|
+
"Shl": lambda expr, conv, _, ia: _op_with_unified_size(
|
|
173
|
+
operator.lshift, conv, expr.operands[0], expr.operands[1], ia
|
|
174
|
+
),
|
|
175
|
+
"Sar": lambda expr, conv, _, ia: _op_with_unified_size(
|
|
176
|
+
operator.rshift, conv, expr.operands[0], expr.operands[1], ia
|
|
177
|
+
),
|
|
178
|
+
"Concat": lambda expr, conv, _, ia: claripy.Concat(*[conv(operand, ins_addr=ia) for operand in expr.operands]),
|
|
146
179
|
# There are no corresponding claripy operations for the following operations
|
|
147
|
-
"DivMod": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
148
|
-
"CmpF": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
149
|
-
"Mull": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
150
|
-
"Mulls": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
151
|
-
"Reinterpret": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
152
|
-
"Rol": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
153
|
-
"Ror": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
154
|
-
"LogicalXor": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
155
|
-
"Carry": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
156
|
-
"SCarry": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
157
|
-
"SBorrow": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
158
|
-
"ExpCmpNE": lambda expr, _, m: _dummy_bools(expr, m),
|
|
159
|
-
"CmpORD": lambda expr, _, m: _dummy_bvs(expr, m), # in case CmpORDRewriter fails
|
|
160
|
-
"GetMSBs": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
161
|
-
"InterleaveLOV": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
162
|
-
"InterleaveHIV": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
180
|
+
"DivMod": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
181
|
+
"CmpF": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
182
|
+
"Mull": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
183
|
+
"Mulls": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
184
|
+
"Reinterpret": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
185
|
+
"Rol": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
186
|
+
"Ror": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
187
|
+
"LogicalXor": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
188
|
+
"Carry": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
189
|
+
"SCarry": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
190
|
+
"SBorrow": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
191
|
+
"ExpCmpNE": lambda expr, _, m, *args: _dummy_bools(expr, m),
|
|
192
|
+
"CmpORD": lambda expr, _, m, *args: _dummy_bvs(expr, m), # in case CmpORDRewriter fails
|
|
193
|
+
"GetMSBs": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
194
|
+
"InterleaveLOV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
195
|
+
"InterleaveHIV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
163
196
|
# catch-all
|
|
164
|
-
"_DUMMY_": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
197
|
+
"_DUMMY_": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
165
198
|
}
|
|
166
199
|
|
|
167
200
|
#
|
|
@@ -610,6 +643,7 @@ class ConditionProcessor:
|
|
|
610
643
|
),
|
|
611
644
|
False,
|
|
612
645
|
),
|
|
646
|
+
ins_addr=dst_block.addr,
|
|
613
647
|
)
|
|
614
648
|
|
|
615
649
|
if type(src_block) is ConditionalBreakNode:
|
|
@@ -638,10 +672,10 @@ class ConditionProcessor:
|
|
|
638
672
|
if isinstance(last_stmt.target, ailment.Expr.Const):
|
|
639
673
|
return claripy.true()
|
|
640
674
|
# indirect jump
|
|
641
|
-
target_ast = self.claripy_ast_from_ail_condition(last_stmt.target)
|
|
675
|
+
target_ast = self.claripy_ast_from_ail_condition(last_stmt.target, ins_addr=last_stmt.ins_addr)
|
|
642
676
|
return target_ast == dst_block.addr
|
|
643
677
|
if type(last_stmt) is ailment.Stmt.ConditionalJump:
|
|
644
|
-
bool_var = self.claripy_ast_from_ail_condition(last_stmt.condition)
|
|
678
|
+
bool_var = self.claripy_ast_from_ail_condition(last_stmt.condition, ins_addr=last_stmt.ins_addr)
|
|
645
679
|
if isinstance(last_stmt.true_target, ailment.Expr.Const) and last_stmt.true_target.value == dst_block.addr:
|
|
646
680
|
return bool_var
|
|
647
681
|
return claripy.Not(bool_var)
|
|
@@ -766,7 +800,7 @@ class ConditionProcessor:
|
|
|
766
800
|
f"Condition variable {cond} has an unsupported operator {cond.op}. Consider implementing."
|
|
767
801
|
)
|
|
768
802
|
|
|
769
|
-
def claripy_ast_from_ail_condition(self, condition, nobool: bool = False) -> claripy.ast.Bool:
|
|
803
|
+
def claripy_ast_from_ail_condition(self, condition, nobool: bool = False, *, ins_addr: int = 0) -> claripy.ast.Bool:
|
|
770
804
|
# Unpack a condition all the way to the leaves
|
|
771
805
|
if isinstance(condition, claripy.ast.Base): # pylint:disable=isinstance-second-argument-not-valid-type
|
|
772
806
|
return condition
|
|
@@ -782,20 +816,24 @@ class ConditionProcessor:
|
|
|
782
816
|
# does it have a variable associated?
|
|
783
817
|
if condition.variable is not None:
|
|
784
818
|
var = claripy.BVS(
|
|
785
|
-
f"ailexpr_{condition!r}-{condition.variable.ident}",
|
|
819
|
+
f"ailexpr_{condition!r}-{condition.variable.ident}-{ins_addr:x}",
|
|
820
|
+
condition.bits,
|
|
821
|
+
explicit_name=True,
|
|
786
822
|
)
|
|
787
823
|
else:
|
|
788
|
-
var = claripy.BVS(
|
|
824
|
+
var = claripy.BVS(
|
|
825
|
+
f"ailexpr_{condition!r}-{condition.idx}-{ins_addr:x}", condition.bits, explicit_name=True
|
|
826
|
+
)
|
|
789
827
|
self._condition_mapping[var.args[0]] = condition
|
|
790
828
|
return var
|
|
791
829
|
if isinstance(condition, ailment.Expr.Convert):
|
|
792
830
|
# convert is special. if it generates a 1-bit variable, it should be treated as a BoolS
|
|
793
831
|
if condition.to_bits == 1:
|
|
794
|
-
var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
|
|
832
|
+
var_ = self.claripy_ast_from_ail_condition(condition.operands[0], ins_addr=ins_addr)
|
|
795
833
|
name = "ailcond_Conv(%d->%d, %d)" % (condition.from_bits, condition.to_bits, hash(var_))
|
|
796
834
|
var = claripy.BoolS(name, explicit_name=True)
|
|
797
835
|
else:
|
|
798
|
-
var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
|
|
836
|
+
var_ = self.claripy_ast_from_ail_condition(condition.operands[0], ins_addr=ins_addr)
|
|
799
837
|
name = "ailexpr_Conv(%d->%d, %d)" % (condition.from_bits, condition.to_bits, hash(var_))
|
|
800
838
|
var = claripy.BVS(name, condition.to_bits, explicit_name=True)
|
|
801
839
|
self._condition_mapping[var.args[0]] = condition
|
|
@@ -838,7 +876,7 @@ class ConditionProcessor:
|
|
|
838
876
|
condition.verbose_op,
|
|
839
877
|
)
|
|
840
878
|
lambda_expr = _ail2claripy_op_mapping["_DUMMY_"]
|
|
841
|
-
r = lambda_expr(condition, self.claripy_ast_from_ail_condition, self._condition_mapping)
|
|
879
|
+
r = lambda_expr(condition, self.claripy_ast_from_ail_condition, self._condition_mapping, ins_addr)
|
|
842
880
|
|
|
843
881
|
if isinstance(r, claripy.ast.Bool) and nobool:
|
|
844
882
|
r = claripy.BVS(f"ailexpr_from_bool_{r!r}", 1, explicit_name=True)
|
|
@@ -70,6 +70,7 @@ class Decompiler(Analysis):
|
|
|
70
70
|
update_memory_data: bool = True,
|
|
71
71
|
generate_code: bool = True,
|
|
72
72
|
use_cache: bool = True,
|
|
73
|
+
expr_collapse_depth: int = 16,
|
|
73
74
|
):
|
|
74
75
|
if not isinstance(func, Function):
|
|
75
76
|
func = self.kb.functions[func]
|
|
@@ -135,6 +136,7 @@ class Decompiler(Analysis):
|
|
|
135
136
|
self.ail_graph: networkx.DiGraph | None = None
|
|
136
137
|
self.vvar_id_start = None
|
|
137
138
|
self._optimization_scratch: dict[str, Any] = {}
|
|
139
|
+
self.expr_collapse_depth = expr_collapse_depth
|
|
138
140
|
|
|
139
141
|
if decompile:
|
|
140
142
|
self._decompile()
|
|
@@ -333,6 +335,7 @@ class Decompiler(Analysis):
|
|
|
333
335
|
stmt_comments=old_codegen.stmt_comments if old_codegen is not None else None,
|
|
334
336
|
const_formats=old_codegen.const_formats if old_codegen is not None else None,
|
|
335
337
|
externs=clinic.externs,
|
|
338
|
+
binop_depth_cutoff=self.expr_collapse_depth,
|
|
336
339
|
**self.options_to_params(self.options_by_class["codegen"]),
|
|
337
340
|
)
|
|
338
341
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint:disable=import-outside-toplevel
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
|
|
4
5
|
from archinfo import Arch
|
|
5
6
|
|
|
@@ -32,6 +33,10 @@ from .const_prop_reverter import ConstPropOptReverter
|
|
|
32
33
|
from .call_stmt_rewriter import CallStatementRewriter
|
|
33
34
|
from .duplication_reverter import DuplicationReverter
|
|
34
35
|
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from angr.analyses.decompiler.presets import DecompilationPreset
|
|
38
|
+
|
|
39
|
+
|
|
35
40
|
# order matters!
|
|
36
41
|
ALL_OPTIMIZATION_PASSES = [
|
|
37
42
|
RegisterSaveAreaSimplifier,
|
|
@@ -88,9 +93,18 @@ def get_optimization_passes(arch, platform):
|
|
|
88
93
|
return passes
|
|
89
94
|
|
|
90
95
|
|
|
91
|
-
def register_optimization_pass(opt_pass):
|
|
96
|
+
def register_optimization_pass(opt_pass, *, presets: list[str | DecompilationPreset] | None = None):
|
|
92
97
|
ALL_OPTIMIZATION_PASSES.append(opt_pass)
|
|
93
98
|
|
|
99
|
+
if presets:
|
|
100
|
+
from angr.analyses.decompiler.presets import DECOMPILATION_PRESETS
|
|
101
|
+
|
|
102
|
+
for preset in presets:
|
|
103
|
+
if isinstance(preset, str):
|
|
104
|
+
preset = DECOMPILATION_PRESETS[preset] # intentionally raise a KeyError if the preset is not found
|
|
105
|
+
if opt_pass not in preset.opt_passes:
|
|
106
|
+
preset.opt_passes.append(opt_pass)
|
|
107
|
+
|
|
94
108
|
|
|
95
109
|
__all__ = (
|
|
96
110
|
"OptimizationPassStage",
|
|
@@ -119,6 +119,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
119
119
|
self._ail_manager.next_atom(),
|
|
120
120
|
reg_bits,
|
|
121
121
|
src_and_vvars=[], # back patch later
|
|
122
|
+
ins_addr=node.addr,
|
|
122
123
|
)
|
|
123
124
|
phi_dst = VirtualVariable(
|
|
124
125
|
self._ail_manager.next_atom(),
|
|
@@ -126,6 +127,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
126
127
|
reg_bits,
|
|
127
128
|
VirtualVariableCategory.REGISTER,
|
|
128
129
|
oident=reg_offset,
|
|
130
|
+
ins_addr=node.addr,
|
|
129
131
|
)
|
|
130
132
|
|
|
131
133
|
case "stack":
|
|
@@ -135,6 +137,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
135
137
|
self._ail_manager.next_atom(),
|
|
136
138
|
stack_size * self.project.arch.byte_width,
|
|
137
139
|
src_and_vvars=[], # back patch later
|
|
140
|
+
ins_addr=node.addr,
|
|
138
141
|
)
|
|
139
142
|
phi_dst = VirtualVariable(
|
|
140
143
|
self._ail_manager.next_atom(),
|
|
@@ -142,6 +145,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
142
145
|
stack_size * self.project.arch.byte_width,
|
|
143
146
|
VirtualVariableCategory.STACK,
|
|
144
147
|
oident=stack_offset,
|
|
148
|
+
ins_addr=node.addr,
|
|
145
149
|
)
|
|
146
150
|
case _:
|
|
147
151
|
raise NotImplementedError
|
|
@@ -525,7 +525,7 @@ class SimEngineSSARewriting(
|
|
|
525
525
|
**expr.tags,
|
|
526
526
|
)
|
|
527
527
|
|
|
528
|
-
def _get_full_reg_vvar(self, reg_offset: int, size: int) -> VirtualVariable:
|
|
528
|
+
def _get_full_reg_vvar(self, reg_offset: int, size: int, ins_addr: int | None = None) -> VirtualVariable:
|
|
529
529
|
base_off, base_size = get_reg_offset_base_and_size(reg_offset, self.arch, size=size)
|
|
530
530
|
if (
|
|
531
531
|
base_off not in self.state.registers
|
|
@@ -534,13 +534,16 @@ class SimEngineSSARewriting(
|
|
|
534
534
|
):
|
|
535
535
|
# somehow it's never defined before...
|
|
536
536
|
_l.debug("Creating a new virtual variable for an undefined register (%d [%d]).", base_off, base_size)
|
|
537
|
+
tags = {}
|
|
538
|
+
if ins_addr is not None:
|
|
539
|
+
tags["ins_addr"] = ins_addr
|
|
537
540
|
vvar = VirtualVariable(
|
|
538
541
|
self.ail_manager.next_atom(),
|
|
539
542
|
self.next_vvar_id(),
|
|
540
543
|
base_size * self.arch.byte_width,
|
|
541
544
|
category=VirtualVariableCategory.REGISTER,
|
|
542
545
|
oident=base_off,
|
|
543
|
-
|
|
546
|
+
**tags,
|
|
544
547
|
)
|
|
545
548
|
self.state.registers[base_off][base_size] = vvar
|
|
546
549
|
return vvar
|
|
@@ -628,7 +631,11 @@ class SimEngineSSARewriting(
|
|
|
628
631
|
|
|
629
632
|
# no good size available
|
|
630
633
|
# get the full register, then extract from there
|
|
631
|
-
vvar = self._get_full_reg_vvar(
|
|
634
|
+
vvar = self._get_full_reg_vvar(
|
|
635
|
+
reg_expr.reg_offset,
|
|
636
|
+
reg_expr.size,
|
|
637
|
+
ins_addr=reg_expr.ins_addr,
|
|
638
|
+
)
|
|
632
639
|
# extract
|
|
633
640
|
shift_amount = Const(
|
|
634
641
|
self.ail_manager.next_atom(),
|
|
@@ -2148,6 +2148,12 @@ class CConstant(CExpression):
|
|
|
2148
2148
|
elif isinstance(v, Function):
|
|
2149
2149
|
yield get_cpp_function_name(v.demangled_name, specialized=False, qualified=True), self
|
|
2150
2150
|
return
|
|
2151
|
+
elif isinstance(v, str):
|
|
2152
|
+
yield CConstant.str_to_c_str(v), self
|
|
2153
|
+
return
|
|
2154
|
+
elif isinstance(v, bytes):
|
|
2155
|
+
yield CConstant.str_to_c_str(v.replace(b"\x00", b"").decode("utf-8")), self
|
|
2156
|
+
return
|
|
2151
2157
|
|
|
2152
2158
|
if self.reference_values is not None and self._type is not None and self._type in self.reference_values:
|
|
2153
2159
|
if isinstance(self._type, SimTypeInt):
|
|
@@ -3415,7 +3421,17 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3415
3421
|
if reference_values is None:
|
|
3416
3422
|
reference_values = {}
|
|
3417
3423
|
type_ = unpack_typeref(type_)
|
|
3418
|
-
if
|
|
3424
|
+
if expr.value in self.kb.obfuscations.type1_deobfuscated_strings:
|
|
3425
|
+
reference_values[SimTypePointer(SimTypeChar())] = self.kb.obfuscations.type1_deobfuscated_strings[
|
|
3426
|
+
expr.value
|
|
3427
|
+
]
|
|
3428
|
+
inline_string = True
|
|
3429
|
+
elif expr.value in self.kb.obfuscations.type2_deobfuscated_strings:
|
|
3430
|
+
reference_values[SimTypePointer(SimTypeChar())] = self.kb.obfuscations.type2_deobfuscated_strings[
|
|
3431
|
+
expr.value
|
|
3432
|
+
]
|
|
3433
|
+
inline_string = True
|
|
3434
|
+
elif isinstance(type_, SimTypePointer) and isinstance(type_.pts_to, SimTypeChar):
|
|
3419
3435
|
# char*
|
|
3420
3436
|
# Try to get a string
|
|
3421
3437
|
if (
|
|
@@ -3433,7 +3449,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3433
3449
|
# edge cases: (void*)"this is a constant string pointer". in this case, the type_ will be a void*
|
|
3434
3450
|
# (BOT*) instead of a char*.
|
|
3435
3451
|
|
|
3436
|
-
if isinstance(expr.value, int):
|
|
3452
|
+
if not reference_values and isinstance(expr.value, int):
|
|
3437
3453
|
if expr.value in self.project.kb.functions:
|
|
3438
3454
|
# It's a function pointer
|
|
3439
3455
|
# We don't care about the actual prototype here
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# deobfuscator is a collection of analyses that automatically identifies functions where obfuscation techniques are
|
|
2
|
+
# in-use.
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .string_obf_finder import StringObfuscationFinder
|
|
6
|
+
from .string_obf_peephole_optimizer import StringObfType1PeepholeOptimizer
|
|
7
|
+
from .string_obf_opt_passes import StringObfType3Rewriter
|
|
8
|
+
from .api_obf_finder import APIObfuscationFinder
|
|
9
|
+
from .api_obf_peephole_optimizer import APIObfType1PeepholeOptimizer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = (
|
|
13
|
+
"StringObfuscationFinder",
|
|
14
|
+
"StringObfType1PeepholeOptimizer",
|
|
15
|
+
"StringObfType3Rewriter",
|
|
16
|
+
"APIObfuscationFinder",
|
|
17
|
+
"APIObfType1PeepholeOptimizer",
|
|
18
|
+
)
|