Autor Beitrag
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 28.08.05 16:00 
Ich mach mal einen Thread auf in dem es darum geht wie man sein Programm vor dem debuggen/cracken schützen kann.
Ich werde hier im laufe der zeit einige Beispiele posten.

Als erstes einmal etwas, was in 2 Minuten gemacht werden kann und schon den einen oder anderen schlechten Cracker in den Wahnsinn treibt.

hier ein kleines Video wie das geht und ne Erkläung was man wie machen muss

uall.overclock.ch/delphiprotect01.zip

1) Man erstellt ganz normal sein Projekt.
2) Anstatt das Beenden von Delphi übernehmen zu lassen schreibt man bei OnClose (ganz am Schluss) ExitProcess(0) rein,
das wird benötigt damit beim beenden spätr das programm nicht crashed.
3) Im Hauptprogramm (der dpr) fügt man eine Variable ein die dafür sorgt das der Code zum erzeigen des Forms nur einmal ausgeführt wird (das hat interne gründe auf die ich nicht genauer eingehen werde)
4) ausserdem prüft man ob ein Debugger geladen ist (IsDebuggerPresent aus der kernel32.dll importieren bzw meine unit benutzen)
5) Man ändert bei der Sektion Tls +16bytes) mit Hilfe von Suche bei Google LORDPE die daten (sollten 4* 00 sein) ab indem man die durch den Entrypoint + ImageBase ersetzt (Entrypoinz ist d wo nacher AFFEAFFE steht)
6) der Entrypoint wird auf irgend eine Adresse gesetzt (würde er ausgeführt werden crashed es, wird er aber nur wenn ein debugger erkannt wurde!)

Code der geändert werden muss:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  // Variablenfreigabe etc.
  ExitProcess(0);
end;


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
program Project2;

uses
  Forms, uallProtect,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

var first: boolean = true;
begin
  if (not first) or (uallProtect.IsDebuggerPresent) then exit;
  first := false;
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit


Zuletzt bearbeitet von uall@ogc am So 28.08.05 16:17, insgesamt 1-mal bearbeitet
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 28.08.05 16:04 
02

Speziel für Ollydbg hab ich bisl code geschrieben der den Debugger zum crashen bringt
Dieser kann einfach bei wichtigen Funktionen (z.b. Keyeingabe testen) vorher (und nachher) aufgerufen werden.
Ist Ollydbg geladen crashed es :)

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
procedure crash_ollydbg;
asm
  pushad
  push offset @@handler
  xor eax, eax
  push fs:[eax]
  mov fs:[eax], esp
  mov ebx, esp
  push eax
  push $73257325
  push esp
  push $5
  push esp
  push $2
  push eax
  push $40010006
  call RaiseException
@@handler:
  mov eax, [esp+$C]
  mov esp, [eax+$A4]
  xor eax, eax
  pop fs:[eax]
  pop eax
  popad
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  crash_ollydbg;
  form1.caption := 'hallo';
  crash_ollydbg;
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 28.08.05 16:15 
03

Ausnutzen der Trägheit der Debugger.

Wenn man sich mit einem Debugger in ein laufendes Programm "einklingt" (Ollydbg -> attach) werden Thread nicht sofort suspended, d.h. sie laufen noch einige Millisekunden weiter. Das kann man ausnutzen um den Debugger zu erkennen und das Programm zu beenden / crashen. Hier mal ein Beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function proc(a: integer): integer;
begin
  result := 0;
  while not uallProtect.IsDebuggerPresent do
    sleep(10);
  asm
    popad
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var tid: cardinal;
begin
  BeginThread(nil,0,@proc,nil,0,tid);
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 28.08.05 16:26 
von SwissDelphiCenter geklaut aber auch eine Debugger erkennung (für SoftIce)

dazu muss ich aber sagen, jeder der SoftIce bedienen kann, wird das umgehen können ;)

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
//SoftIce in W9x OS

function IsSoftIce95Loaded: Boolean;
var
  hFile: THandle;
begin
  Result := False;
  hFile  := CreateFileA('\\.\SICE', GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL, 0);
  if (hFile <> INVALID_HANDLE_VALUE) then 
  begin
    CloseHandle(hFile);
    Result := True;
  end;
end;



// SoftIce in NT/2000 OS
function IsSoftIceNTLoaded: Boolean;
var
  hFile: THandle;
begin
  Result := False;
  hFile  := CreateFileA('\\.\NTICE', GENERIC_READ or GENERIC_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL, 0);
  if (hFile <> INVALID_HANDLE_VALUE) then 
  begin
    CloseHandle(hFile);
    Result := True;
  end;
end;




procedure TForm1.Button1Click(Sender: TObject);
begin
  if IsSoftIce95Loaded or IsSoftIceNTLoaded then
  begin
    //Do something if Softice is loaded
  end;
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit


Zuletzt bearbeitet von uall@ogc am So 28.08.05 17:09, insgesamt 1-mal bearbeitet
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 28.08.05 16:37 
05

Erkennung von Breakpoints (Haltepunkte)

Breakpoints werden oft benutzt um bestimmte stellen zu finden. Kommt z.b. bei der eingabe eines falschen Keys eine Nachricht, dass der Key falsch eingegeben wurde, wird der Cracker versuchen einen Breakpoint auf die API MessageBoxA zu setzen da diese wahrscheinlich aufgerufen wird.
Diesen kann man Abfragen und dann das Programm z.b. crashen lassen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.FormCreate(Sender: TObject);
begin
  if pbyte(GetProcAddress(GetModuleHandle('user32.dll'),'MessageBoxA'))^ = $CC then // breakpoint an der API ?
  asm
    popad  //crash
    jmp eax
  end;
  MessageBoxA(0,'der eingegebene Key ist falsch',nil,0);
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 07.01.06 16:50 
06

FileCheck

Es gibt ja viele Arten von Filechecks. Ich habe hier mal eine Methode gemacht, die ich sehr schön für Anfänger finde, da man nichts per Hand machen muss. Es reicht die Funktion im OnCreate aufzurufen. Ob sie Programmiertechnisch so toll ist lass ich mal aussen vor. Es funktioniert auch nicht mit irgendwelchen Packern. Beim ersten start der Exe wird eine neue Exe erstellt die den FileCheck beinhaltet. Hier der Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
procedure CheckExe;
var i, h, h2: integer;
    read: cardinal;
    buf: pointer;
    fsize: Cardinal;
    addrm : Pinteger;
    checksum: integer;
    checkx: integer;
begin
  i := $12345678;
  checksum := $12345678;
  h := CreateFileA(PChar(Paramstr(0)),GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,
    nil,OPEN_EXISTING,0,0);

  if (h = 0then
  begin
    CloseHandle(h);
    Exit;
  end;

  if (i = 0then {nichts};

  fsize := GetFileSize(h,nil);
  if (fsize = 0then
  begin
    CloseHandle(h);
    Exit;
  end;

  buf := VirtualAlloc(nil,fsize,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE);
  if (buf = nilthen
  begin
    CloseHandle(h);
    Exit;
  end;

  if (not ReadFile(h,buf^,fsize,read,nil)) or (read <> fsize) then
  begin
    CloseHandle(h);
    Exit;
  end;


  addrm := Pinteger(integer(buf)+integer(@CheckExe)-integer(GetModuleHandle(nil))-$BE0);
  if IsBadReadPtr(addrm,4then
  begin
    CloseHandle(h);
    Exit;
  end;

  if (addrm^ = $12345678then
  begin
    addrm^ := $00000000;
    for i := 0 to fsize div 4 -1 do
      checksum := checksum xor pinteger(integer(buf)+i*4)^;
    addrm^ := checksum;
    h2 := CreateFileA(PChar(Paramstr(0)+' new.exe'),GENERIC_READ or GENERIC_WRITE,
      FILE_SHARE_READ or FILE_SHARE_WRITE, nil,CREATE_ALWAYS,0,0);
    if (h2 <> 0then
    begin
      WriteFile(h2,buf^,fsize,read,nil);
      CloseHandle(h2);
    end;
  end else
  begin
    checkx := addrm^;
    addrm^ := $00000000;
    for i := 0 to fsize div 4 -1 do
      checksum := checksum xor pinteger(integer(buf)+i*4)^;
    if (checkx <> checksum) then
      while true do
      asm
        pop eax
      end;
  end;
  VirtualFree(buf,fsize,MEM_DECOMMIT);
  CloseHandle(h);
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 07.01.06 17:17 
Um nicht die API Funktion IsDebuggerPresent nutzen zu müssen, kann man auch seien eigene kleine Routine schreiben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
asm
  push eax
  mov eax, fs:[$30];
  mov eax, [eax+2];
  mov [BeingDebugged], al
  pop eax
end;

BeingDebugges ist dabei eine globale Variable. Genaueres gibt es hier: www.michael-puff.de/.../AntiCrackig_1.shtml

@uall@ogc: Motzi, Olli und ich hatten uns schon mal zusammengesetzt, und Methoden erläutert, wie man das Debuggen und somit das Crackenr erschweren könnte. Da beide aber unter chronischen Zeitmangel leiden, ist bisher nur dieser eine Artikel fertig geworden. Im zweiten sollte es um diese nette Routine von Olli gehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
        asm
          pushad
          call  @SetupSEHAndRaiseException
          mov   ecx, dword ptr [esp+12]
          mov   eax, fs:[$30]
          movzx  eax, byte ptr [eax+$2]
          and   eax, eax
          jnz   @NoAddOpCodeSize
          mov   dword ptr [ecx+$B8], offset @AfterExceptionCause
          @NoAddOpCodeSize:
          mov   dword ptr [ecx+$04], eax
          mov   dword ptr [ecx+$08], eax
          mov   dword ptr [ecx+$0C], eax
          mov   dword ptr [ecx+$10], eax
          mov   dword ptr [ecx+$14], eax
          and   dword ptr [ecx+$18], $155
          and   dword ptr [ecx+$C0], $FFFFFEFF
          xor   eax, eax
          ret
          @SetupSEHAndRaiseException:
          xor   eax, eax
          push  dword ptr fs:[eax]
          mov   fs:[eax], esp
          @KillCode:
          and   dword ptr [eax+$18], $155
          @AfterExceptionCause:
          pop   dword ptr fs:[$0]
          add   esp, $4
          popad
        end;

Leider bin ich da nicht mehr so ganz mit gekommen und das was ich verstanden habe, habe ich leider schon wieder vergessen. Disen teil sollte eigentlich Motzi schreiben, aber nun ja, Zeitmangel. Nun würde ich gerne diese Artikelserie vortsetzen. Eventuell könntest du dich ja daran beteiligen, wenn du Lust hast. Ich würde dann als Herausgeber etc. fungieren.


Zuletzt bearbeitet von Luckie am Sa 07.01.06 17:32, insgesamt 1-mal bearbeitet
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 07.01.06 17:26 
Das sollte auf 9x ME 2k XP funktionieren.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
function IsDebuggerPresent: boolean; stdcall;
asm
  MOV     EAX, FS:[030H]
  TEST    EAX, EAX
  JS      @@W9X
@@WNT:
  MOV EAX, FS:[$18]
  MOV EAX, [EAX+$30]
  MOVZX EAX, [EAX+2]
  RET
@@W9X:
  MOV EAX, [$BFFC9CE4]
  MOV ECX, [EAX]
  CMP [ECX+$54], 00000001
  SBB EAX, EAX
  INC EAX
  RET
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 07.01.06 18:21 
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
  asm
    pushad                                // alle Register speichern (auf den Stack)
  @SetupSEHAndRaiseException:             //
    xor   eax, eax                        // eax auf 0 setzen
    push  offset @ExceptHandler           // unseren exception handler auf den stack           (1)
    push  dword ptr fs:[eax]              // alten exception handler auf den stack             (2)
    mov   fs:[eax], esp                   // exception handler installieren
  @KillCode:                              //
    and   dword ptr [eax+$18], $155       // code der auf jedenfall crashed [da EAX = 0]       (zu 3)
  @AfterExceptionCause:                   //                                                   (4)
    pop   dword ptr fs:[$0]               // unseren exceptionhandler wieder vom stack nehmen  (2)
    add   esp, $4                         // alte gepushe Exceptionhandler Adresse vom Stack   (1)
    popad                                 // alle Register wiede herstellen
    jmp @ende                             // zum Ende springen


  @ExceptHandler:                         // hier kommt man nach der exception im Killcode hin (3)
    mov   ecx, dword ptr [esp+$C]         // in ECX offset zum contect
    mov   eax, fs:[$30]                   // IsDebuggerPresentCode
    movzx  eax, byte ptr [eax+$2]         //      "
    and   eax, eax                        // ist eax 0?
    jnz   @NoAddOpCodeSize                // wenn nicht springe
    mov   dword ptr [ecx+$B8], offset @AfterExceptionCause // eax = 0, kein debugger da, setze richtige adresse
                                          // zum fortsetzen für den code (EIP)
  @NoAddOpCodeSize:                       //
    mov   dword ptr [ecx+$04], eax        // mache irgend nen quatsch mit den Registern
    mov   dword ptr [ecx+$08], eax        // ist alles egal bis auf ESP
    mov   dword ptr [ecx+$0C], eax        // da mit POPAD eh alles wieder hergestellt wird
    mov   dword ptr [ecx+$10], eax        //
    mov   dword ptr [ecx+$14], eax        //
    and   dword ptr [ecx+$18], $155       // kein Plan?
    and   dword ptr [ecx+$C0], $FFFFFEFF  // lösche SingleStep (Trap) Flag da es sonst wieder zur Exception kommt
    xor   eax, eax                        // unser exception Handler konnte die Exception behandeln
                                          // deshalb Rückgabe = 0, damit KiUserExceptionDistaptcher
                                          // NTContinue aufruft und somit unsere geänderter context
                                          // benutzt wird
    ret                                   //                                                   (zu 4)
  @Ende:                                  //
  end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 07.01.06 18:26 
Was hältst du von Ollis Code? Nur so viel, er wurde schon geknackt, war wohl doch nicht so aufwendig zu umgehen. :(
uall@ogc Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 07.01.06 18:30 
Ja er wurde von mir "geknackt".
Der macht nicht wirklich viel mehr als IsDebuggerPresent, sondern versucht das nur durch nen Excepion Handler schwierigier debuggbar zu machen.

KillCode einfach auskommentieren (0x90 d.h. noppen) und schon ist das umgangen.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit