
Obfuskiere bestimmte Windows-APIs mit anderen APIs.
Verschleiern (verstecken) der PE-Importe vor statischen/dynamischen Analysetools.
Das ist recht einfach: Angenommen, ich habe VirtualProtect verwendet und möchte es mit Sleep verschleiern. Das Tool manipuliert die IAT, sodass der Thunk, der auf VirtualProtect zeigt, stattdessen auf Sleep zeigt. Beim Ausführen der Datei lädt der Windows-Loader Sleep anstelle von VirtualProtect und übergibt die Ausführung an den Einstiegspunkt. Von dort wird die Ausführung an den Shellcode umgeleitet, den das Tool zuvor platziert hat, um die Adresse von VirtualProtect zu finden und sie durch die Adresse von Sleep zu ersetzen, die zuvor vom Loader zugewiesen wurde.
#include <cobf.hpp>
int main() {
cobf obf_file = cobf("sample.exe");
obf_file.load_pe();
obf_file.obf_sym("kernel32.dll", "SetLastError", "Beep");
obf_file.obf_sym("kernel32.dll", "GetLastError", "GetACP");
obf_file.generate("sample_obfuscated.exe");
obf_file.unload_pe();
return 0;
};
config.ini) angegeben werden.cobf.exe <Eingabedatei> <Ausgabedatei> [Konfigurationsdatei]; Vorlage für die Konfigurationsdatei:
; * Abschnitte können wie folgt geschrieben werden:
; [dll_name]
; altes_sym=neues_sym
; * Der DLL-Name ist nicht case-sensitiv, aber
; die alten und neuen Symbole sind es.
; * Sie können den Platzhalter sowohl für den
; DLL-Namen als auch für das alte Symbol verwenden.
; * Sie können '#' am Anfang des alten oder
; neuen Symbols verwenden, um eine Ordinalzahl zu kennzeichnen.
; * Das neue Symbol muss von der DLL exportiert
; werden, damit der Windows-Loader es auflösen kann.
; Zum Beispiel:
; * Verschleiern aller Symbole,
; die aus user32.dll mit der Ordinalzahl 1600 importiert wurden.
[user32.dll]
*=#1600
; * Verschleiern von Symbolen, die sowohl aus
; kernel32.dll als auch aus kernelbase.dll mit Sleep importiert wurden.
[kernel*.dll]
*=Sleep
; * Verschleiern von fprintf mit exit.
[*]
fprintf=exit
Dieses Codebeispiel kompilieren
#include <windows.h>
#include <stdio.h>
int main() {
SetLastError(5);
printf("Letzter Fehler ist %d\n", GetLastError());
return 0;
};
Nach dem Kompilieren sehen die kernel32-Importe so aus:

Nun verschleiern wir sowohl SetLastError als auch GetLastError mit Beep und GetACP (eigentlich ist jede API aus kernel32 in Ordnung, auch wenn sie überhaupt nicht importiert wird).
Die verwendeten Konfigurationen sind:
[kernel32.dll]
SetLastError=Beep
GetLastError=GetACP
Hier ist die Ausgabe (Sie können die Bibliothek auch direkt wie oben gezeigt verwenden).

Schauen wir uns noch einmal die kernel32-Importe an:

Es gibt keine Spur von SetLastError oder GetLastError.
Eine Bestätigung, dass beide Dateien korrekt funktionieren:

IDA HexRays Decompiler

IDA Debugger

Ghidra

ApiMonitor

Das liegt daran, dass alle statischen Analysetools auf den API-Namen angewiesen sind, der in der IAT geschrieben steht, und dieser kann wie gezeigt manipuliert werden.
Bei ApiMonitor tritt aufgrund der Verwendung von IAT-Hooking dasselbe Problem auf.
Auf der anderen Seite hängen bei Tools wie x64dbg die angezeigten API-Namen nur von dem ab, was tatsächlich aufgerufen wird (nicht von dem, was in der IAT steht).

.cobf, um den Shellcode und die anderen benötigten Daten aufzunehmen.git clone https://github.com/d35ha/CallObfuscator.