Computeshader in C# - Vorwort zum Hashcracker

Das Nutzen von GPU-Power ist dank OpenCL, CUDA und DirectX 10.1 nichts besonderes mehr. Besonders ist allerdings, dass man diese Technerlogie auch von .NET nutzen kann.
Dieser Artikel wird eine Einführung in die Arbeit mit der GPU durch C# geben. Kentnisse über DirectX und HLSL (die Shadersprache) sind empfohlen, aber nicht wirklich benötigt. Im nächsten Artikel wird aus diesem vermittelten Wissen ein simpler MySQL 3.2.3 Passwordcracker entstehen.

Wir werden einen DirectX Wrapper verwenden, um Zugriff auf die dort gelagerte ComputerShader-Klasse zu bekommen. Dabei macht es nicht wirklich einen Unterschied ob SlimDX oder SharpDX verwendet wird, SlimDX gefällt mir persönlich besser. SlimDX ist ein Wrapper um viele DirectX 9-11 Funkionen und Klassen. Also enthält SlimDX im Grunde nur Typedefs und “Verlinkungen”, ein Wrapper eben. Daher können wir oft C++-Code 1 zu 1 übernehmen, nur beim Ressourcen Management muss man anders vorgehen, aber dazu später mehr.

Wie schon erwähnt wird Sourcecode zum eigentlichen Cracker erst in dem nächsten Post kommen, dieser Artikel deckt nur die notwendigen Grundlagen dazu ab. Da der Source des Crackers relativ komplex wird, habe ich mich entschieden die Posts aufzutrennen.

Im Grunde Arbeitet ein Shader nach dem “Input -> Output” Prinzip, wir übergeben also Daten an die GPU (Graphics Processing Unit, falls noch nicht bekannt) und rufen diese nach dem Shaderdurchlauf wieder ab. Dabei ist egal ob es sich um den Pixel -, Vertex - oder in unserem Falle dem Computeshader handelt. Die GPU wäre zwar in der Lage, direkt Speicherbereiche zu manipulieren oder sogar ganze Arrays zurückzugeben, aber im Sinne der Komplexität und der Übersicht werde ich eine Unordered Access View verwenden. Eine UAV ist im Grunde ein Speicherbereich, auf den sowohl die CPU, als auch die GPU Zugriff hat. Dabei setzen wir die UAV, rufen den Shader auf, welcher wiederrum den Grafikbereich solange sperrt bis der Shader seine Arbeit verrichtet hat. Dann haben wir wieder Zugriff auf den Speicherbereich und holen die dort ausgelagerte Texture2D ab. Texture2D? Eine Texture2D eignet sich gut zum schreiben der Resultate, da:

  • Wir pro Pixel 4 Byte setzen können (RGBA)
  • Wir ein graphisches Feedback bekommen und kontrollieren können ob der Shader die Texture gefüllt hat
  • Wir nicht durch komplexe Memorybereiche verwirrt werden :P

Nachteil ist natürlich, dass während dem Shaderdurchlauf der BUS blockiert. Wenn wir also sofort die UAV abrufen bleibt der Grafiktreiber so lange hängen, bis der Speicherbereich freigegeben wurde.

Noch etwas sehr grobe Theorie zur GPU: Die GPU besteht aus vielen, asyncron arbeitenen Kernen. Diese sind speziell auf Fließkommazahlen (Floats) ausgelegt und erreichen so zusammen ein vielfaches der CPU Leistung, 2008 wurde sogar die Teraflop-Grenze gepackt:

In June 2008, AMD released ATI Radeon HD4800 series, which are reported to be the first GPUs to achieve one teraFLOPS scale. On August 12, 2024 AMD released the ATI Radeon HD 4870X2 graphics card with two Radeon R770 GPUs totaling 2.4 teraFLOPS.

Das Problem liegt natürlich auf der Hand: Wir haben viele Kerne, also wie unterteilen wir EINE Aufgabe auf VIELE Kerne? In diesem Falle können wir jeweils das Hashcracking in verschiedene Charsets und Längen unterteilen, aber an dem Crack-Prozess selbst können wir nichts “clustern”. Das liegt daran, dass ich als Grundlage die mysqlfast.c verwende. Dieses Programm nutzt die Schwächen beim Passworthashing unter Mysql 323 aus. Eine Erklärung zu dem doch recht simple gehaltenen Hashingalgorithmus gibt es hier. Dabei nutzt dieser Cracker jeweils die schon berechneten Werte als neue Grundlage, so ist ein “Quereinsteigen” in den Crackprozess AFAIK nicht möglich.

Zurück zu dem Computeshader und der UAV: Wir werden sowohl das Ergebnis (ASCII Chars von 30-120), als auch die Ergebnisse von den einzelnen Threads in einer Grafik wiedergeben. Die erste Reihe [0,0] bis [MAXCHAR,0] wird angeben, ob der Hash gefunden wurde. Zwei Reihen darunter, also in der Reihe [2,0] bis [2,PASSLEN] wird jeweils in dem RED Wert von ARGB ein ASCII-Char des Passwords platzfinden.
Ein Crackresultat sieht dementsprechend (gezoomed) so aus:

Folgende Schritte sind also nötig, um ein MySQL 323 Hash mit der GPU zu knacken:

  • Computeshader, UAV und Resourcen initialisieren
  • Zu crackenden Hash (Initialwerte) über einen ConstantBuffer an den Shader übergeben
  • Computeshader compilieren, diesen und die UAV in der GPU setzen
  • Shader aufrufen
  • UAV wieder abrufen und in eine Texture2D wandeln zurückwandeln
  • Texture2D auswerten

Und ich denke nach dieser Liste versteht Ihr auch, warum ich diese Posts trenne :D

Das war es soweit, der nächste Post folgt hoffentlich bald!

Easy

4 people like this post.
  1. Noch keine Kommentare vorhanden.

  1. Noch keine TrackBacks.


+ zwei = 9