Table of Contents
- 1. Scope and Safety
- 2. Lab Environment
- 3. Objective
- 4. Design Overview
- 5. API Summary and Why Each Matters
- 6. What I Verified in the Windows 11 VM
- 7. Why the Run Key Works
- 8. Detection and Defensive View
- 9. Cleanup and Reverting State
- 10. Conclusion
- 11. Sources
1. Scope and Safety {#scope}
This work was performed as a controlled classroom-style persistence experiment to understand how Windows startup mechanisms can be manipulated. I ran it only inside an isolated Windows 11 virtual machine environment to ensure the behavior could not impact my host system. The program intentionally keeps its impact minimal and observable: it creates a single user-level startup entry and uses a visible message box as an execution indicator.
I treated this as a defensive learning task. My goal was not to optimize stealth or evade detection, but to understand: (1) what changes are written to the system, (2) how Windows triggers the behavior at logon, and (3) how analysts can validate and detect this persistence in practice.
2. Lab Environment {#lab}
I used a Windows 11 VM as the test system. I kept the environment isolated because persistence techniques are the same operating system mechanisms used by real malware, and I wanted a setup where I could safely observe changes and revert to a known clean state.
The most important lab practice for this kind of exercise is having snapshots available. It allows you to roll back system state (registry + filesystem) quickly and prevents old persistence entries from contaminating future tests.
3. Objective {#goal}
The objective was to implement and study a common persistence pattern: modifying user-level startup configuration so a program launches automatically at login. The message box is not the main point; it is only a clear signal that the program executed without needing to rely on assumptions.
- Observable execution indicator:
MessageBoxA - Persistence mechanism: startup entry under the current user Run key
4. Design Overview {#design}
Because I did not start with a strong C background, I approached this by learning core C syntax first, then mapping the behavior I wanted into specific WinAPI calls. The program’s logic is simple by design so the persistence mechanism remains the main focus:
- Determine the full path of the running executable.
- Open the current user’s startup registry location with write permission.
- Write the executable path as a string value so Windows can launch it at logon.
- Close handles properly to avoid leaving artifacts like open registry handles.
- Use a message box to prove execution when the program runs.
I intentionally stayed in the current user context because it demonstrates a realistic abuse path without requiring administrator rights. That matters in real scenarios, since many threats try to persist without triggering privilege prompts.
5. API Summary and Why Each Matters {#apis}
These are the core APIs used by the program and the role each one plays:
GetModuleFileNameA // retrieves the full path of the running executable
RegOpenKeyExA // opens the current user startup key with write access
RegSetValueExA // writes a REG_SZ value that points to the executable
RegCloseKey // closes the registry handle cleanly
MessageBoxA // provides an obvious execution indicator
From a security perspective, registry write activity to common startup locations is widely monitored. The behavior is significant because persistence is not about a single execution, it is about shaping the system so the program runs again automatically in the future.
6. What I Verified in the Windows 11 VM {#execution}
My testing workflow focused on confirming system changes and trigger behavior rather than just “running a program once.” The key validations were:
- The program executed correctly and was able to determine its own full path (important for writing a valid startup entry).
- A new startup value existed after execution (proof that the system state changed, not just the program output).
- After a fresh logon session, the program executed automatically again (proof the persistence trigger worked as expected).
For report evidence, the most meaningful screenshots are:
- Initial execution indicator (message box).
- Startup value visible in the registry (showing exactly what was added).
- Execution indicator after logon (confirming automatic launch).
7. Why the Run Key Works {#persistence}
The Run key works because Windows processes specific startup locations during user logon. The system reads configured values and launches them automatically. This is normal behavior used for legitimate software, but it can be abused by unwanted or malicious programs to remain present across sessions.
Using the current user context is particularly relevant because:
- It usually does not require administrative permissions.
- It is straightforward to modify, which is why it is commonly abused.
- It persists across reboots and logon sessions until removed.
8. Detection and Defensive View {#detection}
From a defender perspective, this technique is common because it is easy and reliable. The most useful way to think about it is not “a registry key exists,” but “a process wrote itself into an auto-start location.”
- Autoruns (Sysinternals): quickly lists common persistence locations in one interface.
- Process Monitor (Procmon): can show registry write events when captured during execution.
- EDR / AV telemetry: often flags unsigned binaries modifying common startup keys.
- Baseline comparison: compare startup entries against a known-good machine snapshot.
Even small programs can be suspicious if they exhibit persistence-focused behavior commonly associated with malware. Understanding this is critical because real threats often rely on legitimate Windows mechanisms instead of exploiting vulnerabilities.
9. Cleanup and Reverting State {#cleanup}
After testing, I removed the startup entry so the program would not execute again at logon. In lab environments, cleanup matters because leftover persistence can easily cause confusion in later experiments (multiple binaries triggering at login, stale entries pointing to deleted files, and false conclusions during analysis).
In a VM environment, the cleanest approach is reverting to a snapshot taken before the persistence step. That restores the registry and filesystem to a known clean baseline and keeps the environment consistent for future work.
10. Conclusion {#conclusion}
This exercise made Windows persistence feel concrete instead of theoretical. Rather than thinking of persistence as a “malware trick,” I learned to see it as normal operating system behavior that can be abused. By mapping the technique to specific WinAPI calls and validating the resulting system changes, I practiced how to reason about persistence from both sides: how it is established, how it triggers, and what artifacts it leaves behind for defenders to find.
11. Sources {#sources}
- Microsoft Docs: C language documentation (MSVC): link
- Microsoft Docs: C Language Reference: link
- CS50x (Harvard): Introduction to Computer Science: link
- Harvard Online: CS50 overview: link
- learn-c.org: Interactive C tutorial: link
- Microsoft Docs: PlaySound Win32 reference: link
- CyberArk: Persistence techniques overview: link
- MITRE ATT&CK: T1547.001 Run Keys / Startup Folder: link