#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>

Global $sTitle = 'Random-Obfuscator v2.0'
Global $sObfuscator = StringRegExpReplace(@AutoItExe, '(.+\\).+', '$1') & 'SciTE\Obfuscator\Obfuscator.exe' ; Pfad zum Original-Obfuscator
Global $hGui = GUICreate($sTitle & '     (C) by Oscar (www.autoit.de)', 640, 240)
GUISetBKColor(0xAAAAAA)

GUICtrlCreateGroup('Source', 10, 10, 300, 110)
	GUICtrlSetFont(-1, 14, 400, 0, 'Arial')
	GUICtrlCreateLabel('Filename:', 20, 50, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hSourceFilename = GUICtrlCreateLabel('', 90, 50, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	GUICtrlCreateLabel('Lines:', 20, 70, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hSourceLines = GUICtrlCreateLabel('0', 90, 70, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	GUICtrlCreateLabel('Filesize:', 20, 90, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hSourceFilesize = GUICtrlCreateLabel('0 Bytes', 90, 90, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
GUICtrlCreateGroup('', -99, -99, 1, 1)

GUICtrlCreateGroup('Destination', 330, 10, 300, 110)
	GUICtrlSetFont(-1, 14, 400, 0, 'Arial')
	GUICtrlCreateLabel('Filename:', 340, 50, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hDestFilename = GUICtrlCreateLabel('', 410, 50, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	GUICtrlCreateLabel('Lines:', 340, 70, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hDestLines = GUICtrlCreateLabel('0', 410, 70, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	GUICtrlCreateLabel('Filesize:', 340, 90, 70, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
	$hDestFilesize = GUICtrlCreateLabel('0 Bytes', 410, 90, 200, 25)
	GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
GUICtrlCreateGroup('', -99, -99, 1, 1)

$hProgressPercent = GUICtrlCreateLabel('0%', 295, 130, 60, 18, $SS_CENTER)
GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
$hProgress = GUICtrlCreateProgress(10, 150, 620, 16)

$hStatusLine = GUICtrlCreateLabel(' Select Script . . .', -2, 222, 644, 18, $SS_SUNKEN)
GUICtrlSetBKColor(-1, 0xdddddd)
GUICtrlSetFont(-1, 9, 400, 0, 'Arial')
GUISetState()

$sScriptSource = FileOpenDialog('Select Script', @ScriptDir, 'AutoIt-Script (*.au3)', 3, '', $hGui)
If @error Then _End()
GUICtrlSetData($hSourceFilename, StringRegExpReplace($sScriptSource, '.+\\(.+)', '$1'))
$sSource = FileRead($sScriptSource)
GUICtrlSetData($hSourceFilesize, _StringAddThousandsSep(FileGetSize($sScriptSource), '.', ',') & ' Bytes')
StringReplace($sSource, @CR, '')
GUICtrlSetData($hSourceLines, @extended)

$sSource = StringReplace($sSource, '#AutoIt3Wrapper_Run_Obfuscator', '; #AutoIt3Wrapper_Run_Obfuscator')
$sSource = StringReplace($sSource, '#Obfuscator_Parameters', '; #Obfuscator_Parameters')
$sSource = StringRegExpReplace($sSource, '((\x22|\x27).*(\x22|\x27))|(;\V*)|(?s)((#cs|#comments-start).+?(#ce|#comments-end)\V*)', '$1')
$sSource = StringRegExpReplace($sSource, '(\r\n)\s+', '$1')

GUICtrlSetData($hStatusLine, ' Create Dictionaries . . .')
$oDictVars = ObjCreate('Scripting.Dictionary') ; Variablen-Ersetz-Wörterbuch anlegen
If Not IsObj($oDictVars) Then _End('Cannot create 1st Scripting.Dictionary!')
$oDictVars.CompareMode = 1 ; Textmode (Case-insensitive) einschalten

$oDictFuncs = ObjCreate('Scripting.Dictionary') ; Funktionen-Ersetz-Wörterbuch anlegen
If Not IsObj($oDictFuncs) Then _End('Cannot create 2nd Scripting.Dictionary!')
$oDictFuncs.CompareMode = 1 ; Textmode (Case-insensitive) einschalten

$oDictHelpV = ObjCreate('Scripting.Dictionary') ; Hilfs-Wörterbuch für Zufallsvariablen anlegen
If Not IsObj($oDictHelpV) Then _End('Cannot create 3rd Scripting.Dictionary!')
$oDictHelpV.CompareMode = 1 ; Textmode (Case-insensitive) einschalten

$oDictHelpF = ObjCreate('Scripting.Dictionary') ; Hilfs-Wörterbuch für Zufallsfunktionen anlegen
If Not IsObj($oDictHelpF) Then _End('Cannot create 4th Scripting.Dictionary!')
$oDictHelpF.CompareMode = 1 ; Textmode (Case-insensitive) einschalten

_Exception($sSource) ; Ausnahmen ins Wörterbuch eintragen

GUICtrlSetData($hStatusLine, ' Obfuscate Variables . . .')
$sTmp = StringRegExpReplace($sSource, '(?:\x22|\x27)(.+?)(?:\x22|\x27)', '')
$aVars = StringRegExp($sTmp, '(?i)\$\w+', 3)
If IsArray($aVars) Then
	$aVars = _ArrayUnique($aVars)
	_ArraySort($aVars, 1)
	For $i = 1 To $aVars[0]
		If Not $oDictVars.Exists($aVars[$i]) Then $oDictVars.Add($aVars[$i], _RandomVar())
		$sSource = StringReplace($sSource, $aVars[$i], $oDictVars.Item($aVars[$i]))
		$iPercent = Int(50 / $aVars[0] * $i)
		GUICtrlSetData($hProgress, $iPercent)
		GUICtrlSetData($hProgressPercent, $iPercent & '%')
	Next
EndIf
GUICtrlSetData($hStatusLine, ' Obfuscate Funktions . . .')
$aFuncs = StringRegExp($sTmp, '(?i)Func (\w+)', 3)
If IsArray($aFuncs) Then
	$aFuncs = _ArrayUnique($aFuncs)
	_ArraySort($aFuncs, 1)
	For $i = 1 To $aFuncs[0]
		If Not $oDictFuncs.Exists($aFuncs[$i]) Then $oDictFuncs.Add($aFuncs[$i], _RandomFunc())
		$sSource = StringReplace($sSource, $aFuncs[$i], $oDictFuncs.Item($aFuncs[$i]))
		$iPercent = Int(50 / $aFuncs[0] * $i) + 50
		GUICtrlSetData($hProgress, $iPercent)
		GUICtrlSetData($hProgressPercent, $iPercent & '%')
	Next
EndIf
GUICtrlSetData($hProgress, 100)
GUICtrlSetData($hProgressPercent, '100%')

StringReplace($sSource, @CR, '')
GUICtrlSetData($hDestLines, @extended)

GUICtrlSetData($hStatusLine, ' Save random obfuscated Script . . .')
$sDestFile = StringRegExpReplace($sScriptSource, '(.+)(\..+)', '$1_rnd$2')
GUICtrlSetData($hDestFilename, StringRegExpReplace($sDestFile, '.+\\(.+)', '$1'))
$hFile = FileOpen($sDestFile, 2)
If $hFile <> -1 Then
	FileWrite($hFile, $sSource)
	FileClose($hFile)
EndIf
GUICtrlSetData($hDestFilesize, _StringAddThousandsSep(FileGetSize($sDestFile), '.', ',') & ' Bytes')

GUICtrlSetData($hStatusLine, ' Run Original-Obfuscator . . .   Please wait!')
RunWait('"' & $sObfuscator & '" "' & $sDestFile & '" /cs 1 /cn 1 /cf 1 /cv 1', @ScriptDir, @SW_HIDE) ; Kopie vom Original-Obfuscator bearbeiten lassen
$sDestFile = StringRegExpReplace($sScriptSource, '(.+)(\..+)', '$1_rnd_obfuscated$2')
GUICtrlSetData($hStatusLine, ' Ready.')

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func _End($msg = '')
	If $msg <> '' Then MsgBox(262144+16, 'Error', $msg)
	Exit
EndFunc

Func _Exception($sScript)
	Local $aException
	$aException = StringRegExp($sScript, '(?i)IsDeclared\h*\((.*?)\)', 3) ; Die IsDeclared-Variablen in ein Array holen
	If IsArray($aException) Then
		For $i = 0 To UBound($aException)-1
			If StringLeft($aException[$i], 1) <> '$' Then $aException[$i] = Execute('"$" &' & $aException[$i])
			$oDictVars.Add($aException[$i], $aException[$i]) ; Die IsDeclared-Variablen mit ihrem richtigen Namen ins Wörterbuch eintragen (werden dann nicht umgewandelt)
		Next
	EndIf
	$aException = StringRegExp($sScript, '(?i)Assign\h*\((.*?),', 3) ; Die Assign-Variablen in ein Array holen
	If IsArray($aException) Then
		For $i = 0 To UBound($aException)-1
			If StringLeft($aException[$i], 1) <> '$' Then $aException[$i] = Execute('"$" &' & $aException[$i])
			$oDictVars.Add($aException[$i], $aException[$i]) ; Die Assign-Variablen mit ihrem richtigen Namen ins Wörterbuch eintragen (werden dann nicht umgewandelt)
		Next
	EndIf
	_GetIncludeConsts($oDictVars, StringRegExpReplace(@AutoItExe, '(.+\\).+', '$1') & 'Include')
EndFunc

Func _RandomVar()
	Local $sVar
	Do
		$sVar = '$' & Chr(Random(65, 90, 1))
		For $i = 0 To 7
			$sVar &= Chr(Random(48, 57, 1))
		Next
	Until Not $oDictHelpV.Exists($sVar)
	$oDictHelpV.Add($sVar, $sVar)
	Return $sVar
EndFunc

Func _RandomFunc()
	Local $sFunc
	Do
		$sFunc = Chr(Random(65, 90, 1))
		For $i = 0 To 8
			$sFunc &= Chr(Random(48, 57, 1))
		Next
	Until Not $oDictHelpF.Exists($sFunc)
	$oDictHelpF.Add($sFunc, $sFunc)
	Return $sFunc
EndFunc

Func _GetIncludeConsts(ByRef $oDict, $sPath)
	Local $aIncludeFiles, $sFile, $aConstants
	$aIncludeFiles = _MyFileListToArray($sPath, '*.au3') ; alle Standard-Include-Dateinamen einlesen
	If Not IsArray($aIncludeFiles) Then _End('ERROR! Include-Files not found!')
	For $sInclude In $aIncludeFiles ; alle Include-Dateien durchgehen
		$sFile = FileRead($sPath & '\' & $sInclude) ; Include-Datei einlesen
		$aConstants = StringRegExp($sFile, '(?s)(?:Global|Global Const) (\$.+?)(?:\;|\,|\h)', 3) ; alle Konstanten aus der Include-Datei holen
		If IsArray($aConstants) Then ; wenn welche gefunden wurden, dann...
			For $sConstant In $aConstants ; der Reihe nach durchgehen
				If Not $oDict.Exists($sConstant) Then $oDict.Add($sConstant, $sConstant) ; wenn nicht im Dictionary vorhanden, diesem hinzufügen
			Next
		EndIf
	Next
EndFunc   ;==>_GetIncludeFuncsAndConsts

Func _MyFileListToArray($sPath, $sFilter)
	Local $sFileList = '', $hSearch, $sFile
	If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
	$hSearch = FileFindFirstFile($sPath & $sFilter)
	If @error Then Return
	Do
		$sFile = FileFindNextFile($hSearch)
		If @extended Then ContinueLoop
		$sFileList &= $sFile & '|'
	Until @error
	FileClose($hSearch)
	If $sFileList = '' Then Return
	Return StringSplit(StringTrimRight($sFileList, 1), '|', 2)
EndFunc   ;==>_MyFileListToArray

; #FUNCTION# ====================================================================================================================
; Name...........: _StringAddThousandsSep
; Description ...: Returns the original numbered string with the Thousands delimiter inserted.
; Syntax.........: _StringAddThousandsSep($sString[, $sThousands = -1[, $sDecimal = -1]])
; Parameters ....: $sString    - The string to be converted.
;                  $sThousands - Optional: The Thousands delimiter
;                  $sDecimal   - Optional: The decimal delimiter
; Return values .: Success - The string with Thousands delimiter added.
; Author ........: SmOke_N (orignal _StringAddComma
; Modified.......: Valik (complete re-write, new function name)
; Remarks .......:
; Related .......:
; Link ..........;
; Example .......; Yes
; ===============================================================================================================================
Func _StringAddThousandsSep($sString, $sThousands = -1, $sDecimal = -1)
    Local $sResult = "" ; Force string
    Local $rKey = "HKCU\Control Panel\International"
    If $sDecimal = -1 Then $sDecimal = RegRead($rKey, "sDecimal")
    If $sThousands = -1 Then $sThousands = RegRead($rKey, "sThousand")
    Local $aNumber = StringRegExp($sString, "(\D?\d+)\D?(\d*)", 1) ; This one works for negatives.
    If UBound($aNumber) = 2 Then
        Local $sLeft = $aNumber[0]
        While StringLen($sLeft)
            $sResult = $sThousands & StringRight($sLeft, 3) & $sResult
            $sLeft = StringTrimRight($sLeft, 3)
        WEnd
        $sResult = StringTrimLeft($sResult, StringLen($sThousands)) ; Strip leading thousands separator
        If $aNumber[1] <> "" Then $sResult &= $sDecimal & $aNumber[1]
    EndIf
    Return $sResult
EndFunc   ;==>_StringAddThousandsSep
