← Back to Main Archive

🏗 WithExe

💾 Download WithExe.zip

Provided as compact DLL and LIB + C/C++ and .NET/C# samples provided.

📜 Preface & Motivation

In-process EXE host for Windows x64. Not another PE mapper. Official name WithExe — the Detours counterpart of withdll: contrary to Detour injecting a DLL into a new process: WithExe maps and hosts an EXE inside the original process.

With.dll loads the target with the OS LoadLibrary path and a few tricks so a Windows EXE can be mapped and run inside the caller. Imports, relocs, manifests, and SEC_IMAGE are the loader’s job — not a from-scratch mapper’s.

This is an instrumentation POC, in the same neighborhood as Detours. The two sample hosts follow the Detours samples/withdll skeleton (parse options, load helper DLLs, start) — Run instead of DetourCreateProcessWithDlls.

⚠ Notice & Disclaimer

Binary mapper, tiny on purpose: With.dll is shipped in binary form — a tiny 2 KB DLL (SOURCE\bin\x64\With.dll, copied next to the hosts under REDISTRIBUTABLES\BIN\x64). There is no mapper source in this tree. Drop it in IDA if you are a specialist — 2 KB is not a secret. If you need customization, look below: change a sample host, or LoadLibrary a helper DLL before the guest. SOURCE\include\With.h is the API; SOURCE\lib\x64 has the import library if you link your own host. Rebuild the hosts if you want; do not rebuild the mapper from here.

NO WARRANTY: This is a proof of concept. Unsupported use of the Windows loader. Provided "AS IS" with no warranty. Extra behavior belongs in your host or a helper DLL, not in With.dll. Use, modify, and experiment at your own risk.

🔍 Overview

The sample hosts load one EXE. Helper DLLs come first (LoadLibrary); the first EXE is the guest; everything after that is that guest’s command line. The target EXE being mapped is simply a binary executable—it is not necessarily written in C++; as long as it is a valid Windows PE, the host will process it.

There is also no patch-to-load / patch-to-run story. WithExe does not rewrite the guest’s IAT, and it does not patch system exports to hook start, run, or exit. The subset of redirections it needs is done with the thread’s DRx hardware breakpoints and a vectored handler. The targeted EXE’s import table and system DLL bytes stay as the loader left them.

Layout

SOURCE\
  WithExe\          native host
  WithExeClr\       CLR host
  include\With.h    API
  lib\x64\Release|Debug      With.lib
  bin\x64\With.dll          one mapper (Debug and Release hosts copy this same file)
REDISTRIBUTABLES\BIN\x64\Release|Debug
  With.dll         prebuilt mapper (do not rebuild from this tree)
  WithExe.exe
  WithExeClr.exe   (+ .dll / .deps.json / .runtimeconfig.json)
WithExe.slnx

Hosts build into REDISTRIBUTABLES\BIN\x64\Release and Debug. With.dll is already there; a host rebuild must not delete it.

🚀 Fast Track (Quick Start)

x64 only. Do not rebuild With.dll from this tree — use the prebuilt SOURCE\bin\x64\With.dll (copied next to the hosts on build).

  1. Open the solution: WithExe.slnx in Visual Studio. Platform x64.
  2. Pick a sample: Set the startup project to WithExe (native) or WithExeClr (CLR).
  3. F5: Debugger arguments are %SystemRoot%\System32\notepad.exe. Working directory is REDISTRIBUTABLES\BIN\x64\<config>, so With.dll sits beside the host. Change the arguments for another guest (full path unless the file sits next to the host).

Command line.

MSBuild WithExe.slnx /restore /p:Configuration=Release /p:Platform=x64

Output: REDISTRIBUTABLES\BIN\x64\Release or Debug.

REDISTRIBUTABLES\BIN\x64\Release\WithExe.exe notepad.exe
REDISTRIBUTABLES\BIN\x64\Release\WithExe.exe helper.dll C:\full\path\app.exe --flag
REDISTRIBUTABLES\BIN\x64\Release\WithExe.exe -d C:\full\path\app.exe
REDISTRIBUTABLES\BIN\x64\Release\WithExeClr.exe C:\full\path\app.exe

dlls / exe need a full path unless the file is next to that host EXE. Helpers (any number of DLLs) first, then one EXE, then that EXE’s arguments. A helper DLL is the place for your own detours. -d is host-only (DLL directory + cwd = guest folder).

⚙ Why not PE mapping

A typical PE mapper VirtualAllocates, copies sections, walks imports, applies relocs, and fakes an entry. That is a second loader, always behind the OS, and the image is usually private memory rather than a real image section.

WithExe uses LoadLibrary on the EXE (the image is briefly treated as a DLL for the loader, then restored). Compared to mapping by hand:

🔄 Why not Detours withdll

Detours samples/withdll starts the target with CreateProcess suspended, then injects a DLL into that new PID (WriteProcessMemory / CreateRemoteThread / LoadLibrary, or an entry-point patch). You instrument someone else’s process.

WithExe is the inverse: you write the host; Run maps the EXE into this process. Helper DLLs and Detours-style hooks run as your code in your address space. Same sample shape as withdll (options, helper DLLs, start) — not a remote inject.

💻 Sample hosts

This tree ships two sample hosts. Same job: LoadLibrary With.dll, call Run, map one guest EXE on this thread. They are templates, not a product.

1. Native C++ (SOURCE\WithExe\WithExe.cpp)

2. Managed C# (SOURCE\WithExeClr\WithExeClr.cs)

Command line is the same for both:

WithExe.exe [options] [helper.dll ...] guest.exe [guest args...]

🔧 API

UINT WINAPI Run(LPCWSTR exe, LPCWSTR cmdLine);

x64 only. With.dll must sit next to the host (already true under REDISTRIBUTABLES\BIN). The host thread calls Run. The sample uses LoadLibrary / GetProcAddress; With.lib is there if you want to link your own host.