PE嵌入式签名检测方法
(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];}elsereturn 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文件的签名是存在的