Read-only DLL Inspection — amsi.dll (Part 1)
Read-only DLL Inspection — amsi.dll (Part 1)
Learn a repeatable read-only workflow for Windows DLLs. This part uses amsi.dll as the worked example; the same steps apply to other targets — see Choosing a DLL for read-only inspection.
| Series | read-only-dll-inspection · Part 1 |
| Example target | %windir%\System32\amsi.dll |
| Lab verified | 192.168.50.252 — 101.5 KB, v10.0.19041.4355, signature Valid (inventory) |
| Prerequisites | Lab VM; tools in Step 0; optional target pick from 00-dll-target-selection |
| Refs | PE structure · Microsoft Sysinternals |
Do not rename, patch, replace, or take ownership of system DLLs. Part 2 will go deeper in Ghidra; this part stops at basic x64 vocabulary.
Table of Contents
- What is this guide?
- Step 0 — Set up safely
- Step 1 — Locate amsi.dll and collect its details
- Step 2 — Verify its signature
- Step 3 — Check which processes load it
- Step 4 — Inspect the DLL structure without running it
- Step 5 — Explore it in Ghidra
- Step 6 — Learn the minimum x64 assembly vocabulary
- What to record in your lab notebook
- Navigation
What is this guide?
0. Purpose
Build a repeatable, read-only inspection workflow for Windows DLLs. You will collect facts — path, version, signature, who loads it, PE structure, exports, and decompiler hints — before drawing any security conclusions.
amsi.dll (Antimalware Scan Interface) is the worked example in this part because:
- It is a real Microsoft-signed system DLL.
- Legitimate programs load it when they scan scripts or content.
- Security literature discusses it often, so learning its normal shape prevents false alarms later.
The workflow is DLL-agnostic. Use Choosing a DLL for read-only inspection for tiered candidates (version.dll, wldp.dll, crypt32.dll, …) and a prioritization rubric. Substitute your DLL name in each step below.
This guide is not about bypassing AMSI.
1. High level (explain like I'm five)
Imagine Windows keeps a toolbox of shared parts. A DLL is one part many programs can borrow.
amsi.dll is like a spell-checker for suspicious computer instructions — programs ask it to look at text or scripts before running them.
You are going to:
- Find the toolbox drawer where
amsi.dlllives. - Check the label (version, size, date).
- Check the Microsoft sticker (digital signature).
- See which programs currently borrowed that tool.
- Open the box and read the instruction sheet without turning anything on.
- Use a magnifying glass (Ghidra) to read what the functions probably do.
- Learn a few words of the machine's language (x64 assembly).
You never break the seal. You never swap the part. You only look.
2. Deep breakdown
Each numbered step below follows the same three-part shape:
| Layer | Question it answers |
|---|---|
| 0. Purpose | Why this step exists |
| 1. High level | The idea in plain language |
| 2. Deep breakdown | Exact clicks, commands, and what to write down |
Step 0 — Set up safely
0. Purpose
Create a learning environment where mistakes do not damage your daily machine or teach bad habits (disabling defenses, patching system files).
1. High level (explain like I'm five)
Use a practice computer — like a toy kitchen instead of the real stove. Keep the smoke alarm on. Only bring trusted tools from the real store. Do not take apart Windows' built-in parts.
2. Deep breakdown
Prerequisites checklist
Rules (non-negotiable)
| Rule | Why |
|---|---|
Do not rename, patch, replace, or take ownership of amsi.dll | You are learning inspection, not evasion |
| Do not disable Defender "to make analysis easier" | Real defenders keep protections on; your lab should too |
| Work on copies when a GUI tool imports a file | Import/copy ≠ execute, but copies reduce accidental execution risk |
| Install tools only from official sources | Supply-chain risk is real |
Install these tools (official sources only)
| Tool | Role | Official source |
|---|---|---|
| Process Explorer | See which processes loaded a DLL | Microsoft Sysinternals |
| Process Monitor | Optional; filter file/registry activity during learning | Microsoft Sysinternals |
| Dependencies | Visual import/export dependency graph | Dependencies project releases |
| PE-bear or CFF Explorer | PE headers, sections, imports, exports | PE-bear: hasherezade releases · CFF: ntcore |
| Ghidra | Disassembly and decompilation | NSA Ghidra releases |
| WinDbg Preview | Optional; kernel/user debugging literacy | Microsoft Store — WinDbg Preview |
Optional (helpful for exports listing)
- Visual Studio Build Tools — provides
dumpbin.exefor export tables from the command line.
Suggested VM snapshot
Before you start Step 1, take a VM snapshot named something like pre-amsi-inspection. If you accidentally install a shady "cracker" tool, revert instead of troubleshooting for hours.
Step 1 — Locate amsi.dll and collect its details
0. Purpose
Establish a baseline fingerprint for the file: where it lives, how big it is, which version Windows installed, and when it last changed.
1. High level (explain like I'm five)
Ask Windows: "Where is amsi.dll, how heavy is it, what version is on the sticker, and when was the sticker last updated?"
Write the answers in your notebook. Later, if something looks weird, you compare against this baseline.
2. Deep breakdown
Open PowerShell (normal user is fine)
Press Win, type PowerShell, open Windows PowerShell — not necessarily "Run as administrator" for this step.
64-bit amsi.dll (native on 64-bit Windows)
$path = "$env:windir\System32\amsi.dll"
Get-Item $path | Select-Object FullName, Length, LastWriteTime, VersionInfo
Example shape of output (your numbers will differ; lab .252 on 2026-08-31 shown):
FullName : C:\Windows\System32\amsi.dll
Length : 103936
LastWriteTime : 6/16/2025 1:05:07 PM
VersionInfo : File: C:\Windows\System32\amsi.dll
...
FileVersion: 10.0.19041.4355
ProductVersion: 10.0.19041.4355
32-bit copy on 64-bit Windows (SysWOW64)
64-bit Windows keeps a separate 32-bit compatibility tree. Inspect it separately:
Get-Item "$env:windir\SysWOW64\amsi.dll" |
Select-Object FullName, Length, LastWriteTime, VersionInfo
On pure 32-bit Windows (rare today), only the System32 path applies.
Record this table
| Field | System32 value | SysWOW64 value (if applicable) |
|---|---|---|
| Full path | ||
| File size (bytes) | ||
| File version | ||
| Product version | ||
| Last write time |
What "normal" looks like
- Path is under
%windir%\System32(and optionallySysWOW64). - Version aligns with your Windows build (compare to
winverorGet-ComputerInfo). - Size is stable across machines on the same build — large unexpected differences warrant investigation, not panic.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
Cannot find path | AMSI component not present on edition/sku | Confirm Windows edition; check %windir%\System32 in Explorer |
Access denied on Get-Item | Rare policy restriction | Try read-only Explorer Properties; confirm you are not redirecting with hard links |
Very old LastWriteTime | File not updated recently | Cross-check Windows Update history before assuming tampering |
Step 2 — Verify its signature
0. Purpose
Confirm whether Windows sees the file as authentically signed by Microsoft at inspection time. Signature validation is a core trust signal for system DLLs.
1. High level (explain like I'm five)
Official Microsoft parts come with a tamper-evident sticker. You check the sticker with Windows' own checker. Valid means the sticker passed right now.
A bad sticker is a clue, not automatic proof that hackers were here — investigate calmly.
2. Deep breakdown
PowerShell method
$path = "$env:windir\System32\amsi.dll"
Get-AuthenticodeSignature $path |
Format-List Status, StatusMessage, SignerCertificate
Healthy result (conceptual):
Status : Valid
StatusMessage : Signature verified.
SignerCertificate : [Subject]
CN=Microsoft Windows
...
Repeat for SysWOW64 if you are cataloging both copies.
File Explorer method
- Open
C:\Windows\System32in File Explorer. - Right-click
amsi.dll→ Properties. - Open the Digital Signatures tab.
- Select the signature → Details.
- Note signer name, timestamp, and thumbprint if shown.
Record
| Check | System32 | SysWOW64 |
|---|---|---|
Status | ||
Signer (CN=...) | ||
| Signature timestamp |
Interpretation guide
| Status | Meaning | Next step |
|---|---|---|
| Valid | Signature verified at inspection time | Continue — expected for stock amsi.dll (confirmed on lab .252: CN=Microsoft Windows) |
| NotSigned | No embedded Authenticode signature | Unusual for inbox amsi.dll; verify image source and update history |
| HashMismatch | File changed after signing | Treat as high-priority; compare hash to known-good on same build; involve IR if production |
| UnknownError | Validation could not complete | Retry; check system time, corp trust stores, and disk health |
Signature proves publisher identity and integrity at signing time, not that every export is harmless. You are still doing read-only structural analysis.
Step 3 — Check which processes load it
0. Purpose
See who is using amsi.dll right now. This connects the file on disk to runtime behavior.
1. High level (explain like I'm five)
Some programs borrow the spell-checker tool while they work. You walk around the computer asking, "Who has amsi.dll in their hands?"
Seeing it in a process is often normal, not scary by itself.
2. Deep breakdown
Process Explorer workflow
- Download and run Process Explorer from Sysinternals.
- Run as administrator only if your policy allows it (helps see more processes; not always required).
- Press
Ctrl+F(Find Handle or DLL). - Search:
amsi.dll - Double-click a match to jump to that process.
- Open the lower pane: View → Lower Pane View → DLLs (if not already showing).
- Select
amsi.dllin the module list and read: path, company/publisher, version.
What to record (per match)
| Process name | PID | DLL path loaded | Publisher | Notes |
|---|---|---|---|---|
powershell.exe | 1234 | C:\Windows\System32\amsi.dll | Microsoft Corporation | example |
| ... |
Expected loaders (examples — your list will vary)
- PowerShell / pwsh — script content scanning
- Scripting hosts and some security-aware applications
- Management or inspection tools that touch scriptable surfaces
What is not a conclusion
| Observation | Do not conclude |
|---|---|
amsi.dll loaded in PowerShell | "Malware is present" |
| Multiple processes load it | "DLL is hijacked" |
| No matches at idle | "AMSI is disabled" (maybe nothing scriptable is running) |
Optional: make it load for practice
In a lab VM only, start a new PowerShell window and run a benign command:
'hello' | Out-Null
Search again in Process Explorer. You are proving the observation method, not attacking anything.
Process Monitor (optional extension)
If you want to see load events over time:
- Start Procmon as admin.
- Filter:
Pathcontainsamsi.dllANDOperationisLoad Image. - Start a new PowerShell instance.
- Confirm a
Load Imageevent appears.
Stop capture when done — Procmon fills disks quickly if left running.
Step 4 — Inspect the DLL structure without running it
0. Purpose
Read the DLL's blueprint on disk: CPU architecture, sections, imported APIs, exported functions, resources, and certificate directory — without executing the file.
1. High level (explain like I'm five)
A DLL is a labeled filing cabinet. You open the cabinet, read the folder tabs, see which other cabinets it borrows tools from, and list which tools it shares — but you never press the "start machine" button.
2. Deep breakdown
Golden rule
Open a copy in PE tools when the tool imports files. In Explorer:
Copy-Item "$env:windir\System32\amsi.dll" -Destination "$env:USERPROFILE\Desktop\amsi-copy.dll"
Analyze amsi-copy.dll on the Desktop. Do not rename the system original.
Tool choice
| Tool | Best for |
|---|---|
| PE-bear | Fast PE tree navigation, sections, imports/exports |
| CFF Explorer | Deep PE header editing view (use read-only here) |
| Dependencies | "What DLLs does this need?" dependency graph |
Review order (same in any PE viewer)
1. Headers
| Field | What it tells you |
|---|---|
| Machine / architecture | AMD64 vs I386 — must match the path you copied |
| Timestamp | Build/link time (hint only; not cryptographically trustworthy) |
| Image base | Preferred load address in memory |
| Subsystem | WINDOWS_GUI / WINDOWS_CUI — how loader treats it |
2. Sections
| Section | Typical role |
|---|---|
.text | Executable code |
.rdata | Read-only constants (strings, vtables) |
.data | Writable globals |
.pdata / .reloc | Exception handling / relocation fixups |
Note virtual size vs raw size — large discrepancies can be normal; huge empty gaps elsewhere might be worth a second look in malware exercises (less common for inbox Microsoft DLLs).
3. Imports
List which Windows APIs amsi.dll calls and from which DLLs (e.g., kernel32.dll, ntdll.dll, ole32.dll).
Ask: "What facilities does this component need?" — memory, COM, registry, RPC, etc.
4. Exports
List functions this DLL offers to other programs. For AMSI, Microsoft documents eight exports in Amsi.h:
| Export | Role (from Microsoft Learn) |
|---|---|
AmsiInitialize | Initialize the AMSI API |
AmsiUninitialize | Tear down the AMSI instance |
AmsiOpenSession | Open a correlated scan session |
AmsiCloseSession | Close a session |
AmsiScanBuffer | Scan a memory buffer |
AmsiScanString | Scan a string |
AmsiNotifyOperation | Notify the antimalware provider of an operation |
AmsiResultIsMalware | Interpret scan result (documented as a macro in the TOC) |
Many blog posts list only six exports and omit AmsiNotifyOperation and AmsiResultIsMalware. Your export table should match Microsoft's function list, not a shortened cheat sheet.
Record the export names and ordinal list. You will revisit these in Ghidra.
5. Resources
Check version info (VS_VERSION_INFO) — should correlate with Step 1 VersionInfo.
Manifest resources may describe activation context or compatibility flags.
6. Security directory
Shows Authenticode-related metadata locations. Correlate with Step 2 — the PE security directory is how signing hooks into the file format.
dumpbin export listing (optional)
If Visual Studio Build Tools are installed, open x64 Native Tools Command Prompt and run:
dumpbin /exports C:\Windows\System32\amsi.dll
This reads metadata only; it does not modify the DLL.
Capture: screenshot or paste the export table into your notebook.
Cross-link
For PE background, see Portable Executable Structure.
Step 5 — Explore it in Ghidra
0. Purpose
Turn static exports into understandable functions: signatures, cross-references, strings, imported APIs, and decompiler approximations — still without patching the binary.
1. High level (explain like I'm five)
Ghidra is a super-powered decoder ring for machine language. You tell it which file to study, it draws maps of the functions, and you label things in your notebook project — not on the real DLL.
The decoder ring guesses. You verify guesses with clues (strings, API names, docs).
2. Deep breakdown
Prepare the file
Use the same desktop copy: amsi-copy.dll. Do not import directly from System32 if your workflow can avoid it.
Create a Ghidra project
- Launch Ghidra.
- File → New Project → Non-Shared Project.
- Name it
amsi-inspection-lab(or similar) and pick a folder under your user profile. - File → Import File → select
amsi-copy.dll. - Accept default format detection (Portable Executable (PE)).
- When asked to analyze, click Yes and accept default analyzers (PE, function ID, decompiler propagation, etc.).
- Wait until analysis finishes (progress bottom-right).
Open the program
Double-click amsi-copy.dll in the project window. Ghidra opens the CodeBrowser.
Find exports
- Open Window → Symbol Tree (if not visible).
- Expand Exports.
- You should see symbols such as
AmsiScanBuffer,AmsiInitialize, etc.
If names are missing (rare for Microsoft DLLs), check Exports view under Window → Defined Strings / Symbol Table and compare to Step 4 export list.
Pick a first function
Start with AmsiInitialize or AmsiScanBuffer — well-documented entry points.
Click the function name → Ghidra jumps to disassembly. Open the decompiler: Window → Decompile (or the dragon icon).
What to examine (checklist per function)
| Artifact | Why it matters |
|---|---|
| Function signature | Return type and parameters (often inferred) |
| Callers (References → Show References to) | Who uses this export inside the DLL |
| Callees | Which internal helpers and Win APIs it uses |
| Strings window | Error messages, registry paths, logging clues |
| Imports | External dependencies (AmsiScanBuffer will touch scanning pipelines) |
| Control flow | Branches for error handling vs success paths |
Document in Ghidra, not in the binary
- Right-click → Label to rename locations for your understanding.
- Window → Comments to attach notes.
- These changes live in the Ghidra project, not on disk in
amsi.dll.
Decompiler hygiene
| Remember | Because |
|---|---|
| Decompiler output is an approximation | Optimizations and metadata loss confuse types |
Names like FUN_180001234 are placeholders | Rename only in the project |
| Microsoft docs beat guesses | Cross-check exports against AMSI API documentation |
| AMSI is vendor-agnostic | Microsoft: any registered antimalware provider can integrate — not Defender-only |
Minimal first-session exercise
- Export list: write all
Amsi*exports. - For
AmsiScanBuffer: note parameter count guess and whether it calls the same internal helper repeatedly. - Find at least one error string near failure branches.
- Find one imported API you recognize (e.g., memory allocation or synchronization).
Stop after 30–45 minutes. Part 2 will extend this into cross-reference tracing and comparison workflows.
Step 6 — Learn the minimum x64 assembly vocabulary
0. Purpose
Give you enough reading glasses to follow Ghidra's disassembly pane without becoming a full-time assembly developer.
1. High level (explain like I'm five)
The CPU reads a recipe one line at a time. Some lines call helpers, some compare numbers, some jump to a different step. Registers are scratch pads holding numbers that are often addresses (where something lives in memory), not always the final answer themselves.
2. Deep breakdown
Core instructions
| Instruction | Plain meaning | Tiny example mental model |
|---|---|---|
call | "Go run that function, then come back" | Calling AmsiInitialize |
cmp / test | "Compare these values; set flags for a branch" | test rax, rax → "is RAX zero?" |
je, jne, ja, ... | "Jump if the last comparison said ..." | jne error_path → branch on not-equal |
mov | Copy bits between register/memory | mov rcx, rdx |
ret | Return from current function | End of export stub |
Registers (Windows x64 calling convention — first pass)
| Register | Role in many calls |
|---|---|
RCX | 1st integer/pointer argument |
RDX | 2nd argument |
R8 | 3rd argument |
R9 | 4th argument |
RAX | Return value (many functions) |
RSP | Stack pointer — where the stack lives |
RBP | Optional frame pointer in some functions |
Additional arguments may spill to the stack. Ghidra often annotates them in the decompiler view.
Pattern recognition drill (in Ghidra)
Open AmsiScanBuffer disassembly and try to spot:
mov rcx, .../mov rdx, ...near the top — likely setting up arguments.- A
callto an internal function or imported API. test eax, eaxorcmpfollowed byje/jne— success vs failure split.retat the end of the function.
Registers hold addresses more often than "numbers"
If you see mov rax, qword ptr [rcx], read it as: "Load the 8-byte value at the memory address stored in RCX into RAX" — not "RCX equals that value."
Study method (10 minutes/day)
| Day | Focus |
|---|---|
| 1 | Identify call and ret in one export |
| 2 | Circle rcx/rdx/r8/r9 setup before a call |
| 3 | Match one je/jne pair to decompiler if |
| 4 | Open Microsoft docs for the same export name side-by-side |
Further reading (vault)
- Portable Executable Structure
- Attack-focused context (read after this guide): Attack AMSI
What to record in your lab notebook
By the end of Part 1, you should have:
Navigation
← Windows Playbook · DLL target selection · Part 1 · Part 2 (coming) →
Related: PE structure · Attack AMSI