上海移动端网站建设,公司网站更新,西安百度竞价代运营,做网站开发背景1. 背景 在一般的驱动开发时#xff0c;创建了符号链接后在应用层就可以访问打开我们的设备并进行通讯。 但我们有时候不希望非自己的进程访问我们的设备并进行交互#xff0c;虽然可以使用 IoCreateDeviceSecure 来创建有安全描述符的设备#xff0c;但大数的用户账户为了方…1. 背景 在一般的驱动开发时创建了符号链接后在应用层就可以访问打开我们的设备并进行通讯。 但我们有时候不希望非自己的进程访问我们的设备并进行交互虽然可以使用 IoCreateDeviceSecure 来创建有安全描述符的设备但大数的用户账户为了方便都是管理员因此该方法不太完整。 2. 一般方法 一般情况下进行限制的方法是允许打开设备但在打开设备后做一些校验如果不通过之后的其它请求都拒绝。 例如 Dell 在一个漏洞驱动 pcdsrvc_x64.pkms 中处理如下IDA逆向代码
__int64 __fastcall DeviceIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{_IO_STACK_LOCATION* pIosp; // r9unsigned int nBytesReturn; // edxULONG nIoControlCode; // ecxunsigned int ntStatus; // ebxDWORD* dwInitailizeCode; // raxpIosp pIrp-Tail.Overlay.CurrentStackLocation;nBytesReturn 0;nIoControlCode pIosp-Parameters.DeviceIoControl.IoControlCode;if (nIoControlCode ! 0x222004 !bInitialized){ntStatus 0xC0000022;pIrp-IoStatus.Information 0i64;LABEL_18:LOBYTE(nBytesReturn) 0;goto LABEL_36;}if (nIoControlCode - 0x222000 0x7C){ntStatus 0;if (nIoControlCode 0x222000){if (pIosp-Parameters.DeviceIoControl.OutputBufferLength 4){*(_DWORD*)pIrp-AssociatedIrp.SystemBuffer 0x6020300;LABEL_16:nBytesReturn 4;goto LABEL_17;}}else{if (nIoControlCode ! 0x222004){ntStatus 0xC0000010;LABEL_17:pIrp-IoStatus.Information nBytesReturn;goto LABEL_18;}if (pIosp-Parameters.DeviceIoControl.InputBufferLength 4 pIosp-Parameters.DeviceIoControl.OutputBufferLength 4)// 初始化驱动{dwInitailizeCode (DWORD*)pIrp-AssociatedIrp.SystemBuffer;if (*dwInitailizeCode 0xA1B2C3D4){bInitialized 1;*dwInitailizeCode 0;}else{*dwInitailizeCode 1;}goto LABEL_16;}}ntStatus 0xC000000D;goto LABEL_17;}......
} 按照原逻辑是在打开使用后发送一个 0x222004 的请求码并传入 0xA1B2C3D4至此以后就相当于初始化了之后的请求都可以正常进行如果没有这个初始化的请求之后的请求都是拒绝的。 虽然这个方法可行但稍微懂点逆向的相当于可以看到源代码逻辑这样只要稍作处理这个方法就失效了。 3. 使用验证数字签名 使用该方法可以在设备打开的逻辑中验证操作进程的数字签名如果为允许的签名就返回成功打开设备也就成功否则返回失败也就打开失败。 驱动中验证PE的数字签名见《Windows驱动中校验数字签名(使用 ci.dll)》。里边有两种方法一种是 CiValidateFileObject另一种是 CiCheckSignedFile。 其中 CiCheckSignedFile 更为严格需要指定签名算法和摘要此摘要是 PE 文件签名后的摘要因此随时 PE 文件的不同摘要也不同这里并不太方便。 因此本文用的是 CiValidateFileObject首先它可以验证签名是否有效即签名后文件进行了篡改后验证是不通过的假的数字签名证书也不能通过验证。再者它可以返回证书链以及每个证书的摘要我们可在在这里判断证书的摘要如果是我们指定的证书则通过验证即使是用的同一证书签名不同的文件也可以一次代码多次使用。 4. 代码
4.1 驱动代码
4.1.1 ci.h
#pragma once#include wdm.h
#include minwindef.h#if DBG
#define KDPRINT(projectName, format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,\projectName ::【 __FUNCTION__ 】 ##format, \##__VA_ARGS__ )
#else
#define KDPRINT(format, ...)
#endif/**
* This struct was copied from wintrust.h and encapsulates a signature used in verifying executable files.
*/
typedef struct _WIN_CERTIFICATE {DWORD dwLength; // Specifies the length, in bytes, of the signatureWORD wRevision; // Specifies the certificate revisionWORD wCertificateType; // Specifies the type of certificateBYTE bCertificate[ANYSIZE_ARRAY]; // An array of certificates
} WIN_CERTIFICATE, * LPWIN_CERTIFICATE;/**
* Describes the location (address) and size of a ASN.1 blob within a buffer.
*
* note The data itself is not contained in the struct.
*/
typedef struct _Asn1BlobPtr
{int size; // size of the ASN.1 blobPVOID ptrToData; // where the ASN.1 blob starts
} Asn1BlobPtr, * pAsn1BlobPtr;/**
* Describes the location (address) and size of a certificate subject/issuer name, within a buffer.
*
* note The data itself (name) is not contained in the struct.
*
* note the reason for separating these fields into their own struct was to match the padding we
* observed in CertChainMember struct after the second short field - once you enclose it
* into a struct, on x64 bit machines there will be a padding of 4 bytes at the end of the struct,
* because the largest member of the struct is of size 8 and it dictates the alignment of the struct.
*/
typedef struct _CertificatePartyName
{PVOID pointerToName;short nameLen;short unknown;
} CertificatePartyName, * pCertificatePartyName;/**
* Contains various data about a specific certificate in the chain and also points to the actual certificate.
*
* note the digest described in this struct is the digest that was used to create the certificate - not for
* signing the file.
*
* note The size reserved for digest is 64 byte regardless of the digest type, in order to accomodate SHA2/3s
* max size of 512bit. The memory is not zeroed, so we must take the actual digestSize into account when
* reading it.
*/
typedef struct _CertChainMember
{int digestIdetifier; // e.g. 0x800c for SHA256int digestSize; // e.g. 0x20 for SHA256BYTE digestBuffer[64]; // contains the digest itself, where the digest size is dictated by digestSizeCertificatePartyName subjectName; // pointer to the subject nameCertificatePartyName issuerName; // pointer to the issuer nameAsn1BlobPtr certificate; // ptr to actual cert in ASN.1 - including the public key
} CertChainMember, * pCertChainMember;/**
* Describes the format of certChainInfo buffer member of PolicyInfo struct. This header maps the types,
* locations, and quantities of the data which is contained in the buffer.
*
* note when using this struct make sure to check its size first (bufferSize) because its not guaranteed
* that all the fields below will exist.
*/
typedef struct _CertChainInfoHeader
{// The size of the dynamically allocated bufferint bufferSize;// points to the start of a series of Asn1Blobs which contain the public keys of the certificates in the chainpAsn1BlobPtr ptrToPublicKeys;int numberOfPublicKeys;// points to the start of a series of Asn1Blobs which contain the EKUspAsn1BlobPtr ptrToEkus;int numberOfEkus;// points to the start of a series of CertChainMemberspCertChainMember ptrToCertChainMembers;int numberOfCertChainMembers;int unknown;// ASN.1 blob of authenticated attributes - spcSpOpusInfo, contentType, etc.Asn1BlobPtr variousAuthenticodeAttributes;
} CertChainInfoHeader, * pCertChainInfoHeader;/**
* Contains information regarding the certificates that were used for signing/timestamping
*
* note you must check structSize before accessing the other members, since some members were added later.
*
* note all structs members, including the length, are populated by ci functions - no need
* to fill them in adavnce.
*/
typedef struct _PolicyInfo
{int structSize;NTSTATUS verificationStatus;int flags;pCertChainInfoHeader certChainInfo; // if not null - contains info about certificate chainFILETIME revocationTime; // when was the certificate revoked (if applicable)FILETIME notBeforeTime; // the certificate is not valid before this timeFILETIME notAfterTime; // the certificate is not valid before this time
} PolicyInfo, *pPolicyInfo;/**
* Given a file digest and signature of a file, verify the signature and provide information regarding
* the certificates that was used for signing (the entire certificate chain)
*
* note the function allocates a buffer from the paged pool -- can be used only where IRQL DISPATCH_LEVEL
*
* param digestBuffer - buffer containing the digest
*
* param digestSize - size of the digest, e.g. 0x20 for SHA256, 0x14 for SHA1
*
* param digestIdentifier - digest algorithm identifier, e.g. 0x800c for SHA256, 0x8004 for SHA1
*
* param winCert - pointer to the start of the security directory
*
* param sizeOfSecurityDirectory - size the security directory
*
* param policyInfoForSigner[out] - PolicyInfo containing information about the signer certificate chain
*
* param signingTime[out] - when the file was signed (FILETIME format)
*
* param policyInfoForTimestampingAuthority[out] - PolicyInfo containing information about the timestamping
* authority (TSA) certificate chain
*
* return 0 if the file digest in the signature matches the given digest and the signer cetificate is verified.
* Various error values otherwise, for example:
* STATUS_INVALID_IMAGE_HASH - the digest does not match the digest in the signature
* STATUS_IMAGE_CERT_REVOKED - the certificate used for signing the file is revoked
* STATUS_IMAGE_CERT_EXPIRED - the certificate used for signing the file has expired
*/
extern C __declspec(dllimport) NTSTATUS _stdcall CiCheckSignedFile(const PVOID digestBuffer,int digestSize,int digestIdentifier,const LPWIN_CERTIFICATE winCert,int sizeOfSecurityDirectory,PolicyInfo* policyInfoForSigner,LARGE_INTEGER* signingTime,PolicyInfo* policyInfoForTimestampingAuthority);/**
* Resets a PolicyInfo struct - frees the dynamically allocated buffer in PolicyInfo (certChainInfo) if not null.
* Zeros the entire PolicyInfo struct.
*
* param policyInfo - the struct to reset.
*
* return the struct which was reset.
*/
extern C __declspec(dllimport) PVOID _stdcall CiFreePolicyInfo(PolicyInfo* policyInfo);/**
* Given a file object, verify the signature and provide information regarding
* the certificates that was used for signing (the entire certificate chain)
*
* note the function allocates memory from the paged pool -- can be used only where IRQL DISPATCH_LEVEL
*
* param fileObject[in] - fileObject of the PE in question
*
* param a2[in] - unknown, needs to be reversed. 0 is a valid value.
*
* param a3[in] - unknown, needs to be reversed. 0 is a valid value.
*
* param policyInfoForSigner[out] - PolicyInfo containing information about the signer certificate chain
*
* param signingTime[out] - when the file was signed
*
* param policyInfoForTimestampingAuthority[out] - PolicyInfo containing information about the timestamping
* authority (TSA) certificate chain
*
* param digestBuffer[out] - buffer to be filled with the digest, must be at least 64 bytes
*
* param digestSize[inout] - size of the digest. Must be at leat 64 and will be changed by the function to
* reflect the actual digest length.
*
* param digestIdentifier[out] - digest algorithm identifier, e.g. 0x800c for SHA256, 0x8004 for SHA1
*
* return 0 if the file digest in the signature matches the given digest and the signer cetificate is verified.
* Various error values otherwise, for example:
* STATUS_INVALID_IMAGE_HASH - the digest does not match the digest in the signature
* STATUS_IMAGE_CERT_REVOKED - the certificate used for signing the file is revoked
* STATUS_IMAGE_CERT_EXPIRED - the certificate used for signing the file has expired
*/
extern C __declspec(dllimport) NTSTATUS _stdcall CiValidateFileObject(struct _FILE_OBJECT* fileObject,int a2,int a3,PolicyInfo* policyInfoForSigner,PolicyInfo* policyInfoForTimestampingAuthority,LARGE_INTEGER* signingTime,BYTE* digestBuffer,int* digestSize,int* digestIdentifier
);
4.1.2 SignatureCheck.h
#pragma once#include wdm.h
#include minwindef.h#define SHA1_IDENTIFIER 0x8004
#define SHA1_DEGIST_LENGTH 20
#define SHA256_IDENTIFIER 0x800C
#define SHA256_DEGIST_LENGTH 32
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
#define PRINT_DIGEST trueBOOLEAN ValidateFileUsingCiValidateFileObject(PFILE_OBJECT fileObject, const BYTE crtDigest[], UINT nLength);
4.1.3 SignatureCheck.cpp
#include SignatureCheck.h
#include ci.hUCHAR HexToChar(UCHAR temp)
{UCHAR dst;if (temp ){// do nothing dst temp;}else if (temp 10) {dst temp 0;}else {dst temp - 10 A;}return dst;
}BOOLEAN ValidateFileUsingCiValidateFileObject(PFILE_OBJECT fileObject , const BYTE crtDigest[], UINT nLength)
{KDPRINT(【IrpCertCheck】, Validating file using CiValidateFileObject...\n);NT_ASSERT(KeGetCurrentIrql() DISPATCH_LEVEL);PolicyInfo signerPolicyInfo {0};PolicyInfo timestampingAuthorityPolicyInfo {0};LARGE_INTEGER signingTime {0};int digestSize 64; //大小必须为64否则返回缓冲区大小太小int digestIdentifier 0;BYTE digestBuffer[64] {0}; //大小必须为64否则返回缓冲区大小太小BOOLEAN bValidate false;const NTSTATUS status CiValidateFileObject(fileObject,0,0,signerPolicyInfo,timestampingAuthorityPolicyInfo,signingTime,digestBuffer,digestSize,digestIdentifier);KDPRINT(【IrpCertCheck】, CiValidateFileObject returned 0x%08X\n, status);if (NT_SUCCESS(status)){
#if PRINT_DIGEST CHAR digestTempBuffer[98] { 0 };for (int i 0; i 32; i){digestTempBuffer[3 * i] signerPolicyInfo.certChainInfo-ptrToCertChainMembers-digestBuffer[i] 4;digestTempBuffer[3 * i 1] signerPolicyInfo.certChainInfo-ptrToCertChainMembers-digestBuffer[i] 0xf;digestTempBuffer[3 * i 2] ;}for (int i 0; i 96; i){digestTempBuffer[i] HexToChar(digestTempBuffer[i]);}KDPRINT(【IrpCertCheck】, Signer certificate:\n digest algorithm - 0x%x\n digest size - %d\r\n digest - %s\n,digestIdentifier, digestSize, digestTempBuffer);
#endifif (RtlCompareMemory(signerPolicyInfo.certChainInfo-ptrToCertChainMembers-digestBuffer, crtDigest, nLength) nLength){bValidate true;}}CiFreePolicyInfo(signerPolicyInfo);CiFreePolicyInfo(timestampingAuthorityPolicyInfo);return bValidate;
}
4.1.4 main.cpp
#include ntddk.h // PsSetCreateProcessNotifyRoutineEx
#include wdm.h
#include wdmsec.h#include SignatureCheck.h
#include ci.h
#pragma comment(lib, Wdmsec.lib)#define IRP_CERT_CHECK_DEVICE_NAME (L\\Device\\IrpCertCheck)
#define IRP_CERT_CHECK_DEVICE_SYMBOLIC_NAME (L\\??\\IrpCertCheck)
#define CTL_CODE_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS)EXTERN_C
NTKERNELAPI
NTSTATUS
PsReferenceProcessFilePointer(IN PEPROCESS Process,OUT PVOID* pFilePointer
);
EXTERN_C
NTKERNELAPI
NTSTATUS
IoQueryFileDosDeviceName(_In_ PFILE_OBJECT FileObject,_Out_ POBJECT_NAME_INFORMATION* ObjectNameInformation
);
DRIVER_UNLOAD Unload;
PDEVICE_OBJECT g_pDeviceObject NULL;const static BYTE Cert256Digest[SHA256_DEGIST_LENGTH] {0xD6, 0x43, 0x45, 0x88, 0x65, 0x45, 0x27, 0x40, 0x44, 0xDD,0x87, 0xD8, 0xCF, 0x67, 0x4B, 0x34, 0x78, 0x42, 0xE5, 0xA3,0x70, 0x35, 0x05, 0xB8, 0x90, 0x15, 0xD4, 0xA4, 0xB7, 0x7F,0xBA, 0x31 };NTSTATUS
DeviceIoControl(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp
)
{UNREFERENCED_PARAMETER(pDeviceObject);NTSTATUS ntStatus STATUS_INVALID_PARAMETER;PIO_STACK_LOCATION pIosp IoGetCurrentIrpStackLocation(pIrp);if (pIosp-Parameters.DeviceIoControl.IoControlCode CTL_CODE_TEST){KDPRINT(【IrpCertCheck】, This Is Test Control Code\n);ntStatus STATUS_SUCCESS;}pIrp-IoStatus.Information 0;pIrp-IoStatus.Status ntStatus;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return ntStatus;
}NTSTATUS CommonDispatchRoutine(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{UNREFERENCED_PARAMETER(pDeviceObject);NTSTATUS ntStatus STATUS_NOT_IMPLEMENTED;pIrp-IoStatus.Information 0;pIrp-IoStatus.Status ntStatus;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return ntStatus;
}NTSTATUS
Create(IN PDEVICE_OBJECT pDeviceObject,IN PIRP pIrp
)
{UNREFERENCED_PARAMETER(pDeviceObject);BOOLEAN bAllow false;NTSTATUS ntStatus STATUS_ACCESS_DENIED;PEPROCESS pCurrentProcess PsGetCurrentProcess();PFILE_OBJECT pFileObject NULL;ntStatus PsReferenceProcessFilePointer(pCurrentProcess, (PVOID*)pFileObject);if (NT_SUCCESS(ntStatus)){POBJECT_NAME_INFORMATION name NULL;ntStatus IoQueryFileDosDeviceName(pFileObject, name);if (NT_SUCCESS(ntStatus)){KDPRINT(【IrpCertCheck】, Operation Process Name:%wZ\n, name-Name);HANDLE hFile NULL;WCHAR szBuffer[MAX_PATH] { 0 };UNICODE_STRING usFileDosPath { 0 };usFileDosPath.MaximumLength MAX_PATH * 2;usFileDosPath.Buffer szBuffer;RtlAppendUnicodeToString(usFileDosPath, L\\??\\);RtlAppendUnicodeStringToString(usFileDosPath, name-Name);OBJECT_ATTRIBUTES oba { 0 };InitializeObjectAttributes(oba, usFileDosPath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);IO_STATUS_BLOCK iosb { 0 };ntStatus ZwOpenFile(hFile, GENERIC_READ, oba, iosb, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);if (NT_SUCCESS(ntStatus)){PFILE_OBJECT pFileRef NULL;ntStatus ObReferenceObjectByHandle(hFile, GENERIC_READ, *IoFileObjectType, KernelMode, (PVOID*)pFileRef, NULL);if (NT_SUCCESS(ntStatus)){//第一个参数的 PFILE_OBJECT 不能直接使用 PsReferenceProcessFilePointer返回的可能//因为映射的方式不同需要重新打开对应的文件取得 PFILE_OBJECTif (ValidateFileUsingCiValidateFileObject(pFileRef, Cert256Digest, SHA256_DEGIST_LENGTH)){ bAllow true;KDPRINT(【IrpCertCheck】, ValidateFileUsingCiValidateFileObject Pass\n);}else{KDPRINT(【IrpCertCheck】, ValidateFileUsingCiValidateFileObject Failed\n);}ObDereferenceObject(pFileRef);}ZwClose(hFile);}}ObDereferenceObject(pFileObject);}else{KDPRINT(【IrpCertCheck】, PsReferenceProcessFilePointer failed, code:0x%08x\n, ntStatus);}if (bAllow){ntStatus STATUS_SUCCESS;}else{ntStatus STATUS_ACCESS_DENIED;}pIrp-IoStatus.Information 0;pIrp-IoStatus.Status ntStatus;IoCompleteRequest(pIrp, IO_NO_INCREMENT);return ntStatus;
}extern C NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{UNREFERENCED_PARAMETER(DriverObject);UNREFERENCED_PARAMETER(RegistryPath);DriverObject-DriverUnload Unload;KDPRINT(【IrpCertCheck】, IrpCertCheck Enter...\n);UNICODE_STRING usDeviceName RTL_CONSTANT_STRING(IRP_CERT_CHECK_DEVICE_NAME);UNICODE_STRING usSddl RTL_CONSTANT_STRING(LD:P(A;;GA;;;WD));//NTSTATUS ntStatus IoCreateDeviceSecure(// DriverObject,// 0,// usDeviceName,// FILE_DEVICE_UNKNOWN,// FILE_DEVICE_SECURE_OPEN,// false,// usSddl,// NULL,// g_pDeviceObject);NTSTATUS ntStatus IoCreateDevice(DriverObject,0,usDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,false,g_pDeviceObject);if (NT_SUCCESS(ntStatus)){UNICODE_STRING usSymbolic RTL_CONSTANT_STRING(IRP_CERT_CHECK_DEVICE_SYMBOLIC_NAME);ntStatus IoCreateSymbolicLink(usSymbolic, usDeviceName);if (NT_SUCCESS(ntStatus)){for (int i 0 ; i IRP_MJ_MAXIMUM_FUNCTION; i){DriverObject-MajorFunction[i] CommonDispatchRoutine;}DriverObject-MajorFunction[IRP_MJ_CREATE] Create;DriverObject-MajorFunction[IRP_MJ_DEVICE_CONTROL] DeviceIoControl;}else{KDPRINT(【IrpCertCheck】, IoCreateSymbolicLink failed, code:0x%08x\n, ntStatus);}}else{KDPRINT(【IrpCertCheck】, IoCreateDevice failed, code:0x%08x\n, ntStatus);}return ntStatus;
}VOID Unload(_In_ struct _DRIVER_OBJECT* DriverObject)
{UNREFERENCED_PARAMETER(DriverObject);KDPRINT(【IrpCertCheck】, IrpCertCheck Enter..\n);UNICODE_STRING usSymbolic RTL_CONSTANT_STRING(IRP_CERT_CHECK_DEVICE_SYMBOLIC_NAME);IoDeleteSymbolicLink(usSymbolic);if (g_pDeviceObject){IoDeleteDevice(g_pDeviceObject);g_pDeviceObject NULL;}
} 4.2 应用层代码
#include iostream
#include windows.h
#include iomanip
#define CTL_CODE_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1000, METHOD_BUFFERED, FILE_ANY_ACCESS)
int main()
{HANDLE hDevice CreateFile(L\\\\.\\IrpCertCheck, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hDevice INVALID_HANDLE_VALUE){std::string strInfo 打开设备失败, 错误码:0x;std::cout strInfo std::setbase(16) std::setfill(0) std::setw(8) GetLastError() std::endl;}else{DWORD nByteRetuen 0;bool bOK DeviceIoControl(hDevice, CTL_CODE_TEST, nullptr, 0, NULL, 0, nByteRetuen, NULL);if (bOK){std::string strInfo 发送控制码成功;std::cout strInfo std::endl;}else{std::string strInfo 发送控制码失败, 错误码:0x;std::cout strInfo std::setbase(16) std::setfill(0) std::setw(8) GetLastError() std::endl;}}
} 5. 代码逻辑及注意事项
驱动中 IRP_MJ_CREATE 对应的 Create 函数调用 ValidateFileUsingCiValidateFileObject 来判断数字签名是否是允许的不允许情况下直接返回失败对应的应用层打开设备也就失败。驱动中 IRP_MJ_CREATE 对应的 Create 函数调用 ValidateFileUsingCiValidateFileObject 的第一个参数 fileObject 不能直接使用 PsReferenceProcessFilePointer 返回的 FILE_OBJECT原因可能是返回的 FILE_OBJECT 对应的文件映射方式不同需要再次使用 ZwOpenFile 返回的文件对象。SignatureCheck.cpp 中的 ValidateFileUsingCiValidateFileObject 函数第 52 行至 66 行打印了验证返回的数字证书摘要此摘要为证书的摘要而非 PE 文件的摘要而此证书为整个证书链最顶层的证书。这个打印逻辑可以用来先获取证书摘要 再通过 第67 至 70 行的判断来决定证书是否通过验证。main.cpp 中的 Cert256Digest 的数据即是上一条方法中获取的证书摘要。应用层逻辑为打开设备成功后送一个控制请求。 6. 实验效果 使用代码中 Cert256Digest 摘要对应的数字证书签名应用层程序如下 加载驱动后运行应用层程序效果如下 可以看到验证通过应用层控制码也发送成功main.cpp 中的 Cert256Digest 数据即为图中红框所标部分。 之后换掉用层程序的数字签名SHA256 改为 SHA1后验证如下 可以发现数字证书虽然验证成功但证书不是我们指定证书最终还是返回失败应用层打开设备直接返回拒绝访问目的达到。
7.注意事项 CiValidateFileObject 由 ci.dll 导出编译驱动时需要链接 ci.dll, 具体方法见《Windows驱动中校验数字签名(使用 ci.dll)》。 在多重数字签名的情况下CiValidateFileObject 只能返回一个签名的摘要因此需要应用层只有一个数字签名。