2017年9月7日星期四

SeRegisterImageVerificationCallback

/*
如何在驱动中获取SYS或者DLL,EXE等的签名信息?
自己编写代码也可以,就是难定位到文件的签名文件,如:用CAT的。

高版本的WDK下有个Early Launch Anti-Malware Driver或者叫elam工程。
这个工程IoRegisterBootDriverCallback的使用有限制,测试了没有成功:平常返回失败,BOOT启动也失败。
不过,在这里看到一个数据结构:PBDCB_IMAGE_INFORMATION。

偶尔你会看到这两个函数:
SeRegisterImageVerificationCallback,SeUnregisterImageVerificationCallback
在网上一搜,果然看到:
http://www.codemachine.com/article_kernel_callback_functions.html
http://eretik.omegahg.com/art/1E.html
其实这两个函数定义在WDK8.1及以上的版本的WDM.H中,且也导出了,所以可直接使用。
本文就是关于这的测试代码。

made by correy
made at 2017.09.07
http://correy.webs.com
*/

#include <fltKernel.h>

PVOID g_CallbackHandle;


VOID PrintHex(_In_reads_bytes_(DataSize) PVOID Data, _In_ ULONG DataSize)
/*++
Routine Description:
This routine prints out the supplied data in hexadecimal form.
Arguments:
Data - Supplies a pointer to the data to be printed.
DataSize - Supplies the length in bytes of the data to be printed.
--*/
{
    PCUCHAR Bytes;
    ULONG Index;

    for (Bytes = (PCUCHAR)Data, Index = 0; Index < DataSize; Index++)
    {
        if ((Index & 15) == 0)
        {
            KdPrint(("\r\n:    "));
        }

        KdPrint(("%02x ", Bytes[Index]));
    }

    KdPrint(("\r\n"));
}


VOID MY_SE_IMAGE_VERIFICATION_CALLBACK_FUNCTION(_In_opt_ PVOID CallbackContext, _In_ SE_IMAGE_TYPE ImageType, _Inout_ PBDCB_IMAGE_INFORMATION ImageInformation)
/*
加载没有签名的驱动这里拦截不到。

估计这里的ImageType的值和传递给SeRegisterImageVerificationCallback的第一个参数的值一样。
*/
{
    UNREFERENCED_PARAMETER(CallbackContext);

    KdPrint(("    ImageType = 0x%08x.\r\n", ImageType));

    // Display the image name and any associated registry path.
    KdPrint(("    Image name \"%wZ\"\r\n", &ImageInformation->ImageName));
    if (ImageInformation->RegistryPath.Buffer != NULL)
    {
        KdPrint(("    Registry path \"%wZ\"\r\n", &ImageInformation->RegistryPath));
    }

    // Did this image fail Code Integrity checks?
    if ((ImageInformation->ImageFlags & BDCB_IMAGEFLAGS_FAILED_CODE_INTEGRITY) != 0)
    {
        KdPrint(("    FAILED Code Integrity checks but boot policy allowed it to be loaded.\r\n"));
    }

    // Display the image's hash.
    if (ImageInformation->ImageHash != NULL && ImageInformation->ImageHashLength != 0)
    {
        KdPrint(("    Image hash algorithm = 0x%08x.\r\n", ImageInformation->ImageHashAlgorithm));
        KdPrint(("    Image hash:"));
        PrintHex(ImageInformation->ImageHash, ImageInformation->ImageHashLength);
    }

    // Display who signed the image (if at all).
    if (ImageInformation->CertificatePublisher.Buffer != NULL)
    {
        KdPrint(("    Image is signed by \"%wZ\".\r\n", &ImageInformation->CertificatePublisher));//重点是获取这个。
        if (ImageInformation->CertificateIssuer.Buffer != NULL)
        {
            KdPrint(("    Certificate issued by \"%wZ\".\r\n", &ImageInformation->CertificateIssuer));
        }

        if (ImageInformation->CertificateThumbprint != NULL && ImageInformation->CertificateThumbprintLength != 0)
        {
            KdPrint(("    Certificate thumb print algorithm = 0x%08x.\r\n", ImageInformation->ThumbprintHashAlgorithm));
            KdPrint(("    Certificate thumb print:"));
            PrintHex(ImageInformation->CertificateThumbprint, ImageInformation->CertificateThumbprintLength);
        }
    }
    else
    {
        KdPrint(("    Not signed.\r\n"));
    }

    KdPrint(("\r\n"));
}


extern "C" void DriverUnload(PDRIVER_OBJECT driver_object)
{
    UNREFERENCED_PARAMETER(driver_object);

    SeUnregisterImageVerificationCallback(g_CallbackHandle);
}


extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
{
    UNREFERENCED_PARAMETER(registry_path);
    PAGED_CODE();

    __debugbreak();

    driver_object->DriverUnload = DriverUnload;

    NTSTATUS status = STATUS_SUCCESS;

#if (NTDDI_VERSION < NTDDI_WINBLUE)
    return STATUS_UNSUCCESSFUL;
#endif

    status = SeRegisterImageVerificationCallback(SeImageTypeDriver, SeImageVerificationCallbackInformational, MY_SE_IMAGE_VERIFICATION_CALLBACK_FUNCTION, NULL, NULL, &g_CallbackHandle);

    return status;
}