diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 42f7b6f6..b154ac25 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -134,6 +134,9 @@
+
+
+
diff --git a/de4dot.code/deobfuscators/Skater_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Skater_NET/Deobfuscator.cs
new file mode 100644
index 00000000..f515734c
--- /dev/null
+++ b/de4dot.code/deobfuscators/Skater_NET/Deobfuscator.cs
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 2011 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.Skater_NET {
+ public class DeobfuscatorInfo : DeobfuscatorInfoBase {
+ public const string THE_NAME = "Skater .NET";
+ public const string THE_TYPE = "sk";
+ public DeobfuscatorInfo()
+ : base() {
+ }
+
+ 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 {
+ Options options;
+
+ StringDecrypter stringDecrypter;
+ EnumClassFinder enumClassFinder;
+
+ 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 DeobfuscatorInfo.THE_NAME; }
+ }
+
+ public Deobfuscator(Options options)
+ : base(options) {
+ this.options = options;
+ StringFeatures = StringFeatures.AllowNoDecryption | StringFeatures.AllowStaticDecryption;
+ }
+
+ protected override int detectInternal() {
+ int val = 0;
+
+ if (stringDecrypter.Detected)
+ val += 100;
+
+ return val;
+ }
+
+ protected override void scanForObfuscator() {
+ stringDecrypter = new StringDecrypter(module);
+
+ if (hasAssemblyReference("Microsoft.VisualBasic"))
+ stringDecrypter.find();
+ }
+
+ bool hasAssemblyReference(string name) {
+ foreach (var asmRef in module.AssemblyReferences) {
+ if (asmRef.Name == name)
+ return true;
+ }
+ return false;
+ }
+
+ public override void deobfuscateBegin() {
+ base.deobfuscateBegin();
+
+ enumClassFinder = new EnumClassFinder(module);
+
+ stringDecrypter.initialize();
+ }
+
+ public override void deobfuscateMethodEnd(Blocks blocks) {
+ if (Operations.DecryptStrings != OpDecryptString.None)
+ stringDecrypter.deobfuscate(blocks);
+ enumClassFinder.deobfuscate(blocks);
+ base.deobfuscateMethodEnd(blocks);
+ }
+
+ public override void deobfuscateEnd() {
+ if (Operations.DecryptStrings != OpDecryptString.None)
+ addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
+
+ base.deobfuscateEnd();
+ }
+
+ public override IEnumerable getStringDecrypterMethods() {
+ var list = new List();
+ return list;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Skater_NET/EnumClassFinder.cs b/de4dot.code/deobfuscators/Skater_NET/EnumClassFinder.cs
new file mode 100644
index 00000000..1e4fee68
--- /dev/null
+++ b/de4dot.code/deobfuscators/Skater_NET/EnumClassFinder.cs
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2011 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 Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Skater_NET {
+ class EnumClassFinder {
+ ModuleDefinition module;
+ FieldDefinition enumField;
+
+ public EnumClassFinder(ModuleDefinition module) {
+ this.module = module;
+ find();
+ }
+
+ void find() {
+ foreach (var type in module.Types) {
+ if (type.HasEvents || type.HasProperties)
+ continue;
+ if (type.Methods.Count != 1)
+ continue;
+ if (type.Fields.Count != 1)
+ continue;
+ var method = type.Methods[0];
+ if (method.Name != ".ctor")
+ continue;
+ var field = type.Fields[0];
+ var fieldType = DotNetUtils.getType(module, field.FieldType);
+ if (fieldType == null)
+ continue;
+ if (!fieldType.IsEnum)
+ continue;
+ enumField = field;
+ return;
+ }
+ }
+
+ public void deobfuscate(Blocks blocks) {
+ foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
+ var instrs = block.Instructions;
+ for (int i = 0; i < instrs.Count - 2; i++) {
+ var ldsfld = instrs[i];
+ if (ldsfld.OpCode.Code != Code.Ldsfld)
+ continue;
+
+ var ldci4 = instrs[i + 1];
+ if (!ldci4.isLdcI4())
+ continue;
+
+ var stfld = instrs[i + 2];
+ if (stfld.OpCode.Code != Code.Stfld)
+ continue;
+
+ var field = stfld.Operand as FieldReference;
+ if (!MemberReferenceHelper.compareFieldReferenceAndDeclaringType(enumField, field))
+ continue;
+ block.remove(i, 3);
+ i--;
+ }
+ }
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Skater_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Skater_NET/StringDecrypter.cs
new file mode 100644
index 00000000..28471637
--- /dev/null
+++ b/de4dot.code/deobfuscators/Skater_NET/StringDecrypter.cs
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 2011 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.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Skater_NET {
+ class StringDecrypter {
+ ModuleDefinition module;
+ TypeDefinition decrypterType;
+ MethodDefinition decrypterCctor;
+ byte[] key;
+ byte[] iv;
+ FieldDefinitionAndDeclaringTypeDict fieldToDecryptedString = new FieldDefinitionAndDeclaringTypeDict();
+
+ public bool Detected {
+ get { return decrypterType != null; }
+ }
+
+ public TypeDefinition Type {
+ get { return decrypterType; }
+ }
+
+ public StringDecrypter(ModuleDefinition module) {
+ this.module = module;
+ }
+
+ public void find() {
+ foreach (var type in module.Types) {
+ if (type.HasProperties || type.HasEvents)
+ continue;
+
+ var cctor = DotNetUtils.getMethod(type, ".cctor");
+ if (cctor == null)
+ continue;
+
+ if (checkType(type)) {
+ decrypterType = type;
+ decrypterCctor = cctor;
+ return;
+ }
+ }
+ }
+
+ public void initialize() {
+ if (decrypterCctor == null)
+ return;
+
+ var instrs = decrypterCctor.Body.Instructions;
+ for (int i = 0; i < instrs.Count - 4; i++) {
+ var ldstr = instrs[i];
+ if (ldstr.OpCode.Code != Code.Ldstr)
+ continue;
+ var encryptedString = ldstr.Operand as string;
+ if (encryptedString == null)
+ continue;
+ if (instrs[i + 1].OpCode.Code != Code.Stsfld)
+ continue;
+ if (instrs[i + 2].OpCode.Code != Code.Ldsfld)
+ continue;
+ if (instrs[i + 3].OpCode.Code != Code.Call)
+ continue;
+ if (instrs[i + 4].OpCode.Code != Code.Stsfld)
+ continue;
+ var field = instrs[i + 4].Operand as FieldDefinition;
+ if (field == null)
+ continue;
+ if (!MemberReferenceHelper.compareTypes(field.DeclaringType, decrypterType))
+ continue;
+
+ var decryptedString = Encoding.Unicode.GetString(DeobUtils.des3Decrypt(Convert.FromBase64String(encryptedString), key, iv));
+ fieldToDecryptedString.add(field, decryptedString);
+ }
+ }
+
+ bool checkType(TypeDefinition type) {
+ foreach (var method in type.Methods) {
+ if (!method.IsStatic || method.Body == null)
+ continue;
+ if (!DotNetUtils.isMethod(method, "System.String", "(System.String)"))
+ continue;
+
+ var salt = getSalt(method);
+ if (salt == null)
+ continue;
+
+ var password = getPassword(method);
+ if (string.IsNullOrEmpty(password))
+ continue;
+
+ var passwordBytes = new PasswordDeriveBytes(password, salt);
+ key = passwordBytes.GetBytes(16);
+ iv = passwordBytes.GetBytes(8);
+ return true;
+ }
+
+ return false;
+ }
+
+ static byte[] getSalt(MethodDefinition method) {
+ foreach (var s in DotNetUtils.getCodeStrings(method)) {
+ var saltAry = fixSalt(s);
+ if (saltAry != null)
+ return saltAry;
+ }
+
+ return null;
+ }
+
+ static byte[] fixSalt(string s) {
+ if (s.Length < 10 || s.Length > 30 || s.Length / 2 * 2 != s.Length)
+ return null;
+
+ var ary = s.ToCharArray();
+ Array.Reverse(ary);
+ for (int i = 0; i < ary.Length; i++)
+ ary[i]--;
+ var s2 = new string(ary);
+
+ var saltAry = new byte[(int)Math.Round((double)s2.Length / 2 - 1) + 1];
+ for (int i = 0; i < saltAry.Length; i++) {
+ int result;
+ if (!int.TryParse(s2.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier, null, out result))
+ return null;
+ saltAry[i] = (byte)result;
+ }
+
+ return saltAry;
+ }
+
+ string getPassword(MethodDefinition decryptMethod) {
+ foreach (var info in DotNetUtils.getCalledMethods(module, decryptMethod)) {
+ var method = info.Item2;
+ if (!method.IsStatic || method.Body == null)
+ continue;
+ if (!MemberReferenceHelper.compareTypes(method.DeclaringType, decryptMethod.DeclaringType))
+ continue;
+ if (!DotNetUtils.isMethod(method, "System.String", "()"))
+ continue;
+
+ var hexChars = getPassword2(method);
+ if (string.IsNullOrEmpty(hexChars))
+ continue;
+
+ var password = fixPassword(hexChars);
+ if (string.IsNullOrEmpty(password))
+ continue;
+
+ return password;
+ }
+ return null;
+ }
+
+ string fixPassword(string hexChars) {
+ var ary = hexChars.Trim().Split(' ');
+ string password = "";
+ for (int i = 0; i < ary.Length; i++) {
+ int result;
+ if (!int.TryParse(ary[i], NumberStyles.AllowHexSpecifier, null, out result))
+ return null;
+ password += (char)result;
+ }
+ return password;
+ }
+
+ string getPassword2(MethodDefinition method) {
+ string password = "";
+ foreach (var info in DotNetUtils.getCalledMethods(module, method)) {
+ var s = getPassword3(info.Item2);
+ if (string.IsNullOrEmpty(s))
+ return null;
+
+ password += s;
+ }
+ return password;
+ }
+
+ string getPassword3(MethodDefinition method) {
+ var strings = new List(DotNetUtils.getCodeStrings(method));
+ if (strings.Count != 1)
+ return null;
+
+ var s = strings[0];
+ if (!Regex.IsMatch(s, @"^[a-fA-F0-9]{2} $"))
+ return null;
+
+ return s;
+ }
+
+ 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 decrypted = fieldToDecryptedString.find(field);
+ if (decrypted == null)
+ continue;
+
+ instrs[i] = new Instr(Instruction.Create(OpCodes.Ldstr, decrypted));
+ Log.v("Decrypted string: {0}", Utils.toCsharpString(decrypted));
+ }
+ }
+ }
+ }
+}
diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs
index 67e94890..cf126953 100644
--- a/de4dot.cui/Program.cs
+++ b/de4dot.cui/Program.cs
@@ -38,6 +38,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Eazfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
+ new de4dot.code.deobfuscators.Skater_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
};