CLI tool
microsoft/avml avatar
microsoft/avml

AVML, volatile memory acquisition without touching the target

AVML - Acquire Volatile Memory for Linux

1,127 stars96 forksRustMIT

At a glance

What is it?
AVML is a Rust tool that captures Linux memory as a single static binary, so that a machine can be imaged without knowing its distribution or kernel in advance and without compiling anything on it. The interesting design is in the transport: the same snapshot can go to a local file, to Azure Blob with a block size derived from the service's own limits, or straight to a collector over TCP, and each route has different failure semantics that the documentation spells out.
Who is it for?
The tool fits an incident responder who needs a memory image from a host they cannot rebuild and cannot compile on, especially on Azure, where the VM extension path removes the need to log in at all, and the streaming mode answers the read-only-root and chain-of-custody cases that a file-first design cannot. It does not fit ARM, it does not work at all under kernel lockdown, and it does not replace an analysis platform, since it produces a LiME format image and nothing more.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The premise is that you cannot build on the machine you are imaging

AVML is a portable volatile memory acquisition tool for Linux, and the whole design follows from one sentence in the summary. It is an x86_64 userland tool written in Rust, intended to be deployed as a static binary, and it can be used to acquire memory without knowing the target operating system distribution or kernel in advance, with no on-target compilation and no fingerprinting needed.

That is the operational problem it solves. A responder who arrives at a machine with a suspected compromise, an incident on a production host, or a system that may be about to be reimaged, faces a specific difficulty. The volatile memory holds the evidence that the disk no longer has, the encryption keys, the network state, the command history of the processes that ran. And the machine is, by definition, in a state where you do not want to install a package manager, a compiler, or a script that might not run.

The static binary answers that. One file, copied in, run, and the image comes out. The Rust choice is part of that, since a statically linked Rust binary has no runtime dependencies to satisfy, and the README's build section shows the toolchain detail that makes it work on a distribution you know nothing about, with MUSL as the target and a single apt line to install it.

The second thing the tool does is give the output a format other tools understand. It uses the LiME output format when compression is off, and LiME is the de facto exchange format for Linux memory images, so an image from a machine with an unknown distribution can still be opened in the analysis tools the responder already has. Choosing a known format is what makes the artefact portable even when the target was not.

Three memory sources, and one that is not portable

The memory sources are listed plainly: /dev/crash, /proc/kcore and /dev/mem. If the memory source is not specified on the command line, AVML will iterate over the memory sources to find a functional one.

That fallback is the difference between a tool that works and a tool that does not, because the three sources are not equally available. The procfs interface is the most portable of the three, the character device is the most restricted, and the crash device is a per-kernel variation whose behaviour is not uniform across distributions. A tool that tries each in turn finds whatever the kernel on this particular machine happens to expose.

The caveat is stated in a note in the README, and it is absolute: if the kernel feature kernel_lockdown is enabled, AVML will not be able to acquire memory. That is not a bug in the tool but a property of the platform, and it is the kind of thing that decides whether an acquisition plan is viable at all, so it belongs in the first paragraph of any evaluation.

There is a subtlety in the source order that is easy to miss, and the README mentions it in the streaming section rather than in the memory sources section. The general list gives the three sources without an order, but the streaming mode is described as picking its source up front with the same preference order as the acquire path's /dev/stdout behaviour, which is /proc/kcore, then /dev/crash, then /dev/mem. So the order is not the order the sources are listed in, and the streaming mode deliberately differs from the acquire mode in one respect that matters, since the source cannot be changed mid-stream and there is therefore no automatic fallback while streaming.

Four subcommands, each behind a Cargo feature

The design choice that makes the binary usable in a constrained build is the feature layout, and the README presents it as a table.

There are four subcommands. acquire is always compiled in and takes a snapshot to a local file, with an optional upload afterwards. convert is gated by the convert feature and converts between AVML, LiME and raw formats. upload is gated by the upload feature and uploads a local file by HTTP PUT or to an Azure block blob. stream is gated by the stream feature and writes a snapshot straight to a destination with no local file at all. All four are enabled by default.

Because each capability is a Cargo feature, a minimal binary is one command away:

bash
cargo build --release --no-default-features

That produces a binary that can acquire memory and nothing else, which is the right shape for an artefact you copy onto a host: fewer code paths, less to audit, a smaller download over a slow link, and a smaller attack surface on a machine that is already suspect.

The Cargo manifest shows a fifth feature that is not a subcommand, status, which pulls in the indicatif crate. That is a progress bar, and it is a separate feature because a progress bar needs a terminal and a machine being imaged may have neither. The dependency list is otherwise lean for a tool of this kind: clap for the command line, byteorder and elf for parsing, thiserror for error types, libc for the system calls, snap for the compression, and the async stack of tokio and reqwest only where the features ask for it.

The crate targets Rust edition 2024 with a minimum supported Rust version of 1.89.0, and the package metadata is straightforward: name avml, version 0.21.0, MIT licence, with the usual categories for a command line utility and the keywords linux, memory-forensics and security.

Uploads that respect the service's own limits

The upload paths are where a memory acquisition tool meets a cloud service, and the README deals with the awkward parts rather than the happy path.

The Azure path is a SAS URL. You generate it on a secure host with the az cli credentials, using az storage blob generate-sas with an expiry, and then hand it to the acquisition command on the target host, with a --delete flag so the local copy is removed after a successful upload. The SAS URL is the authorisation, and putting it on the command line on a machine that is potentially compromised is a decision the operator makes deliberately.

The block behaviour is the detail that shows the tool was written against the service rather than against an API document. The block size is derived automatically so that the snapshot fits within Azure's per-blob 50,000-block limit, and the --sas-block-size option in mebibytes acts as a floor: if the derived minimum is larger, the larger value wins. That is the correct semantics for a safety limit, since a user who asks for a smaller block size than the service allows would otherwise fail halfway through an upload of a forty gigabyte image.

Concurrency is bounded too. The --sas-block-concurrency option caps the number of in-flight stage_block calls, and the peak memory is approximately the concurrency plus one, multiplied by the block size. That formula is stated in the readme because it is the number that decides whether the acquisition host has enough memory to upload at all, and a tool that documents its own peak RAM is one you can plan around.

Failure is handled in the way a forensic tool should. If the snapshot fails mid-upload, the staged blocks are abandoned without being committed, and Azure discards them automatically under its standard policy, so a failed run does not leave a half-written blob that looks complete. The Azure Blob uploads also retry transient failures through the Azure SDK's default exponential backoff policy, eight attempts, capped at one minute of total elapsed time. And the upload subcommand can be used on a snapshot that was captured earlier, with a put form for HTTP PUT and a blob form for a block blob.

Streaming, and what it costs you in resumability

The stream subcommand exists for the cases where writing a snapshot to disk first is a bad idea, and the README names them: a read-only root, limited disk, and forensic chain-of-custody concerns. In the last case the argument is that a file written on the suspect machine is evidence you have to defend, and a byte stream sent straight to a collector never existed there.

The mechanism is simple and the constraints are explicit. The source is picked once at the start, in the preference order /proc/kcore, then /dev/crash, then /dev/mem, with --source to override, and the bytes are written sequentially to the destination. Because the source cannot change mid-stream, there is no automatic fallback, which is a deliberate trade: a consistent stream is worth more than a stream that silently switches sources halfway.

For a collector on another host, the target listens with netcat and the sender connects once:

bash
nc -l 9000 > snapshot.lime
bash
avml stream tcp collector.example.com:9000

The two documented weaknesses are worth reading before you rely on it. If the connection drops mid-stream, the snapshot aborts, and there is no resume. And there is no TLS, so the README advises pairing it with an SSH tunnel or with stunnel if confidentiality and integrity are needed.

Those two facts are related. A single long-lived stream with no resume and no encryption is a fragile path for a forty gigabyte image over the public internet, and the tool is honest about it rather than pretending. The Azure block path, with its chunked upload and its retries, is the more reliable route and the one a careful responder would pick for a large image.

Getting onto an Azure VM without logging in

The Azure VM extension path is the one that most reduces the contact with the machine, and it is documented end to end.

You generate the SAS URL on a secure host, then create a config.json holding two things: the command to execute, which is the acquisition command with the compression flag, the SAS URL and the delete flag, and the file URIs, which point at wherever the AVML binary has been staged. The JSON in the README is exactly that:

json
{
    "commandToExecute": "./avml acquire --compress --sas-url <GENERATED_SAS_URL> --delete",
    "fileUris": ["https://FULL.URL.TO.AVML.example.com/avml"]
}

The extension is then applied with the az command line, naming the resource group, the virtual machine and the publisher, with the customScript extension and the settings file.

The value of this route is that the operator never needs an interactive session on the machine, the image goes straight to blob storage, and the local copy is deleted as part of the same command. It also has a dependency, since the binary has to be reachable at a URL, and that URL is a place where a substitution would be a serious problem, so the staging location matters.

The other cloud path is the same idea with a different signing service. The README describes generating an S3 pre-signed URL or a GCP pre-signed URL and passing it with --url and --delete, which keeps the tool independent of any particular cloud SDK for the storage itself, with the Azure SDK in the picture only for the Azure block path.

Where AVML is the wrong tool

The first limit is the architecture. The tool is x86_64, and the tested distribution matrix in the repository is entirely x86_64 server and desktop distributions, from Ubuntu 16.04 through 26.04, CentOS 7.9, RHEL from 7.9 to 10.2, Debian 11 to 13, Oracle Linux, CBL-Mariner 2.0, Azure Linux 3.0, SUSE Linux Enterprise Server and AlmaLinux. An ARM server, an embedded device, or a container on a Mac is out of scope.

The second is kernel lockdown, which is a hard stop rather than a limitation to work around. A machine with lockdown enabled cannot be imaged by this tool, and no amount of privilege will change that, because the restriction is in the kernel's own policy.

The third is what the tool is and is not. It acquires memory and writes it in the LiME format, with optional Snappy page level compression and conversion between formats available separately. It does not analyse the image, it does not index it, and it does not answer questions about it. For a responder, that is the right division of labour, since the analysis tools are numerous and the acquisition is the hard part to standardise. For a team that wanted a memory forensics platform, this is only the first component.

The fourth is the operational risk of the acquisition itself. Reading /proc/kcore, /dev/crash or /dev/mem can disturb a machine, and on a system with a kernel bug it can crash it. The README does not discuss that risk, which is worth knowing before you point the tool at the only copy of the evidence.

The fifth is the streaming path's fragility, already noted, and the fact that the SAS URL and the pre-signed URL are passed on the command line, where they are visible in the process list of a machine that is supposed to be compromised. The MIT licence and the Microsoft ownership make the tool easy to audit and to obtain support from, and the release history is steady, with v0.21.0 published on 2026-10-09 after v0.20.0 in July and v0.19.0 in June.

Editorial conclusion

The tool fits an incident responder who needs a memory image from a host they cannot rebuild and cannot compile on, especially on Azure, where the VM extension path removes the need to log in at all, and the streaming mode answers the read-only-root and chain-of-custody cases that a file-first design cannot. It does not fit ARM, it does not work at all under kernel lockdown, and it does not replace an analysis platform, since it produces a LiME format image and nothing more. Before running it, check which of the three memory sources your kernel actually exposes, because the automatic fallback only helps when one of them works, and note that the TCP streaming path has no TLS, so it needs a tunnel. The licence is MIT, version 0.21.0 was published on 2026-10-09, and the last push was on 2026-10-16.

Frequently asked questions

Which memory sources does AVML use?

The tool can read /dev/crash, /proc/kcore and /dev/mem, and if the memory source is not specified on the command line it iterates over them to find a functional one. The streaming mode picks one source up front instead, in the order /proc/kcore, then /dev/crash, then /dev/mem, with --source to override.

Can AVML acquire memory when kernel lockdown is enabled?

No. The README notes that if the kernel_lockdown feature is enabled, AVML will not be able to acquire memory, because the restriction is enforced by the platform rather than by the tool.

How do I build a minimal AVML binary?

Each subcommand is gated by a Cargo feature, so a binary that can only acquire memory is built with `cargo build --release --no-default-features`. The default build includes the stream, upload, convert and native-tls features.

How does AVML upload a snapshot to Azure Blob Storage?

Generate a SAS URL with the az cli on a secure host, then run `avml acquire --sas-url ${SAS_URL} --delete output.lime` on the target. The block size is derived automatically so the snapshot fits within Azure's 50,000-block limit, and a failed upload leaves the staged blocks uncommitted so the service discards them.

Is the AVML TCP streaming path encrypted?

No, there is no TLS. The README advises pairing it with an SSH tunnel or with stunnel when confidentiality and integrity are needed, and notes that a connection dropped mid-stream aborts the snapshot with no resume.

Official sources

  1. Issues
  2. License: MIT
  3. microsoft/avml on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/microsoft-avml.svg)](https://hysenlabs.com/projects/microsoft-avml)

Was this useful?