diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index f1f330ca..5659af29 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -194,6 +194,8 @@
+
+
diff --git a/de4dot.code/deobfuscators/Rummage/Deobfuscator.cs b/de4dot.code/deobfuscators/Rummage/Deobfuscator.cs
new file mode 100644
index 00000000..f99473bb
--- /dev/null
+++ b/de4dot.code/deobfuscators/Rummage/Deobfuscator.cs
@@ -0,0 +1,110 @@
+/*
+ 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.Collections.Generic;
+using Mono.Cecil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Rummage {
+ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
+ public const string THE_NAME = "Rummage";
+ public const string THE_TYPE = "rm";
+ const string DEFAULT_REGEX = @"!.";
+ public DeobfuscatorInfo()
+ : base(DEFAULT_REGEX) {
+ }
+
+ public override string Name {
+ get { return THE_NAME; }
+ }
+
+ public override string Type {
+ get { return THE_TYPE; }
+ }
+
+ public override IDeobfuscator createDeobfuscator() {
+ return new Deobfuscator(new Deobfuscator.Options {
+ ValidNameRegex = validNameRegex.get(),
+ });
+ }
+ }
+
+ class Deobfuscator : DeobfuscatorBase {
+ StringDecrypter stringDecrypter;
+
+ internal class Options : OptionsBase {
+ }
+
+ public override string Type {
+ get { return DeobfuscatorInfo.THE_TYPE; }
+ }
+
+ public override string TypeLong {
+ get { return DeobfuscatorInfo.THE_NAME; }
+ }
+
+ public override string Name {
+ get { return TypeLong; }
+ }
+
+ public Deobfuscator(Options options)
+ : base(options) {
+ }
+
+ protected override int detectInternal() {
+ int val = 0;
+
+ int sum = toInt32(stringDecrypter.Detected);
+ if (sum > 0)
+ val += 100 + 10 * (sum - 1);
+
+ return val;
+ }
+
+ protected override void scanForObfuscator() {
+ stringDecrypter = new StringDecrypter(module);
+ stringDecrypter.find();
+ }
+
+ public override void deobfuscateBegin() {
+ base.deobfuscateBegin();
+
+ stringDecrypter.initialize();
+ }
+
+
+ public override void deobfuscateMethodEnd(Blocks blocks) {
+ if (CanRemoveStringDecrypterType)
+ stringDecrypter.deobfuscate(blocks);
+ base.deobfuscateMethodEnd(blocks);
+ }
+
+ public override void deobfuscateEnd() {
+ if (CanRemoveStringDecrypterType) {
+ addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
+ addTypesToBeRemoved(stringDecrypter.OtherTypes, "Decrypted string type");
+ }
+ base.deobfuscateEnd();
+ }
+
+ public override IEnumerable getStringDecrypterMethods() {
+ return new List();
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Rummage/StringDecrypter.cs b/de4dot.code/deobfuscators/Rummage/StringDecrypter.cs
new file mode 100644
index 00000000..fc390be8
--- /dev/null
+++ b/de4dot.code/deobfuscators/Rummage/StringDecrypter.cs
@@ -0,0 +1,256 @@
+/*
+ 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;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Rummage {
+ class StringDecrypter {
+ ModuleDefinition module;
+ MethodDefinition stringDecrypterMethod;
+ FieldDefinitionAndDeclaringTypeDict stringInfos = new FieldDefinitionAndDeclaringTypeDict();
+ int fileDispl;
+ uint[] key;
+ BinaryReader reader;
+
+ class StringInfo {
+ public readonly FieldDefinition field;
+ public readonly int stringId;
+ public string decrypted;
+
+ public StringInfo(FieldDefinition field, int stringId) {
+ this.field = field;
+ this.stringId = stringId;
+ }
+
+ public override string ToString() {
+ if (decrypted != null)
+ return string.Format("{0:X8} - {1}", stringId, Utils.toCsharpString(decrypted));
+ return string.Format("{0:X8}", stringId);
+ }
+ }
+
+ public TypeDefinition Type {
+ get { return stringDecrypterMethod != null ? stringDecrypterMethod.DeclaringType : null; }
+ }
+
+ public IEnumerable OtherTypes {
+ get {
+ var list = new List(stringInfos.Count);
+ foreach (var info in stringInfos.getValues())
+ list.Add(info.field.DeclaringType);
+ return list;
+ }
+ }
+
+ public bool Detected {
+ get { return stringDecrypterMethod != null; }
+ }
+
+ public StringDecrypter(ModuleDefinition module) {
+ this.module = module;
+ }
+
+ public void find() {
+ foreach (var type in module.Types) {
+ var method = checkType(type);
+ if (method == null)
+ continue;
+ if (!getDispl(method, ref fileDispl))
+ continue;
+
+ stringDecrypterMethod = method;
+ break;
+ }
+ }
+
+ static readonly string[] requiredFields = new string[] {
+ "System.UInt32[]",
+ };
+ static readonly string[] requiredLocals = new string[] {
+ "System.Byte[]",
+ "System.Int32",
+ "System.IO.FileStream",
+ };
+ static MethodDefinition checkType(TypeDefinition type) {
+ if (!new FieldTypes(type).exactly(requiredFields))
+ return null;
+ var cctor = DotNetUtils.getMethod(type, ".cctor");
+ if (cctor == null)
+ return null;
+ if (!new LocalTypes(cctor).all(requiredLocals))
+ return null;
+
+ return checkMethods(type);
+ }
+
+ static MethodDefinition checkMethods(TypeDefinition type) {
+ MethodDefinition cctor = null, decrypterMethod = null;
+ foreach (var method in type.Methods) {
+ if (!method.IsStatic || method.Body == null)
+ return null;
+ if (method.Name == ".cctor")
+ cctor = method;
+ else if (DotNetUtils.isMethod(method, "System.String", "(System.Int32)"))
+ decrypterMethod = method;
+ else
+ return null;
+ }
+ if (cctor == null || decrypterMethod == null)
+ return null;
+
+ return decrypterMethod;
+ }
+
+ static bool getDispl(MethodDefinition method, ref int displ) {
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 2; i++) {
+ var mul = instrs[i];
+ if (mul.OpCode.Code != Code.Mul)
+ continue;
+
+ var ldci4 = instrs[i + 1];
+ if (!DotNetUtils.isLdcI4(ldci4))
+ continue;
+
+ var sub = instrs[i + 2];
+ if (sub.OpCode.Code != Code.Sub)
+ continue;
+
+ displ = DotNetUtils.getLdcI4Value(ldci4);
+ return true;
+ }
+
+ return false;
+ }
+
+ public void initialize() {
+ reader = new BinaryReader(new FileStream(module.FullyQualifiedName, FileMode.Open, FileAccess.Read, FileShare.Read));
+ initKey();
+
+ foreach (var type in module.Types)
+ initType(type);
+ }
+
+ void initKey() {
+ reader.BaseStream.Position = reader.BaseStream.Length - 48;
+ key = new uint[4];
+ for (int i = 0; i < key.Length; i++)
+ key[i] = reader.ReadUInt32();
+ }
+
+ void initType(TypeDefinition type) {
+ var cctor = DotNetUtils.getMethod(type, ".cctor");
+ if (cctor == null)
+ return;
+ var info = getStringInfo(cctor);
+ if (info == null)
+ return;
+
+ stringInfos.add(info.field, info);
+ }
+
+ StringInfo getStringInfo(MethodDefinition method) {
+ if (method == null || method.Body == null)
+ return null;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 2; i++) {
+ var ldci4 = instrs[i];
+ if (!DotNetUtils.isLdcI4(ldci4))
+ continue;
+ int stringId = DotNetUtils.getLdcI4Value(ldci4);
+
+ var call = instrs[i + 1];
+ if (call.OpCode.Code != Code.Call)
+ continue;
+ var calledMethod = call.Operand as MethodReference;
+ if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(stringDecrypterMethod, calledMethod))
+ continue;
+
+ var stsfld = instrs[i + 2];
+ if (stsfld.OpCode.Code != Code.Stsfld)
+ continue;
+ var field = stsfld.Operand as FieldDefinition;
+ if (field == null)
+ continue;
+
+ return new StringInfo(field, stringId);
+ }
+
+ return null;
+ }
+
+ public void deobfuscate(Blocks blocks) {
+ foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
+ var instrs = block.Instructions;
+ for (int i = 0; i < instrs.Count; i++) {
+ var instr = instrs[i];
+
+ if (instr.OpCode.Code != Code.Ldsfld)
+ continue;
+
+ var field = instr.Operand as FieldReference;
+ if (field == null)
+ continue;
+ var info = stringInfos.find(field);
+ if (info == null)
+ continue;
+ var decrypted = decrypt(info);
+
+ instrs[i] = new Instr(Instruction.Create(OpCodes.Ldstr, decrypted));
+ Log.v("Decrypted string: {0}", Utils.toCsharpString(decrypted));
+ }
+ }
+ }
+
+ string decrypt(StringInfo info) {
+ if (info.decrypted == null)
+ info.decrypted = decrypt(info.stringId);
+
+ return info.decrypted;
+ }
+
+ string decrypt(int stringId) {
+ reader.BaseStream.Position = reader.BaseStream.Length + (stringId * 4 - fileDispl);
+
+ uint v0 = reader.ReadUInt32();
+ uint v1 = reader.ReadUInt32();
+ DeobUtils.xteaDecrypt(ref v0, ref v1, key, 32);
+ int utf8Length = (int)v0;
+ var decrypted = new uint[(utf8Length + 11) / 8 * 2 - 1];
+ decrypted[0] = v1;
+ for (int i = 1; i + 1 < decrypted.Length; i += 2) {
+ v0 = reader.ReadUInt32();
+ v1 = reader.ReadUInt32();
+ DeobUtils.xteaDecrypt(ref v0, ref v1, key, 32);
+ decrypted[i] = v0;
+ decrypted[i + 1] = v1;
+ }
+
+ var utf8 = new byte[utf8Length];
+ Buffer.BlockCopy(decrypted, 0, utf8, 0, utf8.Length);
+ return Encoding.UTF8.GetString(utf8);
+ }
+ }
+}
diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs
index a3a5f5ac..f8e2472b 100644
--- a/de4dot.cui/Program.cs
+++ b/de4dot.cui/Program.cs
@@ -48,6 +48,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.Eazfuscator_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.MaxtoCode.DeobfuscatorInfo(),
+ new de4dot.code.deobfuscators.Rummage.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Spices_Net.DeobfuscatorInfo(),