/// <inheritdoc /> void IModuleWriterListener.OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { if (evt == ModuleWriterEvent.PESectionsCreated) NativeEraser.Erase(writer as NativeModuleWriter, writer.Module as ModuleDefMD); if (OnWriterEvent != null) { OnWriterEvent(writer, new ModuleWriterListenerEventArgs(evt)); } }
public void PrepareEncryptNativeMethods(ModuleWriterBase moduleWriter) { if (methodToNativeMethod.Count == 0) return; validNativeMethods = new List<MethodDef>(methodToNativeMethod.Count); int len = 12; foreach (var kv in methodToNativeMethod) { if (kv.Key.DeclaringType == null) continue; // Method was removed if (kv.Key.DeclaringType.Module != module) continue; // method.DeclaringType was removed validNativeMethods.Add(kv.Key); len += 3 * 4 + kv.Value.Length; } if (validNativeMethods.Count == 0) return; len = (len & ~15) + 16; encryptedResource.Resource.Data = MemoryImageStream.Create(new byte[len]); }
public void EncryptNativeMethods(ModuleWriterBase moduleWriter) { if (validNativeMethods == null || validNativeMethods.Count == 0) return; Logger.v("Encrypting native methods"); var stream = new MemoryStream(); var writer = new BinaryWriter(stream); writer.Write((uint)0); // patch count writer.Write((uint)0); // mode writer.Write(validNativeMethods.Count); int index = 0; foreach (var method in validNativeMethods) { var code = methodToNativeMethod[method]; var mb = moduleWriter.MetaData.GetMethodBody(method); if (mb == null) { Logger.e("Could not find method body for method {0} ({1:X8})", method, method.MDToken.Raw); continue; } uint codeRva = (uint)mb.RVA; if (mb.IsTiny) codeRva++; else codeRva += (uint)(4 * (mb.Code[1] >> 4)); Logger.v("Native method {0:X8}, code RVA {1:X8}", new MDToken(Table.Method, moduleWriter.MetaData.GetRid(method)).Raw, codeRva); writer.Write(codeRva); writer.Write(0x70000000 + index++); writer.Write(code.Length); writer.Write(code); } if (index != 0) Logger.n("Re-encrypted {0}/{1} native methods", index, totalEncryptedNativeMethods); var resourceChunk = moduleWriter.MetaData.GetChunk(encryptedResource.Resource); var resourceData = resourceChunk.Data; var encrypted = stream.ToArray(); XorEncrypt(encrypted); encrypted = encryptedResource.Encrypt(encrypted); if (encrypted.Length != resourceData.Length) Logger.e("Encrypted native methods array is not same size as original array"); Array.Copy(encrypted, resourceData, resourceData.Length); }
public override void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { if (!options.DecryptMethods || !methodsDecrypter.HasNativeMethods) return; switch (evt) { case ModuleWriterEvent.Begin: // The decrypter assumes RVAs are unique so don't share any method bodies writer.TheOptions.ShareMethodBodies = false; break; case ModuleWriterEvent.MDBeginAddResources: methodsDecrypter.PrepareEncryptNativeMethods(writer); break; case ModuleWriterEvent.BeginWriteChunks: methodsDecrypter.EncryptNativeMethods(writer); break; } }
void IModuleWriterListener.OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { ThrowIfCanceled(); ((ModuleFileProgress)fileProgress).CurrentEventIndex = evt - ModuleWriterEvent.Begin; Debug.Assert(((ModuleFileProgress)fileProgress).CurrentEventIndex >= 0); NotifyProgressUpdated(); }
void EncryptSection(ModuleWriterBase writer) { Stream stream = writer.DestinationStream; var reader = new BinaryReader(writer.DestinationStream); stream.Position = 0x3C; stream.Position = reader.ReadUInt32(); stream.Position += 6; ushort sections = reader.ReadUInt16(); stream.Position += 0xc; ushort optSize = reader.ReadUInt16(); stream.Position += 2 + optSize; uint encLoc = 0, encSize = 0; int origSects = -1; if (writer is NativeModuleWriter && writer.Module is ModuleDefMD) origSects = ((ModuleDefMD)writer.Module).MetaData.PEImage.ImageSectionHeaders.Count; for (int i = 0; i < sections; i++) { uint nameHash; if (origSects > 0) { origSects--; stream.Write(new byte[8], 0, 8); nameHash = 0; } else nameHash = reader.ReadUInt32() * reader.ReadUInt32(); stream.Position += 8; if (nameHash == name1 * name2) { encSize = reader.ReadUInt32(); encLoc = reader.ReadUInt32(); } else if (nameHash != 0) { uint sectSize = reader.ReadUInt32(); uint sectLoc = reader.ReadUInt32(); Hash(stream, reader, sectLoc, sectSize); } else stream.Position += 8; stream.Position += 16; } uint[] key = DeriveKey(); encSize >>= 2; stream.Position = encLoc; var result = new uint[encSize]; for (uint i = 0; i < encSize; i++) { uint data = reader.ReadUInt32(); result[i] = data ^ key[i & 0xf]; key[i & 0xf] = (key[i & 0xf] ^ data) + 0x3dbb2819; } var byteResult = new byte[encSize << 2]; Buffer.BlockCopy(result, 0, byteResult, 0, byteResult.Length); stream.Position = encLoc; stream.Write(byteResult, 0, byteResult.Length); }
void IModuleWriterListener.OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { ThrowIfCanceled(); currentEventIndex = evt - ModuleWriterEvent.Begin; Debug.Assert(currentEventIndex >= 0); if (OnProgressUpdated != null) OnProgressUpdated(this, EventArgs.Empty); }
void CreateSection(ModuleWriterBase writer) { // move some PE parts to separate section to prevent it from being hashed var peSection = new PESection("", 0x60000020); bool moved = false; uint alignment; if (writer.StrongNameSignature != null) { alignment = writer.TextSection.Remove(writer.StrongNameSignature).Value; peSection.Add(writer.StrongNameSignature, alignment); moved = true; } var managedWriter = writer as ModuleWriter; if (managedWriter != null) { if (managedWriter.ImportAddressTable != null) { alignment = writer.TextSection.Remove(managedWriter.ImportAddressTable).Value; peSection.Add(managedWriter.ImportAddressTable, alignment); moved = true; } if (managedWriter.StartupStub != null) { alignment = writer.TextSection.Remove(managedWriter.StartupStub).Value; peSection.Add(managedWriter.StartupStub, alignment); moved = true; } } if (moved) writer.Sections.Add(peSection); // create section var nameBuffer = new byte[8]; nameBuffer[0] = (byte)(name1 >> 0); nameBuffer[1] = (byte)(name1 >> 8); nameBuffer[2] = (byte)(name1 >> 16); nameBuffer[3] = (byte)(name1 >> 24); nameBuffer[4] = (byte)(name2 >> 0); nameBuffer[5] = (byte)(name2 >> 8); nameBuffer[6] = (byte)(name2 >> 16); nameBuffer[7] = (byte)(name2 >> 24); var newSection = new PESection(Encoding.ASCII.GetString(nameBuffer), 0xE0000040); writer.Sections.Insert(random.NextInt32(writer.Sections.Count), newSection); // random padding at beginning to prevent revealing hash key newSection.Add(new ByteArrayChunk(random.NextBytes(0x10)), 0x10); // create index var bodyIndex = new JITBodyIndex(methods.Select(method => writer.MetaData.GetToken(method).Raw)); newSection.Add(bodyIndex, 0x10); // save methods foreach (MethodDef method in methods.WithProgress(context.Logger)) { if (!method.HasBody) continue; MDToken token = writer.MetaData.GetToken(method); var jitBody = new JITMethodBody(); var bodyWriter = new JITMethodBodyWriter(writer.MetaData, method.Body, jitBody, random.NextUInt32(), writer.MetaData.KeepOldMaxStack || method.Body.KeepOldMaxStack); bodyWriter.Write(); jitBody.Serialize(token.Raw, key, fieldLayout); bodyIndex.Add(token.Raw, jitBody); method.Body = NopBody; writer.MetaData.TablesHeap.MethodTable[token.Rid].ImplFlags |= (ushort)MethodImplAttributes.NoInlining; context.CheckCancellation(); } bodyIndex.PopulateSection(newSection); // padding to prevent bad size due to shift division newSection.Add(new ByteArrayChunk(new byte[4]), 4); }
void CreateSections(ModuleWriterBase writer) { var nameBuffer = new byte[8]; nameBuffer[0] = (byte)(name1 >> 0); nameBuffer[1] = (byte)(name1 >> 8); nameBuffer[2] = (byte)(name1 >> 16); nameBuffer[3] = (byte)(name1 >> 24); nameBuffer[4] = (byte)(name2 >> 0); nameBuffer[5] = (byte)(name2 >> 8); nameBuffer[6] = (byte)(name2 >> 16); nameBuffer[7] = (byte)(name2 >> 24); var newSection = new PESection(Encoding.ASCII.GetString(nameBuffer), 0xE0000040); writer.Sections.Insert(0, newSection); // insert first to ensure proper RVA uint alignment; alignment = writer.TextSection.Remove(writer.MetaData).Value; writer.TextSection.Add(writer.MetaData, alignment); alignment = writer.TextSection.Remove(writer.NetResources).Value; writer.TextSection.Add(writer.NetResources, alignment); alignment = writer.TextSection.Remove(writer.Constants).Value; newSection.Add(writer.Constants, alignment); // move some PE parts to separate section to prevent it from being hashed var peSection = new PESection("", 0x60000020); bool moved = false; if (writer.StrongNameSignature != null) { alignment = writer.TextSection.Remove(writer.StrongNameSignature).Value; peSection.Add(writer.StrongNameSignature, alignment); moved = true; } var managedWriter = writer as ModuleWriter; if (managedWriter != null) { if (managedWriter.ImportAddressTable != null) { alignment = writer.TextSection.Remove(managedWriter.ImportAddressTable).Value; peSection.Add(managedWriter.ImportAddressTable, alignment); moved = true; } if (managedWriter.StartupStub != null) { alignment = writer.TextSection.Remove(managedWriter.StartupStub).Value; peSection.Add(managedWriter.StartupStub, alignment); moved = true; } } if (moved) writer.Sections.Add(peSection); // move encrypted methods var encryptedChunk = new MethodBodyChunks(writer.TheOptions.ShareMethodBodies); newSection.Add(encryptedChunk, 4); foreach (MethodDef method in methods) { if (!method.HasBody) continue; MethodBody body = writer.MetaData.GetMethodBody(method); bool ok = writer.MethodBodies.Remove(body); encryptedChunk.Add(body); } // padding to prevent bad size due to shift division newSection.Add(new ByteArrayChunk(new byte[4]), 4); }
public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { if (evt == ModuleWriterEvent.MDBeginCreateTables) { // Add key signature uint sigBlob = writer.MetaData.BlobHeap.Add(ctx.KeySig); uint sigRid = writer.MetaData.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(sigBlob)); Debug.Assert(sigRid == 1); uint sigToken = 0x11000000 | sigRid; ctx.KeyToken = sigToken; MutationHelper.InjectKey(writer.Module.EntryPoint, 2, (int)sigToken); } else if (evt == ModuleWriterEvent.MDBeginAddResources) { // Compute hash byte[] hash = SHA1.Create().ComputeHash(ctx.OriginModule); uint hashBlob = writer.MetaData.BlobHeap.Add(hash); MDTable<RawFileRow> fileTbl = writer.MetaData.TablesHeap.FileTable; uint fileRid = fileTbl.Add(new RawFileRow( (uint)FileAttributes.ContainsMetaData, writer.MetaData.StringsHeap.Add("koi"), hashBlob)); uint impl = CodedToken.Implementation.Encode(new MDToken(Table.File, fileRid)); // Add resources MDTable<RawManifestResourceRow> resTbl = writer.MetaData.TablesHeap.ManifestResourceTable; foreach (var resource in ctx.ManifestResources) resTbl.Add(new RawManifestResourceRow(resource.Item1, resource.Item2, writer.MetaData.StringsHeap.Add(resource.Item3), impl)); // Add exported types var exTbl = writer.MetaData.TablesHeap.ExportedTypeTable; foreach (var type in ctx.OriginModuleDef.GetTypes()) { if (!type.IsVisibleOutside()) continue; exTbl.Add(new RawExportedTypeRow((uint)type.Attributes, 0, writer.MetaData.StringsHeap.Add(type.Name), writer.MetaData.StringsHeap.Add(type.Namespace), impl)); } } }
/// <inheritdoc /> void IModuleWriterListener.OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { if (OnWriterEvent != null) { OnWriterEvent(writer, new ModuleWriterListenerEventArgs(evt)); } }
// Gets notified during module writing public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { switch (evt) { case ModuleWriterEvent.PESectionsCreated: // Add a PE section var sect1 = new PESection(".dummy", 0x40000040); writer.Sections.Add(sect1); // Let's add data sect1.Add(new ByteArrayChunk(new byte[123]), 4); sect1.Add(new ByteArrayChunk(new byte[10]), 4); break; case ModuleWriterEvent.MDEndCreateTables: // All types, methods etc have gotten their new RIDs. Let's print the new values Console.WriteLine("Old -> new type and method tokens"); foreach (var type in writer.Module.GetTypes()) { Console.WriteLine("TYPE: {0:X8} -> {1:X8} {2}", type.MDToken.Raw, new MDToken(Table.TypeDef, writer.MetaData.GetRid(type)).Raw, type.FullName); foreach (var method in type.Methods) Console.WriteLine(" METH: {0:X8} -> {1:X8} {2}", method.MDToken.Raw, new MDToken(Table.Method, writer.MetaData.GetRid(method)).Raw, method.FullName); } break; default: break; } }
void PrintTokens(ModuleWriterBase writer) { if (Logger.Instance.IgnoresEvent(LoggerEvent.Verbose)) return; var md = writer.MetaData; Logger.v("Old -> new tokens: Assembly: {0} (module: {1})", module.Assembly, module.Location); Logger.Instance.Indent(); foreach (var type in module.GetTypes()) { uint newRid; newRid = md.GetRid(type); if (newRid == 0) continue; Logger.v("{0:X8} -> {1:X8} Type: {2}", type.MDToken.ToUInt32(), new MDToken(Table.TypeDef, newRid).ToUInt32(), Utils.RemoveNewlines(type)); Logger.Instance.Indent(); foreach (var method in type.Methods) { newRid = md.GetRid(method); if (newRid == 0) continue; Logger.v("{0:X8} -> {1:X8} Method: {2}", method.MDToken.ToUInt32(), new MDToken(Table.Method, newRid).ToUInt32(), Utils.RemoveNewlines(method)); } foreach (var field in type.Fields) { newRid = md.GetRid(field); if (newRid == 0) continue; Logger.v("{0:X8} -> {1:X8} Field: {2}", field.MDToken.ToUInt32(), new MDToken(Table.Field, newRid).ToUInt32(), Utils.RemoveNewlines(field)); } foreach (var prop in type.Properties) { newRid = md.GetRid(prop); if (newRid == 0) continue; Logger.v("{0:X8} -> {1:X8} Property: {2}", prop.MDToken.ToUInt32(), new MDToken(Table.Property, newRid).ToUInt32(), Utils.RemoveNewlines(prop)); } foreach (var evt in type.Events) { newRid = md.GetRid(evt); if (newRid == 0) continue; Logger.v("{0:X8} -> {1:X8} Event: {2}", evt.MDToken.ToUInt32(), new MDToken(Table.Event, newRid).ToUInt32(), Utils.RemoveNewlines(evt)); } Logger.Instance.DeIndent(); } Logger.Instance.DeIndent(); }
public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { if (otherListener != null) otherListener.OnWriterEvent(writer, evt); if (evt == ModuleWriterEvent.End) PrintTokens(writer); }