Obfuscation
Diejenigen von euch die sich Zeit genommen haben die Intentionen zu lesen weshalb ich diesen Blog schreibe, werden sich jetzt fragen warum ich mich dem Thema Obfuscation widme. Nun, es ist ein Vorteil für jeden Wissen zu teilen, da unsere Welt aber kein Kinder Spielplatz ist auf dem jeder auf alles Zugriff erhalten sollte, ist es unter Umständen sinnvoll seine Quelltexte zu verschleiern. Dabei ist zu beachten das diese absichtliche Veränderung von Programmcode lediglich darauf abzielt den Aufwand für Reverse Engineering stark zu erhöhen, um Veränderung oder Diebstahl von Programmteilen zu erschweren oder um die Funktionalität z.B. von Schadsoftware zu verschleiern. Verschleierung heißt nicht Verschlüsseln, sollten sensible Daten im Script vorliegen so gibt es andere Techniken diese Inhalte zu schützen.
Obfuscation verändert den ausführbaren Code, jedoch nur so, dass die Funktion des Codes erhalten bleibt. Es können Variablen und Funktionsnamen umbenannt werden, es können zusätzliche nicht notwendige Befehle eingefügt werden. Sollte eine entsprechend saubere Code Struktur vorliegen, können Teile des Codes unterschiedlich obfuskiert werden. Die Methoden der Obfuskierung sind zahlreich und abhängig von dem verwendeten Obfuskator.
Im folgenden möchte ich auf 2 unterschiedliche Obfuskatoren eingehen. Zum einen den integrierten Obfuskator in ISESteroids und zum anderen den Obfuskator von Daniel Bohannon Invoke-Obfuscation veröffentlicht auf GitHub. Um die Einstellungen und Optionen der beiden Obfuskatoren gegenüber zustellen verwende ich die Funktion Get-PSScriptRoot.
Obfuskator in ISESteroids
Um die Obfuskierung für ein vorhandenes Script durchzuführen, wählt man den Reiter Tools und anschließend Obfucsate Code…
Es öffnet sich das Fenster für die Einstellungen und Optionen zum obfuskieren des Codes. Der verschleierte Code wird in einem neuen Tab geöffnet, dennoch sollte man beim obfuskieren generell sicherstellen das immer eine BackUp des Scriptes im Klartext vorhanden sein sollte.
Obfuskierung
Das nachfolgende Beispiel soll verdeutlichen inwiefern eine Verschleierung von Parameter, Variablen, Funktionen und Strings erfolgt wenn alle vorhandenen Einstellungsmöglichkeiten ausgenutzt werden. Der Modus der Verschleierung ist in diesem Beispiel Character.
Code :
Function Get-PSScriptRoot { <# .SYNOPSIS "Get-PSScriptRoot" returns the path of the current script .EXAMPLE Get-PSScriptRoot Returns the path of the current script .INPUTS NO .OUTPUTS path of the current script. #> $HW = "Hello World" $PSScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,$HW } Get-PSScriptRoot
Obfuskierter Code:
Function _/==\/====\/\/=\__ { <# .SYNOPSIS "Get-PSScriptRoot" returns the path of the current script .EXAMPLE Get-PSScriptRoot Returns the path of the current script .INPUTS NO .OUTPUTS path of the current script. #> ${__/\_/\/\/=\/\___} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${__/\_/\/\/=\/\___} } _/==\/====\/\/=\__
Konvertierung
Diese Einstellung dient dazu Aliase anstelle des Kommandos zu verwenden. In diesem Fall wird Get-Variable ersetzt durch gv
Obfuskierter und Konvertierter Code:
Function __/\__/\_/\__/\/== { <# .SYNOPSIS "Get-PSScriptRoot" returns the path of the current script .EXAMPLE Get-PSScriptRoot Returns the path of the current script .INPUTS NO .OUTPUTS path of the current script. #> ${_/=====\/\/\_/===} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${_/=====\/\/\_/===} } __/\__/\_/\__/\/==
Bereinigt
Entfernt Kommentare und leere Zeilen.
Obfuskierter, Konvertierter und Bereinigter Code:
Function __/=\/\_/=\_/\__/= { ${_/=====\/=\_/=\__} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${_/=====\/=\_/=\__} } __/=\/\_/=\_/\__/=
Modus
ISESteroids liefert 4 verschiedene Modi zum verschleiern des Codes. Eine global eindeutige Kennung(GUID), Binär, Zeichen und Ziffern.
GUID Modus:
Function d29c234906c64ef29cf3223d019565e3 { ${69e2bb1733214946a92ab2b98cd4fe0d} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${69e2bb1733214946a92ab2b98cd4fe0d} } d29c234906c64ef29cf3223d019565e3
Binary Modus:
Function _01011000100110110 { ${11000001110011010} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${11000001110011010} } _01011000100110110
Character Modus:
Function _/======\/=\/\_/\/ { ${_/==\_/\___/==\/=} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${_/==\_/\___/==\/=} } _/======\/=\/\_/\/
Number Modus:
Function f1 { ${1} = $([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('SABlAGwAbABvACAAVwBvAHIAbABkAA=='))) $PSScriptRoot = gv -Name PSScriptRoot -ValueOnly -ErrorAction Stop return $PSScriptRoot,${1} } f1
Optionen
Es besteht die Möglichkeit neben dem obfuskierten Script eine Obfuskierungs Tabelle zu erzeugen. Diese wird ebenfalls in einem neuen Tab geöffnet. Die Obfuskierungs Tabelle für das bereits bekannte Beispiel Get-PSScriptRoot sieht folgendermaßen aus:
<# ISESteroids Obfuscation Table Date: 2017-09-09 19:47:35 Script: C:\Get-PSSCriptRoot.ps1 This file lists the naming changes introduced by ISESteroids obfuscation. Keep this file confidential. #> $variableTable = @{ '/=====\/=\/\_/\/=' = 'HW' } $functionTable = @{ '_/===\_/\/\__/====' = 'Get-PSScriptRoot' }
Enthalten sind die Daten die ein mögliches Revers-Engineering vereinfachen sollten. Des weiteren gibt es die Option das obfuskierte Script direkt zu speichern und bei Bedarf ein vorhandenes Pester Script ebenfalls zu obfuskieren. Sollte kein Pester Test Script vorhanden sein ist diese Option deaktiviert.
Invoke-Obfuscation
Das von Daniel Bohannon veröffentlichte GitHub Repo Invoke-Obfuscation bietet eine Vielzahl an Einstellungen und Optionen Code zu verschleiern und zu verschlüsseln. Es erhält regelmäßige Updates und ist ausführlich kommentiert. Für diejenigen die mit GitHub Repos noch nicht vertraut sind und nicht vor haben tiefer in die Materie einzusteigen empfiehlt es sich das gesamte Repo via Zip Download zu speichern. Folgt dazu einfach dem Link in der Überschrift und navigiert zu
Im Repo sind folgende Dateien enthalten.
Die unterschiedlichen Möglichkeiten der Verschleierung und Verschlüsselung wurden in unterschiedliche Scripte ausgelagert, der einfachste Weg um sich mit den Methoden vertraut zu machen ist die Funktion Invoke-Obfuscation die im gleichnamigen Modul enthalten ist. In diesem Fall kann das Repo als Modul angesehen werden.
Um es zu verwenden sollte das entpackte Modul unter dem User spezifischen Modul Pfad abgelegt werden:
C:\Users\…….\Documents\WindowsPowerShell\Modules\Invoke-Obfuscation-master\Invoke-Obfuscation.psd1
Damit das Modul verwendet werden kann erfolgt dann der Import in der Session.
Import-Module 'C:\Users\.......\Documents\WindowsPowerShell\Modules\Invoke-Obfuscation-master\Invoke-Obfuscation.psd1' Invoke-Obfuscation
Das Tutorial liefert einen sinnvollen Einstieg zur Handhabung der Funktion.
Invoke-Obfuscation> TUTORIAL
„Es ist praktisch unmöglich, einem Studenten gutes Programmieren beizubringen, wenn er vorher in BASIC programmiert hat. Als potenzielle Programmierer sind sie geistig verstümmelt ohne Hoffnung auf Besserung.“
How do we tell truths that might hurt? 18. Juni 1975 – Edsger Wybe Dijkstra