import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'verify.dart';
/// WinVerifyTrust 函数对指定对象执行信任验证作
const fnWinVerifyTrust = "WinVerifyTrust";
@Packed(1)
// ignore: camel_case_types
final class GUID extends Struct {
@Uint32()
// ignore: non_constant_identifier_names
external int Data1;
@Uint16()
// ignore: non_constant_identifier_names
external int Data2;
@Uint16()
// ignore: non_constant_identifier_names
external int Data3;
@Array(8)
// ignore: non_constant_identifier_names
external Array<Uint8> Data4;
static Pointer<GUID> fromBytes(final Arena arena, final List<int> bytes) {
// 分配 GUID 内存
final guidPtr = arena<GUID>();
try {
final byteData = ByteData.sublistView(Uint8List.fromList(bytes));
guidPtr.ref.Data1 = byteData.getUint32(0, Endian.big);
guidPtr.ref.Data2 = byteData.getUint16(4, Endian.big);
guidPtr.ref.Data3 = byteData.getUint16(6, Endian.big);
// 拷贝 Data4(8个字节)
for (var i = 0; i < 8; i++) {
guidPtr.ref.Data4[i] = bytes[8 + i];
}
return guidPtr;
} catch (e) {
calloc.free(guidPtr);
rethrow;
}
}
}
/// WINTRUST_ACTION_GENERIC_VERIFY_V2 Guid (Authenticode)
///
///----------------------------------------------------------------------------
///
/// Assigned to the pgActionID parameter of WinVerifyTrust to verify the
///
/// authenticity of a file/object using the Microsoft Authenticode
///
/// Policy Provider,
///
/// {00AAC56B-CD44-11d0-8CC2-00C04FC295EE}
///
// ignore: non_constant_identifier_names
final WINTRUST_ACTION_GENERIC_VERIFY_V2 = [
0x00,
0xaa,
0xc5,
0x6b,
0xcd,
0x44,
0x11,
0xd0,
0x8c,
0xc2,
0x00,
0xc0,
0x4f,
0xc2,
0x95,
0xee,
];
/// WINTRUST_FILE_INFO Structure
///
///----------------------------------------------------------------------------
/// Used when calling WinVerifyTrust against an individual file.
///
@Packed(8)
// ignore: camel_case_types
final class WINTRUST_FILE_INFO extends Struct {
/// = sizeof(WINTRUST_FILE_INFO)
@Uint32()
external int cbStruct;
/// required, file name to be verified
external Pointer<Utf16> pcwszFilePath;
/// optional, open handle to pcwszFilePath
external Pointer<Void> hFile;
/// optional: fill if the subject type is known.
external Pointer<GUID> pgKnownSubject;
static int lengthBytes() {
// 32 Bytes
return sizeOf<WINTRUST_FILE_INFO>();
}
static Pointer<WINTRUST_FILE_INFO> allocate(final Arena arena) {
final lengthInBytes = lengthBytes();
final res = arena.allocate<WINTRUST_FILE_INFO>(lengthInBytes);
res.ref.cbStruct = lengthInBytes;
return res;
}
}
/// dwUIChoice
// ignore: constant_identifier_names
const WTD_UI_ALL = 1;
// ignore: constant_identifier_names
const WTD_UI_NONE = 2;
// ignore: constant_identifier_names
const WTD_UI_NOBAD = 3;
// ignore: constant_identifier_names
const WTD_UI_NOGOOD = 4;
/// fdwRevocationChecks
// ignore: constant_identifier_names
const WTD_REVOKE_NONE = 0x00000000;
// ignore: constant_identifier_names
const WTD_REVOKE_WHOLECHAIN = 0x00000001;
/// dwUnionChoice
// ignore: constant_identifier_names
const WTD_CHOICE_FILE = 1;
// ignore: constant_identifier_names
const WTD_CHOICE_CATALOG = 2;
// ignore: constant_identifier_names
const WTD_CHOICE_BLOB = 3;
// ignore: constant_identifier_names
const WTD_CHOICE_SIGNER = 4;
// ignore: constant_identifier_names
const WTD_CHOICE_CERT = 5;
// ignore: constant_identifier_names
const WTD_CHOICE_DETACHED_SIG = 6;
/// dwStateAction
// ignore: constant_identifier_names
const WTD_STATEACTION_IGNORE = 0x00000000;
// ignore: constant_identifier_names
const WTD_STATEACTION_VERIFY = 0x00000001;
// ignore: constant_identifier_names
const WTD_STATEACTION_CLOSE = 0x00000002;
// ignore: constant_identifier_names
const WTD_STATEACTION_AUTO_CACHE = 0x00000003;
// ignore: constant_identifier_names
const WTD_STATEACTION_AUTO_CACHE_FLUSH = 0x00000004;
/// dwProvFlags
// ignore: constant_identifier_names
const WTD_PROV_FLAGS_MASK = 0x0000FFFF;
// ignore: constant_identifier_names
const WTD_USE_IE4_TRUST_FLAG = 0x00000001;
// ignore: constant_identifier_names
const WTD_NO_IE4_CHAIN_FLAG = 0x00000002;
// ignore: constant_identifier_names
const WTD_NO_POLICY_USAGE_FLAG = 0x00000004;
// ignore: constant_identifier_names
const WTD_USE_LOCAL_MACHINE_CERTS = 0x00000008;
// ignore: constant_identifier_names
const WTD_REVOCATION_CHECK_NONE = 0x00000010;
// ignore: constant_identifier_names
const WTD_REVOCATION_CHECK_END_CERT = 0x00000020;
// ignore: constant_identifier_names
const WTD_REVOCATION_CHECK_CHAIN = 0x00000040;
// ignore: constant_identifier_names
const WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x00000080;
// ignore: constant_identifier_names
const WTD_SAFER_FLAG = 0x00000100;
// ignore: constant_identifier_names
const WTD_HASH_ONLY_FLAG = 0x00000200;
// ignore: constant_identifier_names
const WTD_USE_DEFAULT_OSVER_CHECK = 0x00000400;
// ignore: constant_identifier_names
const WTD_LIFETIME_SIGNING_FLAG = 0x00000800;
/// affects CRL retrieval and AIA retrieval
// ignore: constant_identifier_names
const WTD_CACHE_ONLY_URL_RETRIEVAL = 0x00001000;
// ignore: constant_identifier_names
const WTD_DISABLE_MD2_MD4 = 0x00002000;
// ignore: constant_identifier_names
const WTD_MOTW = 0x00004000; // Mark-Of-The-Web
/// Code Integrity driver mode
// ignore: constant_identifier_names
const WTD_CODE_INTEGRITY_DRIVER_MODE = 0x00008000;
/// dwUIContext
// ignore: constant_identifier_names
const WTD_UICONTEXT_EXECUTE = 0;
// ignore: constant_identifier_names
const WTD_UICONTEXT_INSTALL = 1;
///
/// WINTRUST_DATA Structure
///
///----------------------------------------------------------------------------
///
/// Used when calling WinVerifyTrust to pass necessary information into
///
/// the Providers.
@Packed(8)
// ignore: camel_case_types
final class WINTRUST_DATA extends Struct {
/// = sizeof(WINTRUST_DATA)
@Uint32()
external int cbStruct;
/// optional: used to pass data between the app and policy
external Pointer<Void> pPolicyCallbackData;
/// optional: used to pass data between the app and SIP.
external Pointer<Void> pSIPClientData;
/// required: UI choice. One of the following.
@Uint32()
external int dwUIChoice;
/// required: certificate revocation check options
@Uint32()
external int fdwRevocationChecks;
/// required: which structure is being passed in?
@Uint32()
external int dwUnionChoice;
/// 具体的验证对象指针
external Pointer<WINTRUST_FILE_INFO> pFile;
// optional (Catalog File Processing)
@Uint32()
external int dwStateAction;
// optional (Catalog File Processing)
external Pointer<Void> hWVTStateData;
// optional: (future) used to determine zone.
external Pointer<WChar> pwszURLReference;
// optional (Catalog File Processing)
@Uint32()
external int dwProvFlags;
@Uint32()
external int dwUIContext;
//
// #if (NTDDI_VERSION >= NTDDI_WIN8)
// struct WINTRUST_SIGNATURE_SETTINGS_ *pSignatureSettings;
// #endif // #if (NTDDI_VERSION >= NTDDI_WIN8)
external Pointer<Void> pSignatureSettings;
static int lengthBytes() {
// 88 Bytes (WIN10以及之后) 或者 80 Bytes(WIN8以及之前)
return sizeOf<WINTRUST_DATA>();
}
static Pointer<WINTRUST_DATA> allocate(final Arena arena) {
final lengthInBytes = lengthBytes();
final res = arena.allocate<WINTRUST_DATA>(lengthInBytes);
res.ref.cbStruct = lengthInBytes;
return res;
}
}
//
// MessageId: TRUST_E_PROVIDER_UNKNOWN
//
// MessageText:
//
// Unknown trust provider.
//
// ignore: constant_identifier_names
const TRUST_E_PROVIDER_UNKNOWN = 0x800B0001;
//
// MessageId: TRUST_E_ACTION_UNKNOWN
//
// MessageText:
//
// The trust verification action specified is not supported by the specified trust provider.
//
// ignore: constant_identifier_names
const TRUST_E_ACTION_UNKNOWN = 0x800B0002;
//
// MessageId: TRUST_E_SUBJECT_FORM_UNKNOWN
//
// MessageText:
//
// The form specified for the subject is not one supported or known by the specified trust provider.
//
// ignore: constant_identifier_names
const TRUST_E_SUBJECT_FORM_UNKNOWN = 0x800B0003;
// MessageId: TRUST_E_SUBJECT_NOT_TRUSTED
//
// MessageText:
//
// The subject is not trusted for the specified action.
//
// ignore: constant_identifier_names
const TRUST_E_SUBJECT_NOT_TRUSTED = 0x800B0004;
//
// MessageId: TRUST_E_NOSIGNATURE
//
// MessageText:
//
// No signature was present in the subject.
//
// ignore: constant_identifier_names
const TRUST_E_NOSIGNATURE = 0x800B0100;
//
// MessageId: TRUST_E_EXPLICIT_DISTRUST
//
// MessageText:
//
// The certificate was explicitly marked as untrusted by the user.
//
// ignore: constant_identifier_names
const TRUST_E_EXPLICIT_DISTRUST = 0x800B0111;
// ignore: constant_identifier_names
const ERROR_SUCCESS = 0;
/// Windows 数字签名获取与验证
///
/// https://learn.microsoft.com/zh-cn/windows/win32/api/wintrust/nf-wintrust-winverifytrust
///
/// https://learn.microsoft.com/zh-cn/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
class WinVerifyTrust {
/// 动态库加载
late final DynamicLibrary? _trustLib;
late final int Function(
Pointer<Void> hwnd,
Pointer<GUID> pgActionID,
Pointer<Void> pWVTData,
)?
_winVerifyTrust;
/// Checks whether this dynamic library provides a symbol with the given name.
bool _providesSymbol(final String symbolName) {
return _trustLib?.providesSymbol(symbolName) ?? false;
}
WinVerifyTrust() {
try {
_trustLib = DynamicLibrary.open("Wintrust.dll"); // 加载dll,获取句柄
} catch (e) {
_trustLib = null;
debugPrint('Wintrust Load Failed: $e');
}
// 获取函数指针
if (_providesSymbol(fnWinVerifyTrust)) {
_winVerifyTrust = _trustLib!
.lookup<
NativeFunction<
Uint32 Function(Pointer<Void>, Pointer<GUID>, Pointer<Void>)
>
>(fnWinVerifyTrust)
.asFunction();
} else {
_winVerifyTrust = null;
}
}
/// 对文件的签名进行验证
///
/// [file] 需要验证签名的文件的绝对路径
///
/// 比如:"D:\\Source\\build\\windows\\x64\\runner\\Debug\\WebView2Loader.dll"
///
/// return 验证结果
bool verifyEmbeddedSignature(final String file) {
final nativeFile = file.toNativeUtf16();
var verifyRes = false;
using((Arena arena) {
final Pointer<GUID> wvTPolicyGUID = GUID.fromBytes(
arena,
WINTRUST_ACTION_GENERIC_VERIFY_V2,
);
final wfi = WINTRUST_FILE_INFO.allocate(arena);
wfi.ref.pcwszFilePath = nativeFile;
final wtd = WINTRUST_DATA.allocate(arena);
wtd.ref.pFile = wfi;
// Disable WVT UI.
wtd.ref.dwUIChoice = WTD_UI_NONE;
// No revocation checking.
wtd.ref.fdwRevocationChecks = WTD_REVOKE_NONE;
// Verify an embedded signature on a file.
wtd.ref.dwUnionChoice = WTD_CHOICE_FILE;
// Verify action.
wtd.ref.dwStateAction = WTD_STATEACTION_VERIFY;
// WinVerifyTrust verifies signatures as specified by the GUID
// and Wintrust_Data.
var res = _winVerifyTrust?.call(
nullptr,
wvTPolicyGUID,
wtd as Pointer<Void>,
);
if (ERROR_SUCCESS == res) {
verifyRes = true;
}
// Any hWVTStateData must be released by a call with close.
wtd.ref.dwStateAction = WTD_STATEACTION_CLOSE;
res = _winVerifyTrust?.call(nullptr, wvTPolicyGUID, wtd as Pointer<Void>);
});
calloc.free(nativeFile);
return verifyRes;
}
}