diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 5c5ce3c5..18f3ec07 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -84,6 +84,10 @@ + + + + diff --git a/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs index 021e6d11..b09a34fb 100644 --- a/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/CodeVeil/Deobfuscator.cs @@ -205,6 +205,8 @@ namespace de4dot.code.deobfuscators.CodeVeil { proxyDelegateFinder.initialize(); proxyDelegateFinder.find(); + + new ResourceDecrypter(module).decrypt(); } void removeTamperDetection() { diff --git a/de4dot.code/deobfuscators/CodeVeil/ResourceConverter.cs b/de4dot.code/deobfuscators/CodeVeil/ResourceConverter.cs new file mode 100644 index 00000000..2c79c9f9 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/ResourceConverter.cs @@ -0,0 +1,149 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.IO; +using Mono.Cecil; +using de4dot.code.resources; + +namespace de4dot.code.deobfuscators.CodeVeil { + class ResourceConverter { + ModuleDefinition module; + ResourceInfo[] infos; + ResourceDataCreator dataCreator; + + public ResourceConverter(ModuleDefinition module, ResourceInfo[] infos) { + this.module = module; + this.dataCreator = new ResourceDataCreator(module); + this.infos = infos; + } + + public byte[] convert() { + var resources = new ResourceElementSet(); + foreach (var info in infos) + resources.add(convert(info)); + + var memStream = new MemoryStream(); + ResourceWriter.write(module, memStream, resources); + return memStream.ToArray(); + } + + ResourceElement convert(ResourceInfo info) { + var reader = info.dataReader; + reader.BaseStream.Position = info.offset; + + IResourceData resourceData; + int type = (info.flags & 0x7F); + switch (type) { + case 1: // bool + resourceData = dataCreator.create(reader.ReadBoolean()); + break; + + case 2: // byte + resourceData = dataCreator.create(reader.ReadByte()); + break; + + case 3: // byte[] + resourceData = dataCreator.create(reader.ReadBytes(info.length)); + break; + + case 4: // char[] + resourceData = dataCreator.create(reader.ReadChars(info.length)); + break; + + case 5: // sbyte + resourceData = dataCreator.create(reader.ReadSByte()); + break; + + case 6: // char + resourceData = dataCreator.create(reader.ReadChar()); + break; + + case 7: // decimal + resourceData = dataCreator.create(reader.ReadDecimal()); + break; + + case 8: // double + resourceData = dataCreator.create(reader.ReadDouble()); + break; + + case 9: // short + resourceData = dataCreator.create(reader.ReadInt16()); + break; + + case 10: // int + resourceData = dataCreator.create(reader.ReadInt32()); + break; + + case 11: // long + resourceData = dataCreator.create(reader.ReadInt64()); + break; + + case 12: // float + resourceData = dataCreator.create(reader.ReadSingle()); + break; + + case 13: // string + resourceData = dataCreator.create(reader.ReadString()); + break; + + case 14: // ushort + resourceData = dataCreator.create(reader.ReadUInt16()); + break; + + case 15: // uint + resourceData = dataCreator.create(reader.ReadUInt32()); + break; + + case 16: // ulong + resourceData = dataCreator.create(reader.ReadUInt64()); + break; + + case 17: // DateTime + resourceData = dataCreator.create(DateTime.FromBinary(reader.ReadInt64())); + break; + + case 18: // TimeSpan + resourceData = dataCreator.create(TimeSpan.FromTicks(reader.ReadInt64())); + break; + + case 19: // Icon + resourceData = dataCreator.createIcon(reader.ReadBytes(info.length)); + break; + + case 20: // Image + resourceData = dataCreator.createImage(reader.ReadBytes(info.length)); + break; + + case 31: // binary + resourceData = dataCreator.createSerialized(reader.ReadBytes(info.length)); + break; + + case 21: // Point (CV doesn't restore this type) + default: + throw new Exception("Unknown type"); + } + + return new ResourceElement() { + Name = info.name, + ResourceData = resourceData, + }; + } + } +} diff --git a/de4dot.code/deobfuscators/CodeVeil/ResourceDecrypter.cs b/de4dot.code/deobfuscators/CodeVeil/ResourceDecrypter.cs new file mode 100644 index 00000000..49c62ac9 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/ResourceDecrypter.cs @@ -0,0 +1,70 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.IO; +using Mono.Cecil; + +namespace de4dot.code.deobfuscators.CodeVeil { + class ResourceDecrypter { + ModuleDefinition module; + + public ResourceDecrypter(ModuleDefinition module) { + this.module = module; + } + + public void decrypt() { + for (int i = 0; i < module.Resources.Count; i++) { + var resource = module.Resources[i] as EmbeddedResource; + if (resource == null) + continue; + + var decrypted = decrypt(resource.GetResourceStream()); + if (decrypted == null) + continue; + + module.Resources[i] = new EmbeddedResource(resource.Name, resource.Attributes, decrypted); + } + } + + byte[] decrypt(Stream stream) { + try { + stream.Position = 0; + var reader = new BinaryReader(stream); + uint sig = reader.ReadUInt32(); + if (sig == 0xBEEFCACE) + return decryptBeefcace(reader); + //TODO: Decrypt the other type + return null; + } + catch (ApplicationException) { + return null; + } + catch (Exception ex) { + Log.w("Got an exception when decrypting resources: {0}", ex.GetType()); + return null; + } + } + + byte[] decryptBeefcace(BinaryReader reader) { + var resourceReader = new ResourceReader(reader); + return new ResourceConverter(module, resourceReader.read()).convert(); + } + } +} diff --git a/de4dot.code/deobfuscators/CodeVeil/ResourceInfo.cs b/de4dot.code/deobfuscators/CodeVeil/ResourceInfo.cs new file mode 100644 index 00000000..291c5765 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/ResourceInfo.cs @@ -0,0 +1,41 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.IO; + +namespace de4dot.code.deobfuscators.CodeVeil { + class ResourceInfo { + public string name; + public byte flags; + public int offset; + public int length; + public BinaryReader dataReader; + public ResourceInfo(string name, byte flags, int offset, int length) { + this.name = name; + this.flags = flags; + this.offset = offset; + this.length = length; + } + + public override string ToString() { + return string.Format("{0:X2} {1:X8} {2} {3}", flags, offset, length, name); + } + } +} diff --git a/de4dot.code/deobfuscators/CodeVeil/ResourceReader.cs b/de4dot.code/deobfuscators/CodeVeil/ResourceReader.cs new file mode 100644 index 00000000..f8e4d198 --- /dev/null +++ b/de4dot.code/deobfuscators/CodeVeil/ResourceReader.cs @@ -0,0 +1,128 @@ +/* + Copyright (C) 2011-2012 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace de4dot.code.deobfuscators.CodeVeil { + class ResourceReader { + BinaryReader reader; + string resourceReader; + string resourceSet; + + public string ResourceReaderName { + get { return resourceReader; } + } + + public string ResourceSetName { + get { return resourceSet; } + } + + public ResourceReader(Stream stream) { + stream.Position = 0; + reader = new BinaryReader(stream); + } + + public ResourceReader(BinaryReader reader) { + reader.BaseStream.Position = 0; + this.reader = reader; + } + + public ResourceInfo[] read() { + if (reader.ReadUInt32() != 0xBEEFCACE) + throw new ApplicationException("Invalid magic"); + if (reader.ReadUInt32() <= 0) + throw new ApplicationException("Invalid number"); + reader.ReadUInt32(); + resourceReader = reader.ReadString(); + resourceSet = reader.ReadString(); + if (reader.ReadByte() != 1) + throw new ApplicationException("Invalid version"); + + int flags = reader.ReadByte(); + if ((flags & 0xFC) != 0) + throw new ApplicationException("Invalid flags"); + bool inflateData = (flags & 1) != 0; + bool encrypted = (flags & 2) != 0; + + int numResources = reader.ReadInt32(); + if (numResources < 0) + throw new ApplicationException("Invalid number of resources"); + + var infos = new ResourceInfo[numResources]; + for (int i = 0; i < numResources; i++) { + var resourceName = readResourceName(reader, encrypted); + int offset = reader.ReadInt32(); + byte resourceFlags = reader.ReadByte(); + int resourceLength = (resourceFlags & 0x80) == 0 ? -1 : reader.ReadInt32(); + infos[i] = new ResourceInfo(resourceName, resourceFlags, offset, resourceLength); + } + + var dataReader = reader; + if (encrypted) { + var key = new uint[4]; + key[0] = dataReader.ReadUInt32(); + key[1] = dataReader.ReadUInt32(); + int numDwords = dataReader.ReadInt32(); + if (numDwords < 0 || numDwords >= 0x40000000) + throw new ApplicationException("Invalid number of encrypted dwords"); + var encryptedData = new uint[numDwords]; + for (int i = 0; i < numDwords; i++) + encryptedData[i] = dataReader.ReadUInt32(); + key[2] = dataReader.ReadUInt32(); + key[3] = dataReader.ReadUInt32(); + DeobUtils.xxteaDecrypt(encryptedData, key); + byte[] decryptedData = new byte[encryptedData.Length * 4]; + Buffer.BlockCopy(encryptedData, 0, decryptedData, 0, decryptedData.Length); + dataReader = new BinaryReader(new MemoryStream(decryptedData)); + } + + if (inflateData) { + var data = dataReader.ReadBytes((int)(dataReader.BaseStream.Length - dataReader.BaseStream.Position)); + data = DeobUtils.inflate(data, true); + dataReader = new BinaryReader(new MemoryStream(data)); + } + + foreach (var info in infos) + info.dataReader = dataReader; + + return infos; + } + + static string readResourceName(BinaryReader reader, bool encrypted) { + if (!encrypted) + return reader.ReadString(); + + int len = reader.ReadInt32(); + if (len < 0) + throw new ApplicationException("Invalid string length"); + var sb = new StringBuilder(len); + for (int i = 0; i < len; i++) + sb.Append((char)rol3(reader.ReadChar())); + return sb.ToString(); + } + + static char rol3(char c) { + ushort s = (ushort)c; + return (char)((s << 3) | (s >> (16 - 3))); + } + } +}