Jump to content

CodeCrypter - Encrypt your Script


RTFC
 Share

Recommended Posts

@alessandror9: Sorry, I have trouble understanding your questions. :blink:

If you wish to encrypt/decrypt large chunks of data, then have a look at AutoIt's own _Crypt_EncryptData function, or search the forums for "encryption"; there are many solutions (native and user-made) out there for you to try out. (I personally like Ward's >AES, for example).

CodeCrypter, on the other hand, encrypts an AutoIt script, so the encrypted version will run only in an authorised environment. There is no limit on the size of your script (other than fitting into memory). So your lines of AutoIt code will become impossible to read or understand, and when you try to run it, if will fail and stop immediately as soon as it encounters an encrypted line, unless the environment  where you wish to run it is defined as valid at the time of encryption. Encryption is done on a line-by-line basis, for technical reasons, and AutoIt lines cannot exceed 4,095 characters each.

If you wish, you can use a password query dialog to decrypt the encrypted script at runtime (this is default key definition nr.1), but this is not particularly secure, as users tend to write down their passwords somewhere in case they forget. The $CCkey array in MCFinclude.au3 provides a number of alternatives, but you can also define your own, or combine several keys. The important part is that the information you use for encryption should not be stored inside the script itself, but be extractable from the environment where the script is supposed to run (for example, by using a @macro). As far as I know, CodeCrypter is the only AutoIt tool that does not store the decryption key inside the encrypted script.

If I misunderstood your questions, please clarify.

Edited by RTFC
Link to comment
Share on other sites

@RTFC

1) launch codescanner and load my source (WriteMetaCode = True)
2) codecrypter launch and load the source. in main tab I select CreateMCF0 and BackTranslate
3) click RUN and wait for it to complete.

4) unselect CreateMCF0 / BackTranslate and I select encrypt
5) click RUN and await the end of the process

6) the program generates a new AU3 MCF0test
7) I launch this file and it all works but if I launch it as ADMINISTRATOR no longer works.

What can be the problem?

Link to comment
Share on other sites

@alessandror9: Now that is a lot clearer, thank you! ;)

I'm guessing here that you did not change the default key ID 3 = @username (see MCFinclude.au3, array $CCkey). So your encrypted script will query its runtime environment at startup to define the decryption key by calling macro @username. And when you encrypted as user X, and then switch to a different user, in this case, administrator, then of course your script won't run, because the decryption key returned by @username is now different from the one you encrypted with. This is exactly how it is supposed to work. If you use macro @username as your key, then the script will run only if its runtime return matches the one at the time of encryption, either automatically or explicitly defined by you (see below).

So there are two ways to make this work for you:

The lazy option:

Perform the encryption as administrator.

The smart option:

1) Start CodeCrypter, load your script, and navigate to Tab Encrypt.

2) Press the <Decryptor> button to redefine the expected response. If you're currently running as user X, the macro's current response will be "X". In the bottom two boxes, type the username of the administrator on your machine (once in each box, to check for typos). Be extra careful if the name contains a mix of upper- and lower-case letters.

3) Navigate to <Tab> Main and press Run.

In both scenarios, the encrypted script will run only if the macro @username returns the administrator's name to the script at runtime.

Of course, if @username is insufficient or inappropriate, you can use any other function or macro to extract specific data from your target environment, or you can cycle through several different keys.

Hope this clarifies matters. :closedeyes:

Edited by RTFC
Link to comment
Share on other sites

@alessandror9: Please read the example in post #53 in this thread.

You can write your own function that extracts any information from your local environment, or even connects to the internet and communicates with your own server, if you like. All you then have to do is create an entry for it in array $CCkey in MCFinclude.au3 and then use that key ID (the index of that entry in $CCkey) when you encrypt. If you want a fixed encryption that will work anywhere, look in this thread for the solution I earlier suggested to forum member codeFOB (using macro @scriptname); but know that this is less secure than using an environment-dependent key.

Just have a look at the contents of $CCkey and play with it (for example, use a different @macro, or add more entries that call your own functions). I've tried to make it as flexible as possible.

As an aside, the contents of $CCkey are themselves also encrypted (with a fixed key) so casual inspection of the script won't even reveal how you obtain your key.

Best of luck,

RT.

Edited by RTFC
Link to comment
Share on other sites

@legend: I'm afraid you misunderstand how this protection works. :(:huh: Please read the example in post #53 in this thread.

Edit: a dynamic debugger's memory dump would show what the decryption produces at runtime, but this will only yield the plaintext code if the environment's response to the defined key query is identical to the one you defined at the time of encryption. So anyone who steals your exe cannot extract the plaintext unless they also have access to the environment/machine in which your script is allowed to run.

Edited by RTFC
Link to comment
Share on other sites

that gives sense, but in my case, i'm releasing a product, so the decryption key would be on a web server. In just my case,

It might be more secure to rely on obfuscation, since a memory dumb could get the unencrypted code if it's only encrypted

Link to comment
Share on other sites

@legend: Well, check out the encryption solution i suggested to CodeFOB earlier in this thread, using @scriptname (but note the distinction between au3 and exe versions). Any encryption on top of obfuscation will add another layer of complexity that might deter/defeat amateur hackers, even if it's less secure than environment-dependent keys. It's just a thought. :mellow:

Link to comment
Share on other sites

@alessandror9: As I told you before, :x if you want help, you'll have to make a bit (more) of an effort explaining your problem. What is this supposed to even mean: "I do not charge button icons"? I understand that English may not be your first language, but that implies it's even more important to try and convey in sufficient detail what your problem is. I would suggest you post the smallest possible script that reproduces the problem,  and explain what apparently is not working for you. Or would you expect me to just start coding up random scripts with ButtonConstants myself and hope I might stumble across your problem?

I'll be happy to try and help you, but you've got to meet me at least halfway, okay? :ermm:

Link to comment
Share on other sites

@alessandror9: As I told you before, :x if you want help, you'll have to make a bit (more) of an effort explaining your problem. What is this supposed to even mean: "I do not charge button icons"? I understand that English may not be your first language, but that implies it's even more important to try and convey in sufficient detail what your problem is. I would suggest you post the smallest possible script that reproduces the problem,  and explain what apparently is not working for you. Or would you expect me to just start coding up random scripts with ButtonConstants myself and hope I might stumble across your problem?

I'll be happy to try and help you, but you've got to meet me at least halfway, okay? :ermm:

I'm sorry for my English.

I try to make a simple script to play my mistake.

:)))

thanks for the support

Link to comment
Share on other sites

@alessandror9: your English is fine, :)  it's just that you need to explain your issues in greater detail, and a tiny script that reproduces the problem would enable me to investigate it quickly without having to make wild guesses, or waste acres of time on irrelevant side quests. A few sentences along the lines of "X doesn't work"  are just not enough to identify what might be going wrong in a particular case. The only thing I could suggest at this point (based upon past experience) is to ensure you've got the "include Constants" option enabled in CodeScanner's Settings panel, but that should be automatically switched on anyway when you enable WriteMetaCode.

Edited by RTFC
Link to comment
Share on other sites

RTFC:  

Thank you for all your efforts with this as well as answering everyone's questions!

First off, codescanner does not seem to like windows8 (could just be me....), when I run it on my code, it scans for a while and outputs the txt files, but then fails with "Autoit has stopped working"...  Just an FYI.  I copied it over to my win7 box, and it worked fine.

 

I've read over this thread a few times and this seems to be exactly what I want!  I have an application that I would like to deploy to ~400 sites, however I would like to lock it down as much as possible.  In the programs current state, I have it look for (some things), then generates a string on those things, adds a salt based on another thing, and then runs a _Encrypt() on it with SHA256.  Each site is unique, and comes up with its own unique has after this code is completed.  I then have the program look through an array of all sites hashed values, compare, and if it matches, allow access.. and if not, exits.  Works great, except someone can just access my code and remove it.

In this instance, I would probably want to add my procedure to get their local hash somehow....  My understanding though is that since this hash is different for every site, It would not be possible to use this as the "encryption key"...

So, Is something like this possible:

Encrypt my program with a key (static, but long.  Like 64 chars or something)

Use my function call that gets user data and generates a hash, have it return false if user data isn't correct, and then return the key if it is correct?

does having a static key (albeit something of decent length) in itself provide me with decent protection?  Or would the function returning they key be a major flaw in this design?

Once again, THANK YOU FOR YOUR WORK!!!!!

Edited by kaisies
Link to comment
Share on other sites

For instance, a very simplified version:

Change MCFInclude line 192 to:

$CCkey[7]=CheckK() ; should be permanent, so if using your own, do not set with EnvSet()

Then include the function:

Func CheckK()
    $compname = @ComputerName

    Local $aComputerNames[5]

    For $i = 0 to UBound($aComputerNames)-1
        $aComputerNames[$i] ="adsfgfthreyfhjdetyjdtyjsfhysrthjhygffjhmjfgjdhsrthyjyusdtyhjdyf"
    Next


    $aComputerNames[0]="testing"
    $aComputerNames[1]="KAISIES"

    For $i = 0 to UBound($aComputerNames)-1
        If $compname = $aComputerNames[$i] Then
            Return "omgyesitworks"
        EndIf
    Next

    Return False


EndFunc

Then have the script as:

;test script
#include "MCFInclude.au3"

msgbox(0,'',"test")
msgbox(0,'',"test")
msgbox(0,'',"test")

When encrypting using 7, If I click the "Decrypter" button, it properly shows the return as "omgyesitworks". However, when I run Codescanner & CodeCryptor on the above script, it simply does nothing.  I'm guessing this is related to the Return False in the CheckK function if the computer name isn't found.  If I change this to return "no", it also does not work.  My limited understanding of Crypting would lead me to believe that this is because its encrypted, and how can encryption store its own key... perhaps I am wrong/misunderstanding.

Link to comment
Share on other sites

@kaisies: Hi there! Thanks for the kind words, and thanks for your very clear question. :thumbsup:

From what you describe I think you're making it too complicated. As I understand it (haven't run your example yet), your proposed setup would (if it worked) actually weaken CodeCrypter's protection, because you are storing the final hash to be compared in the script itself, as well as the actual key (uh oh :nuke: ) that is used for decryption upon a successful compare ("omgyesitworks"). This part of the exe can itself only be encrypted with a fixed key, so any determined hacker will be able to get access to its content, including your UDF's response upon successful comparison.

By all means, add your own UDF in MCFinclude.au3 to generate a hash from various bits and pieces (this is a good idea), but instead of comparing against a stored list, just return the hash immediately as your key. This means the hash is a dynamic variable that is based upon the actual work environment, and not stored or compared anywhere (which was my reason for writing CodeCrypter). Do not use a fixed response anywhere, let the work environment speak for you to define the runtime decryption key.

This would of course imply that you have to generate a separate exe for each machine you wish to run it on, but this can be automated fairly easily (with AutoIt, for example :D; maybe I should add cmdline options in a future release?). For example, you could send an installer to any target machine that gathers the machine specs and returns them to your server, server generates the hash, calls CodeCrypter to encrypt, and sends the resulting exe to the target.

Link to comment
Share on other sites

Thanks RTFC... I was really hoping not to compile a ton of different EXE's, but it sounds like that would be best.  Spent all morning working on this and pulling my hair out... is there some reason I can't Return a result in my Function added to MCFInclude?

As described above, I open a text file, read some data, and then make a hash of that data.  As you suggested, I will then use this hash to encrypt.  Here is a super simplified version.... To make this work I have a text file on the root c: called "test.txt" with the following data:

StoreData=324647788453262478
StoreNum=1
 
And I have altered Crypt.au3 in the includes folder, uncommenting $CALG_SHA_256.

 

MCFInclude.au3:

; =======================================================================================================================
; Title .........: MCFinclude.au3
; AutoIt Version : 3.3.12
; Description ...: CodeCrypter target's UDFs
; Author.........: A.R.T. Jonkers (RTFC)
; Release........: 1.1
; Latest revision: 23 Jun 2014
; License........: free for personal use; free distribution allowed provided
;                           the original author is credited; all other rights reserved.
; Tested on......: W7Pro/64
; Forum Link.....: http://www.autoitscript.com/forum/topic/155537-mcf-metacode-file-udf/
;
; Related to......: CodeScanner, MCF, CodeCrypter, all by RTFC
; Dependencies...: AES.au3, by Ward; see http://www.autoitscript.com/forum/topic/121985-autoit-machine-code-algorithm-collection/
; Acknowledgements: Ward, for AES.au3, part of AutoIt Machine Code Algorithm Collection\Encode
; ===============================================================================================================================
; Remarks
;
; * Edit/Add keytype definitions in the last UDF of this script: _MCFCC_Init()
;
; * This UDF is called by CodeCrypter, and should be #included into any script
;       you wish to CodeCrypt. Any code prior to this #include will not be encrypted;
;       all code following it will be encrypted.
;
; * Please do NOT explicitly include any other MCF-related scripts into your target script!
;
; * If you make changes to this UDF, save it under a new name and change
;       global variable $MCFinclude in this script to reflect this.
;
; * The default encryption engine is Ward's excellent AES UDF. You have to
;       download that yourself.
;       You can replace this by whatever algorithm you desire, BUT be aware that
;       any code you replace it with has to be FAST ENOUGH not to slow down the
;       the script too much (as it may be called in almost every line).
;       Timing-dependent code (e.g., Adlib calls, user event loops in games) may
;       FAIL if decryption handling time >= loop interval (causing stack queueing
;       and/or stack overflow = crashing or hanging script).
;
; * A list of actions to take when replacing your encryption algorithm is given
;       in the Remarks of MCF.au3
;
; * If processing is too slow, reduce the proportion of encrypted lines <100%
;       by setting  $MCF_ENCRYPT_SUBSET=true, and
;                       $subset_proportion <1 (N*100 = percentage, randomly assigned), or
;                       $subset_proportion >1 (cycled = 1 in N lines encrypted)
;
; * Encryption can be two-pass (nested):
;       - outer shell encrypted with key $CCkey[0], using a fixed string (supplied)
;       - inner shell encrypted with key $CCkey[#], containing whatever you want, defined at runtime
;           some simple examples are provided in _MCFCC_Init()
;   Note: you can switch to single-pass by setting $MCF_ENCRYPT_NESTED=False
;
; * Set your selected keytype by calling _MCFCC_Init(#) (# = number)
;       if instead # = <string>, this string is stored in $CCkey[1] for ENcryption.
;       The declaration of $CCkey[1] in the MCFinclude.au3 included in your script
;       remains an empty string, to be filled at target's runtime by either a parsed
;       commandline parameter or a user password query.
;
; * IMPORTANT: $CCkey[#] (#>0) should NOT contain a fixed definition.
;       Instead, use data retrieved at runtime, for example:
;       - from the user (password query)
;       - from the host machine (e.g, macros, keyfile, machine specs, environment var...)
;       - from a local server or web server
;       - from an external device
;       - use your inagination
;
; * IMPORTANT: you are not restricted to your own user environment;
;       variable $decryption_key can be preset with whatever is expected in the
;       target environment. See CodeCrypter's Remarks for more details.
;
; * if you use environment variables to define a key ($CCkey[#]=EnvGet("SOME_VAR"),
;       and that variable does not exist in the target environment, an empty string
;       would be returned by EnvGet(), triggering a (likely unwanted) password query
;       at startup if it was used as single key or the only empty key in a shuffled
;       range. Any other encryption combination would simply fail.
;       So ensure beforehand that your environment variable exists in the target
;       environment, or use something else instead.
;
; * You can combine multiple keytypes by:
;       1. grouping them consecutively in $CCkey[X] to $CCkey[Y]
;       - setting $MCF_ENCRYPT_SHUFFLEKEY=True
;       - defining the range by setting $CCkeyshuffle_start=X and $CCkeyshuffle_end=Y
;       This way the encryption keytype will be assigned at random per encrypted line.
;
; ===============================================================================================================================

#include-once
; see www.autoitscript.com/forum/topic/121985-autoit-machine-code-algorithm-collection/
#include ".\AES.au3"    ; by Ward
#include <File.au3>
#include <FileConstants.au3>
#include <Crypt.au3>
; NB in AES.au3 replace line 16 : Global Const Enum $AES_CBC_MODE, $AES_CFB_MODE, $AES_OFB_MODE
;                                       by  : Global Const $AES_CBC_MODE=0, $AES_CFB_MODE=1, $AES_OFB_MODE=2

#region Indirection (to be obfuscated only)
; do not edit this region

; if enabled, these functions replace (unencrypted) direct assignments by
; (encryptable) function calls

; this func def should be the first one of this region,
;   as it is used as its start marker
Func _VarIsVar(ByRef $a, ByRef $b)
    $a=$b           ; e.g., for copying arrays
EndFunc


Func _ArrayVarIsVar(ByRef $a, $b, ByRef $c)
    $a[$b]=$c
EndFunc


Func _VarIsArrayVar(ByRef $a, ByRef $b, $c)
    $a=$b[$c]
EndFunc


Func _ArrayVarIsArrayVar(ByRef $a, $b, ByRef $c, $d)
    $a[$b]=$c[$d]
EndFunc


Func _VarIsNumber(ByRef $a, $number)
    $a=Number($number)
EndFunc


Func _ArrayVarIsNumber(ByRef $a, $b, $number)
    $a[$b]=Number($number)
EndFunc

#endregion Indirection (to be obfuscated only)

#region Encryption1 (to be obfuscated only)

; IMPORTANT: if this calls fails, it is likely that AES.au3 was not found in the local directory (so move it there, or edit the path in the #include directive above)
_AES_Startup()

; do NOT edit this part!
Global $MCFinclude="MCFinclude.au3"     ; this script
Global $CCkeytype=0
Global $CCkey[2]                                ; absolute minimum size
$CCkey[0]="0x3CA86772DB0B25CBD8AC911792C2217A9DD04C218DAE0F4261BD76EF512838FBDE2BDA417829E56D62EDE396B376E2CC"  ; do not edit

; you can change the CONTENTS of this call with whatever decryption algorithm you like
; as long as you also change the decryption call in MCF:_EncryptEntry()
Func _MCFCC(Const $hexstring,$index=0)
    Return BinaryToString(_AesDecrypt($CCKey[$index],$hexstring))
EndFunc
; this func def should be the last one of this region,
;   as it is used as its end marker

#endregion Encryption1 (to be obfuscated only)

#region Encryption2 (to be fixed-key encrypted)

_dummyCalls()           ; do not remove!

Func _dummyCalls()  ; DO NOT EDIT!
; prevents MCF:_CreateSingleBuild() from removing the defs as redundant
; this UDF will be fixed-key encrypted

    ; nested keytype for _MCFCCXB calls
    _MCFCC_Init(0,False)        ; DO NOT REMOVE! To be edited by CodeCrypter with your selected keytype!
    _MCFCC("")                  ; DO NOT REMOVE! Otherwise decryptor UDF is considered redundant!

    Local $a=0,$b=1
    Local $c[1]
    _VarIsVar($a,$b)                    ; copy var
    _ArrayVarIsVar($c,0,$a)         ; copy single value into indexed array location
    _VarIsArrayVar($a,$c,0)         ; copy single value from indexed array location
    _ArrayVarIsArrayVar($c,0,$c,0); copy indexed array location to indexed array location
    _VarIsNumber($a,1)              ; assign number to var
    _ArrayVarIsNumber($c,0,1)       ; assign number to indexed array location

EndFunc


Func _MCFCC_Init($type=0,$query=True)
; NOTE: edit/add your keytype definitions here
; this UDF itself will be fixed-key encrypted

    ReDim $CCkey[8]
    If $cmdline[0]>0 Then
        $CCkey[1]=$cmdline[1]   ; option to parse decryption key at commandline
    Else
        $CCkey[1]=""    ; an empty string triggers decryption key (password) query at startup
    EndIf
    $CCkey[2]=@ComputerName ; some simple examples...
    $CCkey[3]=@UserName     ; case-sensitive!
    $CCkey[4]=@LogonDomain
    $CCkey[5]=DriveGetSerial("C:")
    $CCkey[6]=@IPaddress1   ; ensure this is fixed (no DHCP) on the machine that will run your target
    $CCkey[7]=_GetLocalHash()   ; should be permanent, so if using your own, do not set with EnvSet()
    ; add your own definitions here...

    If $type="" Then $type=1
    If $type<=0 Or $type>UBound($CCkey)-1 Then  ; store parsed string or string(out-of-bounds keytype) at index 1
        $CCkeytype=1
        $CCkey[$CCkeytype]=String($type)    ; redefines entry 1 as string(parsed param); does not need to be a number
        Return
    EndIf

    If $CCkey[$type]="" And $query=True Then $CCkey[$type]=InputBox("Protected Application","Please Enter your Password: ","","*",250,140)
    $CCkeytype=$type

EndFunc
; this func def should be the last one of this region,
;   as it is used as its end marker (do NOT rename it)

#endregion Encryption2 (to be fixed-key encrypted)

; Anything below this region will be encrypted twice (when nested encryption is set):
;   1) runtime-encryption using your selected keytype, itself nested inside:
;  2) a fixed-key encryption (using the contents of $CCkey[0] as key)
; If nested encryption is disabled, anything below this region will be encrypted with
;       runtime-encryption using your selected keytype.
;
; Theoretically, it is possible for an attacker to discover HOW you *define* your key,
; but NOT its contents, unless they have full access to your target user environment.
; For example, by decrypting MCFCC_Init and the outer layer of an encrypted call,
; they could discover that you chose to use the serial number of the host's C: drive,
; but unless they have access to that machine to obtain that serial number,
; the contents of your script would remain secure.



Func _GetLocalHash()
    Local $i,$sReturn[2], $sK
    Local $sS[10001], $Salt

    $sS[1]="[WD@%_j?=R2{vJa>"

    For $i = 0 to UBound($sReturn)-1
        $sReturn[$i] = "test"
    Next
    $sReturn[0] = 1

    Local $dir= "C:\"

    Local $hFileOpen = FileOpen($dir & "test.txt" ,0)
    If $hFileOpen = -1 Then
        Return "0xAB434874ABCDF6574EFAC"
    EndIf

    Local $sTmp = FileRead($hFileOpen)
    FileClose($hFileOpen)
    Local $aTmp = StringSplit($sTmp,@CRLF)
    For $i = 0 to UBound($aTmp)-1
        If StringInStr($aTmp[$i],"StoreData=") AND NOT StringInStr($aTmp[$i],";StoreData=") Then
            $sReturn[0] = StringReplace($aTmp[$i],"StoreData=","")
            ExitLoop
        EndIf
    Next
    For $i = 0 to UBound($aTmp)-1
        If StringInStr($aTmp[$i],"StoreNum=") AND NOT StringInStr($aTmp[$i],";StoreNum=") Then
            $sReturn[1] = StringReplace($aTmp[$i],"StoreNum=","")
            ExitLoop
        EndIf
    Next

    _Arraydisplay($sReturn)

    If ($sReturn[0] > 0) and ($sReturn[0] < UBound($sS)-1) Then
        $Salt = $sS[$sReturn[0]]
    Else
        $Salt = $sS[1]
    EndIf

    Local $temp = _CryptK($sReturn[1],$Salt)
    msgbox(0,'',$temp)

    Return $temp
EndFunc


Func _CryptK($sK, $sS)
    Local $i, $bAlgorithm = $CALG_SHA_256
    For $i = 1 to 5000
        $sK = _Crypt_HashData($sK & $sS, $bAlgorithm) ; Create a hash of the text entered.
    Next
    Return $sK
EndFunc

BasicTest.au3:

#include "MCFinclude.au3"

msgbox(0,'',"This is a test.  It worked.")

As cautious as I am to say it, perhaps your UI isn't properly using the returned value from the _GetLocalHash() Function?  Clicking the Decrypt button below the Encryption key im asking it to use does yeild the expected result.  I have included a msgbox of the hash, and it is there and computed correctly, however when I run CodeCrypt on the Code (after scanning), It asks for a password as If I didn't supply one (and then, oddly enough, if I supply the hash shown in the msgbox from the _GetLocalHash() Function, it approves it).  Maybe I'm just stupidly missing something very simple?  :ermm:

Edited by kaisies
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...