Skip to content

Commit d58e3f6

Browse files
committed
Add blog with 0.2 article
1 parent 09a3313 commit d58e3f6

File tree

9 files changed

+1187
-23
lines changed

9 files changed

+1187
-23
lines changed

main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
template_vars = {
1717
'navbar': [
1818
('/', 'Home'),
19+
('blog/', 'Blog'),
1920
('about/', 'About'),
2021
('quick_start/', 'Quick start guide'),
2122
('docs/', 'Documentation'),

mdrend.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,18 @@ def ascii_render(self, code):
5858
scene = '{' + d[1]
5959

6060
color = int(props['color']) if 'color' in props else 0
61-
w = int(props['w']) if 'w' in props else 64
61+
w = int(props['w']) if 'w' in props else 72
6262
h = int(props['h']) if 'h' in props else 32
6363
aspect = float(w / (2 * h))
64+
65+
# These parameters are not actually used in latest asciirend
6466
ortho = bool(props['ortho']) if 'ortho' in props else True
6567
fov = float(props['fov']) if 'fov' in props else 1.0
6668
znear = float(props['znear']) if 'znear' in props else 0.1
6769
zfar = float(props['zfar']) if 'zfar' in props else 100.0
6870

6971
self.scene_props[div_id] = {
70-
'scene': scene,
72+
'scene': scene.replace('\n', ''),
7173
'w': w,
7274
'h': h,
7375
'aspect': aspect,
@@ -77,9 +79,11 @@ def ascii_render(self, code):
7779
'zfar': zfar,
7880
'dynamic_w': bool(props['dynamic_w']) if 'dynamic_w' in props else False,
7981
'dynamic_h': bool(props['dynamic_h']) if 'dynamic_h' in props else False,
82+
'show_usage': bool(props['show_usage']) if 'show_usage' in props else True,
83+
'disable_zoom': bool(props['disable_zoom']) if 'disable_zoom' in props else False,
8084
}
8185

82-
rendered = ar.ascii_render(scene, color, w, h, aspect, ortho, fov, znear, zfar)
86+
rendered = ar.ascii_render(scene, color, w, h, aspect, ortho, fov, znear, zfar, 0.0)
8387
return f'<div class="asciirend" id="asciirend-{div_id}"><pre>{rendered}</pre></div>';
8488

8589
def gh_users_render(self, code):
@@ -102,8 +106,6 @@ def gh_users_render(self, code):
102106
<br/>
103107
"""
104108

105-
print(line)
106-
107109
return output
108110

109111
def block_code(self, code, lang=None):
@@ -119,8 +121,6 @@ def block_code(self, code, lang=None):
119121
except ClassNotFound:
120122
lexer = get_lexer_by_name("html", stripall=True)
121123

122-
print(str(lexer))
123-
124124
formatter = HtmlFormatter()
125125
return highlight(code, lexer, formatter)
126126

@@ -159,19 +159,20 @@ def shortdown(value):
159159
md_rend = md.create_markdown(renderer=renderer, plugins=['strikethrough'])
160160
return md_rend(trimmed)
161161

162-
def markdown(value):
162+
def markdown(value, backlink):
163+
print(backlink)
163164
renderer = CustomizedRenderer()
164165
md_rend = md.create_markdown(renderer=renderer, plugins=['task_lists', 'table', 'footnotes', 'strikethrough'], escape=False)
165166
rendered = md_rend(value)
166167
if renderer.scene_cnt > 0:
167-
javascript = """
168+
javascript = f"""
168169
<script type="module">
169-
import ascii_render from "/static/js/draw.js";
170+
import ascii_render from "{backlink}static/js/draw.js";
170171
"""
171172
for i in range(renderer.scene_cnt):
172173
props = renderer.scene_props[i]
173174
javascript += f'const scene_{i} = \'{props["scene"].rstrip()}\';\n'
174-
javascript += f'ascii_render("asciirend-{i}", scene_{i}, {props["w"] if not props["dynamic_w"] else "null"}, {props["h"] if not props["dynamic_h"] else "null"}, {"true" if props["ortho"] else "false"}, {props["fov"]}, {props["znear"]}, {props["zfar"]});\n'
175+
javascript += f'ascii_render("asciirend-{i}", scene_{i}, {props["w"] if not props["dynamic_w"] else "null"}, {props["h"] if not props["dynamic_h"] else "null"}, {"true" if props["ortho"] else "false"}, {props["fov"]}, {props["znear"]}, {props["zfar"]}, {"true" if props["show_usage"] else "false"}, {"true" if props["disable_zoom"] else "false"});\n'
175176
javascript += """
176177
</script>
177178
"""

src/blog/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Blog
2+
3+
## [Announcing memflow 0.2.0](memflow-0.2.0/)

src/blog/memflow-0.2.0.md

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Announcing memflow 0.2.0
2+
3+
Today, we are proud to release the first stable version of memflow 0.2! 3 years in the making, this
4+
is certainly a monumental release. In this post, we will go through the key changes to the fastest
5+
and most flexible physical memory introspection and forensics framework to date.
6+
7+
## Key changes
8+
9+
### 0. [memflowup](https://github.com/memflow/memflowup)
10+
11+
Not a library change, but the ecosystem change! We now have a rust-written memflowup utility that
12+
makes it much easier to manage your memflow installation. Key features:
13+
14+
- Download binary builds (optional).
15+
- Split between stable and dev versions.
16+
- Custom install scripts, for more complicated plugins
17+
- Used by [`memflow-kvm`](https://github.com/memflow/memflow-kvm) for DKMS install.
18+
- Entry point for these is `install.rhai` script at the root of the package's repo.
19+
20+
You can get started with memflowup by running the following:
21+
22+
```
23+
> curl --proto '=https' --tlsv1.2 -sSf https://sh.memflow.io | sh
24+
```
25+
26+
### 1. OS layers and modularity
27+
28+
With the advent of 0.2 series, we now abstracted most of `memflow-win32` functionality behind
29+
shared set of traits. These traits allow the user to interact with the operating system in unified
30+
manner. In addition, we now made OS a plugin, just as Connectors were in 0.1! And finally, we do
31+
indeed have multiple OS backends available, right now:
32+
33+
- [`memflow-win32`](https://github.com/memflow/memflow-win32), for Windows analysis, given physical
34+
memory access.
35+
- [`memflow-native`](https://github.com/memflow/memflow-native), for syscall based interaction with
36+
the running operating system.
37+
- WIP: `memflow-linux`
38+
- Don't expect much anytime soon, because the challenge of cross-version, zero-knowledge linux
39+
support is a tricky one.
40+
41+
With this, OS-independent code that works with `memflow-win32`, should also work on local OS. Here's
42+
an example of such code:
43+
44+
```rust
45+
use memflow::prelude::v1::*;
46+
47+
// We don't care what type of process we get, so long as it's a process
48+
fn module_address(process: &mut impl Process, module: &str) -> Result<Address> {
49+
let module = process.module_by_name(module)?;
50+
Ok(module.base)
51+
}
52+
```
53+
54+
In addition, modularization of operating systems allows for greater portability of connectors. For
55+
instance, we have now split `memflow-qemu-procfs` into
56+
[`memflow-qemu`](https://github.com/memflow/memflow-qemu), which (optionally) accepts an OS layer.
57+
This way, you can not only analyze QEMU VMs running on your computer, but you can also open them up
58+
in a nested way on a machine that is already being analyzed through DMA. As seen in this chart:
59+
60+
```asciirend
61+
dynamic_w = true
62+
dynamic_h = false
63+
fov = 4.5
64+
ortho = true
65+
disable_zoom = true
66+
# Scene:
67+
{
68+
"camera_props": {
69+
"proj_mode": "Orthographic",
70+
"fov": 1.0,
71+
"near": 0.01,
72+
"far": 100.0
73+
},
74+
"camera_controller":{"fov_y":1.0,"focus_point":[0.0,0.0,0.0],"rot":[-0.19996414, -0.08282786, 0.37361234, 0.90197986],"dist":2.0,"in_motion":"None","scroll_sensitivity":0.02,"orbit_sensitivity":1.0,"last_down":false,"pressed":false},
75+
"objects":[
76+
{
77+
"transform":[
78+
1.0,0.0,0.0,0.0,
79+
0.0,1.0,0.0,0.0,
80+
0.0,0.0,1.0,0.0,
81+
0.0,0.0,0.0,1.0
82+
],
83+
"material":0,
84+
"ty":{
85+
"Primitive":{
86+
"Line":{
87+
"start":[-0.75,0.0,1.5,1.0],
88+
"end":[-0.25,0.0,0.5,1.0]
89+
}
90+
}
91+
}
92+
},
93+
{
94+
"transform":[
95+
1.0,0.0,0.0,0.0,
96+
0.0,1.0,0.0,0.0,
97+
0.0,0.0,1.0,0.0,
98+
0.0,0.0,0.0,1.0
99+
],
100+
"material":0,
101+
"ty":{
102+
"Primitive":{
103+
"Line":{
104+
"start":[-0.25,0.0,0.5,1.0],
105+
"end":[0.25,0.0,-0.5,1.0]
106+
}
107+
}
108+
}
109+
},
110+
{
111+
"transform":[
112+
1.0,0.0,0.0,0.0,
113+
0.0,1.0,0.0,0.0,
114+
0.0,0.0,1.0,0.0,
115+
0.0,0.0,0.0,1.0
116+
],
117+
"material":0,
118+
"ty":{
119+
"Primitive":{
120+
"Line":{
121+
"start":[0.25,0.0,-0.5,1.0],
122+
"end":[0.75,0.0,-1.5,1.0]
123+
}
124+
}
125+
}
126+
},
127+
{
128+
"transform":[
129+
1.0,0.0,0.0,0.0,
130+
0.0,1.0,0.0,0.0,
131+
0.0,0.0,1.0,0.0,
132+
-0.75,0.0,1.5,1.0
133+
],"material":1,"ty":{"Cube":{"size":[1.0,1.0,0.5]}},"text":"memflow-kvm"
134+
},
135+
{
136+
"transform":[
137+
1.0,0.0,0.0,0.0,
138+
0.0,1.0,0.0,0.0,
139+
0.0,0.0,1.0,0.0,
140+
-0.25,0.0,0.5,1.0
141+
],"material":1,"ty":{"Cube":{"size":[1.0,1.0,0.5]}},"text":"memflow-win32"
142+
},
143+
{
144+
"transform":[
145+
1.0,0.0,0.0,0.0,
146+
0.0,1.0,0.0,0.0,
147+
0.0,0.0,1.0,0.0,
148+
0.25,0.0,-0.5,1.0
149+
],"material":1,"ty":{"Cube":{"size":[1.0,1.0,0.5]}},"text":"memflow-qemu"
150+
},
151+
{
152+
"transform":[
153+
1.0,0.0,0.0,0.0,
154+
0.0,1.0,0.0,0.0,
155+
0.0,0.0,1.0,0.0,
156+
0.75,0.0,-1.5,1.0
157+
],"material":1,"ty":{"Cube":{"size":[1.0,1.0,0.5]}},"text":"memflow-win32"
158+
}
159+
],
160+
"bg":{"color":[0.0,0.0,0.0]},
161+
"dithering":{"count_frames":false,"frame_cnt":4181}
162+
}
163+
```
164+
165+
### 2. Stable ABI
166+
167+
In 0.1, the Connectors were turned into plugins through use of Rust trait objects. This was an okay
168+
solution at the time, however, we knew that it was not a safe one - changes in Rust versions could
169+
change the layout of those trait objects, leading to crashes or other misbehavior, in case of
170+
mismatch of plugin's `rustc` version and the one of the user's code. While the layout has remained
171+
stable most of the time, the tides started to shift a few years ago, as more effort was put into
172+
trait objects on the compiler front.
173+
174+
For 0.2, we knew we could not keep the status quo, so, we built `cglue`. The crate allows for
175+
simple and flexible ABI safe code generation, suited for the needs of `memflow`. Throughout the
176+
(very long) beta period, we received 0 crash reports stemming from ABI instability, while 0.1 had
177+
such cases. Therefore, we can conclude that it was a good investment that already made memflow more
178+
stable.
179+
180+
In `0.2.0-betaX` series, you may have encountered "invalid ABI" errors, well, fear not, because in
181+
stable series, we commit to not breaking the ABI across entirety of `0.2` series, so this problem
182+
should be a thing of the past for most users.
183+
184+
### 3. Memory constrained vtop
185+
186+
memflow 0.2 introduces the most scalable virtual address translation backend, period. The backend
187+
is able to walk entire page tree in milliseconds, targeting any modern memory architecture (x86 and
188+
ARM support out-of-the box, sufficient building blocks for RISC-V). In addition, compared to 0.1,
189+
the new backend uses fixed-size buffers, meaning RAM usage will no longer blow up on large
190+
translation ranges.
191+
192+
### 4. 64-bit and 128-bit address spaces, on all architectures
193+
194+
We now support analyzing 64-bit operating systems on 32-bit machines. In addition, if there was a
195+
theoretical 128-bit architecture, we would support that as well. However, it's more of a PoC and we
196+
do not expect this to be needed in the foreseeable future.
197+
198+
The support can be toggled through `64_bit_mem` (default) and `128_bit_mem` features. Do note that
199+
these feature toggles do change memflow's ABI and it should not be possible to mix the plugin
200+
features.
201+
202+
### 5. Shared `MemoryView`
203+
204+
In 0.1, we have had a split between physical and virtual memory. The reason for the split is
205+
caching - we wish minimize latency by caching read-only memory in high-latency scenarios.
206+
However, to tell the cache what mode the memory is in (readable/writeable/executable), you must add
207+
metadata with each request. Meanwhile, this metadata may only be filled in by the virtual address
208+
translation backend.
209+
210+
If user submits an I/O operation - they can't possibly know whether the request is going to a
211+
read-only, or a writeable page, therefore they just submit `UNKNOWN` page flags. This is
212+
complicated, therefore, we have lowered the gap between virtual and physical memory access through
213+
use of `MemoryView` trait. This trait not only removes the need for the user to explicitly submit
214+
the page flags, but also brings all I/O helpers that existed in virtual memory contexts. To use
215+
`MemoryView` on physical memory, just use the `phys_view` function:
216+
217+
```rust
218+
use memflow::prelude::v1::*;
219+
220+
fn main() -> Result<()> {
221+
let inventory = Inventory::scan();
222+
let mut conn = inventory.create_connector("dummy", None, None)?;
223+
224+
// Create a physical memory view
225+
let mut view = conn.phys_view();
226+
227+
// Read from phys addr 0
228+
let value: u64 = view.read(0.into())?;
229+
230+
Ok(())
231+
}
232+
```
233+
234+
### 6. C and C++ are now first-class citizen
235+
236+
The FFI is now automatically generated using `cbindgen` and `cglue-bindgen`. It may initially seem
237+
like a downgrade, however, this way we can ensure entirety of memflow's plugin-focused API surface
238+
can be both accessed, and implemented by foreign languages, such as C and C++.
239+
240+
The key to using the new FFI, is reading Rust documentation and examples, and then finding the
241+
function equivalents in the headers. There are a few quirks here and there, but after understanding
242+
them, using the FFI should not be hard. For inspiration, see the following:
243+
244+
- [C examples](https://github.com/memflow/memflow/tree/0.2.0/memflow-ffi/examples/c)
245+
- [C++ examples](https://github.com/memflow/memflow/tree/0.2.0/memflow-ffi/examples/cpp)
246+
- [CMake template](https://github.com/memflow/memflow-cmake-example)
247+
248+
## Side projects
249+
250+
`memflow` is as useful as the projects utilizing it. To get started with the new version faster,
251+
you may want to have a look at some of them. Here's the list of first-party releases:
252+
253+
- [`reflow`](https://github.com/memflow/reflow) - execute code on top of virtual memory.
254+
- [`scanflow`](https://github.com/memflow/scanflow) - basic CheatEngine features in a command line
255+
interface.
256+
- [`cloudflow`](https://github.com/memflow/cloudflow) (WIP) - flexible filesystem based way to
257+
interact with memflow.
258+
- [`memflow-py`](https://github.com/memflow/memflow-py) - python bindings for memflow (courtesy of
259+
emesare).
260+
261+
## Reflection
262+
263+
0.2 took way longer than we originally anticipated. This is mostly due to changing living
264+
conditions and the fact that both ko1N and I are only working on the project in hobbyist capacity.
265+
In addition, we pushed for perfection from documentation and implementation front - a feat
266+
infeasible at the current point. We do believe memflow is the framework that is going to bring the
267+
most empowerement to users, however, there are still ways to go.
268+
269+
## Next up - Async Metamorphosis
270+
271+
Next, we will work towards integrating [`mfio`](https://github.com/memflow/mfio) into memflow,
272+
which will enable higher scalability and simplicity. The key change is going to be transition from
273+
synchronous to asynchronous API. There are still a lot of open questions regarding this, such as
274+
FFI handling, how much the individual pieces of memflow's code will have to change, and how
275+
multithreading needs to be handled. However, we are confident those questions are not impossible
276+
to solve. Once the metamorphosis is done, we can consider the structure of memflow done. What comes
277+
afterwards, is rapid feature development. It will definitely be an exciting time to be alive. So
278+
let's just get there, shall we?
279+
280+
\- h33p

0 commit comments

Comments
 (0)