using System; using System.Collections.Generic; using System.Text; using dnlib.DotNet; using dnlib.DotNet.MD; using dnlib.DotNet.Writer; using dnlib.PE; using dnlib.W32Resources; using ImageCor20Header = dnlib.DotNet.Writer.ImageCor20Header; namespace dnlib.Protection { /// /// /// public sealed class EncryptedModuleWriterOptions : ModuleWriterOptionsBase { public RandomEncryption encryptor; /// /// Constructor /// /// The module public EncryptedModuleWriterOptions(ModuleDef module) : base(module) { } } /// /// /// public sealed class EncryptedModuleWriter : ModuleWriterBase { readonly ModuleDef module; EncryptedModuleWriterOptions options; List sections; PESection textSection; EncryptionHeader header; /// public override ModuleDef Module => module; /// public override ModuleWriterOptionsBase TheOptions => Options; /// /// Gets/sets the writer options. This is never null /// public EncryptedModuleWriterOptions Options { get => options ??= new EncryptedModuleWriterOptions(module); set => options = value; } /// /// Gets all s. The reloc section must be the last section, so use if you need to append a section /// public override List Sections => sections; /// /// Adds to the sections list, but before the reloc section which must be last /// /// New section to add to the list public override void AddSection(PESection section) { //if (sections.Count > 0 && sections[sections.Count - 1] == relocSection) // sections.Insert(sections.Count - 1, section); //else sections.Add(section); } /// /// Gets the .text section /// public override PESection TextSection => textSection; /// /// Gets the .rsrc section or null if none /// public override PESection RsrcSection => null; /// /// Constructor /// /// The module public EncryptedModuleWriter(ModuleDef module) : this(module, null) { } /// /// Constructor /// /// The module /// Options or null public EncryptedModuleWriter(ModuleDef module, EncryptedModuleWriterOptions options) { this.module = module; this.options = options; } /// protected override long WriteImpl() { try { EncryptionContext.Encryption = options.encryptor; Initialize(); metadata.CreateTables(); return WriteFile(); } finally { EncryptionContext.Encryption = null; } } void Initialize() { CreateSections(); OnWriterEvent(ModuleWriterEvent.PESectionsCreated); CreateChunks(); OnWriterEvent(ModuleWriterEvent.ChunksCreated); AddChunksToSections(); OnWriterEvent(ModuleWriterEvent.ChunksAddedToSections); } /// protected override Win32Resources GetWin32Resources() { return null; } void CreateSections() { sections = new List(); sections.Add(textSection = new PESection(".text", 0x60000020)); } void CreateChunks() { IEncryption enc = EncryptionContext.Encryption; header = new EncryptionHeader() { formatVersion = 1, encryptionInfo = new EncryptionInfo() { algorithm = options.encryptor.Algorithm, version = options.encryptor.AlgoVersion, key = options.encryptor.EncParam, headerEncOpCodes = enc.FileHeaderEnc.GetDecryptionOpCode(), stringEncOpCodes = enc.StringEnc.GetDecryptionOpCode(), blobEncOpCodes = enc.BlobEnc.GetDecryptionOpCode(), userStringEncOpCodes = enc.UserStringEnc.GetDecryptionOpCode(), lazyUserStringEncOpCodes = enc.LazyUserStringEnc.GetDecryptionOpCode(), tableEncOpCodes = enc.TableEnc.GetDecryptionOpCode(), lazyTableEncOpCodes = enc.LazyTableEnc.GetDecryptionOpCode(), methodBoyEncOpCodes = enc.MethodBodyEnc.GetDecryptionOpCode(), }, }; CreateMetadataChunks(module); } void AddChunksToSections() { textSection.Add(constants, DEFAULT_CONSTANTS_ALIGNMENT); textSection.Add(methodBodies, DEFAULT_METHODBODIES_ALIGNMENT); textSection.Add(metadata, DEFAULT_METADATA_ALIGNMENT); } long WriteFile() { //managedExportsWriter.AddExportedMethods(metadata.ExportedMethods, GetTimeDateStamp()); //if (managedExportsWriter.HasExports) // needStartupStub = true; //OnWriterEvent(ModuleWriterEvent.BeginWritePdb); //WritePdbFile(); //OnWriterEvent(ModuleWriterEvent.EndWritePdb); metadata.OnBeforeSetOffset(); OnWriterEvent(ModuleWriterEvent.BeginCalculateRvasAndFileOffsets); var chunks = new List(); chunks.Add(header); //chunks.Add(peHeaders); //if (!managedExportsWriter.HasExports) // sections.Remove(sdataSection); //if (!(relocDirectory.NeedsRelocSection || managedExportsWriter.HasExports || needStartupStub)) // sections.Remove(relocSection); //importAddressTable.Enable = needStartupStub; //importDirectory.Enable = needStartupStub; //startupStub.Enable = needStartupStub; foreach (var section in sections) chunks.Add(section); header.sections = sections; //peHeaders.PESections = sections; //int relocIndex = sections.IndexOf(relocSection); //if (relocIndex >= 0 && relocIndex != sections.Count - 1) // throw new InvalidOperationException("Reloc section must be the last section, use AddSection() to add a section"); uint fileAlignment = 8; uint sectionAlignment = 8; CalculateRvasAndFileOffsets(chunks, 0, 0, fileAlignment, sectionAlignment); OnWriterEvent(ModuleWriterEvent.EndCalculateRvasAndFileOffsets); InitializeChunkProperties(); OnWriterEvent(ModuleWriterEvent.BeginWriteChunks); var writer = new DataWriter(destStream); WriteChunks(writer, chunks, 0, fileAlignment); long imageLength = writer.Position - destStreamBaseOffset; OnWriterEvent(ModuleWriterEvent.EndWriteChunks); //OnWriterEvent(ModuleWriterEvent.BeginStrongNameSign); //if (Options.StrongNameKey is not null) // StrongNameSign((long)strongNameSignature.FileOffset); //OnWriterEvent(ModuleWriterEvent.EndStrongNameSign); //OnWriterEvent(ModuleWriterEvent.BeginWritePEChecksum); //if (Options.AddCheckSum) // peHeaders.WriteCheckSum(writer, imageLength); //OnWriterEvent(ModuleWriterEvent.EndWritePEChecksum); return imageLength; } void InitializeChunkProperties() { header.entryPointToken = GetEntryPoint(); header.metadataRva = metadata.RVA; header.metadataSize = metadata.GetVirtualSize(); //header.imageCor20Header = imageCor20Header; //importAddressTable.ImportDirectory = importDirectory; //importDirectory.ImportAddressTable = importAddressTable; //startupStub.ImportDirectory = importDirectory; //startupStub.PEHeaders = peHeaders; //peHeaders.StartupStub = startupStub; //peHeaders.ImageCor20Header = imageCor20Header; //peHeaders.ImportAddressTable = importAddressTable; //peHeaders.ImportDirectory = importDirectory; //peHeaders.Win32Resources = win32Resources; //peHeaders.RelocDirectory = relocDirectory; //peHeaders.DebugDirectory = debugDirectory; //imageCor20Header.Metadata = metadata; //imageCor20Header.NetResources = netResources; //imageCor20Header.StrongNameSignature = strongNameSignature; //managedExportsWriter.InitializeChunkProperties(); } uint GetEntryPoint() { if (module.ManagedEntryPoint is MethodDef methodEntryPoint) return new MDToken(Table.Method, metadata.GetRid(methodEntryPoint)).Raw; //if (module.ManagedEntryPoint is FileDef fileEntryPoint) // return new MDToken(Table.File, metadata.GetRid(fileEntryPoint)).Raw; //uint nativeEntryPoint = (uint)module.NativeEntryPoint; //if (nativeEntryPoint != 0) // return nativeEntryPoint; return 0; } } }