Grundsatztutorial zum Thema "SoftIce", das Powertool

Autor:ZeroJump
Datum:17.07.2002
Target:
Size:0 Bytes
Tools:SoftIce 4.0x
Art des Cracks:Grundlagen


Einleitung

Ein kleines Vorwort: Hallo Cracker, das hier wird ein großes Stück Arbeit für mich, denn die Beschreibung des einzigartigen Tools SoftIce könnte mehrere Seiten füllen. Da mittlerweile aber das Projekt CIP nach und nach bekannt wird und auch das erste Feedback kommt zu unseren Tutorials, gehe ich mit Freude ans Werk :-))

Ein fettes "Danke" an alle, die CIP unterstützen und bekannt machen im Netz.

In diesem Tutorials möchte ich zeigen, wie man SoftIce "cracker-konform" einrichtet und was man mit SoftIce alles machen kann. Dazu habe ich mal wieder ein ziemlich dämliches Beispiel ausgesucht. Ich habe es gewählt, weil keine anderen Programme benötigt werden, es viele Befehle von SoftIce nutzt, und relativ einfach zu verstehen ist. Wir werden heute die Stundenzahl der Windows-Uhr auf einen absurd falschen Wert setzen, der allerdings nur für eine Sekunde angezeigt wird. Warum, erkläre ich später.

Achtung: Dieses Tutorial wird weiter unten auf ein paar Eigenschaften von C++ mit Bezug auf die Windows-Programmierung zurückgreifen. Gemeint sind unten aufgeführte "Strukturen". Was das ist, wird auch unten erklärt, es ist aber nicht Vorraussetzung, sofort zu verstehen, was damit nun wirklich gemeint ist. Ebenfalls nützlich könnten Kenntnisse über den Aufbau eines Prozessors sein, da dieses Tutorial wohl aber nur Newbiez lesen werden, ist es ebenfalls nicht Vorraussetzung zu wissen, wie ein Prozessor arbeitet. Für das Tutorial wichtige Assemblerbefehle werden erklärt.


Was ist ein Debugger?

SoftIce: Zunächst ein Kernsatz, "SoftIce ist ein Debugger". Damit werden wohl die meisten am Anfang nichts anfangen können. Denn wer weiss schon, was eigentlich ein "Debugger" ist. Sicherlich hat man schon mal das Wort "Bug" gehört, welches Fehler in einer Software beschreibt. Demnach könnte man sich unter einem Debugger doch ein Programm vorstellen, was diese Fehler findet und beseitigt. So ist es allerdings NICHT. Ein Debugger ist lediglich in der Lage ein Programm Anweisung für Anweisung, d.h. Assembler-Zeile für Assembler-Zeile, durchzugehen und dem User zu zeigen, was passiert. Letztenendes ist es Aufgabe des Users Bugs zu finden und diese zu beseitigen, indem er seinen Code anders programmiert, nicht aber etwa mit dem Debugger selbst etwas an dem Programm ändert. Allerdings kann man mit dem Debugger trotzdem in den Programmablauf eingreifen, allerdings nur zur Laufzeit des Programs, also wirklich nur dann, wenn es gerade ausgeführt wird.

Ein Debugger ist also ein Tool für Programmierer, um eventuelle Fehlerquellen aufzuspüren. Für das Cracken wird der Debugger eigentlich missbraucht. Denn der Cracker sucht keine Fehler im Programm, sondern er sucht Serials oder Ansatzpunkte für sein weiteres Vorgehen.

Warum man auch das mit einem Debugger machen kann, sollen die folgenden Zeilen beschreiben...


Breakpoints

Um mit softIce in den Code eines Programms zu kommen benötigt man, egal ob Cracker oder Coder, Breakpoints. Ein Breakpoint beschreibt die Stelle, an der der Debugger das Programm anhält, seine eigene Benutzeroberfläche präsentiert und die weitere Kontrolle über den Programmablauf an den User übergibt. Dieser kann dann "live" mitverfolgen, was mit Daten, Obejekte, etc. weiter passiert.

Mit SoftIce lassen sich verschiedene Arten von Breakpoints setzen:

Breakpoints auf Codezeilen
Breakpoints auf API-Funktionen
Breakpoints auf Speicherstellen

Das sind zunächst die, die man am Anfang benötigt. Es gibt andere, zum Beispiel Breakpoints auf Schnittstellen, die aber nur zum Dongle-Cracking benötigt werden, was wohl keiner am Anfang sofort in Angriff nehmen wird.

Am meisten verwendet werden wohl Breakpoints auf API-Funktionen. Das heißt, man setzt einen Breakpoint auf den Aufruf einer API-Funktion, SoftIce unterbricht dann das Programm an der Stelle der ersten Anweisung dieser aufgerufenen Funtkion. API-Funktionen sind die von Windows zur Verfügung gestellten Funktionen, um dem Programmierer die Arbeit zu ersparen, das Rad jedesmal neu erfinden zu müssen. Nur mit diesen Funktionen kann der Programmierer einfache Windows-Fenster, Controls (Buttons, Text-Felder), etc erstellen und steuern, bzw. kontrollieren.

Breakpoints auf Speicherstellen sind nützlich, wenn man verfolgen möchte, wann ein Programm auf bestimmte Daten zugreift. Wenn man weiss, dass sich die Variable Y an der Adresse Z im Arbeitsspeicher befindet, kann man einen Breakpoint auf die Adresse Z setzen, um zu schauen, wann das Programm auf die Variable Y zurückgreift. SoftIce wird bei jedem Speicherzugriff auf diese Adresse unterbrechen.

Breakpoints auf Codezeilen setzt man, um zu gucken, ob ein Programm überhaupt bis an eine gewisse Stelle im code kommt, oder einen anderen Weg geht. Wenn man weiss, dass das Programm zu dieser Codezeile kommen muss und wissen möchte, was mit den Daten danach passiert, sind diese Breakpoints nützlich.


Daten

Nachdem ihr jetzt theoretisch wisst, wie man in ein Programm kommt, wäre es vielleicht praktisch zu erklären, wie ein Debugger Daten präsentiert, bzw. was softIce Euch alles anzeigen kann.

Die Präsentation von Codezeilen ist ähnlich, wie in WDasm (Tut lesen?!), nämlich in Assembler. Und genau das ist auch gemeint, mit den oben schon oft erwähnten "Code-Zeilen". Natürlich werden Euch keine anweisungen, wie beispielsweise

'cout << "Hello Cracker" << endl;' (C++)

angezeigt, sondern reiner Assembler-Code. SoftIce kann außerdem den Inhalt der Prozessorregister anzeigen und manipulieren. In den Prozessorregistern stehen immer die Daten, die der Prozessor für die aktuelle Ausführung des Befehls benötigt. Ein weiterer wichtiger Punkt ist das Betrachten des Inhalts vom RAM.

Grundsätzlich kann man mit SoftIce alle Daten im RAM, alle Daten in den Registern und sogar Assembleranweisungen manipulieren. Das man damit vorsichtig sein sollte, besonders bei den Assembleranweisungen, dürfte klar sein. Das führt, wenn man es fasch macht, eigentlich grundsätzlich zum Programmabsturz.

Die Vorteile der Manipulation von Daten liegen auf der Hand. Man kann dem Programm vortäuschen, das bestimmte Werte vorhanden sind oder lenkt den Programmablauf in eine andere Richtung, bzw. simuliert bestimmte Situationen.


Installation

Mit diesen Möglichkeiten ist SoftIce das Tool, das wohl am Meisten Möglichkeiten bietet, um ein Programm zu cracken.

Nachdem ihr jetzt wisst, was SoftIce alles kann (ihr wisst noch nicht alles), solltet ihr jetzt natürlich lernen, wie man das ganze in der Praxis anwendet. Dazu gehört auch die richtige Installation des Tools.

Zunächst ist zu klären, dass SoftIce am Besten auf einem Win 9x-Rechner (vielleicht auch ME) läuft und man nur dort das volle Potential des Tools ausschöpfen kann. Unter Win2k, bzw. XP taugt SoftIce wenig.

Falls nur ein 2k-Rechner zur verfügung steht ist es ratsam, entweder ein Win9x parallel zu installieren oder sogar einen extra Rechner anzuschaffen fürs Cracken. Das ist sowieso ratsam, da durch das ganze Installieren von Programmen (Shareware aller Art) der Rechner langsamer und langsamer wird und regelmäßig platt gemacht werden sollte. Oder ihr nutzt DriverSuite 2.7, dieses Tutorial bezieht sich allerdings NICHT darauf.

Ich gehe also davon aus, dass ein Win9x-Rechner zur Verfügung steht. Die Installation von softIce ist genauso simple, wie die Installation eines anderen Programms. Die Serial sollte dem Download beiliegen.

Das SoftIce-Setup wird irgendwann nach einer Grafikkarte fragen, die ihr installiert habt. Hier ist Experimentier-Freude gefragt. Ihr solltet zunächst Eure Karte auswählen und versuchen, ob softIce richtig damit arbeitet. Bei mir war das leider nicht der Fall.

Solltet auch ihr Probleme mit der Grafik haben (ihr merkt das schon beim Arbeiten), so wechselt auf den Standard-VGA-Treiber. Wenn dann immernoch Probleme auftauchen bleibt als einziger Ausweg nur noch der Universal Video Driver, bei dem SoftIce nur noch in einem Fenster angezeigt wird. Ich arbeite auch so, alles andere führt zu Problemen. SoftIce ist dann ein wenig langsamer beim Updaten der Oberfläche, man gewöhnt sich aber dran.

Das Setup fragt dann, ob Veränderungen an der autoexec.bat vorgenommen werden dürfen, zwecks Autostart von softIce. Hier sollte man zunächst einfach das Setup Änderungen vornehmen lassen, was als Konsequenz hat, dass SoftIce bei jedem Start aktiviert und geladen wird. Nachträglich besteht die Möglichkeit, dass man eine kleine Batch-Datei schreibt, die es ermöglicht bei jedem Start zu entscheiden, ob softIce gestartet werden soll.


Konfiguration

Nachdem SoftIce installiert worden ist und der Rechner neu gestartet worden ist, fällt dem präzisen Beobachter vielleicht gleich auf, dass beim Booten irgendwann mal was anderes auf dem Bildschirm steht, als sonst. Hier zeigt sich SoftIce zum ersten mal. Auf der Windows-Ebene wird man von SoftIce zunächst überhaupt nichts mitbekommen.

Die magische und enorm wichtige Tastenkombination "STRG+D" holt SoftIce auf den Screen. Jetzt kommt es auf die Einstellungen an, die in der Datei "winice.dat", der Konfigurationsdatei für SoftIce, getätigt worden sind, wie euer SoftIce aussieht. Ich gehe von der Standardkonfiguration aus. Diese ist für Cracker allerdings etwas unangebracht. Deswegen werden wir jetzt SoftIce für uns passend einrichten.

Bei der farblichen Gestaltung werde ich keine Angaben machen, da sich diese letztenendes von Cracker zu Cracker unterscheidet und eben so festgelegt werden sollte, wie es der User am übersichtlichsten findet. Ich werde beschreiben, wie die Fensteraufteilung am Besten ist und was man machen muss, damit man überhaupt Breakpoints auf die Windows-API-Funktionen setzen kann.

Öffnet also die winice.dat mit einem beliebigen Text-Viewer und sucht nach den EXP= - Zeilen. Dahinter stehen immer die Dateien, die Sice beim Laden berücksichtigen soll.

Ein ";" vor der Zeile bedeutet, dass diese auskommentiert ist, also keine Wirkung hat. Um den Zugriff auf die meisten und wichtigstem API-Funktionen zu erlauben entfernt das ";" vor diesen Zeilen:

;EXP=c:\WINNT\system32\kernel32.dll <--- Zugriff auf Textboxen, Dateizugriffe, etc.
;EXP=c:\WINNT\system32\user32.dll <--- DialogBoxen, etc.
;EXP=c:\WINNT\system32\gdi32.dll <--- Das Grafik-Zeugs (nicht wirklich wichtig)
;EXP=c:\WINNT\system32\advapi32.dll <--- Registry-Zugriff

In diesen 4 Dateien sind die meisten Funktionen enthalten, die man zum Cracken braucht, bzw. die Windows anbietet.

Man kann auch alle ";" vor den anderen EXP-Zeilen entfernen, dann hat man Zugriff auf alle Windows-Funktionen, das wird man allerdings nur selten benötigen und wird daher hier außer Acht gelassen.

Sucht als nächstes die Zeile "FAULTS=". Hier wird festgelegt, ob SoftIce bei Fehlern automatisch eingreifen soll und den Programmablauf unterbrechen kann. Wenn diese Zeile nicht exisitieren sollte, schreibt sie einfach dazu. Meine Erfahrungen haben gezeigt, dass es einfach zu empfehlen ist, diese Zeile auf den Wert "OFF" zu stellen und den Rechner im Falle eines Systemfehlers einfach neu zu booten, anstatt mit SoftIce stundenlang zu versuchen da wieder raus zu kommen.

Bei "PHYSMB=" gehört die Größe Eures Rams hin, damit Sice weiß, wie es den Speicher für sich nutzen, bzw. aufteilen kann.

Das eigentliche "Aussehen" wird von den "INIT=" - Zeilen bestimmt. Da steht im Moment nur ein dickes "X", was für nix steht, außer, dass nach Vornehmen der Einstellungen durch SoftIce einfach weitergebootet wird.

Zunächst gibt es die Befehle wc, wd, wl, wr.

Mit dieses Befehlen kann man bestimmte Fenster in SoftIce an- und abschalten. w = Window, c = Code, d = data, l = locals, r=registers.

Wichtig für den Cracker sind das Data-, das Code- und das Register-Fenster.

Besonders interessant ist das Register-Fenster, weil hier auch die aktuell gesetzen Prozessor-Flags angezeigt werden. (Lernt, wie ein Prozessor arbeitet, sonst gibts kein Durchkommen in der Cracking-Welt)

Die WC- und WD- Befehle kann man noch mit einer Zahl kombinieren, was bewirkt, dass das Fenster auf jeden Fall eingeschaltet ist und X Zeilen groß ist. Beispielsweise bewirkt wc 30 ein Code-Fenster, dass 30 Zeilen Code auf einmal anzeigt. Es ist wichtig ein großes Code und ein großes Data-Fenster zu haben, damit man vorrausschauend denken und planen kann. Das Locals-Fenster ist vollkommen uninteressant und sollte abgeschaltet werden / bleiben.

Der "Lines"-Befehl stellt die insgesamt verfügbaren Zeilen der gesamten SoftIce-Overfläche ein.

Eine INIT-Zeile für die Fensterangaben könnte also wie folgt aussehen: INIT="lines 60; wc 30; wd 20; X;"

Euch ist sicher aufgefallen, dass einzelne Befehle durch ein ";" getrennt werden. Ich weiß gerade nicht genau, ob das Registerfenster und das Locals-Fenster standardmäßig aktiviert oder deaktiviert oder gemischt sind, ihr könnt das ja ausprobieren und gegebenfalls noch den "wr"- oder "wl"-Befehl nutzen, um die Fenster ein- oder auszuschalten.

Eine weitere INIT-Zeile bringt Farbe ins Spiel. INIT="color 1F 1E 71 70 17;X;" Jedes Zeichenpaar stellt die Werte für einen Bereich des Fensters dar, für welche kann ich Euch leider nicht mehr sagen, ausprobieren ist angesagt. Das erste Zeichen stellt den wert für die Hintergrundfarbe, das zweite Zeichen den wert für die Vordergrundfarbe dar. Zulässige Werte gehen von 0 bis F, sind also hexadezimal anzugeben.

Das mit den Farben kann sehr nervig sein, wenn man alles ausprobieren muss, ist aber sehr zu empfehlen, um die perfekte Kombination aus allem zu erhalten.

Wer die Maus in SoftIce lieber deaktiviern möchten, der setzt MOUSE= noch auf OFF. Die Maus macht eigentlich immer irgendwann Probleme und man brauch sie nicht wirklich.

Es gibt noch mehr Einstellungen in der winice.dat, die allerdings im Moment nicht wirklich wichtig sind.


Übung an der Systemuhr

Wenn ihr Eure Traumkonfiguration erreicht habt, dann kann es endlich losgehen. Ich werde Euch jetzt an Hand eines extrem dämlichen Beispiels ein paar Befehle von softIce beibringen. Das Beispiel ist noch blöder als das in meinem Tutorial zu WDasm. Wir werden die Windows-Uhr missbrauchen, indem wir dafür sorgen, dass Windows für eine Sekunde einen absurd falschen Wert für die Stundenangabe in das Text-Feld schreibt.

Ich gehe jetzt natürlich davon aus, dass Euer SoftIce entsprechend konfiguriert ist und auch geladen wird beim Booten.

OK, legen wir los. Zunächst brauchen wir natürlich unsere Windows-Uhr. Die holen wir mit einem Doppelklick auf die Zeit-Anzeige unten rechts in der Task-Leiste auf den Screen. Dort wird in einem Text-Feld die aktuelle System-Zeit auch digital angezeigt, beispielsweise so: 04:23:02

Die Uhr wird wohl noch jeder verstehen hoffe ich. Die Uhr wird offenbar im Sekundentakt aktualisiert. (mein Gott, wie kommt das?) (ich komme mir wirklich albern vor)

Um jetzt mit SoftIce an die Daten zu kommen benötigen wir erst mal einen Ansatzpunkt. Zum Beispiel ist zu überlegen, wie das Edit-Feld eigentlich weiß, wieviel Uhr es ist. (gleich such ich mir was anderes zum Üben, lol)

Zeitangaben werden unter Windows mit den API-Funktionen GetLocalTime und GetSystemTime besorgt. Das weiß ich, weil ich erstens die MSDN-CD's besitze (Microft Developers Network) und man das außerdem in der Win32 SDK Reference nachlesen kann.

Zumindest die Referenz ist ein enorm wichtiger Bestandteil Eurer Ausrüstung. Das MSDN beschreibt allerdings meist detaillierter den Sachverhalt. Saugt die Referenz irgendwo über Google, das aktuelle File ist um die 20 MB groß. Ideal wären natürlich auch die MSDN-CD's. Keine Ahnung, ob man die auch bekommt ohne VB oder VC++ zu kaufen?!

OK, wir waren bei der Zeit. GetLocalTime und GetSystemTime besorgen also die Zeit. Bei beiden Funktionen wird als Parameter eine Datenstruktur übergeben, die nach Aufruf der Funktion die eigentliche Zeit enthält. Jetzt wissen wahrscheinlich nicht viele von Euch, was mit Datenstruktur gemeint ist. Stellt Euch eine Struktur einfach als logische Gruppierung von Variablen vor. Ich kann doch Zeit in Stunden, Minuten, Sekunden, usw. aufteilen, genauso wird es gemacht. Nur, dass zu Zeit hier auch noch das Datum hinzukommt. Die übergebene Datenstruktur ist vom Typ SYSTEMTIME, diese ist auch in der API-Referenz beschrieben:

typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
}

Was ist nun wieder ein WORD? Es ist die Größenangabe der Variable, unter Windows bezeichnet ein Word einen 2 Byte-Wert, also insgesamt 16 Bit. Die einzelnen Variablen, wie wYear, wMonth, etc haben wohl logische Namen und müssen nicht näher erläutert werden. Das kleine "w" steht einfach für "Word"! Interessant ist eben zu wissen, dass durch den Aufruf von GetSystemTime oder GetLocalTime die als Parameter übergebene Struktur SYSTEMTIME mit Werten gefüllt wird, auf die wir Zugriff haben, wie sich zeigen wird.

Welche Funktion letztenendes benutzt wird (GetLocalTime oder GetSystemTime) kann man vorher nicht wissen, man setzt einfach einen Breakpoint auf beide und guckt dann welche Funktion gebreakt hat, SoftIce ist so nett und zeigt das an. Ans Werk: Holt mit "STRG+D" SoftIce auf den Screen. Sieht schon recht verwirrend aus am Anfang. In dem Moment, wo ihr softIce aktiviert werden ALLE anderen Prozesse, ja auch das OS, unterbrochen. Es geht praktisch nix mehr. Lässt sich einfach in einem Netzwerk testen, indem man einfach probiert einen Rechner anzupingen, der SoftIce gerade auf dem Screen hat, von diesem Rechner kommt garantiert keine Antwort. Allerdings stimmt das ja nicht ganz, schließlich ist ja der Prozess SoftIce aktiv und wird bearbeitet. Ich hab keine Ahnung, wie das funktioniert und möchte es ehrlich gesagt im Moment noch nicht wissen.

Auch die UHR läuft in diesem Moment nicht weiter, rofl.

Ihr seid jetzt in den Prozess gebreakt, der gerade vom Prozessor bearbeitet wurde, welcher das ist wird Euch in SoftIce ganz unten rechts in der Ecke angezeigt, bei mir ist das gerade die "kernel32.dll". Natürlich kann das aber auch ein anderer Prozess sein, der auch aktiv ist und gerade bearbeitet wird. Ist aber auch egal, denn wir wollen an die Zeit.

Der Befehl für SoftIce, um einen Breakpoint zu setzen heißt "bpx " beschreibt dabei, worauf ein Breakpoint gesetzt werden soll. Für den bpx-Befehl können das Code-Adressen sein oder eben API-Funktionen.

Der vollständige Befehl um einen Breakpoint auf die GetLocalTime-Funktion zu setzen lautet also "bpx GetLocalTime". Dabei ist peinlichst auf korrekte Schreibweise zu achten. Wenn alles klappt passiert eigentlich gar nix, ansonsten gibt SoftIce eine Fehlermeldung aus, "Symbol not defined". Dann stimmt wohl in Eurer Konfiguration irgendwas nicht.

Wiederholt das ganze auch noc für GetSystemTime, also "bpx GetSystemTime". Jetzt habt ihr 2 Breakpoits. Diese kann man sich wieder auflisten lassen, der Befehl dazu lautet: "bl"

Das Ergebnis des Befehls sieht so aus:

00) BPX KERNEL32!GetLocalTime
01) BPX KERNEL32!GetSystemTime

Die erste Spalte ist die Nummerierung der Breakpoints, die bei 0 startet. Die zweite beschreibt die Art des Breakpoints. BPX bedeutet "Breakpoint on execution". Die letzte Spalte zeigt an, worauf der Breakpoint gesetzt ist. In unserem Fall die beiden API-Funktionen. Das KERNEL32 informiert uns darüber, wo diese Funktionen definiert sind, eben in der kernel32.dll, das "!" ist einfach ein Trennzeichen. Jetzt dürfte auch klar sein, warum wie vorhin die ";" vor den EXP-Anweisungen entfernt haben. SoftIce weiss jetzt, dass es diese API-Funktionen gibt, ansonsten hätte man keinen Zugriff auf die "kernel32.dll".

Damit mit unseren Breakpoints jetzt auch was passiert müssen wir Windows einfach ganz normal weiterlaufen lassen. Dazu gibt man entwerder ein "X" ein oder drückt F5, was wesentlich schneller geht. Ihr seht kurz Windows, dann BREAKT SoftIce. Was ist passiert? Nun, das steht unten im Ausgabefenster von SoftIce:

Break due to BPX KERNEL32!GetLocalTime (ET=374.20 milliseconds)

Das heißt soviel wie, dass SoftIce auf den Breakpoint auf GetLocalTime angesprochen hat. Das mit der Zeitangabe dahinter verstehe ich ehrlich gesagt auch nicht.

Wollt ihr wissen, welcher Prozess nun eigentlich dafür verantwortlich ist, dass die Windows-Zeit aktualisiert wird? Guckt einfach nach unten rechts. Da steht "Rundll32". Ist doch gut zu wissen. :-))

Im Code-Fenster befindet ihr Euch vor der ersten Assembleranweisung die zu der GetLocalTime-Funktion gehört.

Was ist eigentlich mit der GetSystemTime-Funktion? Nun, offenbar hat diese nicht gebreakt und ist daher für den weiteren Verlauf unwichtig, wir löschen deshalb diesen Breakpoint. Das geht mit dem "bc " BreakpointClear-Befehl. ist die Nummer des Breakpoints, den ihr löschen wollt. "bc 1" löscht also den Breakpoint auf GetSystemTime, wer's nicht glaubt, kann sich ja mit "bl" die Liste der Breakpoints danach angucken.

Wir stehen mit unserem Debugger jetzt also mitten in der GetLocalTime-Funktion, befinden uns also mitten im Windows-Jungel, bzw. der "kernel32.dll". Unser Ziel ist aber dahin zu kommen, von wo aus die GetLocalTime-Funktion aufgerufen wird, weil dort ja auch irgendwo die aktuelle Zeit zu finden sein muss. Glücklicherweise gibt es eine einfache Methode da hin zu kommen. Man benutzt die Taste F11, die IMMER zu der Stelle springt, von wo aus die Funktion (der Call) aufgerufen wurde. Drücken wir also F11. SoftIce flattert kurz und wir kommen an der Stelle im Code raus, die auf den Call zu GetLocalTime folgt. Im Code-Fenster sehen wir noch als oberste Anweisung: CALL [KERNEL32!GetLocalTime];

So, jetzt haben wir schon mal die Stelle von wo aus GetLocalTime aufgerufen wird. GetLocalTime braucht aber als Parameter die SYSTEMTIME - Struktur, die VOR dem Call zu GetLocalTime übergeben werden muss. Gucken wir doch mal, was VOR der Call-Anweisung zu GetLocalTime so für Anweisungen stehen im code-Fenster. Dazu müssen wir natürlich hochscrollen können in dem Fenster. Das könnt Ihr durch drücken und gedrückt halten von STRG und den Cursortasten für hoch und runter bewältigen. Scrollt so 4-5 Anweisungen nach oben.

WICHTIG: Bedenkt, dass Ihr natürlich nicht die Anweisungen selbst wieder hochscrollt, sondern lediglich betrachtet, was schon geschehen IST. Nur die markierte Zeile und die darauffolgenden können noch ausgeführt werden.

WICHTIG 2: Die GetLocalTime wird von mehreren Stellen aufgerufen (grummel), wenn bei EUCH die Anweisungen über dem CALL nicht die gleichen sind, wie bei mir, dann drückt F5 (Programm weiterlaufen lassen) und wartet bis SoftIce wieder breakt und wiederholt die obigen Schritte, bis ihr das gleiche Ergebnis habt wie ich.

Die Anweisungen über dem CALL lauten

015F:7800326C 8B7508 MOV ESI, [EBP+08] <--- ESI = Adresse an der Daten der SYSTEMTIME-Struktur
hinterlegt werden.
015F:7800326F 56 PUSH ESI <--- Parameterübergabe

015F:78003270 FF1578730078 CALL [KERNEL32!GetLocalTime] <--- Der Call zu GetLocalTime

So, erstmal ist zu bemerken, dass die Zahlen in der ersten Spalte die Adresse der aktuellen Anweisung ist und außerdem nicht überall gleich ist. Das kann von Windows-Version zu Windows-Version verschieden sein.

Um zu verstehen, was hier passiert sind schon ein paar Assemblerkenntnisse nötig. Die MOV-Anweisung schiebt zunächst einen Wert in das Prozessorregister ESI. Dieser Wert ist die Adresse im RAM, an der die Daten aus der SYSTEMTIME-Struktur hinterlegt werden. Die PUSH-Anweisung übergibt die Adresse aus ESI letztenendes an die Funktion GetLocalTime, die dort dann Daten hinterlegt. Wer genau wissen will, wie Parameterübergabe in Assembler funktioniert sollte das Stack-Tutorial von Medardus lesen, bald auch verfügbar auf CIP (hoffe ich).

Jetzt die Idee: Wir breaken zunächst VOR dem Call zu GetLocalTime, gucken was an der Adresse, die ESI beinhaltet steht und verfolgen, wie sich diese Werte ändern, wenn wir über den Call zu GetLocalTime hinweg-TRACEN.

Also brauchen wir einen neuen Breakpoint. Aber wir löschen erst den alten. Um alle Breakpoints aus einer Liste zu löschen benutzt man den Befehl "bc *". Jetzt setzen wir einen neuen Breakpoint auf die Adresse, an der ESI die Adresse für die SYSTEMTIME-Struktur zugewiesen bekommt. Es ist also ein Breakpoint auf die Adresse 015f:7800326C. Nur reicht es SoftIce, wenn man die Zahl nach dem Doppelpunkt angiebt, d.h ihr gebt ein: "bpx 7800326C". Die Zeile wird irgendwie markiert um deutlich zu machen, dass ein Breakpoint auf sie gesetzt ist. Wie, hängt von Eurer Farb-Konfiguration ab.

Drückt dann F5, um das Programm weiterlaufen zu lassen und wartet bis SoftIce wieder breakt. Nachdem SoftIce wieder erschienen ist, steht der Balken, der die aktuelle Codezeile markiert auf der MOV ESI, [ESP+08] - Anweisung. Diese Zeile ist noch nicht ausgeführt, damit das passiert drückt die Taste F10. Damit kann man eine Anweisung weiterschreiten. Man nennt das TRACEN. Ihr könnt beobachten, dass im Registerfenster der Wert in ESI geändert wird und ESI farblich hevorgehoben wird, was bedeuten soll, dass sich der Wert dieses Registers geändert hat. In der Vorgehensweise, die ich beschrieben habe, käme als nächstes zu schauen, was an der Adresse, die in ESI steht für Daten hinterlegt sind. Dazu brauchen wir das Data-Fenster.

Der Befehl um sich den Inhalt von Speicherstellen anzuzeigen heißt "d ", wobei die Speicheradresse ist. Man kann aber auch schreiben "d esi". Führt den Befehl aus und beobachtet, was im Data-Fenster passiert. Die erste Spalte im Data-Fenster ist die Adresse, die man betrachtet, die nächsten 16 kleinen Spalten zeigen die hinterlegten Daten im Hex-Format, die letzte große zeigt die Hex-Werte als Charakters an. Das ist gut, wenn man auf der Suche nach einer Serial ist oder einem anderen String. Wichtig ist, dass die Adresse aus der ersten Spalte nur die Adresse für die erste der 16 kleinen Spalten ist. Die 2. der 16 kleinen Spalten hat logischerweise die Adresse der 1. kleinen + 1.

Jede kleine Spalte ist 1 Byte. 1 Byte sind 8 Bit. Damit lassen sich 256 Zustände von 0-255 darstellen, wobei 255 hexadezimal ausgedrückt FF ist. Das ist die Erklärung, warum eine kleine Spalte nochmal 2 Zeichen breit ist.

Sicherlich ist Euch aufgefallen, dass Adressen und Daten im Data-Fenster ausschließlich hexadezimal wiedergegeben werden, außer natürlich in der Charakter-Spalte.

Nachdem ihr nun also Euch die Stelle, die in ESI gespeichert ist angeguckt habt (bei mir 0063F854), werdet ihr vielleicht etwas enttäuscht sein?! Nun ja, was habt ihr erwartet? Da stehen einfach ein paar Bytes, im Moment nur Speichermüll, der völlig uninteressant ist. Wichtig wirds ja erst wenn wir über den Call zu GetLocalTime hinwegtracen. Wir benutzen also jetzt wieder unsere Trace-Taste F10, um Anweisung für Anweisung abzuarbeiten. Beobachtet genau den Inhalt der Speicherstelle, die im Data-Fenster angezeigt wird. Nachdem wir über die PUSH - Anweisung hinweggetract haben tut sich gar nix, warum auch, wir übergeben ja lediglich die Adresse als Parameter. Wenn wir aber über den Call zu GetLocalTime hinwegtracen ändert sich im Data-Fenster schlagartig die oberste Zeile. Jetzt hat die Funktion unsere SYSTEMTIME-Struktur mit den aktuellen Werten gefüllt. Ich gebe zu, man sieht das nicht auf den ersten Blick, aber ich werde es jetzt beweisen. Dazu nochmal die SYSTEMTIME-Struktur:

typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
}

Ich habe oben schon erwähnt, das ein WORD 2 Byte groß ist. Wir haben 8 verschiedene Werte in der Struktur, diese muss also eine Größe von insgesamt 2Byte * 8 Werte = 16 Byte haben. Die komplette oberste Zeile im Data-Fenster (außer der Adresse natürlich) hat sich verändert, also alle SECHZEHN kleinen Spalten. Eine Spalte = 1 Byte. Das passt doch: Wir haben gesehen, dass sich 16 Byte verändert haben und die Struktur ist 16 Byte groß.

Jetzt müssen wir nur noch die Daten aufdröseln. Laut Information ist im ersten WORD der Struktur, also in den ersten beiden Bytes das Jahr gespeichert. Im Data-Fenster von SoftIce beschreiben also die ersten beiden kleinen Spalten das Jahr in dem wir uns befinden. Ich geh jetzt mal von 2002 aus. Hmmm, in SoftIce steht in den ersten beiden Spalten "D2 07". Sieht nicht gerade wie 2002 aus. Ist es aber doch. Erstens, das ganze sind Hexadezimalwerte. Zweitens, die Bytes sind vertauscht. Ich weiß nicht warum, ich glaube es liegt an Intel, aber Daten, die in den Arbeitsspeicher geschrieben werden, werden praktisch von rechts nach links geschrieben. In Wirklichkeit muss man also "D2 07" als "07 D2" auffassen. Rechnet man das in dezimal um, so erhält man 2002. SoftIce kann auch rechnen:

Der Befehl "? " gibt das Ergebnis der Berechnung aus. Gibt man dabei einfach einen hexadezimalen Wert an, so erhält man als Ergebnis eben unter anderem auch den dezimalen Wert.

"? 07D2" liefert:

00000007D2 0000002002,

erste Spalte Ergebnis hex, zweite Spalte Ergebnis dez.

Das zweite Word aus der SYSTEMTIME-Struktur soll der aktuelle Monat sein. Bei mir is gerade Oktober. Ich habe also für die nächsten beiden Bytes "0A 00" stehen, vertauscht man diese und rechnet man das in dezimal um "? 000A" so erhält man 10, wie Oktober.

Wir wollten doch aber an der Zeit rumpfuschen. Nehmen wir uns also die Stunden vor. Dazu überspringen wir die nächsten 4 Bytes und widmen uns also der 9. und 10. Spalte. Da stehen bei mir gerade die Werte "02 00". Vertauschen, Umrechnen in dezimal liefert 2, wer hätte das gedacht. 2 Uhr nachts, ja, da arbeite ich noch :-)). In Wirklichkeit is aber schon 4:47 Uhr, weil das Tut-Schreiben so lange dauert :-((.

Das Programm wird sicherlich jetzt nach und nach die Bytes für die Zeit auslesen. Bevor das geschieht werden wir jetzt die Daten manipulieren. Dazu gibt es den "e"-Befehl, wie "edit".

Wenn ihr einfach "e" eingebt, könnt ihr an der aktuell angezeigten Ram-Position runpfuschen, ansonsten wird der Befehl "e" in Kombination mit einer Adresse eingegeben, an der rumgebastelt werden soll. Da wir aber schon da sind, wo wir hinwollen, geben wir einfach "e" ein. Der Cursor springt an das erste Byte, die erste kleine Spalte. Mit den Cursortasten könnt ihr euch bis zu dem Wert für die Stunden durchschlagen. Hier kann jetzt jeder beliebige Wert eingegeben werden, solange er hexadezimale Kriterien erfüllt und kleiner als "FF" (255) ist. ich geb mal 20 ein, was umgerechnet in dezimal 32 wäre. Jetzt steht der Wert für Stunden auf 20 hex, was wohl jedem komisch vorkommen wird. ("es ist zweiunddreißig uhr fünfzehn :-)) ) Die Eingabe im RAM beendet ihr durch drücken von Return.

In allen nachfolgenden Anweisungen ist das Programm damit beschäftigt, die neuen Werte aus der SYSTEMTIME-Struktur in das Text-Feld für die Uhr unterzubringen. Das müssen wir nicht mitverfolgen. Bevor wir das Programm weiterlaufen lassen drücken wir aber F4, um SoftIce zu verstecken, um nochmal einen Blick auf die Zeit werfen zu können. Das SoftIce aber immernoch aktiv ist beweist die Tatsache, dass die Uhr nicht weiterläuft. Nochmaliges drücken der F4-Taste bewirkt das Wiederanzeigen von SoftIce. Unser letzter Breakpoint sollte aktiviert bleiben, dann breakt SoftIce wieder bevor wieder eine neue Zeit (wieder eine vernünftige) in das Text-Feld geschrieben wird. Wir können uns dann mit F4 davon überzeugen, dass unsere Manipulation erfolgreich war. OK, wenn ihr sicher seid, dass der Breakpoint aktiv ist drückt F5. Eventuell sieht euer schnelles Auge noch, dass die Stundenanzeige auf 32 steht, bevor SoftIce wieder breakt, ansonsten benutzt F4, um SoftIce zu verstecken.

So, das sollte geklappt haben. Leider ist die Manipulation nur für eine Sekunde aktiv, dann wird die Zeit erneut ausgelesen und in das Text-Feld geschrieben, aber egal. Noch ein Kommentar, Werte für die Stunden >99 werden nicht in das Text-Feld eingetragen, passen wohl nicht rein. Ich tippe darauf, dass dann einfach der alte Wert erhalten bleibt.

Es sollte ja nur zeigen, wie man mit Sice arbeiten kann. Ich fands lustig.

Zu guter Letzt löscht alle Breakpoints "bc *" und verlasst SoftIce "STRG+D", "X", oder "F5".


Suchen mit SoftIce

Jetzt noch was wichtiges, der Suchbefehl:

"s l ''"

= Speicheradresse von wo ab zu suchen ist
= Speicheradresse bis zu der gesucht wird
= Zeichenkette die gesucht wird

Der Suchbefehl kann immer nützlich sein, wenn man mal den Faden verloren hat und eine günstige Möglichkeit sucht wieder ins Programm zu finden. Beispielsweise sucht man eine Zeichenkette, erhält eine Adresse im RAM und kann einen Memory-Breakpoint darauf setzen.

Wenn man weitersuchen möchte braucht man nur noch "s" einzugeben. Als Werte für und sind einfach der Bereich von 0 bis FFFFFFFF (IMMER Hex-Werte) Standardwerte geworden, also der ganze RAM.


Weitere interessante Features

Memory-Breakpoints: Der Befehl um einen Memory-Breakpoint zu setzen lautet "bpm ", wobei eine beliebige Adresse im RAM sein kann.

Die Tasten F8, F10, F11 und F12:

F8: Mit dieser Taste kann man wenn man im Code-Fenster über einer Call-Anweisung steht in diesen hineingehen, anstatt einfach darüber hinwegzutracen.

F10: Schon beschrieben, damit TRACT (träist) man eine Anweisung weiter

F11: Springt aus einem Call heraus zu dem Punkt, von dem der Call aufgerufen wurde

F12: Springt bis zur nächsten RET-Anweisung. Kann man benutzen, um schneller vorranzukommen, die Funktion lässt sich jetzt schlecht erklären, in den Cracking-Tutorials, wird deutlich werden, was man damit macht.

Register-Werte manipulieren: Mit dem Befehl "r" optional gefolgt von kann man den wert eines Prozessor-Registers manipulieren. Die Eingabe wird durch Drücken von Return abgeschlossen.

Andere Namen für SoftIce: SoftIce wird nur selten als SoftIce bezeichnet. Eingebürgert hat sich die Bezeichnung Sice und auch die Abkürzung SI. Ich habe im Tut probiert "SoftIce" durchzuhalten, kann aber sein, dass irgendwo mal Sice steht, tschuldigung.


Abschließendes

Das war mein Tutorial für SoftIce-Anfänger. Ich weiß nicht, ob es besser ist, als andere die im Netz verfügbar sind, aber ich denke es hilft Newbiez, sich mit SoftIce anzufreunden. Mit der Zeit wird man Routine bekommen und irgendwann mal über dieses Tutorial lachen, bzw. über sich selbst, weil man nix gepeilt hat.

So long, ZJ




Hast Du noch Fragen oder Probleme mit dem Tutorial? Zögere nicht mir eine EMail zu schicken, ich werde versuchen zu helfen: Contact

Besuch uns wieder unter http://cip.katz.ws

oder unser Board: http://cip-board.katz.ws