Move .NET resources read/writer code to dnlib

This commit is contained in:
de4dot 2015-07-08 08:02:34 +02:00
parent 7a282f0962
commit 9e2a9016d2
16 changed files with 77 additions and 1035 deletions

View File

@ -338,16 +338,6 @@
<Compile Include="renamer\TypeNames.cs" />
<Compile Include="renamer\TypeRenamerState.cs" />
<Compile Include="renamer\VariableNameState.cs" />
<Compile Include="resources\BuiltInResourceData.cs" />
<Compile Include="resources\IResourceData.cs" />
<Compile Include="resources\ResourceDataCreator.cs" />
<Compile Include="resources\ResourceElement.cs" />
<Compile Include="resources\ResourceElementSet.cs" />
<Compile Include="resources\ResourceReader.cs" />
<Compile Include="resources\ResourceTypeCode.cs" />
<Compile Include="resources\ResourceWriter.cs" />
<Compile Include="resources\UserResourceData.cs" />
<Compile Include="resources\UserResourceType.cs" />
<Compile Include="SharpZipLib\Checksums\Adler32.cs" />
<Compile Include="SharpZipLib\Checksums\IChecksum.cs" />
<Compile Include="SharpZipLib\Main.cs" />

View File

@ -18,20 +18,33 @@
*/
using System;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using dnlib.IO;
using dnlib.DotNet;
using de4dot.code.resources;
using dnlib.DotNet.Resources;
namespace de4dot.code.deobfuscators.CodeVeil {
class ResourceConverter {
ModuleDefMD module;
ResourceInfo[] infos;
ResourceDataCreator dataCreator;
MyResourceDataCreator dataCreator;
sealed class MyResourceDataCreator : ResourceDataCreator {
public MyResourceDataCreator(ModuleDef module)
: base(module) {
}
protected override string GetAssemblyFullName(string simpleName) {
var asm = TheAssemblyResolver.Instance.Resolve(new AssemblyNameInfo(simpleName), Module);
return asm == null ? null : asm.FullName;
}
}
public ResourceConverter(ModuleDefMD module, ResourceInfo[] infos) {
this.module = module;
this.dataCreator = new ResourceDataCreator(module);
this.dataCreator = new MyResourceDataCreator(module);
this.infos = infos;
}
@ -65,7 +78,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
break;
case 4: // char[]
resourceData = dataCreator.Create(reader.ReadChars(info.length));
resourceData = new CharArrayResourceData(dataCreator.CreateUserResourceType(CharArrayResourceData.ReflectionTypeName), reader.ReadChars(info.length));
break;
case 5: // sbyte
@ -125,11 +138,11 @@ namespace de4dot.code.deobfuscators.CodeVeil {
break;
case 19: // Icon
resourceData = dataCreator.CreateIcon(reader.ReadBytes(info.length));
resourceData = new IconResourceData(dataCreator.CreateUserResourceType(IconResourceData.ReflectionTypeName), reader.ReadBytes(info.length));
break;
case 20: // Image
resourceData = dataCreator.CreateImage(reader.ReadBytes(info.length));
resourceData = new ImageResourceData(dataCreator.CreateUserResourceType(ImageResourceData.ReflectionTypeName), reader.ReadBytes(info.length));
break;
case 31: // binary
@ -147,4 +160,58 @@ namespace de4dot.code.deobfuscators.CodeVeil {
};
}
}
class CharArrayResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Char[],mscorlib";
char[] data;
public CharArrayResourceData(UserResourceType type, char[] data)
: base(type) {
this.data = data;
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, data);
}
public override string ToString() {
return string.Format("char[]: Length: {0}", data.Length);
}
}
class IconResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Drawing.Icon,System.Drawing";
Icon icon;
public IconResourceData(UserResourceType type, byte[] data)
: base(type) {
icon = new Icon(new MemoryStream(data));
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, icon);
}
public override string ToString() {
return string.Format("Icon: {0}", icon);
}
}
class ImageResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Drawing.Bitmap,System.Drawing";
Bitmap bitmap;
public ImageResourceData(UserResourceType type, byte[] data)
: base(type) {
bitmap = new Bitmap(Image.FromStream(new MemoryStream(data)));
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, bitmap);
}
public override string ToString() {
return "Bitmap";
}
}
}

View File

@ -25,7 +25,7 @@ using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
using de4dot.code.resources;
using dnlib.DotNet.Resources;
namespace de4dot.code.deobfuscators.CodeWall {
class AssemblyDecrypter {

View File

@ -23,7 +23,7 @@ using System.Text.RegularExpressions;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.code.renamer.asmmodules;
using de4dot.code.resources;
using dnlib.DotNet.Resources;
using de4dot.blocks;
namespace de4dot.code.renamer {

View File

@ -26,7 +26,7 @@ using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.IO;
using de4dot.blocks;
using de4dot.code.resources;
using dnlib.DotNet.Resources;
namespace de4dot.code.renamer {
public class ResourceKeysRenamer {

View File

@ -1,158 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Runtime.Serialization;
namespace de4dot.code.resources {
public class BuiltInResourceData : IResourceData {
readonly ResourceTypeCode code;
readonly object data;
public object Data {
get { return data; }
}
public ResourceTypeCode Code {
get { return code; }
}
public BuiltInResourceData(ResourceTypeCode code, object data) {
this.code = code;
this.data = data;
}
public void WriteData(BinaryWriter writer, IFormatter formatter) {
switch (code) {
case ResourceTypeCode.Null:
return;
case ResourceTypeCode.String:
writer.Write((string)data);
break;
case ResourceTypeCode.Boolean:
writer.Write((bool)data);
break;
case ResourceTypeCode.Char:
writer.Write((ushort)(char)data);
break;
case ResourceTypeCode.Byte:
writer.Write((byte)data);
break;
case ResourceTypeCode.SByte:
writer.Write((sbyte)data);
break;
case ResourceTypeCode.Int16:
writer.Write((short)data);
break;
case ResourceTypeCode.UInt16:
writer.Write((ushort)data);
break;
case ResourceTypeCode.Int32:
writer.Write((int)data);
break;
case ResourceTypeCode.UInt32:
writer.Write((uint)data);
break;
case ResourceTypeCode.Int64:
writer.Write((long)data);
break;
case ResourceTypeCode.UInt64:
writer.Write((ulong)data);
break;
case ResourceTypeCode.Single:
writer.Write((float)data);
break;
case ResourceTypeCode.Double:
writer.Write((double)data);
break;
case ResourceTypeCode.Decimal:
writer.Write((decimal)data);
break;
case ResourceTypeCode.DateTime:
writer.Write(((DateTime)data).ToBinary());
break;
case ResourceTypeCode.TimeSpan:
writer.Write(((TimeSpan)data).Ticks);
break;
case ResourceTypeCode.ByteArray:
case ResourceTypeCode.Stream:
var ary = (byte[])data;
writer.Write(ary.Length);
writer.Write(ary);
break;
default:
throw new ApplicationException("Unknown resource type code");
}
}
public override string ToString() {
switch (code) {
case ResourceTypeCode.Null:
return "NULL";
case ResourceTypeCode.String:
case ResourceTypeCode.Boolean:
case ResourceTypeCode.Char:
case ResourceTypeCode.Byte:
case ResourceTypeCode.SByte:
case ResourceTypeCode.Int16:
case ResourceTypeCode.UInt16:
case ResourceTypeCode.Int32:
case ResourceTypeCode.UInt32:
case ResourceTypeCode.Int64:
case ResourceTypeCode.UInt64:
case ResourceTypeCode.Single:
case ResourceTypeCode.Double:
case ResourceTypeCode.Decimal:
case ResourceTypeCode.DateTime:
case ResourceTypeCode.TimeSpan:
return string.Format("{0}: '{1}'", code, data);
case ResourceTypeCode.ByteArray:
case ResourceTypeCode.Stream:
var ary = data as byte[];
if (ary != null)
return string.Format("{0}: Length: {1}", code, ary.Length);
return string.Format("{0}: '{1}'", code, data);
default:
return string.Format("{0}: '{1}'", code, data);
}
}
}
}

View File

@ -1,28 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System.IO;
using System.Runtime.Serialization;
namespace de4dot.code.resources {
public interface IResourceData {
ResourceTypeCode Code { get; }
void WriteData(BinaryWriter writer, IFormatter formatter);
}
}

View File

@ -1,235 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using dnlib.DotNet;
namespace de4dot.code.resources {
public class ResourceDataCreator {
readonly ModuleDef module;
readonly ModuleDefMD moduleMD;
readonly Dictionary<string, UserResourceType> dict = new Dictionary<string, UserResourceType>(StringComparer.Ordinal);
readonly Dictionary<string, string> asmNameToAsmFullName = new Dictionary<string, string>(StringComparer.Ordinal);
public ResourceDataCreator(ModuleDef module) {
this.module = module;
this.moduleMD = module as ModuleDefMD;
}
public int Count {
get { return dict.Count; }
}
public BuiltInResourceData CreateNull() {
return new BuiltInResourceData(ResourceTypeCode.Null, null);
}
public BuiltInResourceData Create(string value) {
return new BuiltInResourceData(ResourceTypeCode.String, value);
}
public BuiltInResourceData Create(bool value) {
return new BuiltInResourceData(ResourceTypeCode.Boolean, value);
}
public BuiltInResourceData Create(char value) {
return new BuiltInResourceData(ResourceTypeCode.Char, value);
}
public BuiltInResourceData Create(byte value) {
return new BuiltInResourceData(ResourceTypeCode.Byte, value);
}
public BuiltInResourceData Create(sbyte value) {
return new BuiltInResourceData(ResourceTypeCode.SByte, value);
}
public BuiltInResourceData Create(short value) {
return new BuiltInResourceData(ResourceTypeCode.Int16, value);
}
public BuiltInResourceData Create(ushort value) {
return new BuiltInResourceData(ResourceTypeCode.UInt16, value);
}
public BuiltInResourceData Create(int value) {
return new BuiltInResourceData(ResourceTypeCode.Int32, value);
}
public BuiltInResourceData Create(uint value) {
return new BuiltInResourceData(ResourceTypeCode.UInt32, value);
}
public BuiltInResourceData Create(long value) {
return new BuiltInResourceData(ResourceTypeCode.Int64, value);
}
public BuiltInResourceData Create(ulong value) {
return new BuiltInResourceData(ResourceTypeCode.UInt64, value);
}
public BuiltInResourceData Create(float value) {
return new BuiltInResourceData(ResourceTypeCode.Single, value);
}
public BuiltInResourceData Create(double value) {
return new BuiltInResourceData(ResourceTypeCode.Double, value);
}
public BuiltInResourceData Create(decimal value) {
return new BuiltInResourceData(ResourceTypeCode.Decimal, value);
}
public BuiltInResourceData Create(DateTime value) {
return new BuiltInResourceData(ResourceTypeCode.DateTime, value);
}
public BuiltInResourceData Create(TimeSpan value) {
return new BuiltInResourceData(ResourceTypeCode.TimeSpan, value);
}
public BuiltInResourceData Create(byte[] value) {
return new BuiltInResourceData(ResourceTypeCode.ByteArray, value);
}
public BuiltInResourceData CreateStream(byte[] value) {
return new BuiltInResourceData(ResourceTypeCode.Stream, value);
}
public CharArrayResourceData Create(char[] value) {
return new CharArrayResourceData(CreateUserResourceType(CharArrayResourceData.ReflectionTypeName), value);
}
public IconResourceData CreateIcon(byte[] value) {
return new IconResourceData(CreateUserResourceType(IconResourceData.ReflectionTypeName), value);
}
public ImageResourceData CreateImage(byte[] value) {
return new ImageResourceData(CreateUserResourceType(ImageResourceData.ReflectionTypeName), value);
}
public BinaryResourceData CreateSerialized(byte[] value) {
string assemblyName, typeName;
if (!GetSerializedTypeAndAssemblyName(value, out assemblyName, out typeName))
throw new ApplicationException("Could not get serialized type name");
string fullName = string.Format("{0},{1}", typeName, assemblyName);
return new BinaryResourceData(CreateUserResourceType(fullName), value);
}
class MyBinder : SerializationBinder {
public class OkException : Exception {
public string AssemblyName { get; set; }
public string TypeName { get; set; }
}
public override Type BindToType(string assemblyName, string typeName) {
throw new OkException {
AssemblyName = assemblyName,
TypeName = typeName,
};
}
}
bool GetSerializedTypeAndAssemblyName(byte[] value, out string assemblyName, out string typeName) {
try {
var formatter = new BinaryFormatter();
formatter.Binder = new MyBinder();
formatter.Deserialize(new MemoryStream(value));
}
catch (MyBinder.OkException ex) {
assemblyName = ex.AssemblyName;
typeName = ex.TypeName;
return true;
}
catch {
}
assemblyName = null;
typeName = null;
return false;
}
public UserResourceType CreateUserResourceType(string fullName) {
UserResourceType type;
if (dict.TryGetValue(fullName, out type))
return type;
var newFullName = GetRealTypeFullName(fullName);
type = new UserResourceType(newFullName, ResourceTypeCode.UserTypes + dict.Count);
dict[fullName] = type;
dict[newFullName] = type;
return type;
}
static void SplitTypeFullName(string fullName, out string typeName, out string assemblyName) {
int index = fullName.IndexOf(',');
if (index < 0) {
typeName = fullName;
assemblyName = null;
}
else {
typeName = fullName.Substring(0, index);
assemblyName = fullName.Substring(index + 1).Trim();
}
}
string GetRealTypeFullName(string fullName) {
var newFullName = fullName;
string typeName, assemblyName;
SplitTypeFullName(fullName, out typeName, out assemblyName);
if (!string.IsNullOrEmpty(assemblyName))
assemblyName = GetRealAssemblyName(assemblyName);
if (!string.IsNullOrEmpty(assemblyName))
newFullName = string.Format("{0}, {1}", typeName, assemblyName);
return newFullName;
}
string GetRealAssemblyName(string assemblyName) {
string newAsmName;
if (!asmNameToAsmFullName.TryGetValue(assemblyName, out newAsmName))
asmNameToAsmFullName[assemblyName] = newAsmName = TryGetRealAssemblyName(assemblyName);
return newAsmName;
}
string TryGetRealAssemblyName(string assemblyName) {
var simpleName = Utils.GetAssemblySimpleName(assemblyName);
if (moduleMD != null) {
var asmRef = moduleMD.GetAssemblyRef(simpleName);
if (asmRef != null)
return asmRef.FullName;
}
var asm = TheAssemblyResolver.Instance.Resolve(new AssemblyNameInfo(simpleName), module);
return asm == null ? null : asm.FullName;
}
public List<UserResourceType> GetSortedTypes() {
var list = new List<UserResourceType>(dict.Values);
list.Sort((a, b) => ((int)a.Code).CompareTo((int)b.Code));
return list;
}
}
}

View File

@ -1,29 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
namespace de4dot.code.resources {
public class ResourceElement {
public string Name { get; set; }
public IResourceData ResourceData { get; set; }
public override string ToString() {
return string.Format("N: {0}, V: {1}", Name, ResourceData);
}
}
}

View File

@ -1,39 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace de4dot.code.resources {
public class ResourceElementSet {
Dictionary<string, ResourceElement> dict = new Dictionary<string, ResourceElement>(StringComparer.Ordinal);
public int Count {
get { return dict.Count; }
}
public IEnumerable<ResourceElement> ResourceElements {
get { return dict.Values; }
}
public void Add(ResourceElement elem) {
dict[elem.Name] = elem;
}
}
}

View File

@ -1,180 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using dnlib.DotNet;
using dnlib.IO;
namespace de4dot.code.resources {
[Serializable]
public class ResourceReaderException : Exception {
public ResourceReaderException(string msg)
: base(msg) {
}
}
public struct ResourceReader {
IBinaryReader reader;
ResourceDataCreator resourceDataCreator;
ResourceReader(ModuleDef module, IBinaryReader reader) {
this.reader = reader;
this.resourceDataCreator = new ResourceDataCreator(module);
}
public static ResourceElementSet Read(ModuleDef module, IBinaryReader reader) {
return new ResourceReader(module, reader).Read();
}
ResourceElementSet Read() {
ResourceElementSet resources = new ResourceElementSet();
uint sig = reader.ReadUInt32();
if (sig != 0xBEEFCACE)
throw new ResourceReaderException(string.Format("Invalid resource sig: {0:X8}", sig));
if (!CheckReaders())
throw new ResourceReaderException("Invalid resource reader");
int version = reader.ReadInt32();
if (version != 2)
throw new ResourceReaderException(string.Format("Invalid resource version: {0}", version));
int numResources = reader.ReadInt32();
if (numResources < 0)
throw new ResourceReaderException(string.Format("Invalid number of resources: {0}", numResources));
int numUserTypes = reader.ReadInt32();
if (numUserTypes < 0)
throw new ResourceReaderException(string.Format("Invalid number of user types: {0}", numUserTypes));
var userTypes = new List<UserResourceType>();
for (int i = 0; i < numUserTypes; i++)
userTypes.Add(new UserResourceType(reader.ReadString(), ResourceTypeCode.UserTypes + i));
reader.Position = (reader.Position + 7) & ~7;
var hashes = new int[numResources];
for (int i = 0; i < numResources; i++)
hashes[i] = reader.ReadInt32();
var offsets = new int[numResources];
for (int i = 0; i < numResources; i++)
offsets[i] = reader.ReadInt32();
long baseOffset = reader.Position;
long dataBaseOffset = reader.ReadInt32();
long nameBaseOffset = reader.Position;
long end = reader.Length;
var infos = new List<ResourceInfo>(numResources);
for (int i = 0; i < numResources; i++) {
reader.Position = nameBaseOffset + offsets[i];
var name = reader.ReadString(Encoding.Unicode);
long offset = dataBaseOffset + reader.ReadInt32();
infos.Add(new ResourceInfo(name, offset));
}
infos.Sort((a, b) => a.offset.CompareTo(b.offset));
for (int i = 0; i < infos.Count; i++) {
var info = infos[i];
var element = new ResourceElement();
element.Name = info.name;
reader.Position = info.offset;
long nextDataOffset = i == infos.Count - 1 ? end : infos[i + 1].offset;
int size = (int)(nextDataOffset - info.offset);
element.ResourceData = ReadResourceData(userTypes, size);
resources.Add(element);
}
return resources;
}
class ResourceInfo {
public string name;
public long offset;
public ResourceInfo(string name, long offset) {
this.name = name;
this.offset = offset;
}
public override string ToString() {
return string.Format("{0:X8} - {1}", offset, name);
}
}
IResourceData ReadResourceData(List<UserResourceType> userTypes, int size) {
uint code = ReadUInt32(reader);
switch ((ResourceTypeCode)code) {
case ResourceTypeCode.Null: return resourceDataCreator.CreateNull();
case ResourceTypeCode.String: return resourceDataCreator.Create(reader.ReadString());
case ResourceTypeCode.Boolean: return resourceDataCreator.Create(reader.ReadBoolean());
case ResourceTypeCode.Char: return resourceDataCreator.Create((char)reader.ReadUInt16());
case ResourceTypeCode.Byte: return resourceDataCreator.Create(reader.ReadByte());
case ResourceTypeCode.SByte: return resourceDataCreator.Create(reader.ReadSByte());
case ResourceTypeCode.Int16: return resourceDataCreator.Create(reader.ReadInt16());
case ResourceTypeCode.UInt16: return resourceDataCreator.Create(reader.ReadUInt16());
case ResourceTypeCode.Int32: return resourceDataCreator.Create(reader.ReadInt32());
case ResourceTypeCode.UInt32: return resourceDataCreator.Create(reader.ReadUInt32());
case ResourceTypeCode.Int64: return resourceDataCreator.Create(reader.ReadInt64());
case ResourceTypeCode.UInt64: return resourceDataCreator.Create(reader.ReadUInt64());
case ResourceTypeCode.Single: return resourceDataCreator.Create(reader.ReadSingle());
case ResourceTypeCode.Double: return resourceDataCreator.Create(reader.ReadDouble());
case ResourceTypeCode.Decimal: return resourceDataCreator.Create(reader.ReadDecimal());
case ResourceTypeCode.DateTime: return resourceDataCreator.Create(new DateTime(reader.ReadInt64()));
case ResourceTypeCode.TimeSpan: return resourceDataCreator.Create(new TimeSpan(reader.ReadInt64()));
case ResourceTypeCode.ByteArray: return resourceDataCreator.Create(reader.ReadBytes(reader.ReadInt32()));
case ResourceTypeCode.Stream: return resourceDataCreator.CreateStream(reader.ReadBytes(reader.ReadInt32()));
default:
int userTypeIndex = (int)(code - (uint)ResourceTypeCode.UserTypes);
if (userTypeIndex < 0 || userTypeIndex >= userTypes.Count)
throw new ResourceReaderException(string.Format("Invalid resource data code: {0}", code));
return resourceDataCreator.CreateSerialized(reader.ReadBytes(size));
}
}
static uint ReadUInt32(IBinaryReader reader) {
try {
return reader.Read7BitEncodedUInt32();
}
catch {
throw new ResourceReaderException("Invalid encoded int32");
}
}
bool CheckReaders() {
bool validReader = false;
int numReaders = reader.ReadInt32();
if (numReaders < 0)
throw new ResourceReaderException(string.Format("Invalid number of readers: {0}", numReaders));
int readersSize = reader.ReadInt32();
if (readersSize < 0)
throw new ResourceReaderException(string.Format("Invalid readers size: {0:X8}", readersSize));
for (int i = 0; i < numReaders; i++) {
var resourceReaderFullName = reader.ReadString();
var resourceSetFullName = reader.ReadString();
if (Regex.IsMatch(resourceReaderFullName, @"^System\.Resources\.ResourceReader,\s*mscorlib,"))
validReader = true;
}
return validReader;
}
}
}

View File

@ -1,43 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
namespace de4dot.code.resources {
public enum ResourceTypeCode {
Null,
String,
Boolean,
Char,
Byte,
SByte,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Single,
Double,
Decimal,
DateTime,
TimeSpan,
ByteArray = 0x20,
Stream = 0x21,
UserTypes = 0x40,
}
}

View File

@ -1,148 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using dnlib.DotNet;
namespace de4dot.code.resources {
public class ResourceWriter {
ModuleDefMD module;
BinaryWriter writer;
ResourceElementSet resources;
ResourceDataCreator typeCreator;
Dictionary<UserResourceData, UserResourceType> dataToNewType = new Dictionary<UserResourceData, UserResourceType>();
ResourceWriter(ModuleDefMD module, Stream stream, ResourceElementSet resources) {
this.module = module;
this.typeCreator = new ResourceDataCreator(module);
this.writer = new BinaryWriter(stream);
this.resources = resources;
}
public static void Write(ModuleDefMD module, Stream stream, ResourceElementSet resources) {
new ResourceWriter(module, stream, resources).Write();
}
void Write() {
InitializeUserTypes();
writer.Write(0xBEEFCACE);
writer.Write(1);
WriteReaderType();
writer.Write(2);
writer.Write(resources.Count);
writer.Write(typeCreator.Count);
foreach (var userType in typeCreator.GetSortedTypes())
writer.Write(userType.Name);
int extraBytes = 8 - ((int)writer.BaseStream.Position & 7);
if (extraBytes != 8) {
for (int i = 0; i < extraBytes; i++)
writer.Write((byte)'X');
}
var nameOffsetStream = new MemoryStream();
var nameOffsetWriter = new BinaryWriter(nameOffsetStream, Encoding.Unicode);
var dataStream = new MemoryStream();
var dataWriter = new BinaryWriter(dataStream);
var hashes = new int[resources.Count];
var offsets = new int[resources.Count];
var formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence));
int index = 0;
foreach (var info in resources.ResourceElements) {
offsets[index] = (int)nameOffsetWriter.BaseStream.Position;
hashes[index] = (int)Hash(info.Name);
index++;
nameOffsetWriter.Write(info.Name);
nameOffsetWriter.Write((int)dataWriter.BaseStream.Position);
WriteData(dataWriter, info, formatter);
}
Array.Sort(hashes, offsets);
foreach (var hash in hashes)
writer.Write(hash);
foreach (var offset in offsets)
writer.Write(offset);
writer.Write((int)writer.BaseStream.Position + (int)nameOffsetStream.Length + 4);
writer.Write(nameOffsetStream.ToArray());
writer.Write(dataStream.ToArray());
}
void WriteData(BinaryWriter writer, ResourceElement info, IFormatter formatter) {
var code = GetResourceType(info.ResourceData);
WriteUInt32(writer, (uint)code);
info.ResourceData.WriteData(writer, formatter);
}
static void WriteUInt32(BinaryWriter writer, uint value) {
while (value >= 0x80) {
writer.Write((byte)(value | 0x80));
value >>= 7;
}
writer.Write((byte)value);
}
ResourceTypeCode GetResourceType(IResourceData data) {
if (data is BuiltInResourceData)
return data.Code;
var userData = (UserResourceData)data;
return dataToNewType[userData].Code;
}
static uint Hash(string key) {
uint val = 0x1505;
foreach (var c in key)
val = ((val << 5) + val) ^ (uint)c;
return val;
}
void InitializeUserTypes() {
foreach (var resource in resources.ResourceElements) {
var data = resource.ResourceData as UserResourceData;
if (data == null)
continue;
var newType = typeCreator.CreateUserResourceType(data.TypeName);
dataToNewType[data] = newType;
}
}
void WriteReaderType() {
var memStream = new MemoryStream();
var headerWriter = new BinaryWriter(memStream);
var mscorlibFullName = GetMscorlibFullname();
headerWriter.Write("System.Resources.ResourceReader, " + mscorlibFullName);
headerWriter.Write("System.Resources.RuntimeResourceSet");
writer.Write((int)memStream.Position);
writer.Write(memStream.ToArray());
}
string GetMscorlibFullname() {
var mscorlibRef = module.GetAssemblyRef("mscorlib");
if (mscorlibRef != null)
return mscorlibRef.FullName;
return "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
}
}
}

View File

@ -1,113 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
namespace de4dot.code.resources {
public abstract class UserResourceData : IResourceData {
readonly UserResourceType type;
public string TypeName {
get { return type.Name; }
}
public ResourceTypeCode Code {
get { return type.Code; }
}
public UserResourceData(UserResourceType type) {
this.type = type;
}
public abstract void WriteData(BinaryWriter writer, IFormatter formatter);
}
public class CharArrayResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Char[],mscorlib";
char[] data;
public CharArrayResourceData(UserResourceType type, char[] data)
: base(type) {
this.data = data;
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, data);
}
public override string ToString() {
return string.Format("char[]: Length: {0}", data.Length);
}
}
public class IconResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Drawing.Icon,System.Drawing";
Icon icon;
public IconResourceData(UserResourceType type, byte[] data)
: base(type) {
icon = new Icon(new MemoryStream(data));
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, icon);
}
public override string ToString() {
return string.Format("Icon: {0}", icon);
}
}
public class ImageResourceData : UserResourceData {
public static readonly string ReflectionTypeName = "System.Drawing.Bitmap,System.Drawing";
Bitmap bitmap;
public ImageResourceData(UserResourceType type, byte[] data)
: base(type) {
bitmap = new Bitmap(Image.FromStream(new MemoryStream(data)));
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, bitmap);
}
public override string ToString() {
return "Bitmap";
}
}
public class BinaryResourceData : UserResourceData {
byte[] data;
public BinaryResourceData(UserResourceType type, byte[] data)
: base(type) {
this.data = data;
}
public override void WriteData(BinaryWriter writer, IFormatter formatter) {
writer.Write(data);
}
public override string ToString() {
return string.Format("Binary: Length: {0}", data.Length);
}
}
}

View File

@ -1,42 +0,0 @@
/*
Copyright (C) 2011-2014 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 <http://www.gnu.org/licenses/>.
*/
namespace de4dot.code.resources {
public class UserResourceType {
readonly string name;
readonly ResourceTypeCode code;
public string Name {
get { return name; }
}
public ResourceTypeCode Code {
get { return code; }
}
public UserResourceType(string name, ResourceTypeCode code) {
this.name = name;
this.code = code;
}
public override string ToString() {
return string.Format("{0:X2} {1}", (int)code, name);
}
}
}

2
dnlib

@ -1 +1 @@
Subproject commit 8775c0055bccf44c2717c318e5c2358b06d5b989
Subproject commit 16f047464e4c1649a0d16a745f8797f35ea7e6fe