Source: Juni_2026_Exams/Advance_Forensics/solutions/exam-2025-complete-solution.md
Malware Analysis Exam 2025 β Complete Detailed Solution
Exam Context
VM credentials
| Field | Value |
|---|---|
| VM | Exams MA 2025 (added from second drive in VirtualBox) |
| Username | ieuser |
| Password | <LAB_VM_PASSWORD_FROM_EXAM_PDF> |
| Sample | C:\Temp\sample.exe |
Scoring
| Question | Topic | Marks |
|---|---|---|
| Q1 | File type and packing | 2 |
| Q2 | Files created on execution | 2 |
| Q3 | Code injection β 4 API stages | 4 |
| Q4 | Created thread IDs | 2 |
| Total | 10 |
Delivery: PDF named Exams2025_<YourName>.pdf. Every answer must include at least one screenshot showing the tool used and the result visible.
Lab safety rule: Restore a clean VM snapshot before executing the sample. Never execute the sample outside the isolated VM.
Pre-Exam Setup Checklist
Before touching the sample:
- Boot the VM and confirm you are logged in as
ieuser. - Open VirtualBox settings β Devices β Shared Clipboard β set to Disabled.
- Take a fresh snapshot: Machine β Take Snapshot β "Clean baseline".
- Confirm
C:\Temp\sample.exeexists. Do not execute it yet. - Open ProcMon, CFF Explorer, DiE, PEiD, APIMiner in advance so they are ready.
- Open Notepad++ for reading APIMiner trace files.
Question 1: File Type and Packing (2 marks)
Question text
What is the file type? Is it packed?
Theory background
A Portable Executable (PE) file is the binary format used by Windows for .exe, .dll, and .sys files. PE32 = 32-bit executable; PE32+ = 64-bit executable. This is recorded in the Machine field of the File Header and the Magic field of the Optional Header.
Packing is a compression/encryption technique used by malware to hide its real code and evade static detection. A packed file has its real code compressed or encrypted; a small stub unpacks it into memory at runtime. Packed files have these characteristics:
- Very high entropy (randomness measure approaching 8.0 out of 8.0)
- Few meaningful imports in the Import Directory (the stub only needs a handful)
- Section names associated with known packers (
UPX0,UPX1,.packed,.MPRESS1) - Raw size of packed sections much smaller than Virtual size
- Sections flagged as
packedorExecutable + Writablesimultaneously (unusual)
Tool 1: CFF Explorer β Identify file type
Steps:
- From the desktop, open CFF Explorer VIII.
File β Openβ browse toC:\Temp\sample.exe.- In the left tree click Nt Headers β File Header.
- Read the Machine value.
What to look for:
| Field | Expected value | What it means |
|---|---|---|
| Machine | 014C (I386) |
32-bit Intel x86 = PE32 |
| Characteristics | 0102 |
Executable, 32-bit |
| Number of Sections | 0003 |
Three sections in the PE |
- Click Nt Headers β Optional Header.
- Read Magic:
010B= PE32 (32-bit).020Bwould mean PE32+ (64-bit).
Also record from the file overview panel (top right):
| Field | Value observed in 2025 exam |
|---|---|
| File Name | C:\Temp\sample.exe |
| File Type | Portable Executable 32 |
| File Size | 784.50 KB (803,328 bytes) |
| PE Size | 784.50 KB (803,328 bytes) |
| MD5 | 0AEEE7BAE9D17D90C3C0A4FED83CC439 |
| SHA-1 | F2F68F8424A3F93E64BF9A3B1FCD3AA69F4721D3 |
Screenshot needed: CFF Explorer main window showing File Type = "Portable Executable 32" highlighted.
Tool 2: Detect It Easy (DiE) β Confirm type and detect packing
Steps:
- Open Detect It Easy v3.04 from desktop.
- Drag
C:\Temp\sample.exeonto the DiE window (or File β Open). - Let it scan (the scan bar reaches 100%).
What to read from the DiE main panel:
| Field | Value | Significance |
|---|---|---|
| File type | PE32 | Confirms 32-bit PE |
| Entry point | 00710BE0 |
Very high address β unpacker stub lives here |
| Base address | 00400000 |
Standard x86 base |
| Sections | 0003 |
Three sections |
| Time date stamp | 1970-01-01 02:00:00 |
Zeroed/fake timestamp β evasion indicator |
| Size of image | 00312000 |
~3 MB virtual footprint vs 784 KB on disk = significant decompression expected |
| Architecture | 32-bit, I386 | |
| Mode | Console | |
| Signature line | PE32 / Linker: Microsoft Linker(3.4)[Console32,console] |
The
S ?marker next to the signature means the packer signature was not matched in the signature database β but entropy confirms packing.
- Click the Entropy button (top right panel).
What to read from the Entropy view:
| Region | Offset | Size | Entropy | Status | Name |
|---|---|---|---|---|---|
| PE Header | 00000000 |
00001000 |
7.64268 | packed | PE Header |
| Section 1 | 00000200 |
000C3E00 |
7.99499 | packed | [UPX1] |
| Section 2 | 000C4000 |
00000200 |
1.97007 | not packed | [.rsrc] |
Total entropy: 7.99488 β Status: packed (99%)
An entropy of 8.0 is the theoretical maximum (pure random data). Values above ~7.2 are strongly indicative of compression or encryption. A value of 7.99 means the packed section is essentially random data β consistent with a UPX-compressed payload.
- Note also:
- Section named
UPX1is the primary indicator of UPX packing. - Section named
.rsrcis the resource section β it is NOT packed (low entropy), which makes sense because UPX does not always compress resources.
Screenshot needed: DiE Entropy window showing Total = 7.99488, Status = packed(99%), with section breakdown visible.
Tool 3: PEiD β Cross-verification
Steps:
- Open PEiD v0.95 from desktop.
...button β browse toC:\Temp\sample.exeβ Open.- Click Multi Scan.
- Then click Options β Extra Information (or the
>>button).
What to read:
| Field | Value | Significance |
|---|---|---|
| Entry point | 00310BE0 |
|
| EP Section | UPX1 | Entry point is inside the UPX1 section β packer stub is there |
| First Bytes | 68,00,00,00 |
|
| Entropy | 8.00 (Packed) | Confirms packing |
| EP Check | Packed | PEiD directly flags it |
| Fast Check | Not Packed | Fast check is not reliable for all packers; the full check overrides |
| Detected | Nothing found * |
PEiD didn't identify the specific packer, but entropy check did |
The
UPX1section name combined with entropy 8.0 is strong evidence of UPX packing. PEiD explicitly reports "Packed" in its EP Check.
Screenshot needed: PEiD Extra Information popup showing
Entropy: 8.00 (Packed)andEP Check: Packed.
Supporting evidence: Import directory sparseness
Return to CFF Explorer β Import Directory.
A packed binary typically shows very few imports because the stub resolves imports dynamically at runtime. Check whether the import table is nearly empty compared to a typical executable of the same size. This is secondary evidence supporting packing.
Final Answer β Q1
File type: Portable Executable 32 (PE32) β a 32-bit Windows executable.
Is it packed? YES. Evidence:
| Evidence | Value | Source |
|---|---|---|
| Overall entropy | 7.99488 (~8.0/8.0) | DiE Entropy view |
| Packed section | UPX1 entropy = 7.99499 | DiE Entropy view |
| EP section name | UPX1 | PEiD |
| PEiD EP Check | Packed | PEiD Extra Information |
| PEiD Entropy | 8.00 (Packed) | PEiD Extra Information |
| Virtual/Raw size | Image expands from 784 KB on disk to ~3 MB in memory | DiE / CFF Explorer |
| Fake timestamp | 1970-01-01 02:00:00 | DiE β evasion indicator |
Conclusion: sample.exe is a 32-bit Portable Executable (PE32) that is packed with UPX (or a UPX-like packer). High entropy approaching 8.0, the UPX1 section name at the entry point, and direct confirmation from PEiD all support this conclusion. The packing hides the real malicious code from static analysis tools and antivirus scanners.
Marks strategy for Q1
- State the file type explicitly: "PE32 / 32-bit Portable Executable" = 1 mark.
- State it is packed with at least two supporting pieces of evidence = 1 mark.
- Do NOT just say "the entropy is high" β connect high entropy (7.99) to the meaning (nearly maximum = strong indicator of compression/encryption).
Question 2: Files Created in C:\Temp (2 marks)
Question text
Which files are created on the C:\temp directory when executed?
Theory background
ProcMon (Process Monitor) is a Sysinternals tool that logs every filesystem, registry, process, and network event in real time. When malware runs, it reveals:
- Files it creates, reads, writes, renames, or deletes
- Registry keys it reads or modifies
- Processes/threads it creates
The CreateFile operation in ProcMon does NOT mean "only newly-created files." It is the Windows API call CreateFile() which can open existing files OR create new ones. The Result column (SUCCESS, FILE EXISTS, NAME NOT FOUND) distinguishes the two. We focus on SUCCESS results with a path under C:\Temp.
Self-deletion / transient files: Malware often creates helper files, does its work, then deletes them immediately to reduce forensic evidence. ProcMon catches these even if they are gone before we look at the disk. The SetDispositionInformationFile operation (or SetRenameInformationFile) is used to mark a file for deletion.
Step-by-step procedure
Step 1 β Restore clean snapshot
In VirtualBox: Machine β Restore Snapshot β "Clean baseline" β Restore. This ensures ProcMon captures from a known-clean state with no residual artifacts from a previous run.
Step 2 β Open ProcMon and configure filters
- Double-click
ProcMon.exeon the desktop (or run from Sysinternals folder). - ProcMon starts capturing immediately. Press
Ctrl+Eto stop capture. - Press
Ctrl+Xto clear all existing events. - Open the filter dialog:
Filter β Filterβ¦(orCtrl+L).
Add these filters in this order:
| Column | Relation | Value | Action |
|---|---|---|---|
| Process Name | is | sample.exe |
Include |
| Operation | is | CreateFile |
Include |
| Path | contains | C:\Temp |
Include |
You will also want a Thread filter for Q4: add
Operation contains Threadas a third Include filter. Configure all filters before running the sample so you capture everything in one pass.
- Click OK.
Step 3 β Start capture and execute the sample
- Press
Ctrl+Eto start capture in ProcMon. - Open an elevated Command Prompt (right-click β Run as Administrator).
- Execute the sample:
cd /d C:\Temp
sample.exe
- Wait for the sample to finish all visible activity (a few seconds to a minute).
- Press
Ctrl+Eagain to stop capture. - Save the trace:
File β Save β All events β PML file β C:\Temp\trace.pml. Save before changing filters so you never lose data.
Step 4 β Identify created files
With the filters active (Process Name = sample.exe, Operation = CreateFile, Path contains C:\Temp), read the results.
Observed results from 2025 exam:
Two PIDs are visible: 2272 (the original sample.exe process) and 2824 (a spawned child process). This is already a signal of process-related activity.
Files created (non-self-referential entries):
| Path | PID | Significance |
|---|---|---|
C:\Temp |
2272 | Directory reference during unpacking |
C:\Temp\sample.exe |
2272 | Self-reference (the sample reading itself) |
C:\Temp\old_sample.exe |
2272 | Renamed copy of original β the packer moves the original |
C:\Temp\ui |
2272 | New directory created |
C:\Temp\ui\SwDRM.dll |
2824 | DLL dropped in ui subdirectory |
C:\Temp\IPHLPAPI.DLL |
2824 | DLL dropped (IP Helper API β network functions) |
C:\Temp\WINNSI.DLL |
2824 | DLL dropped (Windows NSI β network state) |
C:\Temp\powrprof.dll |
2824 | DLL dropped (Power Profile helper) |
C:\Temp\config.json |
2824 | Configuration file dropped |
All of these artifacts are deleted almost immediately after creation. This is classic malware self-cleanup behavior β the sample extracts, uses, then removes its components to hinder post-mortem disk analysis.
Why do they still appear in ProcMon? ProcMon captures events at the kernel level in real time, including files that are created and deleted within milliseconds. Even if the file is gone from disk by the time the capture stops, ProcMon already logged the CreateFile (creation) and the SetDispositionInformationFile (deletion) events.
Screenshot needed: ProcMon window with filters active showing the file list. Ensure columns visible include: Time of Day, Process Name, PID, Operation, Path. Highlight the rows showing
old_sample.exe,ui\SwDRM.dll,IPHLPAPI.DLL,WINNSI.DLL,powrprof.dll,config.json.
What each artifact tells us
| Artifact | Interpretation |
|---|---|
old_sample.exe |
UPX self-extraction: the packer renames the original before overwriting it with the unpacked binary |
ui\ directory |
A staging directory for companion files |
SwDRM.dll |
"Software DRM" DLL β likely part of the payload or a dependency |
IPHLPAPI.DLL |
IP Helper API β used for network operations (enumerating connections, ARP, routes) |
WINNSI.DLL |
Windows Network Store Interface β low-level network stack |
powrprof.dll |
Power profile helper β can be abused for DLL hijacking or side-loading |
config.json |
Configuration data for the payload (C2 address, options, keys, etc.) |
The presence of IPHLPAPI.DLL and WINNSI.DLL in C:\Temp (rather than System32) strongly suggests DLL search-order hijacking or DLL side-loading β the malware drops its own versions of legitimate-looking DLLs so that when a process loads them, it loads the malicious version instead.
Final Answer β Q2
Files created in C:\Temp when sample.exe is executed:
C:\Temp\old_sample.exeβ renamed copy of the originalC:\Temp\ui\β newly created subdirectoryC:\Temp\ui\SwDRM.dllC:\Temp\IPHLPAPI.DLLC:\Temp\WINNSI.DLLC:\Temp\powrprof.dllC:\Temp\config.json
All artifacts are deleted almost immediately after creation. Evidence captured via ProcMon CreateFile filter with Process Name = sample.exe and Path contains C:\Temp.
Marks strategy for Q2
- Full list of files = 1 mark.
- Note that they are deleted almost immediately (shows understanding of transient artifacts) = 1 mark.
- Don't forget
old_sample.exeβ students commonly miss it. - Include the
ui\directory as well as its contents.
Question 3: Code Injection β 4 API Stages (4 marks)
Question text
Does it perform code injection? Verify the 4 steps of code injection with API usage (which APIs are used).
Theory background
Process injection is a technique where malicious code is loaded and executed inside the address space of a legitimate process (e.g., explorer.exe, svchost.exe). Benefits for the attacker:
- The malicious code runs under a trusted process name, evading task-manager inspection.
- The injected code inherits the target process's permissions and security context.
- Many security tools whitelist legitimate processes by name.
The four canonical stages of process injection:
| Stage | Goal | Classic APIs | Section-mapping APIs |
|---|---|---|---|
| 1. Target discovery | Find and open a target process | CreateToolhelp32Snapshot, Process32First, Process32Next, OpenProcess |
Same |
| 2. Memory allocation / privilege | Get write access to target memory | VirtualAllocEx, VirtualAlloc, VirtualProtect, AdjustTokenPrivileges, LookupPrivilegeValueW |
NtAllocateVirtualMemory, NtProtectVirtualMemory |
| 3. Payload write / mapping | Put the malicious code into target memory | WriteProcessMemory |
NtCreateSection, NtMapViewOfSection, NtUnmapViewOfSection |
| 4. Execution | Start the payload running | CreateRemoteThread, NtCreateThreadEx, QueueUserAPC |
CreateThread, GetThreadContext, SetThreadContext, ResumeThread |
The 2025 sample uses section-mapping injection (Stage 3) rather than the classic
WriteProcessMemorytechnique. This is more evasive because it avoids the commonly-monitoredWriteProcessMemorycall.
Tool: APIMiner
APIMiner hooks all API calls made by a process and records them to text files. Unlike ProcMon (which shows filesystem/registry/process events), APIMiner records every Windows API function call with its arguments.
Command (run from elevated cmd.exe in C:\Temp):
C:\Users\IEUser\Desktop\APIMiner.lnk --app C:\Temp\sample.exe
Or equivalently via the shortcut directly:
cd /d C:\Temp
"C:\Users\IEUser\Desktop\APIMiner.lnk" --app C:\Temp\sample.exe
APIMiner creates trace files in C:\Temp:
C:\Temp\apiminer_traces.293906.pid_4092.txt (process 1 trace)
C:\Temp\apiminer_traces.293906.pid_1432.txt (process 2 trace)
The run ID (
293906) and PIDs will differ each time. There are two trace files because the sample spawns a child process β each process gets its own trace.
Open both files with Notepad++: File β Open β select both files. Use Search β Find in Files (Ctrl+Shift+F) to search across both traces simultaneously.
Screenshot needed for the command: The cmd.exe window showing the command and the
C:\Tempdirectory afterwards with the two.txtfiles visible.
Stage 1: Target Discovery / Process Opening
What we're looking for: APIs that enumerate running processes and open a handle to a target.
Search in Notepad++: CreateToolhelp32Snapshot then OpenProcess
APIs found in the 2025 exam:
| API | Purpose |
|---|---|
CreateToolhelp32Snapshot |
Creates a snapshot of all running processes (a list of PIDs, names, parent PIDs). The attacker uses this to find a suitable target process. |
Process32First / Process32Next |
Iterates through the snapshot entries one by one. The injector walks the list comparing process names until it finds its target. |
OpenProcess |
Opens a handle to the chosen target process with the required access rights (typically PROCESS_ALL_ACCESS or `PROCESS_VM_WRITE |
Trace evidence:
Line 212: <system>-<0,0x00000000> LdrGetProcedureAddress(... "CreateToolhelp32Snapshot", ...)
Line 185: <system>-<0,0x00000000> LdrGetProcedureAddress(... "OpenProcessToken", ...)
Line 277: <system>-<0,0x00000000> LdrGetProcedureAddress(... "OpenProcess", ...)
LdrGetProcedureAddressis how the unpacked payload resolves API addresses dynamically at runtime (equivalent toGetProcAddress). Seeing it look up injection-related APIs is itself an indicator that these APIs are being used deliberately.
Why this is evidence of injection and not normal behavior: A legitimate application (e.g., a game or a text editor) does not need to enumerate all running processes and open handles to them. The only common legitimate use case is antivirus or process monitoring software β which this sample is clearly not.
Screenshot needed: Notepad++ search results showing
CreateToolhelp32Snapshotfound in the trace, and separatelyOpenProcessfound.
Stage 2: Privilege Escalation and Memory Allocation
What we're looking for: APIs that elevate privileges to ensure cross-process access, and APIs that reserve memory in the target process.
Search in Notepad++: privile (matches both AdjustTokenPrivileges and LookupPrivilegeValueW)
APIs found in the 2025 exam:
| API | Purpose |
|---|---|
LookupPrivilegeValueW |
Looks up the LUID (locally unique identifier) for a named privilege β specifically SeDebugPrivilege. This privilege allows a process to open handles to other processes regardless of security settings. |
AdjustTokenPrivileges |
Enables or disables privileges in an access token. Used here to enable SeDebugPrivilege on the injector's token, giving it the ability to open any process on the system. |
VirtualAlloc |
Allocates a memory region (in the injector's own address space) β used to prepare the payload buffer before mapping it. |
VirtualProtect |
Changes the memory protection flags of a region (e.g., from PAGE_READWRITE to PAGE_EXECUTE_READ). Executable memory is required so the CPU can run the injected code. |
Trace evidence:
Search "privile" (2 hits in 1 file of 2 searched)
C:\Temp\apiminer_traces.293906.pid_1432.txt (2 hits)
Line 25: LdrGetProcedureAddress(... "AdjustTokenPrivileges", ...)
Line 181: LdrGetProcedureAddress(... "LookupPrivilegeValueW", ...)
Also found (Virtual search):
Search "Virtual" (94 hits in 2 files of 2 searched)
C:\Temp\apiminer_traces.293500.pid_4092.txt (28 hits)
Line 3: LdrGetProcedureAddress(... "VirtualAlloc", ...)
...
Line 19: NtAllocateVirtualMemory([process_handle]0xFFFFFFFF, ...)
Line 123: NtProtectVirtualMemory([process_handle]0xFFFFFFFF, ...)
Note:
process_handle = 0xFFFFFFFFis the pseudo-handle for the current process β this is the injector allocating memory in its own space. Later entries with a different handle value indicate cross-process memory operations.
Why SeDebugPrivilege matters: By default, even an administrator-level process cannot open a handle to another user's process or a system process like lsass.exe. SeDebugPrivilege bypasses this restriction. Malware requesting this privilege is a major red flag.
Screenshot needed: Notepad++ showing
AdjustTokenPrivilegesandLookupPrivilegeValueWin search results. Second screenshot showingVirtualAlloc/VirtualProtectresults.
Stage 3: Payload Mapping into Target Memory
What we're looking for: APIs that map a shared memory section into the target process's address space.
This sample uses the section-mapping technique, which is more evasive than WriteProcessMemory because:
WriteProcessMemoryis heavily monitored by EDR/AV tools.- Section mapping uses legitimate OS mechanisms for shared memory β the same used by DLLs loading into multiple processes.
Search in Notepad++: NtCreateSection, NtMapViewOfSection, NtUnmapViewOfSection
APIs found in the 2025 exam:
| API | Purpose |
|---|---|
NtCreateSection |
Creates a section object β a region of memory that can be shared between processes. The payload is written into this section. |
NtMapViewOfSection |
Maps the section into a target process's virtual address space. After this call, both the injector and the target process see the same physical memory pages. The payload is now "in" the target without using WriteProcessMemory. |
NtUnmapViewOfSection |
Unmaps the section from an address space (can be used to unmap an existing module or the section from the injector's own space after mapping it into the target). |
Trace evidence:
Search "NtMapViewOfSection" (7 hits in 1 file of 2 searched)
C:\Temp\apiminer_traces.293906.pid_1432.txt (7 hits)
Line 585: <process>-<0,0x00000000> NtMapViewOfSection([section_handle]...)
Line 592: <process>-<0,0x00000000> NtMapViewOfSection([section_handle]...)
Line 599: <process>-<0,0x00000000> NtMapViewOfSection([section_handle]...)
Line 606: <process>-<-1073741827,0x40000003> NtMapViewOfSection([sec...
Line 613: <process>-<-1073741827,0x40000003> NtMapViewOfSection([sec...
Line 620: <process>-<-1073741827,0x40000003> NtMapViewOfSection([sec...
Line 627: <process>-<-1073741827,0x40000003> NtMapViewOfSection([sec...
Search "NtUnmapViewOfSection" (10 hits in 2 files of 2 searched)
C:\Temp\apiminer_traces.293500.pid_4092.txt (1 hit)
Line 20: <process>-<0,0x00000000> NtUnmapViewOfSection([process_handle]0xFFFFFFFF...)
C:\Temp\apiminer_traces.293906.pid_1432.txt (9 hits)
Line 20, 149, 588, 595, 602, 609, 616, 623, 631: ...NtUnmapViewOfSection(...)
Search "NtCreateSection" (7 hits in 1 file of 2 searched)
C:\Temp\apiminer_traces.293906.pid_1432.txt (7 hits)
Lines 584, 591, 598, 605, 612, 619, 626: NtCreateSection([section_handle]...)
The negative process handle value (
-1073741827, 0x40000003) in someNtMapViewOfSectioncalls indicates cross-process mapping β the section is being mapped into a different process. This is the injection event.
Screenshot needed: Notepad++ search results for each of the three section APIs. Three separate screenshots recommended (one per API).
Stage 4: Execution via Thread Manipulation
What we're looking for: APIs that hijack or create a thread in the target process to execute the injected payload.
This sample uses GetThreadContext / SetThreadContext β an older but effective technique where the injector:
- Suspends a thread in the target process.
- Gets the thread's CPU register state (
GetThreadContext). - Modifies the instruction pointer (EIP/RIP) to point to the injected payload.
- Restores the context (
SetThreadContext), so the thread will jump to the payload when resumed.
Search in Notepad++: Thread (matches all thread-related APIs)
APIs found in the 2025 exam:
| API | Purpose |
|---|---|
CreateThread |
Creates a new thread β used here within the injector process or in the context of the unpacked payload. |
GetThreadContext |
Reads the CPU register state (EIP, EBP, ESP, flags, etc.) of a target thread. Required before modifying execution flow. |
SetThreadContext |
Writes a modified register state back to the thread β crucially, the modified EIP now points to the injected payload. When the thread is resumed, it begins executing the malicious code. |
Also seen (related thread APIs in the trace):
| API | Purpose |
|---|---|
GetCurrentThreadId |
Gets the calling thread's ID β used for book-keeping |
ExitThread |
Clean exit from a thread |
SuspendThread |
Pauses a thread (prerequisite to modifying its context) |
ResumeThread |
Resumes the paused thread β triggers execution of payload after SetThreadContext |
TerminateThread |
Kills a thread |
SetThreadPriority / GetThreadPriority |
Thread scheduling |
CreateProcessInternalW |
Creates a child process (C:\Temp\sample.exe spawning itself or another process) |
Trace evidence:
Search "Thread" (34 hits in 2 files of 2 searched)
C:\Temp\apiminer_traces.293500.pid_4092.txt (11 hits)
Line 13: LdrGetProcedureAddress(... "CreateThread", ...)
Line 36: LdrGetProcedureAddress(... "GetCurrentThreadId", ...)
Line 57: LdrGetProcedureAddress(... "CreateThread", ...)
Line 58: LdrGetProcedureAddress(... "ExitThread", ...)
Line 61: LdrGetProcedureAddress(... "TerminateThread", ...)
Line 63: LdrGetProcedureAddress(... "SuspendThread", ...)
Line 65: LdrGetProcedureAddress(... "ResumeThread", ...)
Line 67: LdrGetProcedureAddress(... "SetThreadPriority", ...)
Line 177: <process>-<1,0x00000001> CreateProcessInternalW([command_line]"C:\Temp\sample.exe", ...)
Search "GetThreadContext" (1 hit in 1 file of 2 searched)
C:\Temp\apiminer_traces.293906.pid_1432.txt (1 hit)
Line 261: <system>-<0,0x00000000> LdrGetProcedureAddress(... "GetThreadContext", ...)
Search "SetThreadContext" (1 hit in 1 file of 2 searched)
C:\Temp\apiminer_traces.293906.pid_1432.txt (1 hit)
Line 317: <system>-<0,0x00000000> LdrGetProcedureAddress(... "SetThreadContext", ...)
Screenshot needed: Notepad++ search results for "Thread" (showing the 34-hit summary), plus separate screenshots for
GetThreadContextandSetThreadContext.
Why this API sequence proves code injection
A single API in isolation could be legitimate. The sequence and cross-process context is what proves injection:
1. CreateToolhelp32Snapshot + OpenProcess β attacker gains handle to victim process
2. LookupPrivilegeValueW + AdjustTokenPrivileges β attacker enables SeDebugPrivilege
VirtualAlloc + VirtualProtect β memory prepared (RWX) for payload
3. NtCreateSection β shared memory section created
NtMapViewOfSection (cross-process) β payload mapped into victim's memory
NtUnmapViewOfSection β section unmapped from attacker's space
4. GetThreadContext + SetThreadContext β victim thread's EIP redirected to payload
ResumeThread β victim thread executes payload
This is a complete injection chain. The cross-process NtMapViewOfSection call (evidenced by the non-self process handle) is the moment the payload enters the victim process.
Final Answer β Q3
YES, sample.exe performs process injection (specifically, section-mapping injection using NtCreateSection / NtMapViewOfSection).
Evidence from APIMiner traces (apiminer_traces.*.pid_1432.txt):
| Stage | APIs | Evidence |
|---|---|---|
| 1. Target discovery | CreateToolhelp32Snapshot, OpenProcess |
Found in pid_1432 trace |
| 2. Privilege + memory | LookupPrivilegeValueW, AdjustTokenPrivileges, VirtualAlloc, VirtualProtect |
Found in pid_1432 trace |
| 3. Payload mapping | NtCreateSection, NtMapViewOfSection, NtUnmapViewOfSection |
Found in pid_1432 trace (cross-process calls visible) |
| 4. Execution | CreateThread, GetThreadContext, SetThreadContext |
Found in both traces |
Conclusion: The API sequence is consistent with and specific to process injection. No legitimate application uses this combination in this order.
Marks strategy for Q3
This question is worth 40% of the exam (4 marks). Each stage = 1 mark.
- Do NOT just list APIs β briefly explain what each API does in the injection context.
- Identify the technique (section-mapping) to show you understand the difference from classic
WriteProcessMemoryinjection. - The
LookupPrivilegeValueW+AdjustTokenPrivilegespair belongs in Stage 2 (privilege), not a separate stage. - For Stage 3, emphasize that
NtMapViewOfSectionis the key call that places the payload into the target process. - For Stage 4, emphasize that
SetThreadContextmodifies the EIP register to redirect execution.
Question 4: Created Thread IDs (2 marks)
Question text
Which threads were created with which IDs?
Theory background
A thread is the unit of execution within a process. A process can have many threads running concurrently. Each thread gets a unique Thread ID (TID), assigned by the OS at creation time.
ProcMon logs Thread Create and Thread Exit events. The Detail column of a Thread Create event shows the new thread's ID. Thread IDs are not stable across runs β re-running the sample will produce different TIDs.
Procedure
- Return to the saved ProcMon trace (
C:\Temp\trace.pml). - Modify filters:
- Keep:
Process Name is sample.exeβ Include - Remove the
CreateFilefilter (or disable it) - Add:
Operation contains Threadβ Include
- Click Apply or OK.
Alternatively, add a direct filter for the event type:
| Column | Relation | Value | Action |
|---|---|---|---|
| Operation | contains | Thread |
Include |
- Look at the Thread Create rows in the Operation column.
- Read the Detail column for each
Thread Createevent.
Results observed in the 2025 exam
| Time of Day | Process Name | PID | Operation | Result | Detail |
|---|---|---|---|---|---|
| 6:46:34.5663268 PM | sample.exe | 2272 | Thread Create | SUCCESS | Thread ID: 3608 |
| 6:46:34.8460706 PM | sample.exe | 2824 | Thread Create | SUCCESS | Thread ID: 3424 |
| 6:46:34.8564529 PM | sample.exe | 2272 | Thread Exit | SUCCESS | Thread ID: 3608 (exit) |
| 6:46:35.0845443 PM | sample.exe | 2824 | Thread Create | SUCCESS | Thread ID: 1176 |
| 6:46:35.1159211 PM | sample.exe | 2824 | Thread Create | SUCCESS | Thread ID: 2684 |
| 6:46:35.1159591 PM | sample.exe | 2824 | Thread Exit | SUCCESS | Thread ID: 2684 |
| 6:46:35.1160306 PM | sample.exe | 2824 | Thread Exit | SUCCESS | Thread ID: 3424 |
Four distinct threads were created:
| Thread ID | Created by PID | Notes |
|---|---|---|
| 3608 | 2272 | Original process β exits quickly |
| 3424 | 2824 | Child/injected process |
| 1176 | 2824 | Child/injected process |
| 2684 | 2824 | Child/injected process β exits quickly |
Key observation: Two different PIDs create threads β PID 2272 (the original sample.exe) and PID 2824 (a spawned process, confirmed by CreateProcessInternalW in the APIMiner trace). This is consistent with the injection activity observed in Q3: the injected code running under PID 2824 creates threads as part of its payload.
Screenshot needed: ProcMon window with Thread filter active, showing the 4 Thread Create events with their Thread IDs visible in the Detail column.
Note on TID reproducibility
The exact TID values (3608, 3424, 1176, 2684) are specific to this execution run. If you re-run the sample, you will see different TID numbers. This is expected β thread IDs are dynamically assigned. When answering this question in the exam:
- Report the IDs from your own execution run.
- The number of threads created (4) is the more reliable indicator β the TIDs will vary.
Final Answer β Q4
Four threads were created when sample.exe was executed:
| # | Thread ID | Creating PID |
|---|---|---|
| 1 | 3608 | 2272 (sample.exe original) |
| 2 | 3424 | 2824 (child process) |
| 3 | 1176 | 2824 (child process) |
| 4 | 2684 | 2824 (child process) |
Evidence: ProcMon trace with filter Operation contains Thread, showing 4 Thread Create events with SUCCESS result. Detail column records the assigned Thread ID for each.
Marks strategy for Q4
- List all 4 IDs (from your own run, your IDs will differ but there should be 4) = 1 mark.
- Mention that TIDs come from two different PIDs, connecting this back to the injection activity = 1 mark.
- If your run produces a different number of threads, report what you see β don't fake the answer.
Complete Marks Summary
| Q | Topic | Max | Strategy |
|---|---|---|---|
| 1 | File type + packing | 2 | State PE32 explicitly; give 2+ packing indicators (entropy + section name + PEiD EP Check) |
| 2 | Files in C:\Temp | 2 | List all 7 artifacts (including old_sample.exe and ui/ directory); note they are deleted instantly |
| 3 | Code injection β 4 stages | 4 | 1 mark per stage; name APIs + explain purpose; name the technique (section-mapping) |
| 4 | Thread IDs | 2 | List all 4 TIDs from your trace; note 2 PIDs are involved |
| Total | 10 |
Common Mistakes to Avoid
| Mistake | Correct approach |
|---|---|
| "The entropy is high" (no number) | State the exact value: 7.99488 |
Forgetting old_sample.exe in Q2 |
It is the first file created β the UPX self-rename step |
| Listing only 3 injection stages | All 4 stages must be shown; privilege escalation (Stage 2) has 2 sub-parts |
Writing WriteProcessMemory for Q3 |
This sample uses NtMapViewOfSection β NOT WriteProcessMemory |
| Showing thread exits as "created threads" | Count only Thread Create operations, not exits |
| No screenshots | Zero marks for any answer without a supporting screenshot |
| Missing the ProcMon Thread filter for Q4 | Must use Operation contains Thread β not the default view |
| Running sample without admin rights | AdjustTokenPrivileges may fail; some behaviors may not trigger |
Tool Quick Reference
| Task | Tool | Key operation |
|---|---|---|
| Identify PE type | CFF Explorer | Nt Headers β File Header β Machine |
| Confirm packing | DiE | Entropy button β Total value |
| Cross-verify packing | PEiD | Multi Scan β Extra Information β EP Check |
| Monitor filesystem activity | ProcMon | Filter: Process Name = sample.exe, Operation = CreateFile, Path contains C:\Temp |
| Trace API calls | APIMiner | APIMiner.lnk --app C:\Temp\sample.exe |
| Read API traces | Notepad++ | Search β Find in Files across both trace txt files |
| Find thread IDs | ProcMon | Filter: Operation contains Thread β Detail column |
Cross-References to Lecture Material
| Q | Topic | Lecture PDF |
|---|---|---|
| Q1 (packing, entropy) | Lecture 4 Static Analysis.pdf β packing indicators, entropy, UPX | |
| Q1 (PE type) | Lecture 2-3 PE and memory.pdf β PE32 structure, Machine field | |
| Q2 (ProcMon filters) | Lecture 5-6 Dynamic Analysis.pdf β ProcMon setup and filtering | |
| Q3 (injection stages) | Lecture 9-10 Classic process injection techniques.pdf | |
| Q3 (API theory) | Lecture 5-6 Dynamic Analysis.pdf β APIMiner usage | |
| Q4 (thread IDs) | Lecture 5-6 Dynamic Analysis.pdf β ProcMon thread events |
See also:
- notes/13-lecture-exercises-step-by-step.md β exercises 41-47 (injection techniques)
- notes/01-tooling-overview.md β complete tool reference
- checklists/malware-analysis-exam-checklist.md β exam day workflow
Source documents: reference_pdfs/Exams2025_Malware_Analysis-2.pdf (questions) and reference_pdfs/Exams2025_Malware_Analysis_Answers.pdf (official answer screenshots). Last verified: June 2026.