2017年6月2日星期五

驱动中获取哈希

/*
功能:驱动中获取哈希。

注意事项:
1.要链接到cng.lib,而不是应用层的Bcrypt.lib,
  否则驱动启动因为找不到以来的文件,而显示错误码:2,及找不到文件。
  具体的做法是:
  SOURCE文件的TARGETLIBS加上$(DDK_LIB_PATH)\cng.lib
  或者:
  sources.props或类似的文件里的TARGETLIBS加上$(DDK_LIB_PATH)\cng.lib。
  再说下是DDK_LIB_PATH,而不是SDK_LIB_PATH。

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


#include <ntifs.h>
#include <windef.h>
#include <Bcrypt.h>
#include <Ntstrsafe.h>


#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4100) // 未引用的形参
#pragma warning(disable:4101) // 未引用的局部变量
#pragma warning(disable:4189) // 局部变量已初始化但不引用


#define TAG 'test' //test


BOOL HASH(IN PBYTE rgbMsg, IN ULONG cbInput, LPWSTR algorithm, OUT PBYTE * Hash, DWORD * HashLen)
    /*
    注意:
    1.多字节和单字节。
    2.算法名区分大小写,否者出现异常。
    3.pbHash由调用者释放。

    参考:https://msdn.microsoft.com/en-us/library/windows/desktop/aa376217(v=vs.85).aspx
    */
{
    BOOL B = FALSE;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    BCRYPT_ALG_HANDLE hAlg = NULL;
    DWORD cbData = 0;//calculate the size of the buffer to hold the hash object
    DWORD cbHashObject    = 0;
    PBYTE pbHashObject = NULL;
    DWORD cbHash = 0;//calculate the length of the hash
    PBYTE pbHash = NULL;
    BCRYPT_HASH_HANDLE hHash = NULL;

    if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlg, algorithm, NULL, 0)))//open an algorithm handle
    {
        goto Cleanup;
    }
    
    if(!NT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0)))
    {
        goto Cleanup;
    }
    pbHashObject = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, cbHashObject, TAG);
    if(NULL == pbHashObject)
    {
        goto Cleanup;
    }
    RtlZeroMemory(pbHashObject, cbHashObject);
    
    if(!NT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0)))
    {
        goto Cleanup;
    }
    pbHash = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, cbHash, TAG);
    if(NULL == pbHash)
    {
        goto Cleanup;
    }
    RtlZeroMemory(pbHash, cbHash);

    if(!NT_SUCCESS(status = BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0)))//create a hash
    {
        goto Cleanup;
    }
    
    if(!NT_SUCCESS(status = BCryptHashData(hHash, rgbMsg, cbInput, 0)))//hash some data
    {
        goto Cleanup;
    }

    //pbHash是哈希内容,cbHash是哈希的长度。
    
    if(!NT_SUCCESS(status = BCryptFinishHash(hHash, pbHash, cbHash, 0)))//close the hash
    {
        goto Cleanup;
    }

    //wprintf(L"Success!\n");

    * Hash = pbHash;
    * HashLen = cbHash;
    B = TRUE;

Cleanup:

    if(hAlg)
    {
        BCryptCloseAlgorithmProvider(hAlg,0);
    }

    if (hHash)    
    {
        BCryptDestroyHash(hHash);
    }

    if(pbHashObject)
    {
        ExFreePoolWithTag(pbHashObject, TAG);
    }

    //if(pbHash)
    //{
    //    HeapFree(GetProcessHeap(), 0, pbHash);
    //}

    return B;
}


BOOL HASHFILE(LPCTSTR lpFileName, LPWSTR algorithm, LPWSTR lpFileHash)
    /*
    注意:lpFileName支持DOS格式,包括流,
         但是不支持:
         1.NT式的,\Device\XXX 
         2.带环境扩展的,%systemroot%
         3.网络的也不行,如:\Device\Mup\vmware-host\Shared Folders\XXX
         4.还有\SystemRoot\system32\drivers\spsys.sys。
    注意:lpFileHash提供的空间要足够大,足够容纳想要的数据。
    */
{
    unsigned int status = STATUS_SUCCESS;
    BOOL B = FALSE;
    HANDLE hFile = NULL; 
    PBYTE buffer = NULL;
    DWORD NumberOfBytesRead = 0;
    PBYTE Hash;
    DWORD HashLen;
    unsigned int i;
    OBJECT_ATTRIBUTES ob;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    LARGE_INTEGER AllocationSize = {0};
    UNICODE_STRING FileName;
    PFILE_OBJECT FileObject = 0;
    LARGE_INTEGER file_size = {0};
    LARGE_INTEGER ByteOffset = {0};

    RtlInitUnicodeString(&FileName, lpFileName);
    InitializeObjectAttributes(&ob, &FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwCreateFile(
        &hFile, 
        FILE_ALL_ACCESS | SYNCHRONIZE, 
        &ob,
        &IoStatusBlock,
        &AllocationSize, 
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_VALID_FLAGS, 
        FILE_OPEN, 
        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 
        NULL,
        0
        );
    if (!NT_SUCCESS (status)) 
    {
        return FALSE;
    }

    status = ObReferenceObjectByHandle(hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL );
    ASSERT (NT_SUCCESS( status ));
    status = FsRtlGetFileSize(FileObject, &file_size);
    ASSERT (NT_SUCCESS( status ));
    ASSERT(file_size.QuadPart);
    ASSERT(0 == file_size.HighPart);

    buffer = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, file_size.LowPart, TAG);//文件过大,这里会失败。
    ASSERT(NULL != buffer);
    
    status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, buffer, file_size.LowPart, &ByteOffset, NULL);
    ASSERT (NT_SUCCESS( status ));

    B = HASH(buffer, file_size.LowPart, algorithm, &Hash, &HashLen);
    if (B)
    {
        //确保lpFileHash的大小大于HashLen
        for (i = 0; i < HashLen; i++)
        {
            RtlStringCchPrintfW(&lpFileHash[i * 2], 4, L"%02X", Hash[i]);
        }
    }

    ExFreePoolWithTag(Hash, TAG);
    ExFreePoolWithTag(buffer, TAG);
    ObDereferenceObject(FileObject);
    ZwClose( hFile );
    return B;
}


VOID Unload(_In_ PDRIVER_OBJECT DriverObject)
{  
    UNREFERENCED_PARAMETER(DriverObject);

    PAGED_CODE();

}


NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    wchar_t buffer[MAX_PATH] = {0};
    BOOL B = FALSE;
    
    UNREFERENCED_PARAMETER(RegistryPath);

    PAGED_CODE();

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;
    
    B = HASHFILE(L"\\Device\\HarddiskVolume1\\test.txt", BCRYPT_SHA256_ALGORITHM, buffer);

    return Status;
}

没有评论:

发表评论