Tài liệu · Tham chiếu
Bộ mẫu bảo vệ
Ứng dụng mẫu gắn sẵn bảo vệ license của ClavisAUH, tạo riêng cho app của bạn với các biện pháp bạn chọn, build được ngay và chép được vào phần mềm của bạn
Bạn nhận được gì
Notebook, một ứng dụng console nhỏ: tầng 1 luôn có sẵn, các biện pháp tầng 2 bạn chọn được thêm vào dưới dạng module. Bạn build, chạy thử với app của mình, rồi chép các file vào phần mềm của bạn.
Chọn và tải trên dashboard, ở Bảo mật ứng dụng › Bộ mẫu bảo vệ. Mỗi bộ mẫu làm cho một app: App ID, địa chỉ API và khoá công khai đã điền sẵn, kit.lock liệt kê mọi file kèm SHA-256.
- GUIDE.md, HUONG-DAN.mdbuild, chạy, gắn vào phần mềm, phát hành
- HOW-IT-WORKS.md, GIAI-THICH.mdmỗi biện pháp làm gì và không làm được gì, như trang này; GIAI-THICH.md mỗi biện pháp một dòng tiếng Việt, kèm giới hạn chính
- TESTING.md, KIEM-TRA.mdcách tự kiểm từng biện pháp
C# (.NET 8), C++ (C++17 với CMake), Python (3.9 trở lên) và Node.js (20 trở lên)
Năm cửa kiểm chứng
Một biện pháp chỉ vào trình chọn của một ngôn ngữ sau năm cửa: thẻ kỹ thuật được người phản biện soi lỗi, rồi trong ngôn ngữ đó có mã, kiểm chứng app hợp lệ chạy bình thường, kiểm chứng phát hiện được tấn công, và kiểm chứng các môi trường hợp lệ mà thẻ liệt kê (máy ảo, mạng chậm, múi giờ khác, cập nhật hệ điều hành) không bị chặn
Lần chạy đầy đủ gần nhất của phòng kiểm chứng, mọi bài kiểm và mọi lựa chọn được build: 2026-11-05
- C#: 25 bài kiểm trên Windows và Linux
- C++: 27 bài kiểm trên Windows và Linux
- Python: 24 bài kiểm trên Windows và Linux
- Node.js: 24 bài kiểm trên Windows và Linux
Bộ chọn sẵn
Cơ bản: có trong mọi bộ mẫu
Nằm sẵn trong ứng dụng mẫu, bạn không cần chọn
Ký response và chống replay
Phần mềm chỉ tin câu trả lời được ký bằng khoá của ứng dụng, gắn với đúng yêu cầu vừa gửi; server giả bị từ chối
Không làm được: Không chặn được bản đã sửa file chạy để bỏ qua kiểm tra; server giả dùng liên tục không bao giờ được báo về
- Phía server
- Không cần bật gì
- Tự kiểm tra
Trong một bản thử, đặt khoá công khai của một app khác vào danh sách khoá công khai trong file cấu hình (hoặc, với app mẫu trong repository có cấu hình trống, đặt
CLAVIS_APP_KEY), build rồi chạyactivate: app dừng vớiFAIL unknown_key.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
Someone runs the software against a server of their own (an "emulator" that answers "license active" to everything), or sits between the software and ClavisAUH and rewrites answers, or replays an answer recorded earlier.
How it works
- Every request is signed on the machine with the device's Ed25519 key, over the app id, method, path, SHA-256 of the body, a timestamp, a nonce and the session id. The server refuses a nonce it has seen (kept 150 seconds) and a timestamp more than 60 seconds from its clock.
- Every answer the server gives once it has identified the app, error answers included, is signed with the app's Ed25519 key over its key id (
kid), the HTTP status, the method, the path, **the nonce of the request it answers**, a timestamp and SHA-256 of the body (CLV1.1). The SDK refuses an answer that is unsigned, signed by a key outside the build's list, signed over anything else, or more than 60 seconds off its corrected clock. No endpoint is exempt; the one answer not held to the 60-second window is the signedclock_skewrefusal, which exists because the machine's clock is wrong (it is still bound to the request's nonce). - Some answers cannot be signed because the server does not know the app yet: missing headers, a bad nonce or encoding, an unknown app, unreadable JSON, an unknown path, a server error while it loads the app, the server's flood guard (429), and any page a proxy or CDN in front of the API sends. The SDK refuses them exactly like a forgery. (A request whose body the route refuses, such as a key too short to be one, was answered unsigned too until the fix that came with this card's second review; it now gets a signed
validation_failed.) - After a refused answer, the SDK remembers it in memory and reports it (
response_verification) with the next answer it can verify, which Protect counts as T1.
What it does not do
- It does not stop someone from patching the executable so that it skips the check or ignores the answer. That is what T6, N2, N3, N4 and N9 address, each only in part.
- It does not hide what travels: TLS does . Anyone who controls the machine can read the requests.
- It does not help if the app's private key leaks (a compromised server). Rotating the key (Signing Key Rotation) protects only the builds shipped after the rotation without the leaked key; builds already installed keep trusting it, and nothing revokes a key they carry.
- A fake server used all the time is never reported: the report goes to the same address as everything else and is only sent after a verified answer, and the count lives in memory. The SDK still refuses every fake answer; T1 in Protect only sees tampering that comes and goes.
- It does not stop a customer from sharing a valid key: that is T4 and Protect T5.
False alarms
- A machine clock more than 60 seconds off: the server answers
clock_skew(signed), the SDK corrects its clock and retries once. The correction lives in memory, so a clock more than 5 minutes off raises Protect T3 (clock drift, weight 6) at every launch of the software. - A clock almost exactly 60 seconds off sits between the two limits: the server still accepts the request, but the answer's time is just outside the SDK's own 60-second window, so every answer is refused as
stale_responsewith noclock_skewto learn from. The customer has to set the clock right; the SDK's sentence forstale_responsesays to check the clock. - Unsigned infrastructure answers are failed tries, not forgeries. A 502 from the reverse proxy while the API restarts, a CDN error or challenge page, the flood guard's 429, a company proxy's block page or
407: the SDK refuses each one and tries again, and nothing is reported. Otherwise one outage would raise T1 on every license at once. The price: a fake server that only ever answers with unsigned errors stays invisible, but it also changes nothing. An unsigned200, or an answer with a wrong signature, is still reported. - A wrong API address or public key in the build gives
unsigned_responseorunknown_keyfor every call: a configuration error that shows on the first test run, not later. - A transparent TLS proxy (one that re-encrypts without changing the bytes) is invisible to it: the signature is end to end. A proxy that blocks, rewrites or asks for credentials is not, as above.
Không nhúng secret
Bản build chỉ mang App ID, địa chỉ API và khoá công khai; bước quét chặn các dạng bí mật nó biết và các giá trị bạn liệt kê
Không làm được: Chỉ bắt các dạng bí mật nó biết và giá trị bạn liệt kê; mã trong file chạy vẫn đọc được
- Phía server
- Không cần bật gì
- Tự kiểm tra
build.ps1(hoặcbuild.sh) kết thúc bằngOK secrets; đưa một chuỗi nhưclv_live_kèm 32 chữ cái hoặc chữ số vào một câu app in ra thì build dừng.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
Anything inside the executable can be read by whoever has the file: strings, resources, configuration shipped beside it. A secret placed there (a key that signs, a Seller API key, a password to another service) is a secret given to every customer and every cracker.
How it works
- The software carries only the app id, the API address and the app's public key. The public key verifies answers; it cannot sign anything.
- The device makes its own key pair on first run (T3); the server learns only its public half.
- The app's private key is generated and sealed on the server and is never shown or downloadable.
- The kit adds a build scan: a test that reads every file the build ships and fails when it finds something shaped like a secret: a Seller API key (
clv_live_orclv_test_followed by 32 letters and digits), a webhook secret (whsec_), a PEM private key block, what a test run leaves in a state folder (device.key,license.key,offline.token, aclv1.token), or a value the seller lists in asecrets.denyfile in the folder the scan runs from (the kit's root forbuild.ps1andbuild.sh), one per line (their own third-party keys). - It searches each file as bytes (UTF-8 reads the same for these shapes), as UTF-16, because C# string literals and C++
L""strings on Windows are stored that way, and as UTF-32, the width of C++L""strings on Linux and macOS. - It opens what is compressed before searching:
.jar,.whl,.zipand.nupkgfiles. - It runs on the publish folder, before any step that hides or packs content: obfuscators that encode strings (N9), and formats that pack everything into one file (PyInstaller, .NET single-file publish, installers).
What it does not do
- It does not keep the seller's own secrets out of the build if the seller writes them in: the scan catches the shapes it knows and the values the seller lists, not every secret.
- It does not protect the code itself: logic in the executable can still be read (N9 makes it harder, nothing makes it impossible).
- A third-party API key the software truly needs at run time cannot be hidden on the client; it belongs on a server (a relay, not built yet).
False alarms
- A test string that only looks like a key (for example
clv_live_in documentation shipped with the build). - PEM test keys inside third-party packages the build ships (
node_modulesin an Electron app, Python dependencies that bundle their own test data).
The seller allows each one by file and value in secrets.allow; the kit never ignores a finding silently.
Khoá thiết bị được giữ an toàn
Khoá ký của máy nằm trong thư mục trạng thái của người dùng: niêm phong bằng DPAPI trên Windows với C# và C++, chỉ người dùng đọc được trên Linux và macOS, còn trên Windows với Python và Node.js thì kín như thư mục chứa nó
Không làm được: Không giữ chỗ (server nhận máy theo linh kiện); người dùng có license vẫn chép được khoá; không gắn với phần cứng
- Phía server
- Không cần bật gì
- Tự kiểm tra
Sau
activate, thư mục trạng thái (%APPDATA%\Notebook, hoặcCLAVIS_STATE_DIR) códevice.key; trên Windows file được niêm phong bằng DPAPI nên tài khoản Windows khác không mở được.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
The device key signs every request. A session belongs to the device whose key opened it, and an offline token is valid only where its key hash (dev) matches. Copied to another machine, the key lets that machine use the first one's sessions and offline tokens.
How it works
- Every request is signed with an Ed25519 device key. The SDKs keep it between runs only through their key helper (
loadOrCreateDeviceKeyand its equivalents) or when the software passes a key in; a client created without one makes a new key in memory each time. The kit's sample app always uses the helper. JavaScript in a browser has no helper. - On Windows, the C# and C++ helpers seal the key with DPAPI for the current user. The C library and the CLI use the C++ SDK, so they do the same.
- On Linux and macOS the helpers keep it in a file readable only by the current user (mode 0600). The C++ helper, used by the C library and the CLI, did not restrict the mode until the fix that came with this card; it now creates the file with 0600 like the others.
- On Windows, the helpers of the JavaScript, Python, Go, Rust and Java SDKs write the seed as is, and the Unix mode means nothing there: the file has the access rights of its folder. A per-user folder (
%APPDATA%, the default the kit uses) is private to the user; a folder chosen elsewhere may not be. - The kits use each SDK's own helper: DPAPI on Windows in C# and C++, a file readable only by the user on Linux and macOS; on Windows, Python and Node.js keep it as text, as private as its folder. A key store in the OS store where the language reaches it (DPAPI from Python and Node.js, Keychain on macOS, libsecret on Linux) is not in the kits yet.
- The server checks every session request against the device's current public key: a session id used with another key is refused with
session_device_mismatch. Protect records it as T5 (key sharing) only on redeem and transfer; a heartbeat,variables(), the update check or a sign-out refused this way raises no signal.
What it does not do
- It does not hold the seat. The server matches a machine by its hashed identifiers (fingerprint, or enough shared components), never by the key; a known machine signing in with a new key simply has its stored key replaced.
- It does not stop malware running as the same user: it can use the key in place, as the software does.
- The licensed user can move it. DPAPI protects the key from other accounts, not from its own user, who can unseal it and seal it again on another machine. That machine then passes the first one's offline tokens. Online, it sends its own identifiers and counts as another device.
- A user-only file can be copied by that user just as well.
- It is not hardware-bound: a key in a TPM or Secure Enclave (N10) would be, and is not built.
False alarms
- Two Windows accounts on one machine (or two state folders) have one fingerprint and two keys. Each sign-in replaces the device's stored key, so the other account's next heartbeat gets
session_device_mismatch. While both run, they keep replacing each other's key and signing in again does not settle it; the kit's guide says to run the software under one account at a time on a one-seat license. - Reinstalling the system or a new user profile loses the key. The machine signs in again with a new key; whether it keeps its seat depends on its identifiers, and the SDKs' default description changes on a reinstall (PLAN6 F.9).
- A roaming profile carries a DPAPI key to another machine of the same user: that machine is still a new device for the seat count, but it can use the first machine's offline token.
Phiên và heartbeat
Phần mềm hỏi lại server theo nhịp, nên tạm khoá hay thu hồi tới được bản đang chạy ở lần heartbeat kế tiếp, không tức thì
Không làm được: Giữa hai lần heartbeat phần mềm vẫn chạy; bản bị sửa có thể bỏ heartbeat; có token offline thì chạy tới khi token hết hạn
- Phía server
- Không cần bật gì
- Tự kiểm tra
Chạy
runvớiCLAVIS_HEARTBEAT_SEC=10(biến này chỉ rút ngắn được nhịp thường 30 phút), tạm khoá key trên dashboard: trong 10 giây app hiện câu cho khách và dừng.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A license checked once at start-up keeps working after it is revoked, suspended or expired, for as long as the software stays open; and a key shared between machines keeps several of them running at once.
How it works
- Activation opens a session bound to the device key. The software sends a heartbeat on a timer, about every 30 minutes by default (the SDKs do not send it by themselves); a session without one for 60 minutes ends, or after three heartbeat intervals when the app turns on short sessions (Short-Lived Session Lease).
- Each heartbeat re-checks the license: suspended, revoked or expired answers end the run with the matching code; suspending, revoking or resetting devices on the dashboard ends the sessions at once, so the next heartbeat gets
session_expiredand the next activation gets the precise reason. - Dead machines give their seat back, two ways: a background job releases a machine silent for the license plan's
deadAfterHours(empty means 72, 0 means never), and it may come back within 7 days on the same seat if one is free; and when the plan sets its own heartbeat, a machine silent for two of its intervals is removed at the next sign-in on that key, after which its own next heartbeat getsdevice_revoked. - An app can cap concurrent sessions per license (Concurrent Session Limit).
- The kit's sample app runs the heartbeat on a timer at its "heartbeat loop" hook point and handles each outcome: continue, retry later (network), or stop and show the user's sentence.
What it does not do
- Between two heartbeats the software keeps running: a revoked license stops at the next heartbeat, not instantly.
- With offline tokens, a copy without network keeps running until the token expires (N5 shortens this).
- A patched executable can skip the heartbeat altogether; T6, N3 and N4 make that less useful.
- A copy that cannot reach the server (the API's address blocked by a firewall) gets network errors, which the kit retries rather than stopping on; it keeps running until its session would have ended (60 minutes, or three Short-Lived Session Lease intervals) or until its offline token runs out, whichever is later. Only a server answer can stop it sooner.
False alarms
- A network drop makes a heartbeat fail with a retryable code, and an answer that cannot be proven to come from the server (a proxy's page, the API restarting) is treated the same way: the kit keeps the software running within the session's time and any offline allowance, rather than stopping at the first failure.
- A laptop waking from a long sleep finds its session ended (
session_expired), or the machine removed (device_revoked) if the plan's heartbeat reaped it. The SDK does not sign in again by itself; the kit's sample activates again with the key it was given, which takes a seat only if one is free. - A plan heartbeat shorter than the software's own interval: the plan's heartbeat setting is not sent to the SDK (only Short-Lived Session Lease's pulse is). If it is shorter than half the interval the software uses (30 minutes by default), another machine's sign-in on the same key removes machines that are running normally, and they get
device_revoked. The kit's guide says to keep the plan heartbeat at least twice the software's interval, or to use Short-Lived Session Lease, whose pulse the software does receive. - With a session cap (Concurrent Session Limit), a session left open by a crash or a close without
logout()counts for up to 60 minutes: a customer who moves to another machine meanwhile getssession_limitand Protect records T7. The kit callslogout()on every normal exit and says so in its guide.
Lỗi được xử lý và nói cho người dùng hiểu
Mọi lỗi đi qua một chỗ và hiện câu cho người dùng; máy không giữ chỗ nào thì không được biết vì sao key hỏng
Không làm được: Client không gửi `x-clavis-proto: 1.1` vẫn biết key nào có thật; với 1.1, vài câu trả lời vẫn cho thấy key tồn tại
- Phía server
- Không cần bật gì
- Tự kiểm tra
Đặt
CLAVIS_LANG=virồi kích hoạt một key đúng định dạng nhưng không có thật (đổi vài ký tự của key thử nghiệm): app hiện câu "Key hoặc thông tin đăng nhập không đúng" vàFAIL invalid_credentials.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
Two harms come from poor error handling. Detailed refusals tell an attacker which keys exist (key enumeration), and errors swallowed or shown as raw codes leave honest users stuck and tempt sellers to "fix" them by ignoring errors, which turns into a bypass.
How it works
- Every failure has one code from a single table shared by the server, every SDK, the C library and the CLI, with a sentence for the user in English and Vietnamese and whether trying again later can help.
- For a CLV1.1 client (one that sends
x-clavis-proto: 1.1, as every official SDK does) on a machine that holds no seat on a key, an unknown, suspended, revoked or expired key answers the sameinvalid_credentials, after a minimum time of 300 ms . The machine holding the seat gets the precise reason. - Failed keys and passwords are limited per app and IP: after 20 failures in 15 minutes the IP gets
too_many_attempts, and Protect T4 (key guessing) is raised. - The kit's sample app has one place that turns an error into what the user sees: the sentence, and for retryable errors a later retry. It never treats an unknown error as success.
What it does not do
- The uniform answer is opt-in by header. A caller that leaves out
x-clavis-proto: 1.1getsinvalid_keyfor an unknown key and the precise reason (license_expired,license_suspended,license_revoked) for a real one, so it can still tell which keys exist. Applying The server to every protocol version is a question for the owner (PLAN6 F.10). - Even for 1.1 callers, some answers show that a key exists: an unused key activates and takes a seat,
device_limitsays the key is full,license_already_registeredsays an account owns it. The server hides why a key fails, not whether a usable or full key exists. - The 300 ms is a floor, not equal timing: a slower refusal can still differ from a fast one.
- It does not stop someone who already has a valid key from sharing it (T4, Protect T5), and it does not stop a patched executable from ignoring errors (T6, N3, N4).
False alarms
- A customer who mistypes a key sees the
invalid_credentialssentence, which says to check the key; a key too short or too long to be one, an empty key, or a username or password the form refuses getsvalidation_failed("check what you entered"). Until the fix that came with this card's second review, those got an unsigned answer that the SDK took for a forged server (T1). - A customer whose key is expired or suspended, on a new or reinstalled machine (no seat there) is told to check the key rather than the real reason; the seller's support should look the key up before answering.
- Everyone behind one shared address (an office, a school, a mobile carrier's NAT) shares the 20-failure limit: enough mistyped keys or passwords there lock all of them out for up to 15 minutes, and Protect raises T4 for that address. With Graduated Enforcement on Act on its own, T4 blocks that address for 24 hours, and every call from it is refused, heartbeats of valid licenses included, until the block ends or the seller undoes it.
Kiểm soát phía server
Tính năng trả phí cần quyền trong gói và dữ liệu chỉ phiên hợp lệ mới nhận
Không làm được: Chỉ bảo vệ những gì thật sự để ở server; giá trị đã tải về máy thì người có license chép ra được; biến toàn app tới cả phiên dùng thử
- Phía server
- Biến report_template và quyền export_report
- Tự kiểm tra
Với key có gói không có
export_report,exporttrả "Your license does not include this feature".
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A check that lives only in the executable can be patched out: change one jump, and the paid feature runs without a license. Everything the feature needs is already on the machine.
How it works
- Values the paid feature needs (a template, a rate, a configuration, a download address) are kept as app variables on the server, and the server gives them only to a valid session: every sign-in answer carries them and
variables()fetches them again; a machine without a session gets nothing. - Variables are scoped to the whole app, to one license, or to one end user. An app-wide variable reaches every session, trials and free accounts included, so the kit's sample also checks the paid entitlement in the signed answer before using one, and its guide says which scope fits paid data.
- Feature flags come from the license plan (entitlements) in the signed answer, so they cannot be edited on the way.
- The kit's sample app ("Notebook") keeps its paid feature's report template as a variable: without a valid session the feature has nothing to work with, patched or not.
What it does not do
- It only protects what the seller actually moves to the server. A feature whose logic and data are all in the executable stays patchable.
- Once a valid session has fetched a variable, its value is on that machine: a customer with a valid license can copy it out, and so can anyone who starts a trial, when the app offers one: trials are given per machine as the machine describes itself, so a cracker can start new ones at will. App-wide variables are therefore not secret from non-paying users of an app with trials or free accounts.
- A seller who caches the value for offline use (the guide describes how, the sample does not) keeps it on disk, where a patched build can read it whatever the offline allowance says. Variables suit data that changes, is large, or is worth little alone; secrets that must never reach a machine belong behind a server call (a relay, not built yet).
- It is not encryption of the executable: N9 is about reading the code.
False alarms
Offline use: a feature that needs a variable does not work offline. The sample app says the feature needs a connection; caching the last value is the seller's choice, with the risk above.
Tuỳ chọn: bạn chọn
Mỗi biện pháp là một module; bỏ module nào thì app vẫn build được
Certificate Pinning
Chỉ nói chuyện với server có khoá TLS nằm trong danh sách ghim; proxy chặn giữa bị từ chối
Không làm được: Không chặn được bản đã sửa file chạy; công cụ cài vào tiến trình vẫn đọc được dữ liệu; proxy kiểm tra HTTPS của công ty hay antivirus làm kết nối hỏng
- Phía server
- Ghim TLS trên máy chủ
- Tự kiểm tra
Chạy app qua proxy chặn giữa (mitmproxy, Fiddler) đã tin gốc của proxy: app không kết nối được và ghi
pin_mismatch.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
Someone on the customer's machine installs their own root certificate and runs an intercepting proxy (Fiddler, mitmproxy, Charles) to read the traffic between the software and ClavisAUH: the license key in activate, a password in login, the variables a valid session receives. The protocol itself is public; what the proxy reveals is these values.
How it works
- The kit replaces the SDK's transport with one that, after the normal TLS checks, compares the SHA-256 of the server certificate's public key (SPKI) with a short list built into the software: the current key and at least one backup key that is not in use yet. No match: the connection is closed before anything is sent.
- Every official SDK takes a custom transport, the place its documentation names for pinning: the
Transportoption in C#, Python, Go, Rust, Java and C++, and thefetchoption in JavaScript. Per language: C#ServerCertificateCustomValidationCallback, C++ libcurlCURLOPT_PINNEDPUBLICKEY, Python the peer certificate of the TLS socket, Node afetchbuilt on an agent whosecheckServerIdentitychecks the pin (the JavaScript guide says the SDK cannot pin: true of browsers and of the defaultfetch; it gets a line about this route when the module ships). The C library and the CLI use the C++ SDK's default transport and cannot take one, so they are out of scope. - The kit's transports also ignore TLS key-log settings they control: Python's context is built without
SSLKEYLOGFILE, and the C++ module removesSSLKEYLOGFILEfrom its own process environment before libcurl starts (libcurl with OpenSSL, on Linux and macOS, would otherwise write the session keys there). - A refused connection surfaces as the SDK's network error, so the software's existing "cannot reach the server" handling applies; the kit adds a distinct log line (
pin_mismatch) for support.
What it does not do
- It does not stop someone who changes the executable: removing the pin check, or hooking the TLS library inside the process, defeats it. Pinning raises the cost of reading the traffic; it is not a barrier against patching.
- Reading the traffic without changing the file still works with the right tools: an instrumentation tool such as Frida attached to the process,
NODE_OPTIONS=--tls-keylogfor Node,SSLKEYLOGFILEfor Electron (Chromium). - Update downloads: the JavaScript SDK downloads through the same
fetchoption, so they are pinned too. The other SDKs' download helpers use a client of their own; the kit downloads the file itself through its pinned transport, from the address in the verified manifest, then checks the SHA-256 the manifest gives. Either way the files are checked against the signed manifest, so they cannot be altered. - It adds nothing to the integrity of answers: T1 already refuses altered or forged answers, pinned or not.
- It cannot be done from JavaScript in a browser (no access to the certificate). Electron and Node can.
- It does not protect the server's own TLS : the API must be on HTTPS with its own domain first. Until ClavisAUH is deployed, there is no production key to pin.
- The deployment must keep a controlled key. The reverse proxy in the deployment guide gets its certificates from Let's Encrypt on its own and makes a new key at each renewal by default; behind the CDN option, clients see the CDN's key, which ClavisAUH does not control. Pinning needs a certificate key the operator keeps and renews with (or a pinned intermediate, with its own risks), decided before any build ships pins.
- The server does not send pins today:
securityHints.pinningis always"off"andspkiPinsempty, so the pins live in the software build only.
False alarms
- TLS inspection breaks pinned connections: a company proxy that re-signs all HTTPS, and on home machines the HTTPS scanning of antivirus suites and parental filters. The seller decides whether such customers matter; the kit documents the symptom and the setting to exclude the API's address.
- Key rotation without a backup pin locks out every installed copy at once. The kit refuses to build with fewer than two pins, and its guide explains the order: add the next key as a pin, ship, then rotate the server key.
- Certificates renewed with the same key do not change the pin; renewals that make a new key (the default of common ACME clients, including the deployment's) do, so key reuse must be switched on deliberately.
Kiểm tra toàn vẹn build
Mỗi lần đăng nhập gửi hash của file chương trình; bản bị sửa hiện thành "bản build lạ" trong Protect
Không làm được: Chính phần mềm gửi hash nên bản bị sửa khéo có thể gửi hash gốc; chỉ hash một file
- Phía server
- Kiểm tra toàn vẹn build (A10)
- Một bản phát hành công khai, cùng file các bản build
- Tự kiểm tra
Tải file của bản build lên một bản phát hành nháp và chạy
node tools/check-release.mjs; bản bị đổi một byte bật Bản build lạ trong Protection.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A cracked copy circulates: the seller's executable with its license check patched, sometimes repackaged under the seller's name. It still talks to ClavisAUH (it needs a session for the data behind T6), and nothing tells the seller that this binary is not one they shipped.
How it works
- At start, the kit computes the SHA-256 of one file, the one that holds the program (see the limits for which), and passes it to the SDK as
buildHash, withappVersion. Every sign-in sends both to the server. - The server knows a hash when it matches any file uploaded under the app's releases, drafts included. A release holds one file per platform, and its published file is what the update check serves, usually the installer; so the kit's release step puts the hashed file in a separate draft release that is never published, under its own version or channel (an app has one release per channel and version). Drafts can be deleted later, published releases cannot, and both count against the workspace's release storage.
- The server compares the hash with the files the seller uploaded to Licensing & releases › Releases. A hash that matches no file, for an app with at least one published release, is an unknown build: Protection raises **Unknown build** (T8). The check runs before the license is looked up, so T8 lands on the machine only when that device key is already registered; a patched copy on a new machine is recorded against its IP address. T8 is raised whether Build Integrity Verification is on or off, and Graduated Enforcement acts on it either way. Build Integrity Verification decides only the answer: off or Warn only lets the build sign in, Block refuses it with
unknown_build. A hash that matches a release the seller blocked getsbuild_blocked. - With Build Integrity Verification on,
initalso tells the SDKreportTamperSignals: true, which N6 uses.
What it does not do
- The hash is reported by the software itself. A cracker who reads the kit's code can make the patched binary send the original file's hash; the server cannot tell. The code says it plainly: a signal, never proof. N2 catches copies made without that extra work, and redistributions that were not built for ClavisAUH at all.
- It does not stop the patched copy from running offline or from running at all when the patch also removes the sign-in. T6 and N3 are what make a copy without sign-in useless.
- It hashes one file only (plugins, other DLLs, scripts loaded later are not covered). In C#, a framework-dependent build keeps its code in
YourApp.dllbeside a small launcher.exe: the kit hashes that main assembly, or the single file when the app is published as one. For Python and Node.js the executable is the interpreter: the kit hashes the main script or bundle, which a cracker can edit just as easily, and other modules are not covered. With N9, Python is compiled by Nuitka and has no script left: the kit then hashes the compiled executable. - It does not sign the executable: that is N8.
False alarms
- A build shipped without uploading its files: every customer on it raises T8, and with Block cannot sign in. Files are uploaded on the Releases page (the Seller API can list, publish and block releases, not upload them), so the kit ships a check script instead: with a
releases:readSeller API key it confirms that the build's hash is listed before the build goes out. - Files changed after release by an installer or a code-signing step: the uploaded hash must be the hash of the file as installed. The kit hashes the file after signing (N8) and uploads that.
- Antivirus "repairs" or a half-done self-update: the hash may be unknown for a while. Warn only keeps those customers signing in, but only while Graduated Enforcement is on Alerts only: with Act on its own, every unknown-build sign-in adds 15 points, so a registered machine is blocked after a few such sign-ins (T8 repeated) and the license is signed out at 60. The guide says to use Warn only with Alerts only.
Chạy code phía server
Chưa có trong bộ mẫu
Không làm được: Chưa có trong bộ mẫu
- Phía server
- Cửa sổ offline trên gói license
- Một Seller API key
- Tự kiểm tra
Chưa có trong bộ mẫu.
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
T6 keeps the paid feature's data on the server, but once a valid session has fetched a variable, a cracker with one valid license can copy the value into a patched build and share that build. Whatever the executable can compute on its own, a patched executable can compute too.
How it works
The feature's essential step runs on a server the seller controls, which serves only calls backed by a license that is valid right now and entitled to the feature:
- The software, signed in, holds a signed offline token from ClavisAUH (
clv1.<payload>.<signature>, payload withapp,lic,dev,iat,nbf,exp,lexp) and its device key. - It calls the seller's endpoint with the token, the device public key, and a signature by the device key over the request body, a timestamp and a nonce.
- The seller's server checks with the kit's reference verifier: the token's signature against the app public key (and
kid),appequal to the seller's app,iat/nbfnot in the future,expnot passed,sha256(device public key)equal todev, the device signature, the timestamp within 60 seconds, the nonce unused. - Then, always, it asks the Seller API for the license (
GET /seller/v1/licenses/{lic}, scopelicenses:read) and requires its status to be usable and its plan's entitlements to include the paid feature. Offline tokens carry neither the plan nor the entitlements, and trials and free accounts receive tokens too, so without this lookup every trial would get the paid work. The answer may be cached for a short time (the kit uses 60 seconds). - Only then does it do the paid work and return the result.
What it does not do
- The device key, the token and a session can be copied by their owner. A licensed customer can export the key (DPAPI protects it from other accounts, not from its own user; the SDKs expose the seed) and build it, the token and the session id into copies for others; heartbeats refresh the token. Every such call then looks like the one licensed machine. The verifier rate-limits per license and device and counts distinct addresses per
lic/dev; ClavisAUH's own Protect does not see it (heartbeats raise no signals, impossible travel needs different devices). - Changes to devices are invisible to the seller's server until the token expires: a device reset, a transfer (old tokens stay valid), a blocked device. The Seller API's device records carry no key hash, so the verifier cannot match
devto a device. Only the license's own status is checked live. - Grace days break it: when a license is past its end date but inside the plan's grace days, ClavisAUH still lets it sign in, but issues tokens that are already expired (
expis capped at the license'slexp). The verifier refuses them, and a heartbeat cannot fix it. The Seller API cannot help: it reports such a license asexpiredand does not show the plan's grace days. So N3 refuses grace-day licenses until F.11 is settled. - It needs offline tokens: a plan with an offline window (at least 1 hour), offline licenses on the workspace (Premium by default) and Online-Only Mode off.
- The Seller API allows 120 requests per minute per key (600 on Premium) and can be switched off for a workspace; the verifier must decide what to do when it answers 429 or not at all. The kit fails closed (no paid work) and says so to the user.
- The seller runs, secures and pays for that server; the kit gives a reference verifier, not hosting.
- It does not hide the result once delivered: a report produced for a valid license can be copied like any file.
False alarms
- Grace days, as above: a customer inside them can sign in to the software but not use the paid work.
- A machine clock far off: the device signature's timestamp is refused. The verifier answers with its own time and the kit retries once with the offset, as the SDK does for
clock_skew. - A token near
expwhile the network is up: the kit sends a heartbeat (which brings a fresh token) before calling. - The Seller API being slow or rate-limited: paid actions fail while it lasts (fail closed).
Kiểm tra license nhiều lớp
Nhiều điểm kiểm tra đọc trạng thái license theo cách riêng và báo điều bất thường về server
Không làm được: Mọi điểm kiểm tra đều tìm và gỡ được; sửa một lệnh gửi báo cáo là tắt hết báo cáo (các điểm kiểm tra vẫn chạy); một mình N4 không chạm ngưỡng A13
- Phía server
- Phản ứng tự động theo rủi ro (A13)
- Tự kiểm tra
Bỏ kiểm tra quyền của chính app trong một bản thử rồi export với gói không có quyền đó, trên license vẫn nhận
report_template(để biến toàn app cho bài này): N4 từ chối và Protection hiện báo cáo can thiệp.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
The license check sits in one place, usually right after start. A cracker finds it, flips one jump, and the whole program is unlocked. Worse, the program itself decides what happens when something looks wrong, so the same patch also removes the reaction.
How it works
- The kit's sample app checks the license state at several hook points, not one: at start, before each paid action, in the heartbeat loop and once at a random moment 2 to 10 minutes after start (at the first hook after it, with no timer or thread of its own). They read the state two ways: the last signed grant's status and state (at start, after each heartbeat and at the random moment), and the entitlement the paid action needs, read from the signed answer rather than through the SDK's
has(), so patching one does not silence the other. Their reports, though, all leave through the SDK's onerequest()call to/v1/client/report. - A check that finds an inconsistency (a paid action reached with no valid grant, a grant that does not say active while online) does not crash or delete anything. It sends a report (
kind: "patched", with which check and why) through the SDK'srequest()at once while the session is live (at most once per kind per session; a check that fires offline sends nothing), and carries on as the license state allows. - The server turns reports into the risk score of the license and device. The tamper kinds (
patched, and N6'sdebugger,vm,hook) count as T9 (weight 4); one signal type adds at most 5 times its weight (20 for T9) to a subject's score; at most 5 reports per session per hour are counted, all kinds together. Beside them, Protect sees everything else (key sharing, impossible travel, unknown builds). Graduated Enforcement decides: alerts only, or, with **Act on its own**, sign out the license's sessions, suspend it, block for 24 hours an address that keeps guessing keys (T4), block a device that keeps raising T5 or T8.
What it does not do
- Every check runs on the customer's machine and can be found and removed. Scattering raises the work per crack; it does not make a crack impossible.
- The report path is a single point of failure: patching the one call that sends reports silences N4 and N6 together, while every check still runs.
- A cracked copy that never signs in again sends no report: N4 sees only copies that still talk to the server, which is why it pairs with T6 and N3 (copies that skip the server lose the paid data).
- N4 alone never reaches Graduated Enforcement's thresholds: T9 is capped at 20 points, below the lowest default (40). A workspace alert rule that matches T9 or low-severity signals still alerts on the first report. Reports past the 5-per-hour limit are dropped while the software is still told
ok, and they share that allowance with N5's rewind reports (offline_rewind, counted as T11, weight 8, which can reach 40 alone) and the SDK's own verification reports (response_verification, counted as T1, weight 18, which can reach the suspend threshold alone). Graduated Enforcement acts on the combined score, driven mostly by T1, T5 and T8. - The C library and the CLI have no call for sending reports, so N4 is for the SDKs only.
- Act on its own is a Premium feature; on Basic, Graduated Enforcement only alerts.
False alarms
- The checks never crash or stop the software. One of them refuses: the paid-action check, when the latest signed answer lacks the entitlement (the kit takes it from each heartbeat too, so a plan changed while the software runs is not refused). A wrong report still adds up to 20 points, and on top of key sharing (T5, up to 75) or unknown builds (T8, up to 75) that can cross the suspend threshold (80) under **Act on its own**.
- A long sleep or hibernation makes the last verified answer old and usually ends the session (60 minutes, or three Short-Lived Session Lease intervals): the heartbeat after waking gets
session_expired. The kit signs in again before its next check, so waking up raises no report. - Automatic suspension on a wrong score is the real risk: the kit's guide says to start with Alerts only, review incidents, then switch. Ended sessions cannot be undone (the customer signs in again). Undoing a suspension leaves the score where it was, so the next signal suspends again unless the seller also uses Dismiss on the license, which sets its risk score back to 0 (closing the incident does not); the guide gives both steps.
Phát hiện chỉnh đồng hồ
Giữ mốc thời gian muộn nhất đã thấy; đồng hồ lùi quá 10 phút so với mốc thì tắt dùng offline tới lần kết nối sau, lần đó báo về server
Không làm được: License bị thu hồi vẫn chạy offline tới hết hạn token; xoá hay khôi phục file mốc là qua được kiểm tra thêm của bộ mẫu
- Phía server
- Cửa sổ offline trên gói license
- Tự kiểm tra
Với gói có cửa sổ offline: ngắt mạng rồi chạy
list(vẫn chạy). Lùi đồng hồ một ngày rồi chạylistlần nữa: dùng offline bị từ chối; có mạng lại, Protection hiện lùi đồng hồ khi offline.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A customer whose license was revoked, suspended or refunded cuts the software off the network and keeps using the offline token it already has. To stretch that token past its expiry, they turn the machine's clock back.
How it works
- Short window. The offline window is the license plan's
offlineTtlSeconds(1 hour to 90 days). Every heartbeat brings a fresh token, so the window counts from the last time the machine reached the server. The kit's guide picks the shortest window the seller's customers can live with, and the kit's build also sets its ownmaxOfflineSec(a cap on a token's age that no server answer can loosen). With Online-Only Mode on, the server's hint is0, so no token is trusted in any process of any build that reachesinit. - What the SDK already refuses. A token for another app or another machine (
devis the hash of this device's key), a token pastexpor past the license'slexp, a token whoseiatornbfis more than 60 seconds in the future (the clock is behind the time it was issued), and, within one process, a token once the clock runs more than 60 seconds behind the last verified server time. - What the kit adds. The SDK forgets that server time when the process ends. The kit keeps a high-water mark: the latest time ever seen (server time from verified answers, and the machine's own time at each start and exit and while running), stored beside the device key: sealed with DPAPI in C# and C++ on Windows, in Python and Node.js a file readable only by the user on Linux and macOS, as private as its folder on Windows. Either way the same user can rewrite it (DPAPI protects it from other accounts, not from its own user). A verified server time also lowers the mark when the machine's clock had run fast, so correcting a fast clock does not lock offline use for good. At start, and at each heartbeat that gets no answer, a clock more than the tolerance behind that mark means a rewind: offline use is refused and the software asks to go online. Back online and signed in, it reports
kind: "offline_rewind", which Protect counts as T11.
What it does not do
- A revoked license still runs **offline until its token's
exp**: the window is the price of working offline. Only Online-Only Mode (online only) removes it. - Deleting or restoring the high-water mark file (with an old backup of the state folder) defeats the kit's extra check; the SDK's own
iat/nbfcheck still holds. A patched executable can skip both. - A machine that never comes back online never reports the rewind.
- The window and the hint only reach builds that call
init; a token already on a machine that never manages to callinitruns until its ownexp.
False alarms
- Normal clock drift and daylight saving are within the tolerance (the kit uses 10 minutes for its own mark; the SDK's checks use 60 seconds against signed times). Daylight saving changes the displayed time, not UTC.
- A clock fixed backwards by the user or by time sync after it ran fast: refused offline until the machine is online once; online use is never blocked by N5. The guide gives the message to show.
- Restoring a whole-disk backup or a VM snapshot sets the clock and the mark back together: no alarm.
- Timezone changes do not move UTC time: no alarm.
- Dual-boot machines where one system keeps the hardware clock in UTC and the other in local time, and **dead CMOS batteries** that reset the clock at boot: the clock lands behind the mark, offline use is refused until the machine is online once, then the server time corrects it. That start reports a rewind (Protect T11, weight 8): a machine that does this at every boot adds up on its own, so check its incidents before acting on them.
Anti-Debugging và phát hiện máy ảo
Thấy debugger hay máy ảo thì chỉ báo về server, không chặn trên máy
Không làm được: Dễ bị qua mặt: có công cụ giấu debugger và máy ảo; chỉ báo về, không tự quyết định gì
- Phía server
- Kiểm tra toàn vẹn build (A10)
- Phản ứng tự động theo rủi ro (A13)
- Tự kiểm tra
Bật A10, chạy app dưới debugger: Protection hiện báo cáo can thiệp.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngcòn chờ
- Không báo nhầmcòn chờ
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngcòn chờ
- Không báo nhầmcòn chờ
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A cracker runs the software under a debugger to find the license check, or in a throwaway virtual machine to try keys and patches without risking their own system. Nothing tells the seller this is happening.
How it works
- The kit looks for a few well-known signs at start and again later in the run:
- Debugger: on Windows,
IsDebuggerPresentandCheckRemoteDebuggerPresent(andDebugger.IsAttachedfor managed debuggers in C#); on Linux, a non-zeroTracerPidin/proc/self/status. - Virtual machine: the system manufacturer and model names that common hypervisors report (VMware, VirtualBox, QEMU/KVM, Parallels; for Hyper-V the model "Virtual Machine", since Microsoft's own Surface devices share its manufacturer name), and in C++ the CPU's hypervisor bit. That bit is also set on physical Windows machines that run Hyper-V, Virtualization-based Security or Memory Integrity, WSL2 or Windows Sandbox, all common on Windows 11; the kit counts it only when Hyper-V does not report the root partition (CPUID leaf 0x40000003, the privilege to create partitions), which is what the physical machine sees.
- What it finds is reported, never acted on locally:
kind: "debugger"orkind: "vm"with a short detail, at most once per kind per session, through the SDK'srequest()on a live session, only when the server's signedinitanswer saysreportTamperSignals: true(Build Integrity Verification on). No crash, no deleted file, no refusal on the machine. - Protect counts each report as T9 in the risk score (weight 4, at most 5 reports per session per hour); Graduated Enforcement (N4) decides what the combined score leads to.
What it does not do
- These checks are easy to defeat. Anti-anti-debug plugins hide debuggers from exactly these calls, and a VM can be configured to report a real manufacturer. N6 catches casual analysis, not a careful cracker.
- It does not detect hooks or injected code in this first round: reliable hook detection depends on the exact functions and builds and is left for later, with its own card.
- It does not decide anything: without Graduated Enforcement the reports only add to a score and an incident.
- It sends nothing when Build Integrity Verification is off (
reportTamperSignalsfalse), so the seller switches Build Integrity Verification on, Warn only at first, to receive these signals. Hints only tighten: a running copy that once receivedtruekeeps reporting until it restarts after Build Integrity Verification is turned off. - Its reports share the report path and the 5-per-hour allowance with N4 (see there), so patching that one call silences both.
False alarms
- Many customers legitimately run in VMs (virtual desktops, Parallels on Mac, cloud workstations). A VM report is information, weighted low, never a block on its own: one signal type adds at most 5 times its weight, 20 for T9, below the lowest default Graduated Enforcement threshold (40). It does add to the combined score: non-persistent virtual desktops look like new machines and raise key sharing (T5, up to 75), cloud workstations can raise impossible travel (T6, up to 50); with the VM's 20 on top, such a license can cross the sign-out (60) or suspend (80) threshold under **Act on its own**. The guide tells sellers with VM customers to keep Graduated Enforcement on Alerts only or to leave VM reports off.
- Developers of the software run it under a debugger all day: the kit's debug builds do not report.
Forensic Watermarking
Dấu người mua nằm trên trang About và cuối mỗi báo cáo; tra dấu ra license và máy
Không làm được: Dấu xoá hay thay được; bản đã crack không mang dấu; dấu chỉ là đầu mối, không phải bằng chứng
- Phía server
- Watermark license (A8)
- Tự kiểm tra
Chạy
about, dán dấu ở dòngLicensed:vào ô tìm kiếm trang License: ra đúng license.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
A cracked copy, an exported file or a screenshot of a licensed feature turns up on a forum. The seller cannot tell which customer it came from, so they cannot act on that license or ask that customer what happened.
How it works
- With Forensic Watermarking on, every successful sign-in returns a buyer mark in
license.mark, shaped<10 hex>.<6 hex>: the first half is fixed per license (made on its first sign-in), the second half is derived from it and this machine's device key. Offline tokens carry the same mark in their signedwmfield. (Until the fix that came with this card's review, a license's first sign-in could produce two different marks; the answer, the token and the stored value now agree.) - The kit puts the mark where a leak carries it: the sample app's About text and a footer line on every file its paid feature exports (a seller adds it to their own log headers and file formats the same way).
- To trace a leaked file, the seller pastes the mark into the search box of Licenses, or sends it to the Seller API's
POST /seller/v1/licenses/lookupas{"mark": …}, which answers the license and, when the second half matches a machine's current device key, that machine (markDevice).
What it does not do
- A mark can be removed. Anyone who finds it in a file or in the executable's output can strip or replace it; it helps against careless sharing, not against a cracker who knows it is there.
- It does not stop the leak; it tells the seller where to look afterwards.
- A cracked executable carries no mark: the mark arrives at run time, after sign-in. N7 traces what a licensed copy produced (files, screenshots, logs), not a redistributed program.
- A mark found in a file is not authenticated: the signature protects the server's answer, not the file. Anyone can copy a real customer's mark into a leaked file to frame them.
- The second half follows the device key: a machine that signs in again with a new key, or a second user account on the same PC, gets another second half. The lookup still finds the license from the first half, but only the machine's current key names the machine; a seller who needs older marks keeps their own record, built from the signed offline token (
lic,dev,wm) rather than from what the software sends, which can be forged. - The mark identifies a license and a machine, not a person: a key shared by its buyer points to the buyer, who may not be the one who leaked.
False alarms
None on the customer's side: the mark changes nothing in how the software runs. The risk is a wrong accusation (a copied or planted mark): the guide tells sellers to treat a mark as a lead to check with the customer, not as proof, and to say in their terms of sale that licensed copies carry a buyer mark (the kit does not write those terms).
Code Signing
Ký bằng chứng chỉ của bạn kèm dấu thời gian, để khách biết file đúng là của bạn
Không làm được: Không chặn crack: bản crack chỉ là không có chữ ký; chứng chỉ bị đánh cắp ký được cả mã độc
- Phía server
- Không cần bật gì
- Tự kiểm tra
Sau
release/N8/sign.ps1, Properties của file có thẻ Digital Signatures mang tên bạn và dấu thời gian.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmđã qua
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngcòn chờ
- Phát hiện được tấn côngcòn chờ
- Không báo nhầmcòn chờ
Node.js: sắp có
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
Someone repackages the seller's software, cracked or with malware added, and passes it around under the seller's name. Customers cannot tell the real file from the fake one, and Windows warns about every unsigned download, which teaches customers to click through warnings.
How it works
- The kit adds a signing step to the sample app's release script, run with the seller's own code-signing certificate:
- Windows:
signtool signwith SHA-256 and an RFC 3161 timestamp, thensigntool verify /pa. - macOS:
codesignwith the hardened runtime, then notarization withnotarytooland stapling (once the kit has a macOS sample). - The signed files are what gets uploaded to Releases, so N2 compares hashes of signed files.
- ClavisAUH's own signed release manifests (CLV1-MANIFEST, used by the SDKs' update check) already let the software verify an update before installing it; N8 is about the first download and the file on disk.
What it does not do
- It does not stop cracking: a cracked copy is simply unsigned or signed by someone else, and runs anyway if the customer accepts the warning.
- It does not prove the software is safe, only who published it.
- A stolen signing key signs malware validly under the seller's name. Revoking the certificate helps only where the operating system checks revocation; a hardware token or a cloud signing service makes theft harder, not impossible.
- It does not remove SmartScreen warnings at once: Windows builds reputation per certificate (and per file) over time.
- ClavisAUH does not sign for the seller and does not hold their certificate; the seller buys one (an organisation validated certificate, or an Apple Developer ID) and keeps its key, ideally on a hardware token or a cloud signing service, as certificate authorities now require.
False alarms
- Antivirus can still flag a signed file, especially a packed one (N9); signing usually lowers that, it does not end it.
- A file changed after signing (an installer that patches it, a resource editor) loses its signature: the release script signs last and verifies.
- A missing timestamp makes every installed copy look unsigned the day the certificate expires: the script refuses to sign without one.
Code Obfuscation
Đổi tên và giấu chuỗi trong mã của app để đọc hiểu tốn công hơn; mapping giữ lại để đọc log lỗi
Không làm được: Chỉ làm chậm việc đọc mã, không ngăn được; chuỗi và một phần tên vẫn đọc được tuỳ ngôn ngữ
- Phía server
- Không cần bật gì
- Tự kiểm tra
Mở
publish/Notebook.dllbằng trình dịch ngược .NET: tên và câu chữ của phần license không còn đọc được.
Kiểm chứng cho C# · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho C++ · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Python · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Kiểm chứng cho Node.js · chạy 2026-11-05 trên Windows và Linux
- Mãđã qua
- Chạy bình thườngđã qua
- Phát hiện được tấn côngđã qua
- Không báo nhầmcòn chờ
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
The shipped program is easy to read: a .NET assembly decompiles back to near-original C#, Python and JavaScript ship as source or close to it, a native binary with symbols names its own functions. Finding the license check takes minutes.
How it works
The kit's release script runs one open-source tool for the language, configured not to break the SDK:
| Language | Tool (license) | What it does |
|---|---|---|
| C# | Obfuscar (MIT) | renames non-public types and members, hides strings |
| C++ | the compiler itself | release build, symbols stripped, hidden visibility, link-time optimisation |
| Python | Nuitka (Apache 2.0) | compiles the program to native code (standalone folder, not onefile), no .py files |
| Node.js | javascript-obfuscator (BSD-2-Clause) | renames, flattens control flow, encodes strings |
The SDK's public names stay as they are (the tools are told to exclude them) so the program still links and its calls still match the protocol. The chosen tool and version are written into kit.lock.
What it does not do
- It delays, it does not prevent. Every one of these outputs can be analysed with enough time; deobfuscators exist for common .NET and JavaScript obfuscators.
- It does not protect secrets in the program: there should be none (T2), and obfuscated strings are recovered at run time anyway.
- C++ gets no real obfuscation from open-source tools in this round: the open LLVM obfuscators are unmaintained or, like O-MVLL, aimed at ARM64 mobile targets, not desktop x86-64. Stripping and optimising remove names; **string literals stay readable** in the binary, and so do the names of classes with virtual functions (RTTI). Commercial packers (VMProtect, Themida and the like) go further; the guide describes how to wrap the code around the SDK calls and their drawbacks , without recommending one.
- Nuitka hides the Python source, not names or strings: function, class, module and attribute names stay readable because Python needs them at run time, and its free edition leaves constants readable (string encryption is in the commercial edition).
- javascript-obfuscator renames locals, not properties: method names and the names the files import from each other stay readable, because renaming them would break the calls between files and into the SDK.
- It does not hide network traffic (N1) or stop patching once the check is found (N3, N4).
False alarms
- Antivirus: packed and heavily obfuscated executables are flagged more often. The kit does not pack: Nuitka runs in standalone mode (a folder), not onefile mode, which unpacks itself at start like a packer and is flagged more. Signing (N8) and submitting false positives to vendors is the guide's advice.
- Broken behaviour: renaming breaks code that uses reflection, serialisation by member name or dynamic imports. The kit's configuration excludes the SDK and the sample's serialised types; the seller must add their own, and the positive gate runs the obfuscated build, not the plain one.
- Crash reports and logs carry renamed symbols; the tools' mapping files must be kept per release to read them.
Khoá thiết bị trong chip bảo mật
Chưa làm được: cần khoá P-256 trong giao thức và chứng thực phần cứng
Không làm được: Chưa có trong bộ mẫu
- Phía server
- Không cần bật gì
- Tự kiểm tra
Chưa có trong bộ mẫu.
Bản đầy đủ bằng tiếng Anh: mối đe doạ, cơ chế, điều nó không làm được, báo nhầm
Threat
The device key (T3) is a file. Someone who copies the state folder and the hardware identifiers of a licensed machine can make a second machine look like the first, and a license meant for one machine runs on many.
How it works
- The device key is created inside the machine's TPM (Windows) or Secure Enclave (macOS) and can sign but never be exported. Copying the state folder copies a reference to a key that only exists in that chip.
- The SDK says so with
device.hardwareKey: true, and a server policy Require a hardware key refuses devices without one (with a fallback the seller chooses for machines that have no chip).
What it does not do
- It cannot be built on today's protocol. TPMs in the field and the Secure Enclave sign with ECDSA P-256 (TPMs also RSA), not Ed25519, while CLV1.1 device signatures are Ed25519 only. N10 needs a protocol version that accepts P-256 device keys, on the server and in the native SDKs.
- A self-reported flag proves nothing. Without attestation (a TPM key attestation, Apple's App Attest), a patched client can claim
hardwareKey: truefor a file key. A real check needs the server to verify an attestation, which is a separate project. - It does not stop a cracked executable that skips the license check, nor a customer running the software for others (N3, N4, Protect).
- Many machines have no usable chip (older PCs, most virtual machines, Linux without a TPM 2.0 stack), so a strict policy locks real customers out unless a fallback exists.
False alarms
- Machines without a TPM, with the TPM disabled in firmware, or in VMs without a virtual TPM: they need the fallback.
- A TPM cleared during a firmware update or a Windows reset loses the key: the machine has to be reset by the seller or the customer, like a new machine.
Không biện pháp nào chặn được mọi thứ: giới hạn của từng biện pháp nằm trong mục của nó ở trên và trong HOW-IT-WORKS.md của bộ mẫu. Những gì biện pháp báo về hiện trên Protection; các cấu hình phía server được giải thích trong hai chế độ bảo vệ