in net/JetBrains.FormatRipper/src/Pe/PeSignatureInjector.cs [22:121]
public static unsafe void InjectSignature(Stream sourceStream, Stream outputStream, IPeSignatureTransferData signatureTransferData)
{
if (!outputStream.CanWrite) throw new ArgumentException("Provided stream is not writeable");
sourceStream.Position = 0;
IMAGE_DOS_HEADER ids;
StreamUtil.ReadBytes(sourceStream, (byte*)&ids, sizeof(IMAGE_DOS_HEADER));
if (MemoryUtil.GetLeU2(ids.e_magic) != Magic.IMAGE_DOS_SIGNATURE)
throw new FormatException("Invalid DOS magic");
sourceStream.Position = MemoryUtil.GetLeU4(ids.e_lfanew);
uint peMagic;
StreamUtil.ReadBytes(sourceStream, (byte*)&peMagic, sizeof(uint));
if (MemoryUtil.GetLeU4(peMagic) != Magic.IMAGE_NT_SIGNATURE)
throw new FormatException("Invalid PE magic");
long imageFileHeaderPosition = sourceStream.Position;
sourceStream.Position = 0;
StreamUtil.CopyBytes(sourceStream, outputStream, imageFileHeaderPosition);
IMAGE_FILE_HEADER ifh;
StreamUtil.ReadBytes(sourceStream, (byte*)&ifh, sizeof(IMAGE_FILE_HEADER));
ifh.TimeDateStamp = MemoryUtil.GetLeU4(signatureTransferData.TimeDateStamp);
StreamUtil.WriteBytes(outputStream, (byte*)&ifh, sizeof(IMAGE_FILE_HEADER));
ushort iohMagic;
StreamUtil.ReadBytes(sourceStream, (byte*)&iohMagic, sizeof(ushort));
StreamUtil.WriteBytes(outputStream, (byte*)&iohMagic, sizeof(ushort));
uint numberOfRvaAndSizes = 0;
switch (MemoryUtil.GetLeU2(iohMagic))
{
case Magic.IMAGE_NT_OPTIONAL_HDR32_MAGIC:
{
if (MemoryUtil.GetLeU4(ifh.SizeOfOptionalHeader) < sizeof(IMAGE_OPTIONAL_HEADER32))
throw new FormatException("Invalid 32-bit option header size");
IMAGE_OPTIONAL_HEADER32 ioh;
StreamUtil.ReadBytes(sourceStream, (byte*)&ioh, sizeof(IMAGE_OPTIONAL_HEADER32));
numberOfRvaAndSizes = Math.Max(MemoryUtil.GetLeU4(ioh.NumberOfRvaAndSizes), ImageDirectory.IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
ioh.CheckSum = MemoryUtil.GetLeU4(signatureTransferData.CheckSum);
StreamUtil.WriteBytes(outputStream, (byte*)&ioh, sizeof(IMAGE_OPTIONAL_HEADER32));
}
break;
case Magic.IMAGE_NT_OPTIONAL_HDR64_MAGIC:
{
if (MemoryUtil.GetLeU4(ifh.SizeOfOptionalHeader) < sizeof(IMAGE_OPTIONAL_HEADER64))
throw new FormatException("Invalid 64-bit option header size");
IMAGE_OPTIONAL_HEADER64 ioh;
StreamUtil.ReadBytes(sourceStream, (byte*)&ioh, sizeof(IMAGE_OPTIONAL_HEADER64));
numberOfRvaAndSizes = Math.Max(MemoryUtil.GetLeU4(ioh.NumberOfRvaAndSizes), ImageDirectory.IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
ioh.CheckSum = MemoryUtil.GetLeU4(signatureTransferData.CheckSum);
StreamUtil.WriteBytes(outputStream, (byte*)&ioh, sizeof(IMAGE_OPTIONAL_HEADER64));
}
break;
default:
throw new FormatException("Unsupported PE image optional header");
}
long existingSignatureOffset = 0;
int rvaSize = checked((int)numberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY));
fixed (IMAGE_DATA_DIRECTORY* iddsBuf = new IMAGE_DATA_DIRECTORY[numberOfRvaAndSizes])
{
StreamUtil.ReadBytes(sourceStream, (byte*)iddsBuf, rvaSize);
existingSignatureOffset = MemoryUtil.GetLeU4(iddsBuf[ImageDirectory.IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress);
iddsBuf[ImageDirectory.IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = MemoryUtil.GetLeU4(signatureTransferData.SignatureBlobOffset);
iddsBuf[ImageDirectory.IMAGE_DIRECTORY_ENTRY_SECURITY].Size = MemoryUtil.GetLeU4(signatureTransferData.SignatureBlobSize);
StreamUtil.WriteBytes(outputStream, (byte*)iddsBuf, rvaSize);
}
long payloadEndOffset = existingSignatureOffset != 0 ? existingSignatureOffset : sourceStream.Length;
long signaturePadding = signatureTransferData.SignatureBlobOffset - payloadEndOffset;
if (signaturePadding < 0)
throw new SignatureInjectionException($"Target file content length ({payloadEndOffset} bytes) is bigger than the desired signature start offset ({signatureTransferData.SignatureBlobOffset} bytes).");
if (signaturePadding >= SignatureAlignment)
throw new SignatureInjectionException($"The difference between unsigned file size ({payloadEndOffset} bytes) and the desired signature start offset ({signatureTransferData.SignatureBlobOffset} bytes) is bigger than maximum allowed padding size {SignatureAlignment-1} bytes");
StreamUtil.CopyBytes(sourceStream, outputStream, payloadEndOffset - sourceStream.Position);
if (signaturePadding > 0)
{
var padding = new byte[signaturePadding];
outputStream.Write(padding, 0, padding.Length);
}
WIN_CERTIFICATE wc = new WIN_CERTIFICATE()
{
dwLength = MemoryUtil.GetLeU4(signatureTransferData.SignatureBlobSize),
wRevision = MemoryUtil.GetLeU2(signatureTransferData.CertificateRevision),
wCertificateType = MemoryUtil.GetLeU2(signatureTransferData.CertificateType),
};
StreamUtil.WriteBytes(outputStream, (byte*)&wc, sizeof(WIN_CERTIFICATE));
outputStream.Write(signatureTransferData.SignatureBlob, 0, signatureTransferData.SignatureBlob.Length);
}