czardas Posted October 7, 2014 Share Posted October 7, 2014 (edited) ORfuscate your script. I'm not sure if this exists, but it is intended as a pre-obfuscation tool. It might be a new invention! While it does not guarantee any protection by itself, ORfuscation does offer some benefit in certain situations. It's more useful in cases where knowing the original numbers is essential to fully understand a script. In other cases it's just adds a slight inconvenience to the reverse engineer due to superflous internal routines. You may wish to convert globals to magic numbers before ORfuscation. I believe PreExpand by guinness will do this. Additional features such as creating fake constants may be included in a future release. Please do not post ORfuscated scripts on the forum. You may post them in this thread if it is relevant to the topic or provides an interesting example. Please double check to make sure that your scripts are still functional after ORfuscation. The example at the end of the script (lines 236 onwards) should be removed before testing with your own script. ; expandcollapse popup; #FUNCTION# ==================================================================================================================== ; Name...........: ORfuscate ; Description ...: Refactorization of magic numbers, 32-bit integers and hard coded BitOR() arguments. ; Syntax.........: ORfuscate($sScript) ; Parameters ....: $sScript - String input of an AutoIt script. ; Return values .: Success - Returns the orfuscated script. ; Failure - Returns the original script and sets @error to the following values: ; |@error = 1 : Script contains no data. ; |@error = 2 : No suitable separators found (this should not happen). ; Author ........: czardas ; Modified.......: ; Remarks .......: This is an experimental project with very little testing - so use at your own risk. ; Link ..........: ; Example .......: ; =============================================================================================================================== Func ORfuscate($sScript) If $sScript = "" Then Return SetError(1, 0, "") ; Get suitable padding to separate strings, comments and directives from the AutoIt. Local $iCount = 63743 ; BMP Private Range Upper Limit $sScript &= @LF Local $sIgnoreOn = " " & __GetSubstitute($sScript, $iCount) & " " ; Spaces are used for extra padding. If @error Then Return SetError(2, 0, $sScript) Local $sIgnoreOff = " " & __GetSubstitute($sScript, $iCount) & " " If @error Then Return SetError(2, 0, $sScript) Local $bIsAutoIt = True, _ ; The current position is outside strings, comments and directives. $sNotAutoIt = "", _ ; Strings, comments or directives to avoid. $sExpected = "", _ ; Regexp pattern to match the termination of a string, comment or directive. $sNextChar, $sNewAutoIt = "" ; Identify strings, comments and directives. For $i = 1 To StringLen($sScript) $sNextChar = StringMid($sScript, $i, 1) If $bIsAutoIt Then If StringRegExp($sNextChar, '[#''";]') Then $sNewAutoIt &= $sIgnoreOn & $sNextChar $bIsAutoIt = False Switch $sNextChar Case "#" $sExpected = StringRegExp(StringMid($sScript, $i, 4), "(?:)(#cs\b)") ? "(?:)([\r\n]\h*#ce\b.*\v)" : "\v" Case "'" $sExpected = "'" Case """" $sExpected = """" Case ";" $sExpected = "\v" EndSwitch Else $sNewAutoIt &= $sNextChar EndIf Else $sNotAutoIt &= $sNextChar If StringRegExp($sNotAutoIt, $sExpected) Then $sNewAutoIt &= $sNotAutoIt & $sIgnoreOff $bIsAutoIt = True $sExpected = "" $sNotAutoIt = "" EndIf EndIf Next ; Split the script to reveal 32-bit integers, Bitwise-OR'ed integers and also capture the rest of the code. Local $aAutoIt = StringRegExp($sNewAutoIt, "(?i)(?s)(?U)(" & $sIgnoreOn & ".+" & $sIgnoreOff & ")|\b\d*\.\d+\b|\b\d*\.?\d+e[\+\-]?\d+\b|(?<=[\s=,/\Q[(+-*^?:\E])(\d+|0x[A-F0-9]+|BitOR\h*\([x\h0-9,A-F]+\))(?=[\s=,/\Q)]+-*^?:\E])|\$*\b\w+\b|.", 3) ; Search for integers Local $iBound = UBound($aAutoIt), $iInt32, $sIdx = "" For $i = 0 To $iBound -1 $iInt32 = "" If StringIsInt($aAutoIt[$i]) Or StringRegExp($aAutoIt[$i], "(?i)(\A0x[A-F\d]{1,8}\z)") Or StringRegExp($aAutoIt[$i], "(?i)(BitOR\h*\([x\h\d,A-F]+\))") Then $iInt32 = Execute($aAutoIt[$i]) If VarGetType ($iInt32) <> "Int32" Then ContinueLoop $aAutoIt[$i] = $iInt32 $sIdx &= $i & "," Next If Not $sIdx Then Return SetExtended(1, $sScript) ; No changes can be made Local $aIdx = StringSplit(StringTrimRight($sIdx, 1), ",", 2) Local $iBoundIdx = Ubound($aIdx) Local $aSplit, $aMagic[$iBoundIdx][2][3] For $i = 0 to $iBoundIdx -1 $aSplit = MagicSplit($aAutoIt[$aIdx[$i]]) $aMagic[$i][0][0] = $aSplit[0] ; 1st int $aMagic[$i][1][0] = $aSplit[1] ; 2nd int $aSplit = MagicSplit($aMagic[$i][0][0]) $aMagic[$i][0][1] = $aSplit[0] ; 1st int - 1st element $aMagic[$i][0][2] = $aSplit[1] ; 1st int - 2nd element $aSplit = MagicSplit($aMagic[$i][1][0]) $aMagic[$i][1][1] = $aSplit[0] ; 2nd int - 1st element $aMagic[$i][1][2] = $aSplit[1] ; 2nd int - 2nd element Next ;_WalkThrough3D($aMagic, "zx") Local $sCheckDupes For $i = 0 to $iBoundIdx -1 If $aMagic[$i][0][0] = 0 Then If $aMagic[$i][1][1] = 0 Or $aMagic[$i][1][2] = 0 Then $aAutoIt[$aIdx[$i]] = MagicFormat($aAutoIt[$aIdx[$i]]) Else $aAutoIt[$aIdx[$i]] = "BitOR(" & MagicFormat($aMagic[$i][1][1]) & ", " & MagicFormat($aMagic[$i][1][2]) & ")" EndIf ElseIf $aMagic[$i][1][0] = 0 Then If $aMagic[$i][0][1] = 0 Or $aMagic[$i][0][2] = 0 Then $aAutoIt[$aIdx[$i]] = MagicFormat($aAutoIt[$aIdx[$i]]) Else $aAutoIt[$aIdx[$i]] = "BitOR(" & MagicFormat($aMagic[$i][0][1]) & ", " & MagicFormat($aMagic[$i][0][2]) & ")" EndIf ElseIf Random(0, 1, 1) Then $aAutoIt[$aIdx[$i]] = "BitOR(" $sCheckDupes = "|" For $j = 0 To 1 For $k = 1 To 2 If $aMagic[$i][$j][$k] <> 0 And Not StringInStr($sCheckDupes, "|" & $aMagic[$i][$j][$k] & "|") Then $aAutoIt[$aIdx[$i]] &= MagicFormat($aMagic[$i][$j][$k]) & ", " $sCheckDupes &= $aMagic[$i][$j][$k] & "|" EndIf Next Next $aAutoIt[$aIdx[$i]] = StringTrimRight($aAutoIt[$aIdx[$i]], 2) & ")" ElseIf $aMagic[$i][0][0] <> $aMagic[$i][1][0] Then $aAutoIt[$aIdx[$i]] = "BitOR(" & MagicFormat($aMagic[$i][0][0]) & ", " & MagicFormat($aMagic[$i][1][0]) & ")" Else $aAutoIt[$aIdx[$i]] = MagicFormat($aAutoIt[$aIdx[$i]]) EndIf Next $sScript = "" For $i = 0 To $iBound -1 $sScript &= $aAutoIt[$i] Next $sScript = StringReplace($sScript, $sIgnoreOn, "") $sScript = StringReplace($sScript, $sIgnoreOff, "") $sScript = StringTrimRight($sScript, 1) ; Remove LF added at the start Return $sScript EndFunc Func XORSplit($i32Bit) ; Splits an integer into two randomly selected bitwise exclusive integers. If Not IsInt($i32Bit) Or $i32Bit >= 2^32 Or $i32Bit < 0x80000000 Then Return SetError(1, 0, 0) Local $aXOR[2] $aXOR[0] = 0 ; Randomly select which bits to reproduce in the first return value. => $aXOR[0] Local $iBitPos For $i = 0 To 31 $iBitPos = 2^$i If BitAND($i32Bit, $iBitPos) = $iBitPos And Random(0, 1, 1) Then $aXOR[0] = BitOR($aXOR[0], $iBitPos) Next ; Check the sign bit. If BitAND($i32Bit, 0x80000000) = 0x80000000 And Random(0, 1, 1) Then $aXOR[0] = BitOR($aXOR[0], 0x80000000) ; Exclude the bits set to one (in the first return value) from the original input. $aXOR[1] = BitXOR($i32Bit, $aXOR[0]) Return $aXOR ; Array values can be Bitwise-OR'ed together to reproduce the original input. EndFunc ;==> XORSplit Func ORSplit($i32Bit) ; Splits an integer into two randomly selected bitwise non-exclusive integers. If Not IsInt($i32Bit) Or $i32Bit >= 2^32 Or $i32Bit < 0x80000000 Then Return SetError(1, 0, 0) Local $aOR[2] $aOR[0] = 0 $aOR[1] = 0 ; Randomly select which bits to reproduce in either one or both return values. Local $iBitPos, $iSwitch = Random(1,3,1) For $i = 0 To 31 $iBitPos = 2^$i If BitAND($i32Bit, $iBitPos) = $iBitPos Then For $n = 1 To 2 If BitAND($iSwitch, $n) = $n Then $aOR[$n -1] = BitOR($aOR[$n -1], $iBitPos) Next $iSwitch = Random(1,3,1) ; Set the switch for the next run. EndIf Next ; Check the sign bit. If BitAND($i32Bit, 0x80000000) = 0x80000000 Then For $n = 1 To 2 If BitAND($iSwitch, $n) = $n Then $aOR[$n -1] = BitOR($aOR[$n -1], 0x80000000) Next EndIf Return $aOR ; Array values can be Bitwise-OR'ed together to reproduce the original input. EndFunc ;==> ORSplit Func MagicFormat($iInt) Return '0x' & StringRegExpReplace(Hex($iInt), '\A0{0,'& 2*Random(2,3,1) &'}', '') EndFunc Func MagicSplit($iInt) Local $aSplit = ORSplit($iInt) If $aSplit[0] = $iInt Or $aSplit[1] = $iInt Or $aSplit[0] = 1 Or $aSplit[1] = 1 Then $aSplit = XORSplit($iInt) Return $aSplit EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: __GetSubstitute ; Description ...: Searches for a character to be used for substitution, ie one not contained within the input string ; Syntax.........: __GetSubstitute($string, ByRef $iCountdown) ; Parameters ....: $string - The string of characters to avoid ; $iCountdown - The first code point to begin checking ; Return values .: Success - Returns a suitable substitution character not found within the first parameter ; Failure - Sets @error to 1 => No substitution character available ; Author ........: czardas ; Comments ......; This function is connected to the function _CSVSplit and was not intended for general use ; $iCountdown is returned ByRef to avoid selecting the same character on subsequent calls to this function ; Initially $iCountown should be passed with a value = 63743 ; =============================================================================================================================== Func __GetSubstitute($string, ByRef $iCountdown) If $iCountdown < 57344 Then Return SetError(1, 0, "") ; Out of options Local $sTestChar For $i = $iCountdown To 57344 Step -1 $sTestChar = ChrW($i) $iCountdown -= 1 If Not StringInStr($string, $sTestChar) Then Return $sTestChar EndIf Next Return SetError(1, 0, "") ; Out of options EndFunc ;==> __GetSubstitute ; ==> Example - ORfuscate this script. ; See what it does to an array of numbers: Local $aArrayOfNumbers[8] = [387, 0xFFFFFFFF, BitOR(1,2,4,8,16,32,64,128), 0.178, 13/167, 0.1e-78, -876, 20] Global $hFile = FileOpen(@ScriptFullPath) Global $sScript = FileRead($hFile) FileClose($hFile) ConsoleWrite(ORfuscate($sScript) & @CRLF) #cs Ignores multiline comments 100, 0xFFFFFFFF, BitOR(23, 57) #ce ; Have fun! Bugfix line 123 Edited October 7, 2014 by czardas Leo1906, Mobius and mesale0077 3 operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Mobius Posted October 9, 2014 Share Posted October 9, 2014 An interesting idea czardas , oh btw congrats are in order I think czardas 1 Link to comment Share on other sites More sharing options...
czardas Posted October 9, 2014 Author Share Posted October 9, 2014 Thanks Mobius on both counts. This is a first attempt and I still need to iron some things out (requires frequency analysis, testing and fine tuning). operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
mesale0077 Posted October 9, 2014 Share Posted October 9, 2014 do you think string example msgbox(0,"","hello word") ORfuscate for "hello word" ? nice script Link to comment Share on other sites More sharing options...
czardas Posted October 9, 2014 Author Share Posted October 9, 2014 (edited) ORfuscator is aimed at integers only. To use it with strings would require additional pre-processing and I don't think the technique is really suitable (maybe it's worth investigating). Too much pre-processing will make programs sluggish, which I'm trying to avoid. I think there are better methods to use for string obfuscation: for example using regular expressions. The numbers appearing in code are vitally important for most scripts to function properly, and they are relatively easy to extract and manipulate. I believe it may be possible to exploit this fact in ways that will improve program security. It's early days yet, and there will always be limitations to any technique. Edited October 9, 2014 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Guest Posted October 10, 2014 Share Posted October 10, 2014 ORfuscator is aimed at integers only. I think there is no point in obfuscating numbers ..I do not think you can understand tow much from a number .. but string is another story and that what i want to obfuscate. But i didn't obfuscate string for this reason: with strings would require additional pre-processing and I don't think the technique is really suitable (maybe it's worth investigating). Too much pre-processing will make programs sluggish, which I'm trying to avoid. If you have technique to obfuscate strings without the requirement of additional processing then i would welcome that! Link to comment Share on other sites More sharing options...
czardas Posted October 10, 2014 Author Share Posted October 10, 2014 (edited) I think there is no point in obfuscating numbers . Well actually, this depends entirely on the design of your program. The main idea here is to eventually rip some of the numbers out of the code altogether and conceal them somewhere (perhaps in an encrypted key). That will just about break most scripts that use constants. The point being that lots of work will be needed to get the script working again if someone tries to decompile it. This part of the plan still needs consideration. Can you tell me what the obfuscated code >here is doing? I don't think it's obvious when you first read it, although analysis reveals that it is actually the function Sleep(). Generate lots of code like that and it will be a nightmare to reconstruct the original script. Now suppose someone tries anyway - the level of success will be related to the number of bugs which need fixing. The more subtle the bugs, the longer this process will take. If the debugging takes longer than the release cycle for your program, then it may become a waste of time - although it's only a theory right now and the suitability of such a method will vary. I don't believe there are any really watertight solutions to program security. You just have to prevent the ship from sinking for the duration of the voyage. Edited October 10, 2014 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Morthawt Posted October 10, 2014 Share Posted October 10, 2014 (edited) I just wish the official obfuscator was not discontinued. I used to use that to protect a gaming clan's modpack files installer/updater that I wrote to prevent nosey people seeing how the protection worked to easily bypass it. Edited October 10, 2014 by Morthawt Free and easy Autoit scripting video tutorials (plus more videos always coming!) General video tutorials, especially correct and safe TeamSpeak permissions tutorials. Link to comment Share on other sites More sharing options...
czardas Posted October 10, 2014 Author Share Posted October 10, 2014 I found some obfuscated scripts quite easy to reconstruct. I only wanted to learn from the process by figuring out how it worked when I attempted to reconstruct the code. I'm trying to find ways around some of the limitations. At least I am learning new things as I go. I may hit a brick wall yet, but I think that's part and parcel of being inquisitive. operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Guest Posted October 11, 2014 Share Posted October 11, 2014 (edited) Well actually, this depends entirely on the design of your program. The main idea here is to eventually rip some of the numbers out of the code altogether and conceal them somewhere (perhaps in an encrypted key). That will just about break most scripts that use constants. The point being that lots of work will be needed to get the script working again if someone tries to decompile it. This part of the plan still needs consideration. Can you tell me what the obfuscated code >here is doing? I don't think it's obvious when you first read it, although analysis reveals that it is actually the function Sleep(). Generate lots of code like that and it will be a nightmare to reconstruct the original script. Now suppose someone tries anyway - the level of success will be related to the number of bugs which need fixing. The more subtle the bugs, the longer this process will take. If the debugging takes longer than the release cycle for your program, then it may become a waste of time - although it's only a theory right now and the suitability of such a method will vary. I don't believe there are any really watertight solutions to program security. You just have to prevent the ship from sinking for the duration of the voyage. According to the result of your script, if the new numbers requires additional processing then I think that it is unless to do that.. Unlike like a sentence($sentence , "sentence" , sentence() ), numbers is not something that tell you something.. I think that obfuscating $sentence , "sentence" , sentence() + injection confusing code is enough. but i don't want to obfuscate sentences(this type: "sentence") because I'm afraid that in this way the script will require additional processing.. Your example here: Will definitely require more processing. Anyway I am considering to use BinaryToString() for obfuscating sentences. Is there a better function that takes less processing power? EDIT: Well actually, this depends entirely on the design of your program. The main idea here is to eventually rip some of the numbers out of the code altogether and conceal them somewhere (perhaps in an encrypted key) OK, now i got it.. I would love to use this technique but without encryption/obfuscating numbers. And about sentences (this type: "sentence") also without encryption because it definitely require additional processing.. about this type of sentences I prefer to use some obfuscation technique which does not require additional processing power.. and I have no idea about such a technique.. Edited October 11, 2014 by Guest Link to comment Share on other sites More sharing options...
czardas Posted October 11, 2014 Author Share Posted October 11, 2014 (edited) gil900 - You raise some valid points. Unfortunately I do not have a general solution for latency incurred. However it should make very little difference in situations where constants are already being Bitwise-OR'ed together - the code might even run faster. I may add an option to exclude a set of functions selected by the developer. This can be done manually at the moment by separating functions (with less critical responce times) into a separate library. I don't mind a slight delay at startup when security features are running, or when a user initiates a new instance of a process. Many programs display latent behaviour when rollback, or similar, actions are invoked. Automatically recognizing the parts of a script where speed takes priority does not seem feasible, and I don't believe there can ever be a perfect solution that fits all situations. What I am suggesting here are ideas that can be developed, combined and personalized to suit particular requirements. I don't know of any reliable way to obfuscate code without incurring latency. I'm not saying it's impossible, but it seems that way to me. As regards the example in the other thread - I think you will find the added delay to be less than inherent fluctuations associated with the obfuscated function - Sleep() does not keep perfect time. Some of the techniques described in this thread can be adapted to work with strings. Unfortunately this seems somewhat more complicated, and I haven't yet come up with a general solution that I'm satisfied with. If I come up with something, you'll be the first to know. Edited October 11, 2014 by czardas operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Guest Posted October 11, 2014 Share Posted October 11, 2014 (edited) OK, I will read the other parts of your post later. About this: I don't know of any reliable way to obfuscate code without incurring latency. I'm not saying it's impossible, but it seems that way to me. Yesterday I was thinking about some technique for obfuscating strings.. the idea is to make algorithm that that changes this(example): $var = "This is sentence" to this: $var = "T" $var &= "h" $var &= "i" $var &= "s" $var &= " " $var &= "i" $var &= "s" $var &= " " $var &= "s" $var &= "e" $var &= "n" $var &= "t" $var &= "e" $var &= "n" $var &= "c" $var &= "e" In large-scale scripts that may be very effective (depending on the person ..).In the event that there are many sentences in the script, it will add a lot of rows - which is good.But this idea must upgrade .. you can still read it but it will be less convenient ..I thought reverse the order of the letters so that it will be someting like this: e c n e t n e s s i s i h T And that way it will be more difficult to read.. I think that this method does not require any additional processing power .. but maybe I'm wrong. Even if so, then the addition of processing power that will be required will be approximately 0 I don't mind a slight delay at startup when security features are running, or when a user initiates a new instance of a process. Many programs display latent behaviour when rollback, or similar, actions are invoked. If the idea is to decode the encrypted data(that written in separated place) only when the script/function starts the first time, then i don't mind to incorporate encryption in the obfuscation of this area and scope(I hope you understand what I mean). I even prefer to do so.. Edited October 11, 2014 by Guest Link to comment Share on other sites More sharing options...
czardas Posted October 11, 2014 Author Share Posted October 11, 2014 The problem with most methods of this kind is that the code can be run and then data extracted. If it is possible to break the code without compromising the compiled script, then you might have more success - I can't guarantee how much. Anyway as I said earlier, ORfuscator is experimental and may also have applications for something else. operator64 ArrayWorkshop Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now