valysis 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- valysis-1.0.0/LICENSE +21 -0
- valysis-1.0.0/PKG-INFO +225 -0
- valysis-1.0.0/README.md +209 -0
- valysis-1.0.0/pyproject.toml +25 -0
- valysis-1.0.0/src/valysis/__init__.py +21 -0
- valysis-1.0.0/src/valysis/common.py +12 -0
- valysis-1.0.0/src/valysis/dual_interval.py +173 -0
- valysis-1.0.0/src/valysis/intervals.py +846 -0
- valysis-1.0.0/src/valysis/memory.py +334 -0
- valysis-1.0.0/src/valysis/product.py +285 -0
- valysis-1.0.0/src/valysis/tristate.py +173 -0
valysis-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [year] [fullname]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
valysis-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: valysis
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A platform/hardware agnostic Value Set Analysis (VSA) library for Reverse Engineering tools.
|
|
5
|
+
Author-email: nulsie <donotmailme@mail.com>
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Topic :: Security
|
|
10
|
+
Classifier: Topic :: Software Development :: Disassemblers
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Project-URL: Codeberg, https://codeberg.org/nulsie/valysis
|
|
13
|
+
Project-URL: GitHub, https://github.com/nulsie/valysis
|
|
14
|
+
Project-URL: Homepage, https://codeberg.org/nulsie/valysis
|
|
15
|
+
|
|
16
|
+
valysis - a VSA library for Python
|
|
17
|
+
|
|
18
|
+
There is a distinct lack of dedicated VSA(Value Set Analysis) libraries in Python, like literally, there is none. You woud say that
|
|
19
|
+
there are things like Angr, but they are not dedicated for VSA, but as large frameworks for building or basing entire RE tools, As i was
|
|
20
|
+
trying to make a IR(Intermediate Representation) based static analysis RE tool in Python a while ago, i found the issue, and as it is commonly known,
|
|
21
|
+
creating entire VSA engines and CFGs from scratch are notoriously difficult if not impossible and litearly there was no dedicated VSA library
|
|
22
|
+
available. So i made an entire fully functional precision-focused library dedicated just for VSA from scratch and arguably the first in Python, and that is *valysis*.
|
|
23
|
+
|
|
24
|
+
valysis is decoupled from any specific instruction set architecture or Intermediate Representation (IR). It provides a sound, flexible backend domain engine which is superior in precision rate than Angr(from the tests I've done in a short-term)^^ that can be attached to
|
|
25
|
+
Ghidra PCODE, IDA Microcode, Triton ASTs, Binary Ninja LLIL/MLIL, or custom emulation lifters. To preserve precision across mixed
|
|
26
|
+
arithmetic-bitwise code, the lib combines Circular Strided Interval(better than the usual standard of using the less precision-focused Strided Interval) with Tristate BitVectors via mutual reduction. Then it natively supports arbitrary bit-widths (8, 16, 32, 64, 128bits) per variable.
|
|
27
|
+
And also accurately tracks `signed` and `unsigned` ranges bit-by-bit which eliminates domain divergence under signed and unsigned branch conditions(more on this is discussed below*).
|
|
28
|
+
The memory modeling handles pointers and mem regions quite well tuned for practical usage(and was a pain to write)^. And as is a inherent quality of life with static analysis, valysis is hardware/software agnostic.
|
|
29
|
+
valysis also keeps exact discrete sets for small cardinalities before widening to abstract domains (ideal for jump tables and flag sets).
|
|
30
|
+
|
|
31
|
+
And IMO the best thing outta all about this is that, valysis is completely external deps-free, as almost everything was written from scratch(the only dep used being the prepackaged `math` lib)
|
|
32
|
+
And also you should know that valysis only deals with VSA and nothing else like the lifters or CFG(you have to DIY, as the point of this lib is to build a VSA-dedicated lib)
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
+-----------------------------------------------------------------------+
|
|
37
|
+
| Target Lifter / Engine |
|
|
38
|
+
| (e.g., Ghidra PCODE / IDA Microcode / IR) |
|
|
39
|
+
+-----------------------------------------------------------------------+
|
|
40
|
+
|
|
|
41
|
+
v
|
|
42
|
+
+-----------------------------------------------------------------------+
|
|
43
|
+
| Memory State & ValueSets |
|
|
44
|
+
| - Tracks value mappings across multiple MemoryRegions |
|
|
45
|
+
| - Manages byte-level serialization / endianness / strong & weak updates|
|
|
46
|
+
+-----------------------------------------------------------------------+
|
|
47
|
+
|
|
|
48
|
+
v
|
|
49
|
+
+-----------------------------------------------------------------------+
|
|
50
|
+
| HybridSetDomain |
|
|
51
|
+
| - If cardinality <= K (e.g., 8): Track exact discrete value set |
|
|
52
|
+
| - If cardinality > K: Widens automatically to VSAReducedState |
|
|
53
|
+
+-----------------------------------------------------------------------+
|
|
54
|
+
|
|
|
55
|
+
v
|
|
56
|
+
+-----------------------------------------------------------------------+
|
|
57
|
+
| VSAReducedState (Product) |
|
|
58
|
+
| - Synchronizes CircularStridedInterval and TristateBitVector |
|
|
59
|
+
| - Executes mutual reduction via _reduce() to tighten upper/lower bounds|
|
|
60
|
+
+-----------------------------------------------------------------------+
|
|
61
|
+
/ \
|
|
62
|
+
v v
|
|
63
|
+
+-------------------------------+ +---------------------------------+
|
|
64
|
+
| CircularStridedInterval (CSI) | | TristateBitVector (TBV) |
|
|
65
|
+
| - Stride, Lower, Upper bounds | | - Known 1s, Known 0s, Unknowns |
|
|
66
|
+
| - Extended GCD intersections | | - Bitwise AND, OR, XOR, Shifts |
|
|
67
|
+
| - Modular arithmetic wrapping | | - Bounds derivation for product |
|
|
68
|
+
+-------------------------------+ +---------------------------------+
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Functioning of valysis
|
|
73
|
+
|
|
74
|
+
*it achieves this by pairing two dedicated components rather than relying on a single domain:
|
|
75
|
+
|
|
76
|
+
Bit-by-bit tracking done by `TristateBitVector`
|
|
77
|
+
|
|
78
|
+
Bit-level accuracy is handled by tracking individual bits using two explicit bitmasks: ones and zeros. Every bit position is tracked as a known 1, a known 0, or unknown (?). This preserves exact bitwise state across AND, OR, XOR, and shift operations without immediately degrading to broad numeric ranges.
|
|
79
|
+
|
|
80
|
+
Signed & Unsigned Domain Tracking by `DualInterval`
|
|
81
|
+
|
|
82
|
+
Signed versus unsigned range tracking is handled by maintaining both an unsigned domain (u_domain) and a signed domain (s_domain) simultaneously. Instead of picking one representation and losing precision during signed/unsigned comparisons, the _synchronize() method shifts domain bounds by the sign bit to cross-refine both contexts.
|
|
83
|
+
|
|
84
|
+
^ *Strong vs. Weak Updates*: You correctly attempt strong updates only when a pointer resolves to a single, unambiguous concrete offset within a `MemoryRegion`.
|
|
85
|
+
|
|
86
|
+
*Endianness Support*: The store and load functions respect endianness by properly extracting and concatenating byte-sized slices.
|
|
87
|
+
|
|
88
|
+
*Safety Net*: If a memory access points to an unknown offset, it safely degrade the read to a topological maximum (CircularStridedInterval.top and TristateBitVector.top).
|
|
89
|
+
|
|
90
|
+
Mathematically speaking, these is the processes or theories implemented in the lib:
|
|
91
|
+
|
|
92
|
+
1. Circular Strided Interval (CSI)
|
|
93
|
+
|
|
94
|
+
A Circular Strided Interval over $b$-bit modular arithmetic is defined as:
|
|
95
|
+
|
|
96
|
+
$$s[l, u]_{2^b}$$
|
|
97
|
+
|
|
98
|
+
Where $s$ is the stride, $l$ is the lower bound, $u$ is the upper bound, and all operations wrap modulo $M = 2^b$. The set of values represented by $s[l, u]$ is:
|
|
99
|
+
|
|
100
|
+
$$\gamma(s[l, u]) = \{ (l + k \cdot s) \pmod{2^b} \mid 0 \le k \le \lfloor ((u - l) \pmod{2^b}) / s \rfloor \}$$
|
|
101
|
+
|
|
102
|
+
Wrapped Intervals & Splitting
|
|
103
|
+
|
|
104
|
+
When $l > u$, the interval wraps around zero. To perform non-modular operations safely (like division or multiplication), the wrapped interval is split into two contiguous linear components:
|
|
105
|
+
|
|
106
|
+
$$\text{split}(s[l, u]) = \{ s[l, \text{first\_upper}], s[\text{second\_lower}, u] \}$$
|
|
107
|
+
|
|
108
|
+
Intersection via Extended Euclidean Algorithm
|
|
109
|
+
|
|
110
|
+
To compute the intersection of two strided intervals $s_1[l_1, u_1]$ and $s_2[l_2, u_2]$, the engine solves the linear congruence equation for common points:
|
|
111
|
+
|
|
112
|
+
$$l_1 + x \cdot s_1 \equiv l_2 + y \cdot s_2 \pmod{2^b}$$
|
|
113
|
+
|
|
114
|
+
Using the Extended GCD algorithm:
|
|
115
|
+
|
|
116
|
+
$$g = \gcd(s_1, s_2) = x_0 s_1 + y_0 s_2$$
|
|
117
|
+
|
|
118
|
+
A solution exists if and only if $(l_2 - l_1) \pmod g = 0$. The resulting combined stride is the least common multiple:
|
|
119
|
+
|
|
120
|
+
$$s_{\text{lcm}} = \frac{s_1 \cdot s_2}{\gcd(s_1, s_2)}$$
|
|
121
|
+
|
|
122
|
+
2. Tristate BitVector (Known-Bits)
|
|
123
|
+
|
|
124
|
+
The `TristateBitVector` tracks the state of every individual bit in a $b$-bit vector using two integer masks: `ones` ($v_{\text{ones}}$) and `zeros` ($v_{\text{zeros}}$).
|
|
125
|
+
|
|
126
|
+
* **Known 1**: Bit $i$ has $v_{\text{ones}}[i] = 1, v_{\text{zeros}}[i] = 0$
|
|
127
|
+
* **Known 0**: Bit $i$ has $v_{\text{ones}}[i] = 0, v_{\text{zeros}}[i] = 1$
|
|
128
|
+
* **Unknown (?)**: Bit $i$ has $v_{\text{ones}}[i] = 0, v_{\text{zeros}}[i] = 0$
|
|
129
|
+
|
|
130
|
+
Domain Invariant
|
|
131
|
+
|
|
132
|
+
$$v_{\text{ones}} \land v_{\text{zeros}} = 0$$
|
|
133
|
+
|
|
134
|
+
If $v_{\text{ones}} \land v_{\text{zeros}} \neq 0$, the domain state is empty ($\bot$).
|
|
135
|
+
|
|
136
|
+
Bounds Extraction
|
|
137
|
+
|
|
138
|
+
Minimum and maximum integer values bounded by a tristate vector are derived directly:
|
|
139
|
+
|
|
140
|
+
$$\text{min\_val} = v_{\text{ones}}$$
|
|
141
|
+
|
|
142
|
+
$$\text{max\_val} = v_{\text{ones}} \mid (\sim(v_{\text{ones}} \mid v_{\text{zeros}}) \land (2^b - 1))$$
|
|
143
|
+
|
|
144
|
+
3. Reduced Product Reduction Method
|
|
145
|
+
|
|
146
|
+
The reduced product domain $\mathcal{D}_{\text{reduced}} = \text{CSI} \times \text{Tristate}$ executes reduction (`_reduce()`) to maintain maximal precision:
|
|
147
|
+
|
|
148
|
+
$$\text{reduce}(\langle \text{CSI}, \text{Tristate} \rangle) \to \langle \text{CSI}', \text{Tristate}' \rangle$$
|
|
149
|
+
|
|
150
|
+
1. **Tristate Bounds $\to$ CSI**:
|
|
151
|
+
|
|
152
|
+
$$l' = \max(l, \text{tri\_min}), \quad u' = \min(u, \text{tri\_max})$$
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
Bounds are aligned to the stride $s$:
|
|
157
|
+
|
|
158
|
+
$$l'' = l' + ((s - (l' - l) \pmod s) \pmod s)$$
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
2. **CSI Alignment $\to$ Tristate**:
|
|
162
|
+
If stride $s = 2^k$, the lowest $k$ bits must be zero:
|
|
163
|
+
|
|
164
|
+
$$v_{\text{zeros}}' = v_{\text{zeros}} \mid (2^k - 1)$$
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
3. **CSI Equivalences $\to$ Tristate**:
|
|
168
|
+
If $l == u$, all bits are known:
|
|
169
|
+
|
|
170
|
+
$$v_{\text{ones}}' = v_{\text{ones}} \mid l, \quad v_{\text{zeros}}' = v_{\text{zeros}} \mid (\sim l \land \text{mask})$$
|
|
171
|
+
|
|
172
|
+
If you're choosing valysis, you might want:
|
|
173
|
+
|
|
174
|
+
1. **Native Bitwise Precision**: Standard interval analysis suffers from over-approximation on operations like `x & 0xFFFFFFF0` or `x | 0x03`. valysis’s reduced product continuously tightens bounds during bitwise manipulation.
|
|
175
|
+
2. **Easy Lifter Integration**: Plug valysis directly into Ghidra PCODE or IDA Microcode analysis plugins without setting up complex binary lifting environments.
|
|
176
|
+
3. **Deterministic Abstract Execution**: Fast execution with direct arithmetic semantics, eliminating solver overhead.
|
|
177
|
+
4. **Vulnerability Analysis Ready**: Features explicit hooks for division-by-zero detection (`VSADivisionByZero`), carrying surviving abstract states to allow paths to fork correctly upon partial zero-division.
|
|
178
|
+
|
|
179
|
+
^^why & how it outperforms angr in precision
|
|
180
|
+
|
|
181
|
+
* angr's strided intervals track numbers as $s[l, u]$. When performing a bitwise operation like x & 0x00FF0000, intervals collapse because bit-masking disrupts contiguous range bounds. angr must widen the stride or convert the value into an unconstrained range $[0, 0xFFFFFFFF]$, while
|
|
182
|
+
the Reduced Product Domain ($\text{CSI} \times \text{TBV}$) of valysis executes bitwise operations natively in the TristateBitVector domain ($\text{TBV}$) without losing known bits. The reduction operator $\rho$ then projects these known bits back into the CircularStridedInterval ($\text{CSI}$) to re-tighten the lower and upper numeric bounds.
|
|
183
|
+
* In angr, comparing signed values across the sign-bit boundary ($2^{b-1}$) causes standard unsigned intervals to span the entire integer space while valysis's DualInterval maintains an unsigned interval $\mathcal{U}$ and a shifted signed interval $\mathcal{S}$ in parallel. Whenever a branch constraint is evaluated, the result is computed in the optimal domain and propagated to the other domain via the bijection:
|
|
184
|
+
|
|
185
|
+
$$\mathcal{U}_{\text{refined}} = \mathcal{U} \sqcap \text{shift}(\mathcal{S}, 2^{b-1})$$
|
|
186
|
+
|
|
187
|
+
* angr's aggressive over-approximation forces small jump tables (e.g., switch cases targeting offsets 0x10, 0x20, 0x30) into a single wide interval $16[16, 48]$ that includes non-existent targets like 0x28 while valysis defers abstraction by keeping precise discrete sets $\{0x10, 0x20, 0x30\}$ until set cardinality exceeds a threshold ($k=8$), ensuring $100\%$ precision on control flow dispatches.
|
|
188
|
+
|
|
189
|
+
so if you don't want the entire heavy angr lib and just want a library to handle just the VSA with better precision, valysis might be your best bet in Python.
|
|
190
|
+
|
|
191
|
+
*Note: and obviously because i focused on precision, there is a noticable issue with performance ovehead, but this would surely be addressed in the coming updates*
|
|
192
|
+
|
|
193
|
+
installing it:
|
|
194
|
+
|
|
195
|
+
pip:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
pip install valysis
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
GIT clone:
|
|
202
|
+
|
|
203
|
+
Codeberg:
|
|
204
|
+
```bash
|
|
205
|
+
git clone https://codeberg.org/nulsie/valysis.git
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
GitHub:
|
|
209
|
+
```bash
|
|
210
|
+
git clone https://github.com/nulsie/valyssis.git
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
ON BUG REPORTING:
|
|
214
|
+
|
|
215
|
+
There is currently performance issues and resource overhead with the lib and as this is the first version, there will be bugs for sure: the performance issues will surely be fixed in later versions and is aready in development, if you find any bugs, be sure to [contact](https://nulsie.mywire.org) me so i can discover them faster and push update real-quick.
|
|
216
|
+
|
|
217
|
+
references & acknowledgments
|
|
218
|
+
|
|
219
|
+
* **Hacker's Delight (2nd Edition)** by Henry S. Warren, Jr. — The bitwise bounds algorithms for bitwise `AND` and `OR` operations (`_hd_min_and`, `_hd_max_and`, `_hd_min_or`, `_hd_max_or`) used in `CircularStridedInterval` are based on the logical operations theorems in Chapter 4.
|
|
220
|
+
* **G. Balakrishnan and T. Reps** — *Analyzing Memory Accesses in x86 Executables* (The foundational paper introducing Value Set Analysis and Circular Strided Intervals).
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
author: nulsie license: MIT
|
|
225
|
+
|
valysis-1.0.0/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
valysis - a VSA library for Python
|
|
2
|
+
|
|
3
|
+
There is a distinct lack of dedicated VSA(Value Set Analysis) libraries in Python, like literally, there is none. You woud say that
|
|
4
|
+
there are things like Angr, but they are not dedicated for VSA, but as large frameworks for building or basing entire RE tools, As i was
|
|
5
|
+
trying to make a IR(Intermediate Representation) based static analysis RE tool in Python a while ago, i found the issue, and as it is commonly known,
|
|
6
|
+
creating entire VSA engines and CFGs from scratch are notoriously difficult if not impossible and litearly there was no dedicated VSA library
|
|
7
|
+
available. So i made an entire fully functional precision-focused library dedicated just for VSA from scratch and arguably the first in Python, and that is *valysis*.
|
|
8
|
+
|
|
9
|
+
valysis is decoupled from any specific instruction set architecture or Intermediate Representation (IR). It provides a sound, flexible backend domain engine which is superior in precision rate than Angr(from the tests I've done in a short-term)^^ that can be attached to
|
|
10
|
+
Ghidra PCODE, IDA Microcode, Triton ASTs, Binary Ninja LLIL/MLIL, or custom emulation lifters. To preserve precision across mixed
|
|
11
|
+
arithmetic-bitwise code, the lib combines Circular Strided Interval(better than the usual standard of using the less precision-focused Strided Interval) with Tristate BitVectors via mutual reduction. Then it natively supports arbitrary bit-widths (8, 16, 32, 64, 128bits) per variable.
|
|
12
|
+
And also accurately tracks `signed` and `unsigned` ranges bit-by-bit which eliminates domain divergence under signed and unsigned branch conditions(more on this is discussed below*).
|
|
13
|
+
The memory modeling handles pointers and mem regions quite well tuned for practical usage(and was a pain to write)^. And as is a inherent quality of life with static analysis, valysis is hardware/software agnostic.
|
|
14
|
+
valysis also keeps exact discrete sets for small cardinalities before widening to abstract domains (ideal for jump tables and flag sets).
|
|
15
|
+
|
|
16
|
+
And IMO the best thing outta all about this is that, valysis is completely external deps-free, as almost everything was written from scratch(the only dep used being the prepackaged `math` lib)
|
|
17
|
+
And also you should know that valysis only deals with VSA and nothing else like the lifters or CFG(you have to DIY, as the point of this lib is to build a VSA-dedicated lib)
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
+-----------------------------------------------------------------------+
|
|
22
|
+
| Target Lifter / Engine |
|
|
23
|
+
| (e.g., Ghidra PCODE / IDA Microcode / IR) |
|
|
24
|
+
+-----------------------------------------------------------------------+
|
|
25
|
+
|
|
|
26
|
+
v
|
|
27
|
+
+-----------------------------------------------------------------------+
|
|
28
|
+
| Memory State & ValueSets |
|
|
29
|
+
| - Tracks value mappings across multiple MemoryRegions |
|
|
30
|
+
| - Manages byte-level serialization / endianness / strong & weak updates|
|
|
31
|
+
+-----------------------------------------------------------------------+
|
|
32
|
+
|
|
|
33
|
+
v
|
|
34
|
+
+-----------------------------------------------------------------------+
|
|
35
|
+
| HybridSetDomain |
|
|
36
|
+
| - If cardinality <= K (e.g., 8): Track exact discrete value set |
|
|
37
|
+
| - If cardinality > K: Widens automatically to VSAReducedState |
|
|
38
|
+
+-----------------------------------------------------------------------+
|
|
39
|
+
|
|
|
40
|
+
v
|
|
41
|
+
+-----------------------------------------------------------------------+
|
|
42
|
+
| VSAReducedState (Product) |
|
|
43
|
+
| - Synchronizes CircularStridedInterval and TristateBitVector |
|
|
44
|
+
| - Executes mutual reduction via _reduce() to tighten upper/lower bounds|
|
|
45
|
+
+-----------------------------------------------------------------------+
|
|
46
|
+
/ \
|
|
47
|
+
v v
|
|
48
|
+
+-------------------------------+ +---------------------------------+
|
|
49
|
+
| CircularStridedInterval (CSI) | | TristateBitVector (TBV) |
|
|
50
|
+
| - Stride, Lower, Upper bounds | | - Known 1s, Known 0s, Unknowns |
|
|
51
|
+
| - Extended GCD intersections | | - Bitwise AND, OR, XOR, Shifts |
|
|
52
|
+
| - Modular arithmetic wrapping | | - Bounds derivation for product |
|
|
53
|
+
+-------------------------------+ +---------------------------------+
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Functioning of valysis
|
|
58
|
+
|
|
59
|
+
*it achieves this by pairing two dedicated components rather than relying on a single domain:
|
|
60
|
+
|
|
61
|
+
Bit-by-bit tracking done by `TristateBitVector`
|
|
62
|
+
|
|
63
|
+
Bit-level accuracy is handled by tracking individual bits using two explicit bitmasks: ones and zeros. Every bit position is tracked as a known 1, a known 0, or unknown (?). This preserves exact bitwise state across AND, OR, XOR, and shift operations without immediately degrading to broad numeric ranges.
|
|
64
|
+
|
|
65
|
+
Signed & Unsigned Domain Tracking by `DualInterval`
|
|
66
|
+
|
|
67
|
+
Signed versus unsigned range tracking is handled by maintaining both an unsigned domain (u_domain) and a signed domain (s_domain) simultaneously. Instead of picking one representation and losing precision during signed/unsigned comparisons, the _synchronize() method shifts domain bounds by the sign bit to cross-refine both contexts.
|
|
68
|
+
|
|
69
|
+
^ *Strong vs. Weak Updates*: You correctly attempt strong updates only when a pointer resolves to a single, unambiguous concrete offset within a `MemoryRegion`.
|
|
70
|
+
|
|
71
|
+
*Endianness Support*: The store and load functions respect endianness by properly extracting and concatenating byte-sized slices.
|
|
72
|
+
|
|
73
|
+
*Safety Net*: If a memory access points to an unknown offset, it safely degrade the read to a topological maximum (CircularStridedInterval.top and TristateBitVector.top).
|
|
74
|
+
|
|
75
|
+
Mathematically speaking, these is the processes or theories implemented in the lib:
|
|
76
|
+
|
|
77
|
+
1. Circular Strided Interval (CSI)
|
|
78
|
+
|
|
79
|
+
A Circular Strided Interval over $b$-bit modular arithmetic is defined as:
|
|
80
|
+
|
|
81
|
+
$$s[l, u]_{2^b}$$
|
|
82
|
+
|
|
83
|
+
Where $s$ is the stride, $l$ is the lower bound, $u$ is the upper bound, and all operations wrap modulo $M = 2^b$. The set of values represented by $s[l, u]$ is:
|
|
84
|
+
|
|
85
|
+
$$\gamma(s[l, u]) = \{ (l + k \cdot s) \pmod{2^b} \mid 0 \le k \le \lfloor ((u - l) \pmod{2^b}) / s \rfloor \}$$
|
|
86
|
+
|
|
87
|
+
Wrapped Intervals & Splitting
|
|
88
|
+
|
|
89
|
+
When $l > u$, the interval wraps around zero. To perform non-modular operations safely (like division or multiplication), the wrapped interval is split into two contiguous linear components:
|
|
90
|
+
|
|
91
|
+
$$\text{split}(s[l, u]) = \{ s[l, \text{first\_upper}], s[\text{second\_lower}, u] \}$$
|
|
92
|
+
|
|
93
|
+
Intersection via Extended Euclidean Algorithm
|
|
94
|
+
|
|
95
|
+
To compute the intersection of two strided intervals $s_1[l_1, u_1]$ and $s_2[l_2, u_2]$, the engine solves the linear congruence equation for common points:
|
|
96
|
+
|
|
97
|
+
$$l_1 + x \cdot s_1 \equiv l_2 + y \cdot s_2 \pmod{2^b}$$
|
|
98
|
+
|
|
99
|
+
Using the Extended GCD algorithm:
|
|
100
|
+
|
|
101
|
+
$$g = \gcd(s_1, s_2) = x_0 s_1 + y_0 s_2$$
|
|
102
|
+
|
|
103
|
+
A solution exists if and only if $(l_2 - l_1) \pmod g = 0$. The resulting combined stride is the least common multiple:
|
|
104
|
+
|
|
105
|
+
$$s_{\text{lcm}} = \frac{s_1 \cdot s_2}{\gcd(s_1, s_2)}$$
|
|
106
|
+
|
|
107
|
+
2. Tristate BitVector (Known-Bits)
|
|
108
|
+
|
|
109
|
+
The `TristateBitVector` tracks the state of every individual bit in a $b$-bit vector using two integer masks: `ones` ($v_{\text{ones}}$) and `zeros` ($v_{\text{zeros}}$).
|
|
110
|
+
|
|
111
|
+
* **Known 1**: Bit $i$ has $v_{\text{ones}}[i] = 1, v_{\text{zeros}}[i] = 0$
|
|
112
|
+
* **Known 0**: Bit $i$ has $v_{\text{ones}}[i] = 0, v_{\text{zeros}}[i] = 1$
|
|
113
|
+
* **Unknown (?)**: Bit $i$ has $v_{\text{ones}}[i] = 0, v_{\text{zeros}}[i] = 0$
|
|
114
|
+
|
|
115
|
+
Domain Invariant
|
|
116
|
+
|
|
117
|
+
$$v_{\text{ones}} \land v_{\text{zeros}} = 0$$
|
|
118
|
+
|
|
119
|
+
If $v_{\text{ones}} \land v_{\text{zeros}} \neq 0$, the domain state is empty ($\bot$).
|
|
120
|
+
|
|
121
|
+
Bounds Extraction
|
|
122
|
+
|
|
123
|
+
Minimum and maximum integer values bounded by a tristate vector are derived directly:
|
|
124
|
+
|
|
125
|
+
$$\text{min\_val} = v_{\text{ones}}$$
|
|
126
|
+
|
|
127
|
+
$$\text{max\_val} = v_{\text{ones}} \mid (\sim(v_{\text{ones}} \mid v_{\text{zeros}}) \land (2^b - 1))$$
|
|
128
|
+
|
|
129
|
+
3. Reduced Product Reduction Method
|
|
130
|
+
|
|
131
|
+
The reduced product domain $\mathcal{D}_{\text{reduced}} = \text{CSI} \times \text{Tristate}$ executes reduction (`_reduce()`) to maintain maximal precision:
|
|
132
|
+
|
|
133
|
+
$$\text{reduce}(\langle \text{CSI}, \text{Tristate} \rangle) \to \langle \text{CSI}', \text{Tristate}' \rangle$$
|
|
134
|
+
|
|
135
|
+
1. **Tristate Bounds $\to$ CSI**:
|
|
136
|
+
|
|
137
|
+
$$l' = \max(l, \text{tri\_min}), \quad u' = \min(u, \text{tri\_max})$$
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
Bounds are aligned to the stride $s$:
|
|
142
|
+
|
|
143
|
+
$$l'' = l' + ((s - (l' - l) \pmod s) \pmod s)$$
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
2. **CSI Alignment $\to$ Tristate**:
|
|
147
|
+
If stride $s = 2^k$, the lowest $k$ bits must be zero:
|
|
148
|
+
|
|
149
|
+
$$v_{\text{zeros}}' = v_{\text{zeros}} \mid (2^k - 1)$$
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
3. **CSI Equivalences $\to$ Tristate**:
|
|
153
|
+
If $l == u$, all bits are known:
|
|
154
|
+
|
|
155
|
+
$$v_{\text{ones}}' = v_{\text{ones}} \mid l, \quad v_{\text{zeros}}' = v_{\text{zeros}} \mid (\sim l \land \text{mask})$$
|
|
156
|
+
|
|
157
|
+
If you're choosing valysis, you might want:
|
|
158
|
+
|
|
159
|
+
1. **Native Bitwise Precision**: Standard interval analysis suffers from over-approximation on operations like `x & 0xFFFFFFF0` or `x | 0x03`. valysis’s reduced product continuously tightens bounds during bitwise manipulation.
|
|
160
|
+
2. **Easy Lifter Integration**: Plug valysis directly into Ghidra PCODE or IDA Microcode analysis plugins without setting up complex binary lifting environments.
|
|
161
|
+
3. **Deterministic Abstract Execution**: Fast execution with direct arithmetic semantics, eliminating solver overhead.
|
|
162
|
+
4. **Vulnerability Analysis Ready**: Features explicit hooks for division-by-zero detection (`VSADivisionByZero`), carrying surviving abstract states to allow paths to fork correctly upon partial zero-division.
|
|
163
|
+
|
|
164
|
+
^^why & how it outperforms angr in precision
|
|
165
|
+
|
|
166
|
+
* angr's strided intervals track numbers as $s[l, u]$. When performing a bitwise operation like x & 0x00FF0000, intervals collapse because bit-masking disrupts contiguous range bounds. angr must widen the stride or convert the value into an unconstrained range $[0, 0xFFFFFFFF]$, while
|
|
167
|
+
the Reduced Product Domain ($\text{CSI} \times \text{TBV}$) of valysis executes bitwise operations natively in the TristateBitVector domain ($\text{TBV}$) without losing known bits. The reduction operator $\rho$ then projects these known bits back into the CircularStridedInterval ($\text{CSI}$) to re-tighten the lower and upper numeric bounds.
|
|
168
|
+
* In angr, comparing signed values across the sign-bit boundary ($2^{b-1}$) causes standard unsigned intervals to span the entire integer space while valysis's DualInterval maintains an unsigned interval $\mathcal{U}$ and a shifted signed interval $\mathcal{S}$ in parallel. Whenever a branch constraint is evaluated, the result is computed in the optimal domain and propagated to the other domain via the bijection:
|
|
169
|
+
|
|
170
|
+
$$\mathcal{U}_{\text{refined}} = \mathcal{U} \sqcap \text{shift}(\mathcal{S}, 2^{b-1})$$
|
|
171
|
+
|
|
172
|
+
* angr's aggressive over-approximation forces small jump tables (e.g., switch cases targeting offsets 0x10, 0x20, 0x30) into a single wide interval $16[16, 48]$ that includes non-existent targets like 0x28 while valysis defers abstraction by keeping precise discrete sets $\{0x10, 0x20, 0x30\}$ until set cardinality exceeds a threshold ($k=8$), ensuring $100\%$ precision on control flow dispatches.
|
|
173
|
+
|
|
174
|
+
so if you don't want the entire heavy angr lib and just want a library to handle just the VSA with better precision, valysis might be your best bet in Python.
|
|
175
|
+
|
|
176
|
+
*Note: and obviously because i focused on precision, there is a noticable issue with performance ovehead, but this would surely be addressed in the coming updates*
|
|
177
|
+
|
|
178
|
+
installing it:
|
|
179
|
+
|
|
180
|
+
pip:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
pip install valysis
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
GIT clone:
|
|
187
|
+
|
|
188
|
+
Codeberg:
|
|
189
|
+
```bash
|
|
190
|
+
git clone https://codeberg.org/nulsie/valysis.git
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
GitHub:
|
|
194
|
+
```bash
|
|
195
|
+
git clone https://github.com/nulsie/valyssis.git
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
ON BUG REPORTING:
|
|
199
|
+
|
|
200
|
+
There is currently performance issues and resource overhead with the lib and as this is the first version, there will be bugs for sure: the performance issues will surely be fixed in later versions and is aready in development, if you find any bugs, be sure to [contact](https://nulsie.mywire.org) me so i can discover them faster and push update real-quick.
|
|
201
|
+
|
|
202
|
+
references & acknowledgments
|
|
203
|
+
|
|
204
|
+
* **Hacker's Delight (2nd Edition)** by Henry S. Warren, Jr. — The bitwise bounds algorithms for bitwise `AND` and `OR` operations (`_hd_min_and`, `_hd_max_and`, `_hd_min_or`, `_hd_max_or`) used in `CircularStridedInterval` are based on the logical operations theorems in Chapter 4.
|
|
205
|
+
* **G. Balakrishnan and T. Reps** — *Analyzing Memory Accesses in x86 Executables* (The foundational paper introducing Value Set Analysis and Circular Strided Intervals).
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
author: nulsie license: MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["flit_core >=3.2,<4"]
|
|
3
|
+
build-backend = "flit_core.buildapi"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "valysis"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A platform/hardware agnostic Value Set Analysis (VSA) library for Reverse Engineering tools."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "nulsie", email = "donotmailme@mail.com" }
|
|
14
|
+
]
|
|
15
|
+
dependencies = []
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Topic :: Security",
|
|
19
|
+
"Topic :: Software Development :: Disassemblers",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://codeberg.org/nulsie/valysis"
|
|
24
|
+
"Codeberg" = "https://codeberg.org/nulsie/valysis"
|
|
25
|
+
"GitHub" = "https://github.com/nulsie/valysis"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .common import VSADivisionByZero
|
|
2
|
+
from .intervals import CircularStridedInterval
|
|
3
|
+
from .dual_interval import DualInterval
|
|
4
|
+
from .tristate import TristateBitVector
|
|
5
|
+
from .product import VSAReducedState, HybridSetDomain
|
|
6
|
+
from .memory import MemoryRegion, AbsoluteRegion, GlobalRegion, ValueSet, MemoryState
|
|
7
|
+
|
|
8
|
+
__version__ = "1.0.0"
|
|
9
|
+
__all__ = [
|
|
10
|
+
"VSADivisionByZero",
|
|
11
|
+
"CircularStridedInterval",
|
|
12
|
+
"DualInterval",
|
|
13
|
+
"TristateBitVector",
|
|
14
|
+
"VSAReducedState",
|
|
15
|
+
"HybridSetDomain",
|
|
16
|
+
"MemoryRegion",
|
|
17
|
+
"AbsoluteRegion",
|
|
18
|
+
"GlobalRegion",
|
|
19
|
+
"ValueSet",
|
|
20
|
+
"MemoryState"
|
|
21
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class VSADivisionByZero(Exception):
|
|
2
|
+
def __init__(self, message: str, surviving_state: 'CircularStridedInterval'):
|
|
3
|
+
super().__init__(message)
|
|
4
|
+
self.surviving_state = surviving_state
|
|
5
|
+
|
|
6
|
+
def _exgcd(a: int, b: int) -> tuple[int, int, int]:
|
|
7
|
+
x0, x1, y0, y1 = 1, 0, 0, 1
|
|
8
|
+
while b != 0:
|
|
9
|
+
q, a, b = a // b, b, a % b
|
|
10
|
+
x0, x1 = x1, x0 - q * x1
|
|
11
|
+
y0, y1 = y1, y0 - q * y1
|
|
12
|
+
return a, x0, y0
|