diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 4d7cddd4..2ce039ec 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -91,6 +91,7 @@ + diff --git a/de4dot.code/deobfuscators/DeobfuscatorBase.cs b/de4dot.code/deobfuscators/DeobfuscatorBase.cs index 4b44e47e..69288f19 100644 --- a/de4dot.code/deobfuscators/DeobfuscatorBase.cs +++ b/de4dot.code/deobfuscators/DeobfuscatorBase.cs @@ -77,7 +77,7 @@ namespace de4dot.deobfuscators { } public Func IsValidName { - get { return (name) => optionsBase.ValidNameRegex.isMatch(name); } + get { return (name) => checkValidName(name); } } public DeobfuscatorBase(OptionsBase optionsBase) { @@ -94,6 +94,10 @@ namespace de4dot.deobfuscators { this.module = module; } + protected virtual bool checkValidName(string name) { + return optionsBase.ValidNameRegex.isMatch(name); + } + public virtual int earlyDetect() { return 0; } diff --git a/de4dot.code/deobfuscators/RandomNameChecker.cs b/de4dot.code/deobfuscators/RandomNameChecker.cs new file mode 100644 index 00000000..2f42c19e --- /dev/null +++ b/de4dot.code/deobfuscators/RandomNameChecker.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.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; + +namespace de4dot.deobfuscators { + static class RandomNameChecker { + static Regex noUpper = new Regex(@"^[^A-Z]+$"); + static Regex allUpper = new Regex(@"^[A-Z]+$"); + + public static bool isNonRandom(string name) { + if (name.Length < 5) + return true; + if (noUpper.IsMatch(name)) + return true; + if (allUpper.IsMatch(name)) + return true; + + for (int i = 0; i < name.Length - 1; i++) { + if (isDigit(name[i])) + return false; + if (i > 0 && isUpper(name[i]) && isUpper(name[i - 1])) + return false; + } + + var words = getCamelWords(name); + int vowels = 0; + foreach (var word in words) { + if (word.Length > 1 && hasVowel(word)) + vowels++; + } + switch (words.Count) { + case 1: + return vowels == words.Count; + case 2: + case 3: + return vowels >= 1; + case 4: + case 5: + return vowels >= 2; + case 6: + return vowels >= 3; + case 7: + return vowels >= 4; + default: + return vowels >= words.Count - 4; + } + } + + static bool hasVowel(string s) { + foreach (var c in s) { + switch (c) { + case 'A': + case 'a': + case 'E': + case 'e': + case 'I': + case 'i': + case 'O': + case 'o': + case 'U': + case 'u': + case 'Y': + case 'y': + return true; + } + } + return false; + } + + static List getCamelWords(string name) { + var words = new List(); + var sb = new StringBuilder(); + + for (int i = 0; i < name.Length; i++) { + char c = name[i]; + if (isUpper(c)) { + if (sb.Length > 0) + words.Add(sb.ToString()); + sb.Length = 0; + } + sb.Append(c); + } + if (sb.Length > 0) + words.Add(sb.ToString()); + + return words; + } + + // Returns true if random, false if unknown + public static bool isRandom(string name) { + int len = name.Length; + if (len < 5) + return false; + + var typeWords = getTypeWords(name); + + if (countNumbers(typeWords, 2)) + return true; + + int lower, upper, digits; + countTypeWords(typeWords, out lower, out upper, out digits); + if (upper >= 3) + return true; + bool hasTwoUpperWords = upper == 2; + + foreach (var word in typeWords) { + if (word.Length > 1 && isDigit(word[0])) + return true; + } + + // Check for: lower, digit, lower + for (int i = 2; i < typeWords.Count; i++) { + if (isDigit(typeWords[i - 1][0]) && isLower(typeWords[i - 2][0]) && isLower(typeWords[i][0])) + return true; + } + + if (hasTwoUpperWords && hasDigit(name)) + return true; + + // Check if it ends in lower, upper, digit + if (isLower(name[len - 3]) && isUpper(name[len - 2]) && isDigit(name[len - 1])) + return true; + + return false; + } + + static bool hasDigit(string s) { + foreach (var c in s) { + if (isDigit(c)) + return true; + } + return false; + } + + static List getTypeWords(string s) { + var words = new List(); + var sb = new StringBuilder(); + + for (int i = 0; i < s.Length; ) { + if (isDigit(s[i])) { + sb.Length = 0; + while (i < s.Length && isDigit(s[i])) + sb.Append(s[i++]); + words.Add(sb.ToString()); + } + else if (isUpper(s[i])) { + sb.Length = 0; + while (i < s.Length && isUpper(s[i])) + sb.Append(s[i++]); + words.Add(sb.ToString()); + } + else if (isLower(s[i])) { + sb.Length = 0; + while (i < s.Length && isLower(s[i])) + sb.Append(s[i++]); + words.Add(sb.ToString()); + } + else { + sb.Length = 0; + while (i < s.Length) { + if (isDigit(s[i]) || isUpper(s[i]) || isLower(s[i])) + break; + sb.Append(s[i++]); + } + words.Add(sb.ToString()); + } + } + + return words; + } + + static bool countNumbers(List words, int numbers) { + int num = 0; + foreach (var word in words) { + if (string.IsNullOrEmpty(word)) + continue; + if (isDigit(word[0]) && ++num >= numbers) + return true; + } + return false; + } + + // 2+ chars only + static void countTypeWords(List words, out int lower, out int upper, out int digits) { + lower = 0; + upper = 0; + digits = 0; + + foreach (var word in words) { + if (word.Length <= 1) + continue; + char c = word[0]; + if (isDigit(c)) + digits++; + else if (isLower(c)) + lower++; + else if (isUpper(c)) + upper++; + } + } + + static bool isLower(char c) { + return 'a' <= c && c <= 'z'; + } + + static bool isUpper(char c) { + return 'A' <= c && c <= 'Z'; + } + + static bool isDigit(char c) { + return '0' <= c && c <= '9'; + } + } +} diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs index 52a2a904..9ee8ed36 100644 --- a/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/dotNET_Reactor/Deobfuscator.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.MyStuff; @@ -27,7 +28,7 @@ using de4dot.blocks; namespace de4dot.deobfuscators.dotNET_Reactor { class DeobfuscatorInfo : DeobfuscatorInfoBase { public const string THE_NAME = ".NET Reactor"; - const string DEFAULT_REGEX = @"!^[a-zA-Z0-9]{6,}(?:`\d+)?$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX; + const string DEFAULT_REGEX = DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX; BoolOption decryptMethods; BoolOption decryptBools; BoolOption restoreTypes; @@ -139,6 +140,18 @@ namespace de4dot.deobfuscators.dotNET_Reactor { base.init(module); } + static Regex isRandomNameRegex1 = new Regex(@"^[a-zA-Z0-9]{9,11}$"); // methods, fields, props, events + static Regex isRandomNameRegex2 = new Regex(@"^[a-zA-Z0-9]{18,19}(?:`\d+)?$"); // types, namespaces + protected override bool checkValidName(string name) { + if (isRandomNameRegex1.IsMatch(name) || isRandomNameRegex2.IsMatch(name)) { + if (RandomNameChecker.isRandom(name)) + return false; + if (!RandomNameChecker.isNonRandom(name)) + return false; + } + return base.checkValidName(name); + } + protected override int detectInternal() { int val = 0;