A DLL or data file that your application writes to disk is, from an attacker's point of view, the easy case. It is a copyable file in a folder. It can be opened in a disassembler while your program is not even running, patched and swapped back, and it stays on disk long after the session that needed it has ended.
In-memory loading is the answer to that problem: the sensitive module is mapped into the running process from an encrypted source, so the plain, runnable bytes are never written to disk. This guide explains why files on disk are easy to grab, what in-memory loading actually does, how PapelShip maps files into memory, where the technique stops, and what to pair it with.
Why files on disk are easy to grab
The weakness of a file on disk is not any one flaw; it is everything about being a file. Once sensitive logic ships as bytes in a folder, four problems come with it at once.
- Copied. A file is just bytes on disk; anyone who can read the folder can take it elsewhere.
- Inspected at rest. A DLL sitting on disk can be opened in a disassembler without the program ever running.
- Patched. The file can be modified and swapped back in, changing what the program does on its next launch.
- Persistent. It stays on disk after the app closes, waiting to be found, long after the session that needed it has ended.
Shipped as a file on disk
- A copyable file in a folder
- Readable by static tools at rest
- Can be patched and swapped back
- Stays behind after the app closes
Mapped into memory
- No plaintext file written to disk
- Decrypted only in the running process
- Gone when the process exits
- Delivered only to an authenticated session
The gap between these two columns is the whole argument for in-memory loading. A file on disk is available to anyone with access to the machine, at any time, whether your program is running or not. A module that only ever exists inside a running, authenticated process is available for a far narrower window, to a far narrower set of people, and it leaves nothing behind to study at leisure afterwards.
What in-memory loading actually does
When a program uses a normal DLL, the operating system reads that DLL from disk and maps it into the program's memory so the processor can run it. In-memory loading does the mapping step itself: it takes the module from an encrypted source and lays it out in the process's address space directly, so the plain, runnable bytes are never written to disk as a file. PapelShip's Map Files feature works like a PE loader, mapping your files into memory, and the in-memory execution path can stream encrypted DLLs into memory without writing bytes to disk.
The practical effect is that the easy attacks disappear. There is no file in a folder to copy, nothing on disk for a static tool to open at rest, and nothing left behind when the process exits. An attacker has to work against a running process instead of a file sitting still, which is a much higher bar.
It is worth being precise about the word "securely". Mapping a file into memory on its own is just a loading technique; the security comes from where the bytes start and how they travel. In PapelShip the module is encrypted at rest on the server and sent only to a client that has already authenticated, so the mapped-into-memory step is the end of a protected path, not a trick applied to a file that was lying around unprotected.
How PapelShip maps files into memory
In PapelShip this builds on server-side delivery. The module is held on the server, encrypted, and delivered only to an authenticated license, the same way server-side strings and files work. It then maps into the process rather than landing on disk. The sequence is short.
- 01
Authenticate
The app starts a session and authenticates the license for this device. Nothing protected is delivered before this succeeds.
- 02
Request the module
The authenticated client asks for the encrypted module from the server, over the protected channel.
- 03
Stream encrypted
The bytes arrive encrypted. There is no plaintext copy written to a file anywhere along the way.
- 04
Map into memory
Map Files lays the module out in the process's address space, the way a PE loader would, so it is ready to run.
- 05
Execute, then discard
The module runs from memory for the life of the session and is gone when the process exits.
For the shipped executable itself, qPapelPacker+ adds a further packing layer, so the binary a customer downloads is harder to read at rest as well. In-memory loading protects the modules you deliver after authentication; packing protects the launcher that asks for them.
What belongs in memory, and what does not
In-memory loading has a cost: the module has to be fetched and mapped at runtime, so it is worth reserving for the parts that actually matter. The test is simple. Would an attacker learn something useful, or save real effort, by reading this on disk? If yes, it is a candidate for in-memory delivery. If not, the complexity is not earning its keep.
- Good candidates: the modules that contain your real logic, premium features, or the code that decides what a license may do.
- Also worth moving server-side: keys, URLs and constants, which belong in server-side strings and files rather than in any client file at all.
- Usually fine on disk: large, non-sensitive assets and anything already public, where mapping into memory adds cost without adding protection.
Be honest about the limits
In-memory loading is a cost-raising technique, not a magic one. The runnable code still has to exist in memory for the processor to execute it, and anyone with full control of a machine can, in principle, inspect the memory of a process running on it. That is a property of how computers work, not a shortcoming of any one product.
What in-memory loading removes is the cheap, repeatable attack: copying a file, reading it at rest, patching it and swapping it back. What it does not remove is a determined attacker working against the live process. Treating it as the whole defence is the mistake; treating it as one strong layer is correct.
The honest framing is a matter of economics, not absolutes. Protection is about making an attack cost more than the result is worth, for long enough that your product has moved on by the time anyone succeeds. In-memory loading shifts that balance in your favour; it does not end the game. Any vendor who tells you a single feature makes code impossible to extract is selling confidence, not security.
Pair it with integrity checks and qPAnalyzer
A module in memory should be watched, not just hidden from disk. Two things do that, and they solve different problems from the mapping itself.
First, runtime integrity checks confirm the code in memory is the code you shipped. qPapel Auth exposes auth.CheckMemoryIntegrity(), which detects unauthorised changes such as instruction patching, including JMP and NOP edits, and auth.CheckTextIntegrity(), which performs CRC, session-based and JMP/NOP checks. Run them before you trust a mapped module.
// Check the running code before using a mapped module.
if (!auth.CheckMemoryIntegrity()) {
// Memory was patched (for example JMP/NOP edits). Stop here.
return;
}
if (!auth.CheckTextIntegrity()) {
// CRC or session-based check failed. Stop here.
return;
}
// Only now request and map the protected module.Second, qPAnalyzer watches the environment the process runs in, flagging dumpers, memory scanners and renamed analysis tools that static blacklists miss. Together, the file is not on disk, the code in memory is verified, and the tools trying to reach it are detected.
In-memory loading
No plaintext file on disk
Server-side delivery
Modules sent only after auth
Integrity checks
Memory and code verified at runtime
qPAnalyzer
Dumpers and renamed tools flagged
For the full picture of how these layers interlock, see the software protection stack for C++ and C# and why protection has to go beyond static blacklists.
The order matters as much as the parts. Authenticate first, so nothing protected moves until the license is verified; deliver the module encrypted and map it into memory, so there is no file to grab; verify it at runtime, so a tampered module is caught; and watch the environment, so the tools that would attack it are flagged. Each step assumes the one before it, which is why they are worth adopting together rather than one in isolation.
Perguntas frequentes
auth.CheckMemoryIntegrity() and auth.CheckTextIntegrity() so a mapped module is confirmed unmodified before you trust it.Keep the valuable parts off disk
In-memory loading is a straightforward idea with a real payoff: the parts of your product worth stealing are never written to disk where they are easy to grab. Map them into memory from an encrypted, authenticated source, verify them at runtime, and let qPAnalyzer watch the environment around them.
None of this makes your code untouchable, and any honest account of software protection says so. What it does is turn a quick copy job into a long, uncertain one, which for most products is exactly the trade worth making.
Equipa de Segurança qPapel
Licenciamento e proteção de software