A robust, feature-rich manual map DLL injection library for Windows x64 processes. This implementation provides stealthy DLL injection with automatic cleanup capabilities, SEH support, and memory wiping for anti-detection.
[!NOTE] Disclaimer: The repo was vibe coded based on injection code snippet I used in a certain game.
- Manual Mapping: Inject DLLs without using
LoadLibrary, avoiding detection by basic anti-cheat systems - Randomized Base Address: ASLR-style random base address allocation for injected DLLs
- SEH Support: Full Structured Exception Handling support for x64 DLLs
- Automatic Cleanup: Track and clean up injected DLLs with memory wiping
- PE Header Wiping: Automatically wipes PE headers after injection to reduce detection footprint
- Import Resolution: Handles all import tables and delayed imports
- TLS Callbacks: Properly executes Thread Local Storage callbacks
- Base Relocations: Handles relocation tables when DLL isn't loaded at preferred base
Unlike traditional LoadLibrary injection, manual mapping:
- Allocates memory in the target process
- Manually writes PE sections to target memory
- Resolves imports by walking the Import Address Table
- Applies base relocations if needed
- Executes TLS callbacks
- Calls the DLL entry point (DllMain)
- Registers exception handlers for SEH support
Target Process Memory:
┌─────────────────────────┐
│ PE Headers (wiped) │
├─────────────────────────┤
│ .text (code section) │
├─────────────────────────┤
│ .data (data section) │
├─────────────────────────┤
│ .rdata (read-only) │
├─────────────────────────┤
│ Other sections... │
└─────────────────────────┘
#include "ManualMapInjection.h"
int main() {
// Open target process
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
// Load your DLL into memory
std::ifstream file("YourDll.dll", std::ios::binary | std::ios::ate);
size_t fileSize = file.tellg();
file.seekg(0);
std::vector<BYTE> dllData(fileSize);
file.read(reinterpret_cast<char*>(dllData.data()), fileSize);
file.close();
// Inject the DLL
if (Inject::InjectDllData(hProcess, dllData.data(), dllData.size(), "YourDll.dll")) {
std::cout << "Injection successful!" << std::endl;
} else {
std::cerr << "Injection failed!" << std::endl;
}
// Cleanup when done
Inject::PerformCleanup();
CloseHandle(hProcess);
return 0;
}// Clean up all tracked injections
Inject::PerformCleanup();
// Or use selective cleanup (custom implementation)
Inject::CleanupInjectionTracking(); // Just stop tracking without freeingInjects a DLL into the target process using manual mapping.
Parameters:
hProcess- Handle to the target process (requires PROCESS_ALL_ACCESS)dllData- Pointer to DLL file data in memorydllSize- Size of the DLL data in bytesdllName- Optional name for tracking (can be nullptr)
Returns: true on success, false on failure
bool ManualMapDll(HANDLE hProc, BYTE* pSrcData, bool SEHExceptionSupport, DWORD fdwReason, LPVOID lpReserved, const std::string& dllName)
Low-level manual mapping function with full control.
Parameters:
hProc- Target process handlepSrcData- DLL data bufferSEHExceptionSupport- Enable x64 SEH support (recommended: true)fdwReason- DLL entry reason (typicallyDLL_PROCESS_ATTACH)lpReserved- Reserved parameter for DllMaindllName- Name for tracking purposes
Returns: true on success, false on failure
Cleans up all tracked DLL injections by:
- Wiping memory contents (zeros out the original PE size)
- Freeing allocated memory regions
- Clearing the injection tracking list
Note: This should be called before your injector exits to avoid leaving traces.
Returns the number of currently tracked injections.
Returns: Number of active injections being tracked
Stops tracking injections without freeing memory. Use this if you want to leave DLLs injected but stop managing them.
- Visual Studio 2019 or later
- Windows SDK 10.0.19041.0 or later
- C++17 support
- Clone the repository:
git clone https://github.com/thetobysiu/ManualMapInjection.git
cd ManualMapInjection- Open the solution in Visual Studio or build via command line:
msbuild ManualMapInjection.sln /p:Configuration=Release /p:Platform=x64- The library will be built to
x64/Release/
mkdir build
cd build
cmake ..
cmake --build . --config Release┌──────────────────────────────────────────────────────────────┐
│ Injector Process │
├──────────────────────────────────────────────────────────────┤
│ 1. Load DLL file into memory │
│ 2. Validate PE structure │
│ 3. Allocate memory in target process (random base address) │
│ 4. Write PE headers and sections │
│ 5. Allocate mapping context structure │
│ 6. Write shellcode to target process │
│ 7. Create remote thread executing shellcode │
│ 8. Wait for shellcode completion │
│ 9. Wipe PE headers for stealth │
│ 10. Track injection for cleanup │
└──────────────────────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────────────────────┐
│ Target Process │
├──────────────────────────────────────────────────────────────┤
│ Shellcode executes: │
│ 1. Apply base relocations │
│ 2. Resolve imports (LoadLibrary + GetProcAddress) │
│ 3. Execute TLS callbacks │
│ 4. Register SEH exception handlers │
│ 5. Call DllMain(DLL_PROCESS_ATTACH) │
└──────────────────────────────────────────────────────────────┘
The shellcode runs in the target process and performs all necessary PE loading operations:
void Shellcode(MAPPING_CTX* pData) {
// 1. Base relocation
// 2. Import resolution
// 3. TLS callback execution
// 4. SEH handler registration
// 5. DllMain invocation
}- Random Base Addresses: Makes detection harder by avoiding predictable memory locations
- PE Header Wiping: Removes PE signatures after injection
- Memory Cleanup: Zeroes memory before freeing to avoid forensic analysis
- No LoadLibrary: Bypasses API monitoring on LoadLibrary calls
Manual mapping is not completely undetectable. Potential detection methods include:
- Memory scanning for code signatures
- Monitoring of
VirtualAllocExandWriteProcessMemory - Detection of unbacked memory regions (memory not backed by a file on disk)
- Analysis of execution from non-module memory
- SEH handler registration monitoring
Q: Injection fails with no error message
- Ensure target process is x64 (32-bit not supported)
- Verify you have sufficient privileges (run as administrator)
- Check that the DLL architecture matches (x64)
Q: DLL injects but crashes immediately
- Enable SEH support:
ManualMapDll(..., true, ...) - Verify all DLL dependencies are available in the target process
- Check that the DLL doesn't use TLS variables improperly
Q: Memory cleanup fails
- Some memory regions may be protected by the OS
- VMProtect or other packers may expand memory regions
- Check that you're not trying to cleanup while DLL code is still executing
- Injection Time: ~10-50ms depending on DLL size
- Memory Overhead: DLL size + ~8KB for shellcode and mapping context
- Cleanup Time: ~5-20ms depending on number of tracked injections
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please read CONTRIBUTING.md for details on the code of conduct and the process for submitting pull requests.
This software is provided for educational purposes only. The author does not condone the use of this software for malicious purposes, cheating in games, or any other illegal activities. Users are responsible for ensuring they comply with all applicable laws and terms of service.
- Based on manual mapping techniques documented by the Windows internals community
- SEH support implementation inspired by x64 PE loader specifications
- Thanks to the open-source community for PE format documentation
Created to demonstrate advanced C++ and Windows internals knowledge, including:
- PE file format parsing
- Process memory manipulation
- Windows API expertise
- x64 assembly and shellcode development
- Multi-threaded programming with synchronization primitives
- Low-level Windows security mechanisms
Note: This is a technical demonstration of Windows internals programming. Always use responsibly and ethically.