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)));
+ }
+ }
+}