Overview: Why Protect a WinCC Project?
WinCC (versions 5 and 6, both classic and the early TIA-aligned runtime) stores an entire SCADA project as a set of unencrypted files on the engineering station and on the runtime station. The runtime database (typically a .pdb project file plus the GraCS directory containing .pdl pictures, .fct actions, .pas scripts, .db archives, and .log files) can be copied from a working plant, transported to a competitor's PC, and reopened in WinCC Explorer. Because the C actions and VBS scripts are not compiled to native code, they are plain text and can be edited freely by anyone with WinCC engineering installed. The WinCC software license itself is tied to a license key (either a software license on the hard disk or, in later versions, a USB license stick called the Automation License Manager / ALM dongle), but the project is not protected by that mechanism. This article documents the field-proven techniques used by integrators to bind a WinCC V5/V6 runtime project to a specific PC using a hardware security key (USB dongle), MAC address binding, encrypted project media, and password-locked C scripts.
Architecture Constraints of WinCC V5 and V6
Before any protection strategy is selected, the engineer must understand the file layout and runtime model of WinCC V5/V6 because they dictate the attack surface:
| Component | File Type | Readable Without Password | Copyable | Executable Without Dongle |
|---|---|---|---|---|
| WinCC Explorer Project File |
*.pdb / *.mcp
|
Yes (binary, opens in WinCC) | Yes | Yes |
| Graphics (Pictures) |
*.pdl in GraCS\
|
Yes (opens in Graphics Designer) | Yes | Yes |
| C Actions / Global Script | *.fct |
Yes (plain-text C source) | Yes | Yes |
| VBS Actions | *.pas |
Yes (plain-text VBScript) | Yes | Yes |
| Tag Management / Archives |
*.db, *.ldf
|
Binary, but portable | Yes | Yes |
| Compiled Runtime | None — V5/V6 do not produce a compiled runtime image | N/A | N/A | N/A |
Because every project file is unencrypted and the project itself contains no native binary runtime, any third party with a matching or higher WinCC version and a valid runtime license can copy the GraCS folder plus the project file to a new PC and start the application. The standard Siemens Automation License Manager (ALM) license for WinCC Runtime only proves that the local PC is authorized to run WinCC, not that the running project is the integrator's original one.
Hardware Dongle Concepts and Vendors
A hardware dongle (also called a hardware key, security key, or HASP/HL key) is a physical USB device that contains a secure element. Modern security keys implement cryptographic challenge-response or store a per-customer secret that is not extractable to the host. The conceptual model is well documented by the major consumer-platform vendors for the FIDO2 / WebAuthn case:
- Microsoft — Set up a security key as your verification method describes a USB or NFC security key as a second factor that proves physical presence of the user.
- Google — Titan Security Key uses a hardware chip with integrity-verified firmware to make the key resistant to cloning.
- Apple — About Security Keys for Apple Account treats the key as a small external device that must be present at sign-in.
The industrial-grade equivalents follow the same architecture but expose a vendor-specific DLL instead of a FIDO2 interface. For WinCC V5/V6 the typical candidates are:
| Vendor / Product | Interface | DLL API Style | Notes for WinCC |
|---|---|---|---|
| SafeNet (Thales) Sentinel HL / HASP SRM | USB |
hasp_login(), hasp_read(), hasp_encrypt()
|
Widely deployed in industrial software; runtime library redistributable |
| MatrixLock ( WIBU-Systems CodeMeter ) | USB / SD / CF |
CmAccess(), CmGetInfo()
|
Supports binding to a feature ID and a per-license expiry |
| Aladdin HASP4 / HASP HL | USB / Parallel (legacy) |
hasp() legacy calls |
Still found on older WinCC V5 / V6 stations |
| Rockwell FactoryTalk Activation (reference) | USB | Vendor-locked to FT | Not directly usable in WinCC, but proves the dongle model is industry-standard |
| YubiKey (FIDO2) / Titan / Feitian | USB / NFC | WebAuthn / CCID | Designed for browser SSO, not for runtime licensing of WinCC |
Implementation Strategy: Indirect Binding via C Script
Because WinCC V5/V6 does not compile C actions to native code, the protection logic must be embedded into the C action and triggered on every meaningful event. The recommended pattern is to verify the dongle at three points in the project lifecycle:
- Project open (WinCC startup): check the dongle, abort Runtime start if absent.
- Periodic background check (global action, e.g. every 60 s): confirm the dongle is still present; if removed, degrade to a safe state.
- Critical action gating (e.g. motor start, setpoint write, recipe load): re-check before each write that affects the process.
Step 1 — Vendor DLL Registration
Copy the vendor-supplied runtime DLLs (e.g. hasp_windows_103275.dll, CmActLicense.dll) into the WinCC project directory <Project>\bin\ or into %SystemRoot%\System32\. The vendor license runtime must be installed on the runtime PC; the matching developer SDK only needs to be present on the engineering station where the C action is written.
Step 2 — Declare the Dongle API in the C Action
Open the Global Script editor in WinCC Explorer, create a new C action, and declare the API prototypes. The example below uses the legacy SafeNet HASP API; substitute the equivalent calls for your dongle vendor.
// ----- WinCC V5/V6 C action: Dongle presence check -----
#include "apdefap.h"
// Vendor prototype (HASP HL example)
extern "C" int WINAPI hasp_login(int feature, int vendor_code,
void *handle);
extern "C" int WINAPI hasp_check_service(int feature, int vendor_code);
extern "C" int WINAPI hasp_logout(void *handle);
#define HASP_FEATURE 1 // assigned by vendor
#define HASP_VENDOR 0x1234ABCD // your vendor code
BOOL g_dongleOK = FALSE;
static void *g_handle = NULL;
void CheckDongleOnStart(void)
{
int rc = hasp_login(HASP_FEATURE, HASP_VENDOR, &g_handle);
g_dongleOK = (rc == 0);
if (!g_dongleOK) {
// Optional: log to internal WinCC tag for diagnostics
SetTagBit("@DongleMissing", TRUE);
} else {
SetTagBit("@DongleOK", TRUE);
}
}
The function CheckDongleOnStart() should be called from a startup function in the project's ApStart sequence or attached to the @Startup project function so it fires when WinCC Runtime is launched.
Step 3 — Periodic Re-Verification in a Global Action
Configure a WinCC global action that runs every 60 seconds and re-validates the dongle:
void OnTimedDongleCheck(void)
{
int rc = hasp_check_service(HASP_FEATURE, HASP_VENDOR);
if (rc != 0) {
// Dongle removed or service stopped
SetTagBit("@DongleOK", FALSE);
SetTagBit("@DongleMissing", TRUE);
// Safe-state: clear enable tags, raise alarm
SetTagBit("@Plant_Enable", FALSE);
SetTagWord("@DongleAlarm", 1001); // 1001 = dongle removed
}
}
Schedule the action via the WinCC scheduler: trigger = cyclic, period = 60 s, pointer = OnTimedDongleCheck. For WinCC V6, the equivalent VBScript wrapper would use CreateObject("HASP.HLAPI"); for older V5 the legacy HASP4 API uses hasp(1, 0) returning a session handle.
Step 4 — Gate Critical Writes
For any C action that writes a tag tied to a process output (motor start, valve open, setpoint, recipe), add a guard that requires @DongleOK == TRUE:
if (GetTagBit("@DongleOK") == FALSE) {
SetTagBit("Motor_Start_CMD", FALSE);
SetTagWord("@LastError", 2003); // 2003 = protected action blocked
return;
}
// Original action logic follows
SetTagBit("Motor_Start_CMD", TRUE);
MAC Address Binding as a Second Layer
Even with a dongle, an attacker who can read the dongle's session bytes can in principle replay them. A second binding layer — the MAC address of the host's primary network interface — adds friction. WinCC V5/V6 supports reading the MAC through a C action that calls the Win32 IP Helper API:
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
BOOL ReadPrimaryMac(BYTE macOut[6])
{
ULONG bufLen = 0;
GetAdaptersInfo(NULL, &bufLen); // first call -> size
PIP_ADAPTER_INFO pInfo = (PIP_ADAPTER_INFO)malloc(bufLen);
if (GetAdaptersInfo(pInfo, &bufLen) != ERROR_SUCCESS) {
free(pInfo); return FALSE;
}
memcpy(macOut, pInfo->Address, 6); // first adapter
free(pInfo);
return TRUE;
}
// Compare against a hard-coded expected MAC
static const BYTE EXPECTED_MAC[6] = { 0x00, 0x0E, 0x8C, 0x4A, 0x12, 0x9F };
void VerifyMacAtStartup(void)
{
BYTE mac[6];
if (!ReadPrimaryMac(mac)) return;
if (memcmp(mac, EXPECTED_MAC, 6) != 0) {
SetTagBit("@DongleOK", FALSE);
SetTagWord("@DongleAlarm", 1002); // 1002 = MAC mismatch
}
}
The expected MAC is a constant in the C source. To make the check less obvious, do not store it as a six-byte literal: XOR it with a project-specific 6-byte key first, or read it from a registry value that is written during commissioning. The MAC check must run on the same startup hook as the dongle check; if either fails, Runtime must not start the plant.
Password-Protected C and VBS Actions
WinCC's C actions and VBS actions support a script-level password. The protection is in the editor only — the source text is still stored on disk — but it prevents a casual user from opening the script in Graphics Designer and deleting the dongle check. To apply the password:
- In WinCC Explorer, right-click the Global Script node and select Open.
- Open the action and choose Edit > Password.
- Set a strong password (minimum 12 characters, mixed case, digits, one symbol). The password applies to both read and write of the script source.
Combine script-level passwords with the dongle and MAC binding: a password by itself stops the casual integrator, a dongle stops the determined user, MAC binding raises the cost of forging a runtime environment.
Encrypted USB as Project Carrier
An alternative to a license-only dongle is to ship the project on an encrypted USB stick (e.g. an Apricorn Aegis, iStorage datAshur, or an IronKey device). WinCC Runtime is then configured to load the project from a path on the USB rather than from C:\Siemens\WinCC\.... The encrypted USB enforces two properties at once:
- Without the PIN, the project files cannot be enumerated or copied, so the project cannot be exfiltrated.
- If the operator tries to start Runtime without the USB inserted, the project path is missing and Runtime fails to start.
Configure the encrypted-USB approach in WinCC Explorer > Computer > Properties > Startup: set the project path to the mount letter of the encrypted USB (e.g. E:\Project\MyPlant.pdb). Combine with an AutoStart entry in the Windows shell startup folder so that Runtime launches immediately after the user logs in; with a USB-only project, the plant cannot be reproduced without that physical key.
Hardening the Runtime PC
Dongles and encrypted USB devices still rely on the host PC being cooperative. Apply these host-level controls:
| Control | Mechanism | Defeats |
|---|---|---|
| Disable Windows hot-keys | Group Policy > User Configuration > Administrative Templates > Windows Components > File Explorer > Turn off Windows+X hotkeys | Operator opening Explorer, copying files |
| Disable Task Manager | HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr = 1 |
Operator killing WinCC Runtime |
| Run Runtime as a custom shell | HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell = "C:\Siemens\WinCC\bin\WinCCExplorer.exe -r" |
Operator reaching the desktop |
| Restrict USB write to approved devices only | Group Policy > Removable Storage Access | Copying project to unencrypted USB |
| Disable WinCC Explorer and Graphics Designer | File system ACL — deny read/execute to operator user | Operator opening project in configuration mode |
| Disable right-click context menus in Runtime | WinCC project property > Disable hotkeys and context menu | Operator invoking task switcher |
Each of these controls can be bypassed by an administrator with a Windows recovery disk, but the combination raises the cost above the value of the project for a typical plant deployment.
Limitations and Known Bypass Techniques
No WinCC V5/V6 protection scheme is cryptographically complete. Document these limitations for the customer before commissioning:
-
PDL copy attack: An attacker can create a blank WinCC project, delete the default
GraCScontents, and copy in the protected project's.pdl,.fct, and.pasfiles. Pictures will render, but internal tags and alarms that referenced global script variables will fail. If the dongle check is implemented as a missing-tag return, the attacker can stub the tag and bypass it. -
Script edit attack: An attacker who recovers the script password can simply delete the
CheckDongleOnStart()call. Mitigate by distributing the check logic across many small C actions and by adding redundant checks in the periodic background task. -
DLL proxy attack: An attacker can replace the vendor DLL with a stub that always returns success. Mitigate by signing the DLL and verifying the signature inside the C action (Win32
WinVerifyTrust). - Dongle emulation: A determined attacker can build a software emulator for the dongle's challenge-response. Field-grade industrial dongles (SafeNet Sentinel HL with SL key, WIBU CodeMeter with CmDongle) include anti-emulation features, but no dongle is unbreakable given enough time.
- Project export/import via WinCC Excel tool: The WinCC Excel-based tag export/import tool accesses the project database directly. If the project is opened in configuration mode without a dongle check, the attacker can rebuild the project offline.
Commissioning and Verification Checklist
Run this checklist on the customer PC before signing off the project:
- Insert the dongle. Start WinCC Runtime. Confirm
@DongleOK = TRUEwithin 5 seconds. - Remove the dongle. Within 60 seconds, confirm
@DongleOK = FALSEand@Plant_Enable = FALSE. - Reinsert the dongle. Confirm Runtime resumes normal operation without a manual restart.
- Copy the entire project folder to a second PC that has a WinCC runtime license but no dongle. Attempt to start Runtime. Confirm Runtime aborts and an alarm is raised.
- Open Graphics Designer on the engineering PC. Try to open each C action. Confirm a password prompt is shown for the protected actions.
- Boot the runtime PC and confirm WinCC Runtime starts automatically without the operator reaching the Windows desktop.
- From a second PC, ping the runtime PC. Confirm the project is not served on any open SMB share.
- Edit the registry to disable the dongle vendor service. Confirm Runtime aborts within one scheduling cycle.
Comparison of Protection Methods
| Method | Strength | Implementation Cost | Defeats | Does Not Defeat |
|---|---|---|---|---|
| USB hardware dongle (SafeNet, WIBU) | High | Medium — DLL integration, action edits | Casual copying, blank-project attack | DLL proxy, dongle emulator |
| MAC address binding | Medium | Low — Win32 IP Helper in C action | PC swap, accidental license transfer | MAC spoofing, NIC replacement |
| Script password | Low | Trivial | Casual browsing, accidental edits | Password recovery, file copy |
| Encrypted USB project carrier | High (for offline attacks) | Low — path change in WinCC | Project exfiltration via file copy | PC cloning with the USB plugged in |
| Custom shell + auto-start | Medium | Low — registry change | Operator reaching the desktop | Administrator with recovery media |
| Combined: dongle + MAC + encrypted USB + custom shell | Very high (for a SCADA project) | Medium | All of the above | State-level adversary with dongle emulator and recovery disk |
Field Notes and Pitfalls
- Never store the dongle vendor code as a literal in the C action. Either encrypt it with a per-project key or read it from a registry value written during commissioning.
- Do not put all the protection logic in a single global action. Spread checks across the picture-level actions so that removing one check does not defeat the entire scheme.
- If the project uses VBS actions (WinCC V6), the equivalent of
hasp_login()is aCreateObjectcall to the vendor COM object. The vendor COM object is also a plain-text reference and can be removed; protect it behind a password the same way you would protect a C action. - If the customer requires the same project to be licensed for two PCs, buy a multi-seat dongle (vendor feature "2 network seats") and embed the seat count in the C action.
- Document the protection scheme in a sealed file left with the customer. If the dongle is lost, the integrator needs the vendor code and the expected MAC to issue a replacement.
- Always test the protection on a fresh PC with no project history. The most common commissioning failure is that the dongle check passes on the engineering PC (because the DLL is installed there) and fails on the runtime PC (because the runtime DLL is missing or blocked by antivirus).
- Some dongle vendors require a separate "runtime" redistribution license for the DLL. The development SDK is for engineering only and is not redistributable.
FAQ
Can I use a YubiKey, Titan, or Apple security key to protect a WinCC V5/V6 project?
No. YubiKey, Google Titan, and the Apple security key implement the FIDO2 / WebAuthn protocol for second-factor authentication on web services (see Microsoft's security-key guide and Google's Titan page). They do not expose a generic challenge-response API that a WinCC C action can call. Use an industrial dongle vendor (SafeNet Sentinel HL, WIBU CodeMeter, or Aladdin HASP) instead.
Why not just buy one WinCC runtime license and stop the customer from copying the project?
A WinCC runtime license authorizes the PC to run WinCC; it does not bind the project to that PC. Without additional protection, the customer's engineer can copy the GraCS folder and the project file to any PC that has its own valid WinCC runtime license and run the same SCADA application there.
Does a password-protected C action stop a determined attacker from removing the dongle check?
No. The WinCC C action password is editor-level only; the source text is still present on disk. A password slows down a casual user but does not stop someone who is willing to spend time recovering the password. Combine the password with code-level obfuscation (split checks across many actions, indirect calls, and runtime tag gating) and with a hardware dongle.
What is the difference between a hardware dongle and an encrypted USB project carrier?
A hardware dongle is a small USB device with a secure element that answers cryptographic challenges; the WinCC project lives on the PC's hard disk and the dongle is checked at runtime. An encrypted USB project carrier stores the project files on a hardware-encrypted USB stick; the dongle is the file system itself, and the project cannot run without the unlocked stick inserted. The two approaches are complementary and are often combined in high-value SCADA deployments.
How do I recover a project if the dongle vendor goes out of business?
Buy the dongle from a vendor that publishes a long-term support roadmap (Thales/SafeNet and WIBU-Systems have 10+ year histories in industrial automation) and keep a record of the vendor code, the feature ID, and the runtime DLL version. If the vendor disappears, the runtime DLL can still call the dongle on existing hardware; the limitation is that you cannot license new dongles. Plan for this by purchasing a small spare pool of pre-programmed dongles at project hand-over.