Ask ten developers how they protect their software and you'll often hear ten single answers: an obfuscator, a packer, a license API, an anti-debug library. Each one helps against one kind of attack. None is enough on its own, because each covers a different part of how products are actually attacked.
A software protection stack is the alternative: several layers, each answering a different question, arranged so that one layer covers what the others can't. This guide walks through the six layers we recommend for C++ and C# products, what each one stops, how the emphasis changes between native and managed code, and the order in which to adopt them.
Why one protection tool is never enough
Every protection technique has a blind spot. An obfuscator makes code harder to read but does nothing about a shared key. A license check stops sharing but can be targeted if it runs only on the client. A blacklist stops known tools and misses everything else. Attackers don't need to beat all of these. They need to find the one gap you left open.
Layering works because the gaps don't line up. Getting past one layer only leads to the next, and the most important layers, the ones on the server, aren't on the attacker's machine at all.
A good stack also gives every layer a single, clear job. When each one answers exactly one question, it is easy to see which question is still unanswered for your product, and easy to explain to a customer why a particular check exists.
Licensing and HWID
Server-side keys bound to a device
Integrity checks
Memory, text and CRC32 checks
Anti-debug and anti-VM
Debuggers and VMs detected
Process and window blacklists
Known tools blocked remotely
Server-side data
Strings, files, settings per session
qPAnalyzer
Unknown tools flagged and scored
The six layers of a software protection stack
1. Licensing and HWID binding
The question: who may run this software, and on which machine? License keys are issued per order, checked on the server and bound to a hardware ID on first activation. Keys can be generated, paused, banned and inspected in real time, and the Computers page shows which devices use which keys. This layer stops casual key sharing and gives you a lever to cut off abuse without a release. What is HWID locking covers the mechanics.
What it doesn't cover: a licensed customer who studies or modifies their own copy. A valid key on the right machine passes this layer, which is why the next layers exist.
2. Integrity checks
The question: is this the build you shipped? In qPapel Auth, auth.CheckMemoryIntegrity() checks whether the program's memory has been modified at runtime, for example by instruction patching. auth.CheckTextIntegrity() adds CRC, session-based and patch checks, and a CRC32 check can be switched on from Remote Settings. Build Control prevents your file from being modified, patched or opened by unauthorised tools.
What it doesn't cover: inspection that doesn't change anything. Someone can watch a program run without modifying it, so integrity checks pair with anti-debug and runtime detection.
3. Anti-debug and anti-VM
The question: is someone inspecting the program while it runs? qPapel Auth detects an attached debugger and can ban the offending license, and anti-VM detection notices virtual machines commonly used for analysis. Anti-dumping routines, memory protection and anti-tamper hardening are built in regardless of your settings.
What it doesn't cover: tools that observe from outside the process. Those are the job of blacklists and qPAnalyzer.
4. Process and window blacklists
The question: is a known analysis tool running? Remote Settings let you block window titles, class names, active processes and debugging tools without compiling a new build, and target rules by app version, country or user group. Blacklists are fast and cheap, and only catch tools that are already known.
What it doesn't cover: renamed, private and newly released tools. A list can only name what someone has already added to it.
5. Server-side data
The question: what does a modified build actually get? SS Strings keep sensitive values on PapelShip's servers and deliver them only to authenticated sessions. SS Files serve files to authenticated clients instead of bundling them, and encrypted DLLs can be streamed into memory without writing to disk. A build that has been modified to skip the earlier layers receives none of this, so it is incomplete. This is the layer that changes the economics, as explained in client-side protection vs server-side secrets.
What it doesn't cover: a value after it has been delivered to a valid session. Keep lifetimes in memory short, and let the runtime layers watch the session while it lasts.
6. qPAnalyzer runtime detection
The question: is an unknown tool running? qPAnalyzer is AI-assisted runtime threat detection. It inspects UI layout patterns, window handles and memory signatures, analyses a screenshot of a flagged window and assigns a threat score from 0 to 100%. A per-product whitelist and a "Not a threat" action keep false positives down. Read how qPAnalyzer detects renamed and custom tools.
What it doesn't cover: deciding what to do. qPAnalyzer produces evidence and a score; your risk engine thresholds and the server-side ban decide the outcome.
How the layers work together when your app starts
The layers aren't separate products bolted together. In a single launch they hand off to each other, and the server sits at the centre of every decision.
01Key exchange
A fresh, encrypted session
02Key, hardware ID, build
Plus local check results
03License and device checked
Active, bound, not banned
04Server-side data released
Strings, files, Remote Settings
05Runtime findings
Integrity, anti-debug, qPAnalyzer
06Policy applied
Warn, restrict, close or ban
Notice what this means for a modified copy. If it skips the local checks, it still has to pass the server's license and device checks before it receives anything. If it passes those with a valid key, its runtime findings still reach the server, and a ban stops the key everywhere at the next check.
What each layer stops
Mapping common threats to the layer that handles them makes the overlap clear. Most threats are covered by more than one layer, which is exactly the point.
| Threat | Main layer | Backed up by |
|---|---|---|
| A key shared in a group chat | Licensing and HWID | Key bans, device management |
| A modified build | Integrity checks | Server-side data |
| Live inspection with a debugger | Anti-debug | Blacklists, qPAnalyzer |
| Running inside a VM for analysis | Anti-VM | qPAnalyzer |
| A well-known tool open next to the app | Blacklists | qPAnalyzer |
| A renamed or private tool | qPAnalyzer | Anti-debug |
| Extracting API keys from the binary | Server-side data | Integrity checks |
| A leaked build passed around | Server-side data | Licensing, Binary Trace |
C++ vs C#: the same stack, different emphasis
The six layers apply equally to native and managed code. What changes is where the pressure falls.
- C# compiles to intermediate language that decompiles back to readable code relatively easily. That puts more weight on server-side data: ship no secrets in the assembly, keep sensitive values in SS Strings and treat anything left in the binary as readable. The guide to C# licensing without hard-coded secrets goes into detail.
- C++ is harder to read, but a compiled binary can still be modified at the instruction level. Integrity checks and server-side decisions make sure a single changed branch doesn't give away the product. See C++ authentication and licensing.
qPapel Auth provides native SDKs for both. The EasyAuth library added C# support in the 7.0 release, and the Default Library remains available for existing C++ projects.
In what order should you adopt the layers?
You don't need every layer on day one. Adopt them in the order that returns the most protection for the least effort.
- 01
Licensing and HWID
Immediate revenue protection. Every sale becomes a key bound to one device, checked on the server.
- 02
Server-side data
The highest return for the effort. Move your three most valuable strings or files to the server first.
- 03
Integrity checks
Call the integrity functions at points that matter, not only at start-up, and switch on the CRC32 check.
- 04
Anti-debug, anti-VM and blacklists
Enable them from Remote Settings. This takes minutes and filters out low-effort attempts.
- 05
qPAnalyzer
Turn it on once the base is in place, start in observe mode, tune the whitelist, then enable actions.
Operating the stack after release
A protection stack isn't something you install and forget. A few routine habits keep it effective.
- Review findings weekly. Check the Computers page and the Threat Vault, whitelist legitimate tools and mark false positives as "Not a threat".
- Watch reset and ban patterns. Frequent HWID resets on one key usually mean sharing.
- Change values remotely. Rotate server-side strings and adjust Remote Settings when you suspect exposure, without a rebuild.
- Set response thresholds. The risk engine's warn, restrict, close and ban thresholds should match each product's value.
- Keep sales and licensing connected. When the store and qPapel Auth share one dashboard, refunds, bans and resets stay in sync.
- Give staff the access they need, no more. Staff panels let support handle resets and key questions without the owner account.
When something does go wrong, such as a build turning up where it shouldn't, the same tools carry the response. Detecting leaked builds with Binary Trace walks through a step-by-step plan.
The qPapel Auth product page shows how licensing, Remote Settings and server-side data fit together in one dashboard.
よくある質問
Protect your product in layers
Single-tool protection fails in predictable ways. A stack where each layer answers its own question, and where the most important decisions and data stay on the server, keeps holding as attackers adapt.
Start with licensing and your most valuable server-side data this week, then add the remaining layers one at a time. Each one closes a gap the others leave open.
qPapelセキュリティチーム
ライセンス管理とソフトウェア保護