<!--coloro:Green--><span style="color:Green"><!--/coloro--><!--sizeo:5--><span style="font-size:18pt;line-height:100%"><!--/sizeo-->Das Thema: Software besser schützen (Teil 2)<br /><br /><!--sizec--></span><!--/sizec--><!--colorc--></span><!--/colorc-->Im zweiten Teil geht es darum Methoden zu coden um es den Crackern schwerer zu machen.<br /><br /><br />Vorab:<br /><!--coloro:Black--><span style="color:Black"><!--/coloro--><!--sizeo:2--><span style="font-size:10pt;line-height:100%"><!--/sizeo-->OK<br />Wir haben im ersten Teil gelernt, dass es nicht auf viele oder komlizierte Algos ankommt, denn die Cracker setzen an der der Stelle an, wo die ausgelesene ID mit der gespeicherten verglichen wird.<br />Aber was kann man dann tuen?<br />Darum soll es in diesem Teil gehen.<br /><br />Was benötigt ein Reverser um ein Programm zu cracken?<br />Um sich gegen bestimmte Methoden und Technicken der Cracker zu schütze muss man erstmal wissen wie sie vorgehen.<br />Die standart Vorgehensweise wurde ja bereits in Teil 1 behandelt.<br />Dabei sind wie so vorgegangen:<br /><br />-String suchen<br />-Auf Messageboxen achten<br />-Sprung zur Fehlermeldung suchen<br />-Sprung patchen<br /><br />Außerdem benötigt jeder reverser einen Debugger mit dem er tracen, BPs setzen und viele andere Sachen machen kann.<br /><br />Gegenmaßnamen:<br /><br />Jetzt geht es darum anhand der oben gesammelten Liste Gegenmaßnahmen zu entwickeln.<br /><br />Bleiben wir also mal bei der absolut wichtigsten Sache für den Cracker:<br />Sein Debugger.<br />Ohne ihn würde garnichts laufen.<br />Wie wäre es also zu versuchen zu erkennen ob unser Programm gerade in einem Debugger läuft?<br />Es gibts viele Methgoden zu erkennen ob ein Debugger läuft.<br />Einige sind leicht zu umgehen, einige schwer.<br />Die einfachste Methode ist die IsDebuggerPresent API.<br /><br />Unser Code sieht also jetzt so aus:<br /><!--sizec--></span><!--/sizec--><!--colorc--></span><!--/colorc-->Visual Basic:
<br /><!--coloro:Black--><span style="color:Black"><!--/coloro--><!--sizeo:2--><span style="font-size:10pt;line-height:100%"><!--/sizeo--><br />Es wird also lediglich die API aufgerufen und wieder überprüfrt ob der Rückgabewert 1 also ob unser programm debugged ist und demendsprechend das Programm beendet.<br /><br />Also laden wir das Proramm mal in Olly und starten es direkt.<br />Unser programm hat gemerkt, dass es debugged war und sich beendet.<br />Allerdings liegt auch hier das Problehm in der IF Abfrage die genau wie die Hardware ID sehr leicht gepatched werden kann.<br />Eine Idee wäre wenn unser Programm debugged ist einen Integer auf 1 zu setzen den wir dann hinterher nochmal überprüfen können.<br /> <br /><!--sizec--></span><!--/sizec--><!--colorc--></span><!--/colorc-->Visual Basic:
<br /><br />Der Cracker wird jetzt nur den ersten Check patchen, da der andere das Programm nicht direkt beendet.<br />Ein anderer Vorteil ist, dass man nun sehr oft im Programm checken kann ob debugged = 10 ist.<br />Das gleiche kann man auch mit dem Hardware ID check machen. Das mache ich hier allerdings nicht, da under Programm dann nur noch aus if Abfragen bestehen würde.<br /><br />Ein weiteres problehm bei unserer isdebuggerpresnent API ist, dass sie ein Olly Plugin einfach unwirksam machen kann ohne dass der Cracker etwas patchen muss.<br /><br />Deshalb wäre es von Vorteil einen weiteren Anti Debug Check einzubauen, der nicht so leicht durch ein Plugin unwirksam gemacht werden kann.<br /><br />Wir benötigen Volgende APIs:<br />GetCurrentProcessId<br />OpenProcess<br />und <br />NtQueryInformationProcess<br /><br />Ich habe mal eine Funktion dazu geschrieben:<br /><br />Visual Basic:
Code:
<br />private Function ret() As String<br />Dim pID As Long<br />Dim hProcess As Long<br />Dim bla As Long<br /><br />pID = GetCurrentProcessId 'Prozess ID auslesen<br />hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0&, pID) 'Handle zum Prozess speichern<br />ret = NtQueryInformationProcess(hProcess, 7&, bla, Len(bla), ByVal 0&) 'Debug Port vom Prozess ermitteln und in bla speichern<br />ret = bla<br />End Function<br />
<br /><br />Um nun zu prüfen ob ein Debugger läuft muss man überprüfen ob ret = -1 ist.<br /><br />Ihr merkt schon, dass im Grunde alles in einer IF Abfrage endet, die wieder ganz leicht gepatched werden kann.<br /><br />So sieht der Code jetzt aus:<br /><br />Visual Basic:
Code:
<br />Private Declare Function IsDebuggerPresent Lib "kernel32.dll" () As Long<br />Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long<br />Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long<br />Private Declare Function NtQueryInformationProcess Lib "ntdll" (ByVal ProcessHandle As Long, ByVal InformationClass As Long, ByRef ProcessInformation As Any, ByVal ProcessInformationLength As Long, ByRef ReturnLength As Any) As Long<br />private Const PROCESS_QUERY_INFORMATION = &H400&<br /><br />Private Sub Form_Load()<br />Me.Hide<br />Dim UsrName as string<br />Dim SavedUsrName as string<br />dim Debugged as integer<br /><br />UsrName = environ("Username")<br />SavedUsrName = "Max Mustermann"<br /><br />if IsDebuggerPresent = 1 then<br />end<br />end if<br /><br />if IsDebuggerPresent = 1 then<br />debugged = 10<br />end if<br /><br />if ret = -1 then<br />end<br />end if<br /><br />if UsrName = SavedUsrname Then<br />Me.show<br />else<br />Msgbox "Sorry falscher Name!"<br />end<br />end if<br /><br />if debugged = 10 then<br />end <br />end if<br /><br />End Sub<br /><br />private Function ret() As String<br />Dim pID As Long<br />Dim hProcess As Long<br />Dim bla As Long<br /><br />pID = GetCurrentProcessId 'Prozess ID auslesen<br />hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0&, pID) 'Handle zum Prozess speichern<br />ret = NtQueryInformationProcess(hProcess, 7&, bla, Len(bla), ByVal 0&) 'Debug Port vom Prozess ermitteln und in bla speichern<br />ret = bla<br />End Function<br />
<br /><br /><br />Ok das sollte erstmal reichen mit AntiDebug Protections.<br /><br />Wie würde der Cracker jetzt wohl vorgehen wenn er keine Plugins verwenden würde?<br />Wahrscheinlich würde er einen BreakPoint auf die API IsDebuggerPresent und NtQueryInformationProcess setzen um zu gucken ob diese aufgerufen werden.<br /><br />Dagegen hab ich ausnahmsweise einmal ein Mittel was NICHT in einer IF Abfrage endet:<br />Eine Funktion die den Breakpoint einfach ignoriert <br />Das funktioniert so:<br />Wenn man in Olly einen Breakpoint setzt überschreibt Olly das erste Byte der API mit "CC".<br />Meine Funktion Überschreibt dieses Byte nun wieder mit dem original Byte, sodass Olly nicht mehr breakt.<br /><br />Benötigte APIs:<br />GetProcAddress<br />GetModuleHandle<br />VirtualProtect<br />CopyMemory<br /><br /><br />Visual Basic:
Code:
<br />Private Function ProtectAPI(Library As String, Name As String, OldHexByte As Byte) As Boolean<br />Dim Ret(1 To 2) As Byte 'Byte array für die Rückgabewerte der APIs<br />Dim mAddress As Long ' API Adresse<br />Dim OldFlag As Long ' Altes Protection Flag<br /><br />mAddress = GetProcAddress(GetModuleHandle(Library), Name) 'Die Adresse von der API die man schützen will ermitteln<br />If mAddress = 0 Then<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />If VirtualProtect(mAddress, 1, PAGE_EXECUTE_READWRITE, OldFlag) = 0 Then 'Schreibzugriff auf das erste Byte der API holen<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />CopyMemory ByVal mAddress, OldHexByte, 1 'Das original Byte an die Adresse kopieren <br /><br />If VirtualProtect(mAddress, 1, OldFlag, VarPtr(OldFlag)) = 0 Then ' Altes Flag wieder herstellen<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />ProtectAPI = True<br /><br />End Function<br />
<br /><br />Die ersten beiden Parameter sollten klar sein.<br />Nur woher weiss ich das original Byte der API?<br />Ich habe es immer so gemacht:<br />Beliebiges programm in olly laden -> rechtsklick -> search for -> Name in all modules<br /><br />Dann den namen der API eintippen, Doppelklick drauf und links steht dann das erste Byte.<br /><br />Das is dann also unser Code:<br /><br />Visual Basic:
Code:
<br />Private Declare Function IsDebuggerPresent Lib "kernel32.dll" () As Long<br />Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long<br />Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long<br />Private Declare Function NtQueryInformationProcess Lib "ntdll" (ByVal ProcessHandle As Long, ByVal InformationClass As Long, ByRef ProcessInformation As Any, ByVal ProcessInformationLength As Long, ByRef ReturnLength As Any) As Long<br />Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long<br />Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)<br />Private Declare Function VirtualProtect Lib "kernel32.dll" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flNewProtect As Long, ByRef lpflOldProtect As Long) As Long<br />Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long<br /><br />Private Const PAGE_EXECUTE_READWRITE = &H40<br />Private Const PROCESS_QUERY_INFORMATION = &H400&<br /><br />Private Sub Form_Load()<br />Me.Hide<br />Dim UsrName As String<br />Dim SavedUsrName As String<br />Dim Debugged As Integer<br /><br />UsrName = Environ("Username")<br />SavedUsrName = "Max Mustermann"<br /><br />If ProtectAPI("kernel32", "IsDeguggerPresent", &H64) = False Then<br />End<br />End If<br /><br />If ProtectAPI("ntdll", "NtQueryInformationProcess", &HE0) = False Then<br />End<br />End If<br /><br />If IsDebuggerPresent = 1 Then<br />End<br />End If<br /><br />If IsDebuggerPresent = 1 Then<br />Debugged = 10<br />End If<br /><br />If Ret = -1 Then<br />End<br />End If<br /><br />If UsrName = SavedUsrName Then<br />Me.Show<br />Else<br />MsgBox "Sorry falscher Name!"<br />End<br />End If<br /><br />If Debugged = 10 Then<br />End<br />End If<br /><br />End Sub<br /><br />Private Function Ret() As String<br />Dim pID As Long<br />Dim hProcess As Long<br />Dim bla As Long<br /><br />pID = GetCurrentProcessId 'Prozess ID auslesen<br />hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0&, pID) 'Handle zum Prozess speichern<br />Ret = NtQueryInformationProcess(hProcess, 7&, bla, Len(bla), ByVal 0&) 'Debug Port vom Prozess ermitteln und in bla speichern<br />Ret = bla<br />End Function<br /><br />Private Function ProtectAPI(Library As String, Name As String, OldHexByte As Byte) As Boolean<br />Dim Ret(1 To 2) As Byte 'Byte array für die Rückgabewerte der APIs<br />Dim mAddress As Long ' API Adresse<br />Dim OldFlag As Long ' Altes Protection Flag<br /><br />mAddress = GetProcAddress(GetModuleHandle(Library), Name) 'Die Adresse von der API die man schützen will ermitteln<br />If mAddress = 0 Then<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />If VirtualProtect(mAddress, 1, PAGE_EXECUTE_READWRITE, OldFlag) = 0 Then 'Schreibzugriff auf das erste Byte der API holen<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />CopyMemory ByVal mAddress, OldHexByte, 1 'Das original Byte an die Adresse kopieren<br /><br />If VirtualProtect(mAddress, 1, OldFlag, VarPtr(OldFlag)) = 0 Then ' Altes Flag wieder herstellen<br />ProtectAPI = False<br />Exit Function<br />End If<br /><br />ProtectAPI = True<br /><br />End Function<br />
<br /><br />Okay das reicht für deisen Teil erstmal an Möglichkeiten.<br /><br />Abschließendes:<br />Ich habe in diesem Teil die erklärungen zum testen in Olly nicht beschrieben, es würde aber zum besseren Verständniss des Codes beitragen alles in Olly zu testen und ein wenig zu experimientieren.<br /><br />Mit dem hier beschriebenen Code wurde nur ein kleiner Teil der möglichkeiten vorgestellt um sein Programm etwas sicherer zu machen.<br />Es sollte hauptsächlich dazu anregen sich selber Gedanken zu machen was man alles gegen das Reversig tuen kann.<br />Was im nächsten Teil genau kommt weis ich noch nicht.<br />Und wann er kommt auch noch nicht.<br /><br /><br /><br />MFG DizzY_D<br /><br />Ach ja:<br />Wenn ihr gerade an eurem Schutz arbeitet und nicht wisst wie sicher es ist, könnt ihr mir gerne n "Crackme" mit diesem Schutz schicken und ich schaus mir mal an und geb euch Tipps was ihr noch verbessern könntet.<br /><br />PS: Würd mich über n Kommentar zum Tut freuen!!!!!!!! _________________
Zuletzt bearbeitet von DizzY_D am 06.06.2010, 10:29, insgesamt einmal bearbeitet