using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using dnlib.DotNet; using dnlib.DotNet.Writer; using dnlib.IO; using dnlib.PE; namespace dnlib.Protection { public enum Algorithm { None, Custom, } /// /// /// public class EncryptionInfo { public const int KeyLength = 256; public Algorithm algorithm; public int version; public byte[] key; // 256 bytes public byte[] headerEncOpCodes; public byte[] stringEncOpCodes; public byte[] blobEncOpCodes; public byte[] userStringEncOpCodes; public byte[] lazyUserStringEncOpCodes; public byte[] tableEncOpCodes; public byte[] lazyTableEncOpCodes; public byte[] methodBoyEncOpCodes; private static byte[] originalSignature { get; } = Encoding.UTF8.GetBytes("Hello, HybridCLR"); public byte[] encryptedSignature; /// /// /// /// public uint GetVirtualSize() => 4 + 4 + KeyLength + 4 + GetAlignedLength(headerEncOpCodes) + 4 + GetAlignedLength(stringEncOpCodes) + 4 + GetAlignedLength(blobEncOpCodes) + 4 + GetAlignedLength(userStringEncOpCodes) + 4 + GetAlignedLength(lazyUserStringEncOpCodes) + 4 + GetAlignedLength(tableEncOpCodes) + 4 + GetAlignedLength(lazyTableEncOpCodes) + 4 + GetAlignedLength(methodBoyEncOpCodes) + 16; public static uint GetAlignedLength(byte[] bytes) { return (uint)((bytes.Length + 3) & ~0x3); } public void WriteBytesAigned(DataWriter writer, byte[] bytes) { writer.WriteUInt32((uint)bytes.Length); writer.WriteBytes(bytes); int padding = (int)(4 - (writer.Position % 4)); if (padding != 4) { writer.WriteBytes(new byte[padding]); } } public void WriteTo(DataWriter writer) { writer.WriteUInt32((uint)algorithm); writer.WriteUInt32((uint)version); Debug.Assert(key.Length == KeyLength); writer.WriteBytes(key); WriteBytesAigned(writer, headerEncOpCodes); WriteBytesAigned(writer, stringEncOpCodes); WriteBytesAigned(writer, blobEncOpCodes); WriteBytesAigned(writer, userStringEncOpCodes); WriteBytesAigned(writer, lazyUserStringEncOpCodes); WriteBytesAigned(writer, tableEncOpCodes); WriteBytesAigned(writer, lazyTableEncOpCodes); WriteBytesAigned(writer, methodBoyEncOpCodes); encryptedSignature = CreateEncryptedSignature(); Debug.Assert(encryptedSignature.Length == 16); writer.WriteBytes(encryptedSignature); } private byte[] CreateEncryptedSignature() { byte[] encSig = new byte[originalSignature.Length]; Array.Copy(originalSignature, encSig, originalSignature.Length); EncryptionContext.Encryption.SignatureEnc.Encrypt(encSig, 0, (uint)encSig.Length, key); return encSig; } } /// /// /// public interface IBytesEncryptor { Algorithm Algorithm { get; } Int32 AlgoVersion { get; } byte[] Encrypt(byte[] content, byte[] encryptionParam); byte[] EncryptString(string content, byte[] encryptionParam); byte[] EncryptUserString(string content, byte[] encryptionParam); byte[] EncryptBlob(byte[] content, byte[] encryptionParam); } /// /// format: /// file magic numer := 'CDPH' /// encryption_info := |algorithm : uint32_t | version: uint32_t | param: uint8_t[32]| signature: uint8_t[128]| /// cli_header := | rva: uint32_t | size: uint32_t | entryPointToken: uint32_t | /// section_count : int32_t /// section_descs := | Section { raw_offset: uint32_t | raw_size : uint32_t | rva_start: uint32_t | virtual_size: uint32_t } | ... /// secion_datas := | uint8_t[length] | ... /// public class EncryptionHeader : IChunk { public ImageCor20Header imageCor20Header; // ================= public string fileMagic = "CDPH"; public int formatVersion; public EncryptionInfo encryptionInfo; public uint entryPointToken; public RVA metadataRva; public uint metadataSize; public List sections; private FileOffset _fileOffset; /// /// /// public FileOffset FileOffset => _fileOffset; private RVA _rva; public RVA RVA => _rva; public uint CalculateAlignment() => 4; private uint _length; public uint GetFileLength() => _length; public uint GetVirtualSize() => _length; public void SetOffset(FileOffset offset, RVA rva) { _fileOffset = offset; _rva = rva; // compute length _length = (uint)Encoding.UTF8.GetByteCount(fileMagic) + 4 // formatVersion + encryptionInfo.GetVirtualSize() // encryptionInfo + 12 // cli header + 4 + 16 * (uint)sections.Count; } /// /// /// /// public void WriteTo(DataWriter writer) { writer.WriteBytes(Encoding.UTF8.GetBytes(fileMagic)); writer.WriteInt32(formatVersion); encryptionInfo.WriteTo(writer); writer.WriteInt32((int)entryPointToken); writer.WriteUInt32((uint)metadataRva); writer.WriteUInt32(metadataSize); writer.WriteUInt32((uint)sections.Count); foreach(var section in sections) { writer.WriteUInt32((uint)section.FileOffset); writer.WriteUInt32(section.GetFileLength()); writer.WriteUInt32((uint)section.RVA); writer.WriteUInt32(section.GetVirtualSize()); } } } }