Deobfuscation mit Mono.Cecil
Ein kleiner Artikel für den heutigen Abend. Es geht um das fixxen einer “String-Encryption” (eigentlich ein simples Encoding) mit Hilfe von Mono.Cecil. Dabei werden wir alle Methoden zu dieser String-Encryption-Klasse mit einem ldstr-Opcode ersetzen und dabei natürlich nebenher den String decodieren.
Die String-Encryption-Klasse besteht aus einem großen Byte-Array (XORed). Alle 59 statischen Methoden dieser Klasse beinhalten in etwa folgendes:
public static string smethod_16() { return (string_0[15] ?? smethod_0(15, 313, 8)); } |
Alle dieser Methoden liefern also string_0[X] zurück ODER wenn dieses NULL ist smethod_0(X,Y,Y). X ist in diesem Fall die “ID” des Strings, Y wird später besprochen.
Nehmen wir also an wir finden einen Call zu einer solchen Funktion, dann speichern wir die MethodDefinition (quasi die Methoden-Klasse unter Mono.Cecil) ab und übergeben diese unserer Funktion:
if (Globals.lstTypes[i].lstMethods[j].Object.Body.Instructions[k].OpCode.Code == Mono.Cecil.Cil.Code.Call) { String sTemp = Globals.lstTypes[i].lstMethods[j].Object.Body.Instructions[k].GetInstructionString(); if (sTemp.Contains("PrivateImplementationDetails")) { MethodDefinition MD = (MethodDefinition)Globals.lstTypes[i].lstMethods[j].Object.Body.Instructions[k].Operand; String sTempDecoded = Utils.GetDecodedStringFromMD(MD, byte_0); Globals.lstTypes[i].lstMethods[j].Object.Body.Instructions[k] = new Mono.Cecil.Cil.Instruction(Mono.Cecil.Cil.OpCodes.Ldstr, sTempDecoded); } } |
Wenig übersichtlich, ich weis Auf jeden Fall gehen wir alle Methoden durch und prüfen ob diese einen “Call” Opcode enthalten. Wenn ja, so wird geprüft ob eine Funktion aus dem <PrivateImplementationDetails>-Namespace gecalled wird, wenn ja haben wir eine Funktion smethod_X(). Diese erhalten wir über den Operand des Call-OpCodes.
Unsere gefundene MethodDefinition (smethod_X) wird nun an die Utils-Funktion übergeben, zusammen mit dem großen byte-Array mit wohl all den Strings drin. Diese im nächsten Absatz besprochene Funktion liefert uns den decodierten String. Der eigentliche Methodenaufruf (call smethod-X) wird nun durch ein “Ldstr DekodierterString” ersetzt, also wird der dekodierte String direkt geladen, nicht durch die decoding-Funktion.
Zum eigentlichen Decoding. Diese Funktion ist schnell erklärt, es geht mehr um die Mono.Cecil-Funktionsweise:
public static String GetDecodedStringFromMD(MethodDefinition MD, byte[] Array) { int[] iParams = new int[3]; for (int i = 0; i < MD.Body.Instructions.Count; i++) { if (MD.Body.Instructions[i].GetInstructionString().Contains("call")) { iParams[0] = (int)MD.Body.Instructions[i - 3].Operand; iParams[1] = (int)MD.Body.Instructions[i - 2].Operand; iParams[2] = (int)MD.Body.Instructions[i - 1].Operand; } } return Encoding.Default.GetString(Array, iParams[1],iParams[2]); } |
Vor dem eigentlichen Decode-Call werden 3 Argumente der Funktion übergeben (X, Y, Y) Diese werden ausgelesen, danach folgt die GetString-Funktion mit den ausgelesenen Parametern (Y) als Anfangsoffset und Länge. In Falle von smethod_16() wäre das ein Startoffset von 313 und eine Länge von 8 Zeichen. Und mehr macht die Utils-Funktion auch nicht. Und so leicht ist Mono.Cecil zu bedienen
Greez Easy
ich raff nicht, wie ich anhand dieser Informationen die aus den deinen Zemra-Sourcen rausbekomme bzw. deobfuszieren kann :/
Du kannst den Source anschauen und verstehen, ihn aber nicht (ohne sehr großen Aufwand) wieder lauffähig machen. Der Source reicht zum verstehen des Bots, aber nicht um ihn effektiv verwenden zu können, sorry
Hatte mich nur gewundert, weil du ja hier (http://coderz.cc/showthread.php?p=48345) geschrieben hast, das das String-Encoding des Zemra-Bots anhand dieses Postes geknackt werden könnte…
###############
Der “PrivateImplementationDetails” ist ein vom Compiler erzeugter Namespace, welcher u.a. interne Strukturen beinhaltet und Arrays initialisiert. In diesem Fall wurde hier einfach die String-Encoding Klasse reingebaut, welche übrigens im Blogpost vor dem Zerma-Post “geknackt” wurde. Dabei wurde ein eigener Deobfuscator geschrieben, welcher alle Strings direkt einsetzt, ohne den Call.
################
Erstmal sorry, hatte den Kommentar für einen Kommentar des “Zemra-Posts” gehalten, nicht richtig geschaut… :/
Auf jeden Fall hat der Source des Zemra-Bots weiterhin diese “String-Verschlüsselung” eingebaut, wie z.B. in dieser Zeile hier:
Dabei liefert smethod_19 einen String zurück, dies ist “String-Verschlüsselung”. Diese wurde mit dem selbstgeschriebenen Deobfuscator umgangen, darüber handelt der Blogpost.
Ich sehe gerade dass im Source überhaupt der-Namespace fehlt, daher ist eine Entschlüsselung unmögllich … Obwohl das keine Absicht war passt das so, das Risiko dass Zemra doch neu gebuildet wird ist so geringer…