Native C++ compiles to machine code, and it is tempting to believe that compiled means protected. It doesn't. A license check that ends in a single if is one patched conditional jump away from a working crack, and the people who crack software rarely read your source. They attach debuggers, hook functions, watch network traffic and patch instructions in memory. C++ authentication for licensed software has to assume all of that is happening.
This guide walks through a licensing flow built on that assumption: how the session is set up, why the license decision belongs on the server, what integrity checks catch, and how to wire it into a C++ application with qPapel Auth. The principles hold whichever licensing system you use.
What C++ authentication has to defend against
Every useful design starts with a threat model, and for desktop software the honest one is blunt: the attacker owns the machine. They have your binary, administrator rights, every public reverse-engineering tool and as much time as they want. Within that model, five kinds of attack have to fail.
| Attack | Typical tools | What has to stop it |
|---|---|---|
| Static analysis | IDA, Ghidra, Binary Ninja | No secrets or decision logic worth finding |
| Dynamic analysis | x64dbg, WinDbg | Debugger detection and runtime analysis |
| Traffic interception | Fiddler, Wireshark, mitmproxy | Encrypted, signed traffic with per-session keys |
| Memory manipulation | Cheat Engine, ReClass | Memory integrity checks and anti-dumping |
| Binary patching | Hex editors, patch scripts | Server-side decisions and code integrity checks |
No single control covers all five. That is why serious C++ licensing is built as a chain, where defeating one link still leaves the attacker without a working product. The rest of this guide follows that chain from the first packet to the last integrity check.
How a secure C++ licensing session works
A protected session has five stages. Each one closes a gap the previous one leaves open, and the order matters: nothing valuable reaches the application until the server has made its decision.
01Key exchange
Fresh session keys, none stored in the binary
02Signed handshake reply
A fake server can't produce it
03License key + HWID
Encrypted and signed in transit
04License verdict
Expiry, bans and HWID checked here
05Request strings and files
Only after a positive verdict
06Server-side data
Sent to memory, never in the build
1. Key exchange
When the application starts, client and server agree on fresh session keys through a key exchange. Modern designs typically use ephemeral elliptic-curve Diffie-Hellman, such as X25519, so the keys are derived at runtime and never stored in the binary. An attacker who extracts every byte of your executable still doesn't have them, and a recorded session can't be replayed later because the next one uses different keys.
qPapel Auth opens every session with a key exchange and rotates its AES-256 session keys for each session. If that step fails, the SDK reports a specific Key Exchange or Handshake Error, separate from errors such as Banned Computer or Unverified Build, so you can tell a failed handshake apart from a licensing problem.
2. Encrypted, signed traffic
Every request and response after the handshake is encrypted and signed. Encryption hides the contents from proxies such as Fiddler or mitmproxy. The signature matters even more, because it lets the client tell a genuine server reply from a forged one. Without it, an attacker can stand up a fake server that answers "license valid" to anything, which is one of the oldest cracks there is.
3. Server-side license and HWID check
The client sends the license key and a hardware fingerprint inside the protected channel and then waits. It never works out for itself whether the license is valid. The server checks that the key exists, hasn't expired or been banned, and is bound to this machine's hardware ID. Because none of that logic ships in the binary, there is nothing local to patch into saying yes.
4. Server-side strings and files
This is the step that turns licensing into real protection. After a positive verdict, the server delivers what the application actually needs to run: configuration values, endpoints, offsets, constants and whole files. In qPapel Auth these are server-side strings and server-side files, streamed to the authenticated session and kept out of the build you ship. A build with its license check patched out never receives them.
5. An ongoing session, not a one-off check
A check that only happens at startup can be beaten by patching the process after it has passed. qPapel Auth ties every run to a server session with rolling session keys, and Session Token Enforcement in Remote Settings lets you set a maximum active session duration and lock sessions to an IP address. When you expire or ban a key in the dashboard, the application receives the new status on its next check.
Why the license decision must stay on the server
The most important rule in C++ authentication is short: the client reports, the server decides. Any check that runs entirely inside your process can be found and changed. The classic crack flips a conditional jump from JE to JMP, or overwrites a call with NOP instructions, and the application carries on as if the license were valid.
Moving the decision to the server changes what a patch achieves. The attacker can still skip your local if, but skipping it doesn't create a valid session, and without a valid session the server sends nothing. The same thinking applies to everything else of value in the binary.
| Asset | Risk if it ships in the binary | Where it should live |
|---|---|---|
| License decision | Patched to always succeed | Server verdict over a signed channel |
| Validation algorithm | Copied into a key generator | On the server only |
| API keys and tokens | Pulled out with a strings scan | Your own backend, or a server-side string |
| Config, offsets, constants | Edited to change behaviour | Server-side strings after login |
| Premium modules and DLLs | Copied and reused without a license | Server-side files or in-memory loading |
Native code has one more option for that last row. Instead of shipping a protected module on disk, qPapel Auth can stream encrypted DLLs into memory without writing them to disk, and its Map Files feature maps your files into memory much like a PE loader. In-memory loading to protect DLLs covers how it works and when it is worth the effort.
Integrity checks: catching patched code and memory
Server-side decisions make patches less useful. Integrity checks make them visible. Two kinds of tampering matter in a running C++ process.
- Changes to the code itself. A cracker edits instructions in the executable, or in its code section after it has loaded, to skip a check or change a result.
- Changes to memory at runtime. A debugger or memory editor writes into the live process, patching an instruction or a value at the exact moment it matters.
qPapel Auth exposes both as calls you place in your own code. auth.CheckTextIntegrity() performs CRC checks, session-based checks and checks for JMP and NOP patches. auth.CheckMemoryIntegrity() checks whether the program's memory has been modified at runtime, including instruction patching such as JMP and NOP changes. On top of those, Remote Settings has switchable Integrity Check and CRC32 Check protections, and Build Control prevents your file from being modified, patched or opened by unauthorised tools.
// Illustrative: where qPapel Auth integrity checks fit in a C++ app.
// CheckTextIntegrity and CheckMemoryIntegrity are real SDK names.
// StartLicensedSession, RunMainLoop and ExportProject are your own code.
int main()
{
if (!StartLicensedSession()) // key exchange, license and HWID check
return 1; // fail closed: no session, no app
auth.CheckTextIntegrity(); // CRC, session and JMP/NOP checks
auth.CheckMemoryIntegrity(); // runtime memory modification
RunMainLoop();
}
void OnExportClicked()
{
auth.CheckMemoryIntegrity(); // check again before valuable work
ExportProject();
}How to integrate qPapel Auth into a C++ application
The integration lives in your startup path, before any sensitive code runs. These are the steps in order, with the points where most first integrations go wrong.
- 01
Get the current SDK files
Take the latest Lib and Include files from the official Example project, and
qPapelAuth64.dllfrom the Downloads page of your PapelShip dashboard. When the security and encryption layers change, old libraries stop working, so always build against the current release. - 02
Choose the Default Library or EasyAuth
The Default Library is still fully supported. EasyAuth is the newer library, with C# support as well as C++, better error handling and security policy diagnostics. PapelShip recommends moving projects to EasyAuth gradually as it matures.
- 03
Authenticate before anything valuable runs
Start the session at the top of
main, before your main window opens or your configuration loads. Nothing worth protecting should execute on an unauthenticated session. - 04
Load what you need from the server
Move configuration, endpoints and sensitive constants into server-side strings, and premium assets into server-side files. Read them after login and hold them in memory only as long as you need them.
- 05
Add integrity checks and switch on protections
Place
auth.CheckTextIntegrity()andauth.CheckMemoryIntegrity()at startup and before valuable operations, then enable Anti VM, Ban on Debugger, the session system and HWID Lock in Remote Settings. - 06
Fail closed
No server, a bad response or a failed check means the application exits. An offline fallback that runs the full product is a back door, so if you must support offline use, limit it tightly in time and scope.
EasyAuth also tells the user why a session ended. When a security policy closes the application, it shows "Security Policy Closing.." along with extra information about the cause, which keeps support conversations short for genuine customers who trip a rule by accident. Product details and plans are on the qPapel Auth page.
Anti-debug, anti-VM and runtime detection for native code
Licensing decides who may run your software. Runtime protection decides whether the environment it runs in can be trusted. Debuggers are the main tool used against native code, followed by memory editors and virtual machines, which let an attacker snapshot a session and rewind it as often as they like.
qPapel Auth's Remote Settings let you block window titles, class names, processes and debugging tools, detect virtual machines and ban a license when a debugger attaches, all without compiling a new build. Anti-dumping routines, memory protection and anti-tamper hardening protect the binary regardless of those settings. Because the policy is delivered remotely, you can update protection without rebuilding when a new tool appears.
Blacklists only catch tools you already know about. A renamed or recompiled debugger slips past a list of process names, which is why qPAnalyzer looks at UI layout patterns, window handles and memory signatures instead, captures a screenshot of the flagged window and adds to a risk score with warn, restrict, close and ban thresholds you set. Anti-reverse-engineering beyond static blacklists explains that approach in depth.
License and HWID
Who may run it, and on which PC
Protected session
Key exchange, encrypted signed traffic
Server-side data
Strings and files only after login
Integrity checks
Patched code and memory detected
Runtime detection
Blacklists, anti-VM and qPAnalyzer
Common mistakes in C++ license checks
Most cracked C++ products weren't beaten by anything clever. They were beaten by one of a handful of design shortcuts.
- One boolean guards everything. A single
isLicensedflag is the first thing a cracker searches for. Make features depend on server data rather than on a flag. - Secrets in string literals. API keys, encryption keys and download URLs in the binary are visible to anyone who runs a strings scan. Obfuscating them only delays the moment they are decrypted in memory.
- Trusting the local clock. Expiry worked out from the system time can be beaten by changing the date. Let the server decide whether a license has expired.
- Checking once at startup. Attaching after launch and patching mid-session defeat one-time checks. Keep the session alive and re-check before valuable work.
- Generous offline fallbacks. If the app runs in full when the server is unreachable, blocking the server is the crack.
- Stale SDKs. Old libraries miss protocol and protection updates. Rebuild when the SDK changes rather than months later.
The same mistakes appear in managed code, with one extra problem: .NET assemblies decompile back to readable source. C# licensing without hard-coded secrets covers that side.
Veelgestelde vragen
Build C++ software that fails safely when cracked
Secure C++ authentication isn't one clever check. It is a protected session, a decision made on the server, data that only arrives after that decision, integrity checks that notice patches and runtime detection that notices the tools behind them. Each layer is ordinary on its own. Together they mean that bypassing any single one leaves the attacker with a build that doesn't work.
Start with the server-side decision and server-side data, because they change the economics of cracking the most. Add integrity checks and runtime detection next, and keep the SDK current so the protection improves without you rewriting anything.
qPapel-securityteam
Licenties en softwarebescherming