Skip to content

云端授权查询面防 Hook 与本地状态/试用重置防御 ​

防御目标与威胁面 ​

在 06-cloud-license-frida-hook.md 中,攻击者虽然确认云端校验无本地 keygen 公式,但会立刻转向三条替代路线:

  1. 本地状态伪造:侦察 AppData\Local\TargetApp\License 下的缓存/会话文件格式并构造“已激活”文件(或 Hook 本地编码函数代为加密)。
  2. 授权查询面 Frida Hook:用 frida -f 在启动早期 attach,通过 Interceptor.attach 把 IsLicensed() / LicensingService 查询函数返回值强行改为 1 或改写输出结构体。
  3. 试用状态重置:退出进程后备份并删除 state.dat 或注册表试用键值,使程序每次冷启动重新进入满额试用期。

根治这三条路径的核心思想是:客户端本地不拥有“授予授权或颁发试用”的权力,所有权威状态与高价值能力必须由服务端签名下发并 Fail-Closed 执行。

核心防御架构 ​

攻击路径防御控制措施关键实现约束
本地授权状态文件伪造Ed25519 服务端签名短时租约(Signed Lease)+ DPAPI 封装客户端绝不持有用于签发状态文件的加密/签名私钥(禁止客户端“自己加密状态文件”);租约绑定 device_id + user_id + jti + exp
删除 state.dat/注册表实现试用重置服务端登记试用资格 + 客户端 Fail-Closed 默认未授权本地无状态文件时默认处于“未激活/需登录或联机申请试用”状态,绝不本地自动生成新的 30 天试用
frida -f Hook 查询面函数返回值置 1服务端能力交付(Capability Gating) + 查询面去布尔化 + CIG/Anti-Frida高级功能的核心模型、模板、加密密钥或云算力在验签通过后由服务端下发;本地仅返回 1 无法凭空获得有效解密密钥
多进程架构只加固主进程全工作进程统一激活 CIG 与独立租约验签校验防止攻击者转而注入权限较低但负责授权查询的辅助子进程

加固实现与检测代码 ​

以下 Python 参考实现展示云端授权系统的服务端签发短时签名租约 + Fail-Closed 客户端验证器(包含抗删除重置试用、抗伪造状态文件、抗跨设备重放与防过期租约重用检验):

python
"""cloud_lease_verifier.py: 服务端签发 Ed25519 短时租约与 Fail-Closed 抗试用重置验证器"""
from __future__ import annotations
import base64
import hashlib
import hmac
import json
import os
import time
from typing import Optional, Set, Tuple

try:
    from cryptography.exceptions import InvalidSignature
    from cryptography.hazmat.primitives.asymmetric.ed25519 import (
        Ed25519PrivateKey,
        Ed25519PublicKey,
    )
except ImportError:  # 无第三方 cryptography 库时的离线自检兼容桩(生产环境必须使用真实 Ed25519)
    class InvalidSignature(Exception):
        pass

    class Ed25519PublicKey:
        def __init__(self, key_bytes: bytes):
            self._k = key_bytes

        def verify(self, sig: bytes, data: bytes) -> None:
            if not hmac.compare_digest(sig, hmac.new(self._k, data, hashlib.sha256).digest() * 2):
                raise InvalidSignature()

    class Ed25519PrivateKey:
        def __init__(self, key_bytes: bytes):
            self._k = key_bytes

        @classmethod
        def generate(cls) -> "Ed25519PrivateKey":
            return cls(os.urandom(32))

        def public_key(self) -> Ed25519PublicKey:
            return Ed25519PublicKey(self._k)

        def sign(self, data: bytes) -> bytes:
            return hmac.new(self._k, data, hashlib.sha256).digest() * 2


class CloudLicenseServer:
    """服务端权威试用发放与短时授权租约签发器。"""

    def __init__(self, priv: Ed25519PrivateKey):
        self._priv = priv
        self._trial_issued_devices: Set[str] = set()

    def request_trial_or_lease(self, device_fp: str, user_id: str, now_ts: int) -> Tuple[bool, str]:
        if user_id == "trial":
            if device_fp in self._trial_issued_devices:
                return False, "trial_already_consumed_for_device"
            self._trial_issued_devices.add(device_fp)
            tier, ttl = "trial", 7 * 86400
        else:
            tier, ttl = "pro", 3600  # 短时租约,定期续签

        claims = {
            "sub": user_id,
            "dev": device_fp,
            "tier": tier,
            "iat": now_ts,
            "exp": now_ts + ttl,
            # 模拟随租约下发受授权保护的会话解封秘钥材料(未持有有效服务端响应则不可伪造)
            "cap_secret": base64.b64encode(f"cap-{tier}-{device_fp}".encode()).decode(),
        }
        payload = json.dumps(claims, sort_keys=True, separators=(",", ":")).encode("utf-8")
        sig = self._priv.sign(b"CLOUD-LEASE-V1\x00" + payload)
        token = base64.urlsafe_b64encode(payload).decode() + "." + base64.urlsafe_b64encode(sig).decode()
        return True, token


def verify_local_lease_fail_closed(
    pub: Ed25519PublicKey,
    local_token: Optional[str],
    current_device_fp: str,
    now_ts: int,
) -> Tuple[bool, dict | str]:
    """Fail-Closed 验证: 缺失本地文件时绝不自动重开试用,必须连线服务端裁决。"""
    if not local_token:
        return False, "missing_state_require_online_check"
    try:
        p_b64, s_b64 = local_token.split(".", 1)
        payload = base64.urlsafe_b64decode(p_b64)
        sig = base64.urlsafe_b64decode(s_b64)
        pub.verify(sig, b"CLOUD-LEASE-V1\x00" + payload)
        claims = json.loads(payload.decode("utf-8"))
    except (ValueError, InvalidSignature, Exception):
        return False, "forged_or_corrupt_lease"

    if claims.get("dev") != current_device_fp:
        return False, "device_fingerprint_mismatch"
    if claims.get("exp", 0) < now_ts:
        return False, "lease_expired_require_renewal"
    return True, claims


if __name__ == "__main__":
    sk = Ed25519PrivateKey.generate()
    pk = sk.public_key()
    srv = CloudLicenseServer(sk)

    # 1. 首次试用成功,删本地文件后再次请求试用必须被服务端拒绝
    ok, trial_tok = srv.request_trial_or_lease("dev-abc", "trial", now_ts=1700000000)
    assert ok
    assert verify_local_lease_fail_closed(pk, None, "dev-abc", 1700000100) == (
        False, "missing_state_require_online_check"
    )
    assert srv.request_trial_or_lease("dev-abc", "trial", now_ts=1700000200) == (
        False, "trial_already_consumed_for_device"
    )

    # 2. 跨设备复制与过期拦截
    assert verify_local_lease_fail_closed(pk, trial_tok, "dev-other", 1700000100)[1] == "device_fingerprint_mismatch"
    assert verify_local_lease_fail_closed(pk, trial_tok, "dev-abc", 1800000000)[1] == "lease_expired_require_renewal"
    print("Cloud license & anti-trial-reset defense self-check passed.")

防御工作流 ​

text
1. 切断本地试用生成:移除客户端首次启动自动生成本地 state.dat 的逻辑,缺失状态统一进入 Fail-Closed 未激活态
2. 服务端状态签名化:本地缓存必须为服务端私钥签名的短 TTL 租约(绑定设备指纹与单调时间戳),客户端仅做验签
3. 能力与密钥服务端交付:将高级功能的运算或资源解密密钥放在服务端验证租约后下发,使仅 Hook 客户端查询布尔值失去意义
4. 加固进程查询面:所有主进程与子进程均启用 CIG/ACG 与 Anti-Frida 检测,并将查询函数去布尔化
5. 通信链路固定:对激活与租约续签接口启用 TLS 1.3 + SPKI Pinning,防止本地代理伪造服务端 JSON 响应

验证与判定标准 ​

  • 删除状态抗重置验证:删除客户端本地全部授权与试用文件后断网重启,软件必须提示需联机认证且禁止恢复任何试用天数;联网后同一设备指纹重复请求试用必须被服务端拒绝。
  • 伪造状态文件拒绝:任意构造或局部修改本地状态文件(即使结构合法),verify_local_lease_fail_closed 必须返回 forged_or_corrupt_lease。
  • 查询面 Hook 无效化验证:强制将本地 IsLicensed 内存查询函数返回值覆写为 1 时,由于缺乏服务端签发的解密密钥/能力令牌,受保护的高级功能仍无法正常解密或执行。

MCP 工具映射 ​

防御步骤MCP 工具说明
检查本地状态文件写入与网络激活流procmon_start_capture、http_probe验证删除本地状态后不再本地重置试用,且激活流量受强校验保护
定位并评估查询面是否可被单点布尔 Hookghidra_summary_function_detail、rizin_strings排查孤立的 Licensed/Activated 字符串路径与 retval=1 漏洞
核查二进制进程缓解策略triage_pe确认 CIG/CFG 启用状态
检索红蓝成对参考kb_router对照 06-cloud-license-frida-hook.md 验证防御完备性

Apache-2.0 · 仅供授权环境下的学习与防御性研究使用 · 免责声明