I'm trying to sign an existing Portable Executable manually.
I'm following instructions found in this document:
The following code tries to get the part-to-be-hashed from the image:
// Variables
// full: vector<char> holding the image
// d: vector<char> where to store the data-to-be-hashed
// sections: vector of the sections, ensuring size > 0
// nt/pnt* : pointer inside full that points to the beginning of NT header
// Sort Sections
std::sort(sections.begin(), sections.end(), [](const section& s1, const section& s2) -> bool
{
if (s1.sec->PointerToRawData < s2.sec->PointerToRawData)
return true;
return false;
});
// Up to where?
size_t BytesUpToLastSection = ((char*)(sections[sections.size() - 1].sec) - full.data()) + sizeof(image_section_header);
d.resize(BytesUpToLastSection);
memcpy(d.data(), full.data(), BytesUpToLastSection);
// We remove the certificate table entry (8 bytes)
size_t offset = 0;
if (nt.Is32())
{
offset = offsetof(optional_header_32, DataDirectory[DIR_SECURITY]);
}
else
{
offset = offsetof(optional_header_64, DataDirectory[DIR_SECURITY]);
}
offset += sizeof(nt.FileHeader) + sizeof(nt.Signature);
offset += pnt - full.data();
d.erase(d.begin() + offset, d.begin() + offset + 8);
// We remove the checksum (4 bytes)
if (nt.Is32())
offset = offsetof(optional_header_32,CheckSum);
else
offset = offsetof(optional_header_64,CheckSum);
offset += sizeof(nt.FileHeader) + sizeof(nt.Signature);
offset += pnt - full.data();
d.erase(d.begin() + offset, d.begin() + offset + 4);
// Counter
size_t SUM_OF_BYTES_HASHED = 0;
if (nt.Is32())
SUM_OF_BYTES_HASHED = std::get<optional_header_32>(nt.OptionalHeader).SizeOfHeaders;
else
SUM_OF_BYTES_HASHED = std::get<optional_header_64>(nt.OptionalHeader).SizeOfHeaders;
for (auto& ss : sections)
{
if (ss.sectionData.sz == 0)
continue;
s = d.size();
d.resize(d.size() + ss.sectionData.sz);
memcpy(d.data() + s, ss.sectionData.p, ss.sectionData.sz);
SUM_OF_BYTES_HASHED += ss.sec->SizeOfRawData;
}
size_t FILE_SIZE = full.size();
if (FILE_SIZE > SUM_OF_BYTES_HASHED)
{
// Not entering here, test executable does not have extra data
}
There must be a problem somewhere. Signing this data and then updating the executable Certifcate Entry and appending the PCKS#7 signature results in an executable that is not recognized by Windows. Right click-> "Invalid Signature".
When comparing with the result of signtool.exe
, the signature is different. When I try to verify this signature with CryptVerifyDetachedMessageSignature
, there's an error 0x80091007 which means that the hash is incorrect.
Which means that I don't calculate correctly the "what to be signed" buffer. What do I miss?
I even hardcoded the removal of the entries:
d = full;
d.erase(d.begin() + 296, d.begin() + 296 + 8);
d.erase(d.begin() + 216, d.begin() + 216 + 4);
Thanks a lot.
Signature (Image Only) After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte signature that identifies the file as a PE format image file. This signature is "PE\0\0" (the letters "P" and "E" followed by two null bytes).
The PE entry point is defined in the IMAGE_OPTIONAL_HEADER structure, in the AddressOfEntryPoint field: A pointer to the entry point function, relative to the image base address. For executable files, this is the starting address. For device drivers, this is the address of the initialization function.
The Portable Executable (PE) format is a file format for executables, object code, DLLs and others used in 32-bit and 64-bit versions of Windows operating systems. The PE format is a data structure that encapsulates the information necessary for the Windows OS loader to manage the wrapped executable code.
The PE file format is a data structure that contains the information necessary for the Windows OS loader to manage the wrapped executable code. Nearly every file with executable code that is loaded by Windows is in the PE file format, though some legacy file formats do appear on rare occasion in malware.
I found the solution.
The signature inside the PE is not a typical PKCS#7, it contains also specific authenticated and unauthenticated attributes described in the document.
Once these are satisfied, the signature is OK. However I can't use CAdES because Windows will not accept any other authenticated attributed in the list, which is required for CAdES to be validated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With