(1)参考wine的代码,微软说的那个方法有些复杂(除非是一些特殊的pe),正常情况下的pe文件,各个节都是紧密排列的有序的,只需跳过checksum security_dir 和security_dir.VA之后的数据就行,当然微软是比较严谨的


/* See https://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
 * for details about the hashing.
 */
static BOOL SOFTPUB_HashPEFile(HANDLE file, HCRYPTHASH hash)
{
    DWORD checksum, security_dir;
    IMAGE_DOS_HEADER dos_header;
    union
    {
        IMAGE_NT_HEADERS32 nt32;
        IMAGE_NT_HEADERS64 nt64;
    } nt_header;
    IMAGE_DATA_DIRECTORY secdir;
    LARGE_INTEGER file_size;
    DWORD bytes_read;
    BOOL ret;

    if (!GetFileSizeEx(file, &file_size))
        return FALSE;

    SetFilePointer(file, 0, NULL, FILE_BEGIN);
    ret = ReadFile(file, &dos_header, sizeof(dos_header), &bytes_read, NULL);
    if (!ret || bytes_read != sizeof(dos_header))
        return FALSE;

    if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
        return FALSE;
    if (dos_header.e_lfanew >= 256 * 1024 * 1024) /* see RtlImageNtHeaderEx */
        return FALSE;
    if (dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader.MajorLinkerVersion) > file_size.QuadPart)
        return FALSE;

    SetFilePointer(file, dos_header.e_lfanew, NULL, FILE_BEGIN);
    ret = ReadFile(file, &nt_header, sizeof(nt_header), &bytes_read, NULL);
    if (!ret || bytes_read < FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.Magic) +
                             sizeof(nt_header.nt32.OptionalHeader.Magic))
        return FALSE;

    if (nt_header.nt32.Signature != IMAGE_NT_SIGNATURE)
        return FALSE;

    if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
    {
        if (bytes_read < sizeof(nt_header.nt32))
            return FALSE;

        checksum     = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
        security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
        secdir       = nt_header.nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
    }
    else if (nt_header.nt32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
    {
        if (bytes_read < sizeof(nt_header.nt64))
            return FALSE;

        checksum     = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);
        security_dir = dos_header.e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
        secdir       = nt_header.nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
    }
    else
        return FALSE;

    if (secdir.VirtualAddress < security_dir + sizeof(IMAGE_DATA_DIRECTORY))
        return FALSE;
    if (secdir.VirtualAddress > file_size.QuadPart)
        return FALSE;
    if (secdir.VirtualAddress + secdir.Size != file_size.QuadPart)
        return FALSE;

    if (!hash_file_data( file, 0, checksum, hash )) return FALSE;
    if (!hash_file_data( file, checksum + sizeof(DWORD), security_dir, hash )) return FALSE;
    if (!hash_file_data( file, security_dir + sizeof(IMAGE_DATA_DIRECTORY), secdir.VirtualAddress, hash ))
        return FALSE;

    return TRUE;
}

(2)对于签名中的hash 应该提取的oid是 SpcIndirectDataContext的OID应为1.3.6.1.4.1.311.2.1.4,而不是属性中的消息摘要,这个字段如果不好找,那就再签名数据部分搜索hash就行了,只要签名有效并包含hash,可以粗略认为这个PE文件的签名是存在的

更多推荐