forked from de4dot/de4dot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
remove stringbuilder crypter (de4dot#202)
* Add files via upload remove stringbuilder crypter * Update Deobfuscator.cs remove stringbuilder crypter * Format this file * Format this file and fix some errors
- Loading branch information
Showing
2 changed files
with
202 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
195 changes: 195 additions & 0 deletions
195
de4dot.code/deobfuscators/Dotfuscator/StringBuilderDecrypter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* | ||
Copyright (C) 2011-2015 [email protected] | ||
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.Linq; | ||
using System.Text; | ||
using dnlib.DotNet; | ||
using dnlib.DotNet.Emit; | ||
|
||
namespace de4dot.code.deobfuscators.Dotfuscator { | ||
|
||
/// <summary> | ||
/// remove stringbuilder crypter | ||
/// </summary> | ||
/// <code> | ||
/// int[] array2 = new int[] | ||
/// { | ||
/// -22, | ||
/// 19, | ||
/// 41, | ||
/// -36 | ||
/// }; | ||
/// StringBuilder stringBuilder2 = new StringBuilder(); | ||
/// stringBuilder2.Append((char)(array2[0] + 98)); | ||
/// stringBuilder2.Append((char)(array2[1] + 92)); | ||
/// stringBuilder2.Append((char)(array2[2] + 56)); | ||
/// stringBuilder2.Append((char)(array2[3] + 136)); | ||
/// string text = stringBuilder2.ToString(); | ||
/// </code> | ||
public class StringBuilderDecrypter { | ||
ModuleDefMD module; | ||
|
||
public StringBuilderDecrypter(ModuleDefMD module) => this.module = module; | ||
|
||
public void StringBuilderClean() { | ||
foreach (var type in module.GetTypes()) { | ||
if (!type.HasMethods) | ||
continue; | ||
|
||
foreach (var method in type.Methods) { | ||
CleanStringBuilder(method); | ||
|
||
} | ||
} | ||
} | ||
|
||
void CleanStringBuilder(MethodDef method) { | ||
if (!method.HasBody) | ||
return; | ||
if (!method.Body.HasInstructions) | ||
return; | ||
if (method.Body.Instructions.Count < 4) | ||
return; | ||
if (method.Body.Variables.Count == 0) | ||
return; | ||
|
||
var instructions = method.Body.Instructions; | ||
|
||
GetStringBuilderFixIndexs(instructions, out var nopIdxs, out var ldstrIdxs); | ||
|
||
foreach (var idx in nopIdxs) { | ||
method.Body.Instructions[idx].OpCode = OpCodes.Nop; | ||
method.Body.Instructions[idx].Operand = null; | ||
} | ||
|
||
foreach (var idx in ldstrIdxs) { | ||
method.Body.Instructions[idx.Key].OpCode = OpCodes.Ldstr; | ||
method.Body.Instructions[idx.Key].Operand = idx.Value; | ||
} | ||
} | ||
|
||
|
||
static void GetStringBuilderFixIndexs(IList<Instruction> instructions, out List<int> nopIdxs, out Dictionary<int, string> ldstrIdxs) { | ||
var insNoNops = instructions.Where(ins => ins.OpCode != OpCodes.Nop).ToList(); | ||
|
||
nopIdxs = new List<int>(); | ||
ldstrIdxs = new Dictionary<int, string>(); | ||
|
||
for (var i = 1; i < insNoNops.Count; i++) { | ||
if (insNoNops[i - 1].IsLdcI4() && | ||
insNoNops[i].OpCode == OpCodes.Newarr && | ||
insNoNops[i].Operand is TypeRef typeRef && | ||
typeRef.FullName == typeof(Int32).FullName) { | ||
int[] data = null; | ||
int index = 0; | ||
var arrLength = insNoNops[i - 1].GetLdcI4Value(); | ||
if (arrLength == 1) { | ||
if (i + 6 < insNoNops.Count && | ||
insNoNops[i + 6].OpCode == OpCodes.Newobj && | ||
insNoNops[i + 6].Operand is MemberRef memberRef && | ||
memberRef.GetDeclaringTypeFullName() == typeof(StringBuilder).FullName && | ||
memberRef.Name == ".ctor" && | ||
insNoNops[i + 3].IsLdcI4()) { | ||
data = new int[arrLength]; | ||
data[0] = insNoNops[i + 3].GetLdcI4Value(); | ||
|
||
index = TryGetStringBuilderAppendData(insNoNops, i + 7, data); | ||
} | ||
} | ||
else if (arrLength == 2) { | ||
if (i + 10 < insNoNops.Count && | ||
insNoNops[i + 10].OpCode == OpCodes.Newobj && | ||
insNoNops[i + 10].Operand is MemberRef memberRef && | ||
memberRef.GetDeclaringTypeFullName() == typeof(StringBuilder).FullName && | ||
memberRef.Name == ".ctor" && | ||
insNoNops[i + 3].IsLdcI4() && | ||
insNoNops[i + 7].IsLdcI4()) { | ||
data = new int[arrLength]; | ||
data[0] = insNoNops[i + 3].GetLdcI4Value(); | ||
data[1] = insNoNops[i + 7].GetLdcI4Value(); | ||
|
||
index = TryGetStringBuilderAppendData(insNoNops, i + 11, data); | ||
} | ||
} | ||
else { | ||
if (i + 5 < insNoNops.Count && | ||
insNoNops[i + 2].OpCode == OpCodes.Ldtoken && | ||
insNoNops[i + 2].Operand is FieldDef fieldDef && | ||
fieldDef.InitialValue != null && | ||
fieldDef.InitialValue.Length / 4 == arrLength && | ||
insNoNops[i + 5].OpCode == OpCodes.Newobj && | ||
insNoNops[i + 5].Operand is MemberRef memberRef && | ||
memberRef.GetDeclaringTypeFullName() == typeof(StringBuilder).FullName && | ||
memberRef.Name == ".ctor") { | ||
data = new int[arrLength]; | ||
for (var j = 0; j < arrLength; j++) { | ||
data[j] = BitConverter.ToInt32(fieldDef.InitialValue, j * 4); | ||
} | ||
|
||
index = TryGetStringBuilderAppendData(insNoNops, i + 6, data); | ||
} | ||
} | ||
|
||
if (index != 0 && data != null) { | ||
var array = new char[data.Length]; | ||
|
||
for (int j = 0; j < data.Length; j++) { | ||
array[j] = (char)data[j]; | ||
} | ||
|
||
for (var j = i - 1; j < index; j++) { | ||
nopIdxs.Add(instructions.IndexOf(insNoNops[j])); | ||
} | ||
|
||
ldstrIdxs.Add(instructions.IndexOf(insNoNops[index]), new string(array)); | ||
|
||
i = index; | ||
} | ||
} | ||
} | ||
} | ||
|
||
static int TryGetStringBuilderAppendData(IList<Instruction> instructions, int index, int[] data) { | ||
var length = data.Length; | ||
|
||
if (index + length * 9 + 3 < instructions.Count && | ||
instructions[index + 9 * length + 2].OpCode == OpCodes.Callvirt && | ||
(instructions[index + 9 * length + 2].Operand as MemberRef)?.Name == "ToString") { | ||
if (instructions[index + 9 * length + 3].IsStloc() || | ||
instructions[index + 9 * length + 3].OpCode == OpCodes.Pop) { | ||
for (var j = 0; j < length; j++) { | ||
var insNoNop = instructions[index + j * 9 + 5]; | ||
if (insNoNop.IsLdcI4()) { | ||
data[j] += insNoNop.GetLdcI4Value(); | ||
} | ||
else { | ||
return 0; | ||
} | ||
} | ||
|
||
return index + 9 * length + 2; | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
} | ||
} |