|
| 1 | +# Copyright (C) 2026 Kevin Ross |
| 2 | +# |
| 3 | +# This program is free software: you can redistribute it and/or modify |
| 4 | +# it under the terms of the GNU General Public License as published by |
| 5 | +# the Free Software Foundation, either version 3 of the License, or |
| 6 | +# (at your option) any later version. |
| 7 | +# |
| 8 | +# This program is distributed in the hope that it will be useful, |
| 9 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | +# GNU General Public License for more details. |
| 12 | +# |
| 13 | +# You should have received a copy of the GNU General Public License |
| 14 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 15 | + |
| 16 | + |
| 17 | +from lib.cuckoo.common.abstracts import Signature |
| 18 | + |
| 19 | +class AntiSandboxWindowsActivation(Signature): |
| 20 | + name = "antisandbox_windows_activation" |
| 21 | + description = "Queries Windows licensing, activation, or genuine status, possibly to detect unactivated sandbox or analysis environments." |
| 22 | + severity = 3 |
| 23 | + confidence = 100 |
| 24 | + categories = ["anti_sandbox", "evasion", "discovery"] |
| 25 | + authors = ["Kevin Ross"] |
| 26 | + minimum = "1.3" |
| 27 | + evented = True |
| 28 | + ttps = ["T1082", "T1497"] # System Information Discovery / Virtualization/Sandbox Evasion |
| 29 | + |
| 30 | + filter_apinames = { |
| 31 | + # 1. API Resolution & Direct SL Hooks |
| 32 | + "LdrGetProcedureAddress", "GetProcAddress", |
| 33 | + "SLIsGenuineLocal", "SLGetWindowsInformation", |
| 34 | + # 2. Registry Queries |
| 35 | + "NtQueryValueKey", "RegQueryValueExA", "RegQueryValueExW", |
| 36 | + # 3. WMI / COM Queries |
| 37 | + "IWbemServices_ExecQuery", "ExecQuery", |
| 38 | + # 4. Command Execution |
| 39 | + "CreateProcessInternalW", "NtCreateUserProcess", "ShellExecuteExW" |
| 40 | + } |
| 41 | + |
| 42 | + def __init__(self, *args, **kwargs): |
| 43 | + Signature.__init__(self, *args, **kwargs) |
| 44 | + self.ret = False |
| 45 | + self.activation_checks = set() |
| 46 | + |
| 47 | + def on_call(self, call, process): |
| 48 | + api = call["api"] |
| 49 | + |
| 50 | + if api in ("SLIsGenuineLocal", "SLGetWindowsInformation"): |
| 51 | + value_name = self.get_argument(call, "ValueName") |
| 52 | + if value_name: |
| 53 | + self.activation_checks.add("Called Licensing API directly: {0} ({1})".format(api, value_name)) |
| 54 | + else: |
| 55 | + self.activation_checks.add("Called Licensing API directly: {0}".format(api)) |
| 56 | + self.mark_call() |
| 57 | + self.ret = True |
| 58 | + |
| 59 | + elif api in ("LdrGetProcedureAddress", "GetProcAddress"): |
| 60 | + func_name = self.get_argument(call, "FunctionName") or self.get_argument(call, "lpProcName") |
| 61 | + if func_name: |
| 62 | + func_lower = func_name.lower() |
| 63 | + |
| 64 | + if func_lower in ("slisgenuinelocal", "slgetwindowsinformation", "slgetwindowsinformationdword", "slgetlicensingstatusinfo"): |
| 65 | + self.activation_checks.add("Resolved Licensing API: {0}".format(func_name)) |
| 66 | + self.mark_call() |
| 67 | + self.ret = True |
| 68 | + |
| 69 | + elif api in ("NtQueryValueKey", "RegQueryValueExA", "RegQueryValueExW"): |
| 70 | + key_name = self.get_argument(call, "FullName") or self.get_argument(call, "ValueName") |
| 71 | + if key_name: |
| 72 | + key_lower = key_name.lower() |
| 73 | + |
| 74 | + if "softwareprotectionplatform" in key_lower or "wpa\\events" in key_lower or "security-spp-genuinelocalstatus" in key_lower: |
| 75 | + self.activation_checks.add("Queried Licensing Value/Registry: {0}".format(key_name)) |
| 76 | + self.mark_call() |
| 77 | + self.ret = True |
| 78 | + |
| 79 | + elif api in ("IWbemServices_ExecQuery", "ExecQuery"): |
| 80 | + query = self.get_argument(call, "Query") |
| 81 | + if query: |
| 82 | + query_lower = query.lower() |
| 83 | + |
| 84 | + if "softwarelicensingproduct" in query_lower or "softwarelicensingservice" in query_lower: |
| 85 | + self.activation_checks.add("WMI Licensing Query: {0}".format(query)) |
| 86 | + self.mark_call() |
| 87 | + self.ret = True |
| 88 | + |
| 89 | + elif api in ("CreateProcessInternalW", "NtCreateUserProcess", "ShellExecuteExW"): |
| 90 | + cmdline = self.get_argument(call, "CommandLine") or self.get_argument(call, "lpCommandLine") or self.get_argument(call, "lpFile") |
| 91 | + if cmdline: |
| 92 | + cmd_lower = cmdline.lower() |
| 93 | + |
| 94 | + if "slmgr" in cmd_lower or "slmgr.vbs" in cmd_lower: |
| 95 | + self.activation_checks.add("Executed Licensing Script: {0}".format(cmdline)) |
| 96 | + self.mark_call() |
| 97 | + self.ret = True |
| 98 | + |
| 99 | + def on_complete(self): |
| 100 | + if self.ret: |
| 101 | + self.data.append({"activation_checks": list(self.activation_checks)}) |
| 102 | + return self.ret |
0 commit comments