SQLiDumper 8.2 - Proxys!

Elektrotechnik wird zunächst einmal Beiseite gelegt, ich habe die Lust zum Reversen wiedergefunden. Ein Bekannter spielte mir ein Sample des SQLiDumpers 8.2 zu. Dieses universelle SQL Injection Tool nimmt faulen Leuten (und damit leider auch Leuten die keine Ahnung haben) die ganze Arbeit ab. Über das Suchen der SQL Injections per Google Dorks kann das Tool die gefunden Lücken direkt exploiten und auch Datensätze dumpen. Deswegen sei direkt gesagt: Das Tool wird hier definitiv nicht veröffentlicht, wer nur darauf aus ist kann sofort aufhören weiterzulesen.

Ich hatte bereits mit einigen alten Versionen dieses Tools zu tun, die immer unzureichend geschützt waren. Mal war es ein nativer Packer, der direkt die schön lesbare .NET Assembly lieferte, mal war der Code zum Generieren von gültigen Keys direkt mitgeliefert. Umso erstaunter war ich also, als ich ein Proxysystem entdeckte. Es ist lange nicht so komplex wie das Proxysystem von Confuser, was bereits behandelt wurde, aber dennoch komplex genug um spannende Erkentnisse mitzunehmen. Öffnen wir doch einfach die Assembly und schauen rein!

proxy_1Ein paar Sachen fallen dem geübten Reverser direkt ins Auge: Wir haben eine Ressourcen Datei (Knappe 10 MB! ) und einen statischen <Module>.cctor-Konstruktor. In diesem Konstruktor stecken die Funktionen, die statische Variablen initialisert. Es wird daher von Obfuscatoren gerne genutzt um Anti-Debug funktionen zu starten oder Ressourcen zu entschlüsseln, denn diese Methode wird vor allen anderen aufgerufen. Des weiteren haben wir keine Namespaces und nur komisch benannte Klassen. Wer im .NET Bereich unterwegs ist erkennt sofort die Namen: Es sind Namen des .NET Frameworks die es so gibt! Allerdings enthalten sie nicht den Inhalt der originalen Framework-Klassen. Auch sieht man schon an dem Icon, dass es sich zum Teil um unterschiedliche Typen handelt. Wir behandeln erstmal den einfachsten Typ: Ein Delegate Proxy.

Man kann sich ein Delegate wie einen Funktionszeiger im .NET Kontext vorstellen. Er kann auf einen Funktion zeigen und verhält sich dann beim Aufruf wie wenn man die Funktion direkt ansprechen würde. Dabei ist das Delegate selbst eine Variable und kann daher verschiedene Werte annehmen. Aufgerufen wird ein solches Delegate über die “Invoke” Funktion. Damit haben wir alle Informationen die es braucht um sich eine solche Delegate-Klasse anzuschauen.

Wir haben hier eine Klasse, die von MulticastDelegate erbt. Dieser ist ein spezieller Delegate , der mehrere Funktionsaufrufe hintereinander machen kann. Warum dieser Typ statt einem normalen Delegate verwendet wurde weis ich auch nicht :) Satteln wir das Pferd von hinten auf und ignorieren erstmal die FindProject Funktion. Spannend ist der statische Konstruktur der vor der ersten Verwendung der Klasse aufgerufen wird. Dieser übergibt drei Werte, die eine Menge Aufschluss geben. Denn Hexencodiert handelt es sich um: 0×2001248, 0xA0005E3 und 0xFFFFFF . Auch hier muss ich leider etwas ausholen, denn es handelt sich um .NET Metadata Tokens. Dies ist eine Tabelle (hier zu finden) in der .NET Assembly die eindeutigen Tokens definiert und miteinander verknüpft. Wenn das Token mit 0×2 anfängt so handelt es sich um eine TypeDef, also um einen Typ der nicht aus bekannten Bibliotheken referenziert sondern frisch definiert wird. Bei genauem Hinschauen sieht man auch, dass dieses Token dem XmlFileSite-Token entspricht (ganz oben auf dem Bild). Dieser erste Parameter übergibt also das eigene Klassentoken . Der zweite Parameter fängt mit 0xA an, was einem Eintrag aus der MemberRef Table entspricht . Hier finden sich alle Methoden die aus anderen Bibliotheken import werden. In diesem Fall handelt es sich um Eintrag 0x5E3 = 1507 in dieser Table:

 

Diese Methode heißt wohl “Read” und besitzt den Eintrag 176 aus der TypeRef Table. In dieser sind alle Typen aufgelistet die irgendwie von anderen Bibliotheken referenziert werden. Ein nachschauen an dieser stelle enthüllt, dass es sich um den Typ “Stream” aus dem System.IO Namespace handelt!

Also handelt es sich bei dem zweiten Parameter um das Token der ProxyMethode Stream.Read(). Und diese besitzt exakt 3 Parameter, ein Byte-Array und zwei Int-Werte. Genau diese finden sich auch in dem Delegate-Funktionsaufruf in der FindProject-Methode! Doch was ist mit dem ersten Parameter vom Typ Object? Nunja, da es sich bei der Stream.Read-Methode nicht um eine statische Funktion handelt braucht sie ein Objekt auf das sich die Methode bezieht. Und genau das wird im ersten Parameter mitgeliefert.

Der dritte Parameter (0xFFFFFF) wird genutzt um die Proxy-Funktion nochmal weiter zu differenzieren falls das Token nicht eindeutig ist. Weiter wird hierdrauf nicht eingegangen, da es sowieso nur ein Sonderfall ist.

Schauen wir also weiter was die Methode mit den drei übergebenen Tokens macht:

public static void FindProject(int ownTypeRef, int delegateRef, int additionalParam)
{
   Type typeFromHandle;
   MethodInfo methodInfo;
 
   // Suche den eigenen Typ raus, erster Parameter
   typeFromHandle = Type.GetTypeFromHandle(ActivityTable.cancel.ResolveTypeHandle(ownTypeRef));
   object methodFromHandle;
   // Suche die Funktion raus, auf die wir das Proxy weiterleiten möchten
   // Entspricht dem zweiten Parameter
   methodFromHandle = MethodBase.GetMethodFromHandle(ActivityTable.cancel.ResolveMethodHandle(delegateRef));
 
   // Caste die MethodBase zu einer MethodInfo (spezielle Klasse von MethodBase)
   methodInfo = DialogOptionsActivatorProvider.FindProject(methodFromHandle);

Damit haben wir eine MethodInfo der Proxy-Methode und können von dieser ein Delegate erstellen. Jetzt müssen wir nur noch rausfinden wo das eigentliche Delegate gesetzt wird. In Falle einer statischen Methode ist das einfach:

// Durchlaufe alle Felder des Typs
 FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField);
			for (int i = 0; i < (int)DockingPaneStreamActivatorProvider.FindProject(fields); i++)
{
   if (methodInfo.IsStatic)
   {
      value = Delegate.CreateDelegate(fieldInfo.FieldType, methodInfo);
   }
}

Man durchläuft also alle Felder und schaut ob es ein statisches ist. Wenn ja, so wird dieses statische Feld auf das richtige Delegate gesetzt. Dabei ist DockingPaneStreamActivatorProvider.FindProject ein Wrapper für Array.Length, liefert also die Anzahl der Felder in dem Array.

Spannender wird es bei normalen Funktionsaufrufen die ein Objekt brauchen. Hier nutzt der Obfuscator dynamische Code-Generation um eine neue Methode zu erzeugen die alle Parameter läd und im Anschluss die Methode im Bezug auf das Objekt aufruft. Das detailierte Besprechen davon würde den Rahmen sprengen, aber es Funktioniert über den ILGenerator. Ein passendes Beispiel findet sich hier.

Damit haben wir die Methoden-Proxies erschlagen und müssen nur jede Referenzierung auf einen solchen Proxy-Type mit den direkten Call ersetzen. Dabei unterscheiden wir zwischen einem statischen call (hier reicht es die Methode zu ersetzen) , einem Konstruktor-Call (hier muss auch der OpCode geändert werden) und einem normalen, nicht statischen call. Der Source dazu findet sich unten im Post.

Es gibt noch weitere Typen, die z.B. nur einen Cast durchführen. Auch diese kann man komplett elemenieren und hat somit einen wesentlich hübscheren Sourcecode.

Der Obfuscator nutzt zudem noch eine String und Constant Encryption um die Orientierung in dem eh schon verwirrenden Sourcecode schwer zu machen. Dabei wird die Ressourcendatei mit TripleDES entschlüsselt, alle Daten finden sich dort in der Ressourcendatei.

Abschließend noch ein kleiner Vergleich zwischen dem Unfuscated und Unobfuscated Sourcecode durch mein Tool:

Mit diesem hübschen Sourcecode ist schnell der Code zum Key-Checken nachvollzogen und ein Keygen geschrieben. Netter Obfuscator, ich hoffe Ihr konntet ein bisschen was dabei lernen ! :)

Abschließend gibt es also nur noch zu sagen:

Sourcecode (lohnt sich sehr mal reinzuschauen!): Program_ProxyOnly (31 Downloads)

Grüße

5 people like this post.
    • li0nsar3c00l
    • 17. Okt. 2016 12:00pm

    obfuscator ist crypto obfuscator, mein team hat vor knapp 4 monaten den crack released :D

  1. Noch keine TrackBacks.