In this video, I show how to use the Antimalware Scan Interface (AMSI) directly from C#.
The goal is to scan files for malicious content by calling AMSI’s native APIs using P/Invoke.
We import the necessary functions from Amsi.dll, open a session, and scan a file that we load through a memory-mapped file.
To make the code cleaner, I also show how to use PreserveSig = false, which lets .NET automatically throw exceptions when an API call fails.
My conclusion from the demo:
Working with native Windows APIs from managed code is not only possible but often practical.
With a few correct declarations and proper marshaling, we can safely extend the power of C# into areas that are typically reserved for C or C++.
Steps Described in the Video
- Importing AMSI Functions
I start by defining a static class with the AMSI functions:AmsiInitialize,AmsiOpenSession, andAmsiScanBuffer.
These are imported fromAmsi.dllusing[DllImport].
Since AMSI uses C-style APIs, this is the only way to call them from managed code. - Using
PreserveSig = false
I setPreserveSig = falseon the DllImport attribute.
This tells the runtime to throw an exception automatically when the native function returns an error.
It simplifies the code and makes it feel more “.NET-like.” - Opening an AMSI Session
I callAmsiInitializeto get a context handle and thenAmsiOpenSessionto begin scanning.
These two steps prepare AMSI to analyze content from the current process. - Mapping a File into Memory
Instead of manually reading bytes, I useMemoryMappedFile.CreateFromFile().
This is a clean way to load large files and gives us direct access to memory regions without extra copies. - Getting an Unsafe Pointer
AMSI expects a pointer to the buffer.
Using the view accessor’sAcquirePointer()method, I obtain abyte*pointer to the mapped data.
This requires unsafe code, which is why I enable “Allow unsafe code” in the project settings. - Scanning the Buffer
I callAmsiScanBufferwith the pointer and the file size.
The function returns anAmsiResult, which I interpret in the code.
Results equal to or aboveAmsiResult.Detectedindicate a malicious file. - Architecture Notes
AMSI DLLs are architecture-specific.
If the project is compiled as AnyCPU, it may default to 32-bit.
Make sure to match the bitness of your process with the system’s AMSI provider. - Cleanup
In the demo, I skip full cleanup for brevity, but in real code, always close the AMSI session and context and dispose of any mapped files properly.
Conclusion
This exercise shows how we can use C# for deep integration with Windows security mechanisms.
Even though AMSI is a native API, calling it from .NET is simple and safe once we understand how interop works.
This type of project helps bridge the gap between high-level productivity and low-level system control, something every Windows developer should be comfortable with.
Why This Matters to TrainSec Students
Understanding AMSI from a developer’s perspective is essential for anyone studying Windows Internals, Malware Analysis, or EDR Development.
This demo shows both sides: how defenders use AMSI to scan for malicious content, and how attackers might study or bypass it.
At TrainSec, we often work at the boundary between managed and unmanaged code, so this kind of exercise helps students connect practical coding with real security mechanisms built into Windows.
Pick Your Path and Join the Elite
Provides the necessary knowledge, understanding, and tools to be a successful Windows OS researcher.
Keep Learning with TrainSec
This content is part of the free TrainSec Knowledge Library, where students can deepen their understanding of Windows internals, malware analysis, and reverse engineering.Subscribe for free and continue learning with us: https://trainsec.net/library
Liked the content?
Subscribe to the free TrainSec knowledge library, and get insider access to new content, discounts and additional materials.