Jump to content

CodeCrypter - Encrypt your Script


RTFC
 Share

Recommended Posts

20 hours ago, Lion66 said:

Then the key will be inside the code.

No, only the query definition, not the expected runtime response! If your OS username is Lion66 and you write:

MsgBox(0,"",@username)

then is "Lion66" in the script to be read by third parties? Of course not; it's returned by the OS to the script at runtime. So what is returned is environment-specific; in this case, if this script is run by any user with a different username, that same macro returns their username instead, and using that to decrypt your encryption will fail. All you need to do is to construct a clever encryption key definition (user password query, hardware ID, server response, hashed IP, your own dedicated UDF's return, whatever). Therewith you target a specific (set of) user-defined boundary condition(s) to be met for the script to be allowed to run. Whenever that is the case, that environment is considered to be safe/valid. So for example, a sysadmin runs an encrypted script with #requireAdmin privileges, and the key extracts data available only at admin-level on the workplace LAN. Any ordinary user can copy the script and take it home (or try and sell it to the competition) but it will never run beyond initialisation elsewhere, as the derived specs used in the de/encryption are unique to that workplace LAN.

Link to comment
Share on other sites

Thanks for your answers, but I still do not understand everything.
First, I mean the case when the client who works the script is trying to hack him.
If I use the username, this is the key that is not in the code, but to which there is access, if you know.
If I use a unique string, then it is inside the code.
And I ask again, is it possible to hack after encryption (on a computer where the script finds the key and works)?

Link to comment
Share on other sites

13 hours ago, Lion66 said:

If I use a unique string, then it is inside the code.

This is a terrible idea, and would completely defeat the purpose of using CodeCrypter in the first place. The whole point is to define encryption keys as runtime calls (macros, WinAPI, UDF, server query...) that retrieve external data.

13 hours ago, Lion66 said:

If I use the username, this is the key that is not in the code, but to which there is access, if you know.

Yeah, the same goes for any password-based access. My default assumption is that a valid user+environment can be trusted, and evil actors are to be prevented from running an encrypted script in any other, invalid environment. If you instead assume that a valid user+environment cannot be trusted, you'll need to define a runtime query that yields an environment-based response that they do not have access to, such as described in my previous post. If you cannot devise such a method, then CodeCrypter is not for you.

Link to comment
Share on other sites

@RTFC, Thanks for your clarification.

So more understandable. But I want to return to the question when the key is some string.
The key is registered in the MCFinclude.au3 file. The file is included in the script.

The encrypted script includes as part of the file so (I use ID = 9):

Func _MCFCC_Init($type= 0,$query= True,$useCNG= False,$updateCCkeys= True)
    Local $String=Execute(_MCFCNG('0x55034992E6E43B9DCC6666078D11D938EF7CC2730A1740383D32753A41F62F18CF7BD39F39168E829E852E8549E5192D'))
    ...
    $CCkey[9]=$String


The key is encrypted. According to the _MCFCNG function, this key is needed for decryption!
So this method is reliable? There is a method to read string?
Thank you.

Link to comment
Share on other sites

1 hour ago, Lion66 said:

the key is some string

I just told you not to do that; it's unsafe and makes teecnryption pointless. The Remarks section of MCFinclude.au3 clearly states:

Quote

; * IMPORTANT: $CCkey[2-99] should NOT contain any fixed definition.
;        Instead, use data retrieved from the work environment at runtime

Regarding the encryption of the contents of the CCkey array, if you study MCFinclude.au3, you'll notice it is divided into #regions:

Spoiler

#region Encryption1 (to be obfuscated only)

...

#endregion Encryption1 (to be obfuscated only)

#region Encryption2 (to be fixed-key encrypted)

<<< this is where array CCkey is defined

#endregion Encryption2 (to be fixed-key encrypted)
;_____________________________________________________________________________________
; Anything below this region will be encrypted using your selected keytype(s).
;

; WARNING: do NOT place any key-generating UDFs below MCFCC_Init(); this won't work!
; Instead, please insert them anywhere within #Region Encryption2 ABOVE MCFCC_Init().
;
; 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 😄 drive,
; but unless they have access to that machine to obtain that serial number,
; the contents of your script would remain secure.
;_____________________________________________________________________________________

Obviously, no encrypted key can decrypt itself and still be useful as such elsewhere; that's why it's fixed-key encrypted instead, and that's why you should never use a fixed string as a key.

Link to comment
Share on other sites

On 11/16/2021 at 5:46 PM, RTFC said:

your own dedicated UDF's return

I do not understand this. Can you give an example?

And what would you advise as an example if the same script should work on multiple computers, without access to the network.

Thanks.

Link to comment
Share on other sites

Func _MyFunction()
    ; place this BEFORE Func _MCFCC_Init() in the same #region!
    Return @UserName & @Year & @Mon
EndFunc

Func _MCFCC_Init($type=0,$query=True,$useCNG=False,$updateCCkeys=True)
; NOTE: edit/add your keytype definitions here for $CCkey array entries 3-N
; this UDF will itself be fixed-key encrypted

    If $updateCCkeys=True Then
        $CCkey[3]=@UserName     ; case-sensitive!
        $CCkey[4]=_MyFunction()
...

Example: UDF _MyFunction() returns for key #4 a runtime string composed of three macros that cause the script to run only for a specific user(name) for the remaining duration of the month at which the script was encrypted. Far more sophisticated UDFs are of course possible, for example, communicating with a server for datetimestamp, hash, licence code, etc).

For multiple machines without any network access(?!) under your administrative control, assuming that the individual machines do have internet access, just set up a simple server to communicate with all instances of your script for validation purposes. Alternatively, use the storeCCprofile utility (part of Codecrypter bundle) to collect each machine-specific profile and produce a separately-encrypted version for each.

Edited by RTFC
clarification
Link to comment
Share on other sites

Thank you, I understood.
The latter is probably the question about use the obfuscation and encryption together.
After encrypte, the names of variables remain unchanged. I would not want it.
If use only obfuscation, the removal of a problem string does not interfere with the work of the script .

Here is this line. I mentioned it.

This is not part of my code. This is part included MCFinclude.au3.

$0B74769B07BE21B9=$tUlong.value

But when use obfuscation and encryption together, remove the row leads to a non-working script.
Can this be solved? And it is strange that no one asked about it.

Edited by Lion66
Link to comment
Share on other sites

14 hours ago, Lion66 said:

remove the row

If you mean just removing a line in the TranslNew.txt array content file, then I can only assume that you never studied the MCF tutorial (please do so now; NB this is a different document from the CodeCrypter FAQ!). TL,DR: If you remove any line in any MCF array content file, all following entries would shift up, so all their indices are then mismatched, producing utter garbage when reconstituting the script. Keep all lines and in their proper order (no additions, no removals, no line swaps) , and just edit their content. You can exclude any part of the obfuscation (or encryption) you wish by restoring the original content for the relevant line(s) from the original content arrays. In your case I would guess that replacing the obufscated $tUlong for the original in the Transl array file would fix your issue. If not, follow the extensive guidelines at the end of the FAQ: place encrypted and original script side by side in two separate Scite sessions (or tabs in one session)  and systematically replace additional small sections of the original with their encrypted equivalent, test run, and repeat. CodeCrypter can also exclude individual UDFs (or even individual lines, if patched by hand) from the encryption process.

14 hours ago, Lion66 said:

And it is strange that no one asked about it.

That should have been a clue that it was you that was doing something wrong rather than the UDF having some major flaw.

 

Now the docs and I have told you:

  • you don't need to obfuscate if you are encrypting, but you want to do it anyway; that's your choice, but it may create additional issues (as indeed here it does); you can solve these through manual patching, but that's your responsibility, not mine;
  • you should never use a fixed string in the CCkey definitions, but you want to do it anyway; that's your choice, but your encryption will be flawed; that's your responsibility, not mine;
  • CodeCrypter's support for objects (dot notation member access for one) is limited, but you want to use it anyway; that's your choice, but it may create additional issues (as indeed here it does); you can solve these through manual patching or rewriting your own code, but that's your responsibility, not mine.

Best of luck with patching your code; if you were to find an actual bug in CodeCrypter (rather than a well-documented limitation you can easily work around), please provide a functional, minimally-sized (<50 lines) reproducer script that illustrates the perceived problem.

Edited by RTFC
typo
Link to comment
Share on other sites

It seems to me that this is an error in UDF, since the same thing happens to any code.
But it is likely that I do something wrong, without conscious of it.
Here is my code, and I attach the file after obfuscation and encryption. In this case, I used ID = 3, but it does not matter.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <MCFinclude.au3>
Local $String = "Hello"
Msgbox(0,"", $String)


I performed:

- codescanner

- codecrypter: Create MCF0 + BackTranslate

- codecrypter: Create MCF0 + Obfuscate (Variables) + Encrypt (Phrases, Strings, Nested Keys. KeyId=3, x86,x64).


In the resulting file, problem line 587 and 1071.
Row of 587 I put at the beginning of the comment sign ";".
Row 1071 I clean "Byref".
I do not remove the lines.
If I use only obfuscation, then these actions solve the problem аnd the script works properly.

But not in the case of the use of obfuscation with encryption together.

MCF0test.au3

Link to comment
Share on other sites

You know what? I was wrong and you were right (well sort of, I managed to break even the BackTranslate option and obfuscation solo; not just obfuscation + encryption). Despite my previous efforts there were still a few stray dot notation struct accessors in my patched version of CryptoNG.au3. Do you know how much I hate dot notation? A lot. I'll be preparing a new update to fix the problem, but you can easily do so yourself already, thus:

  • open the CodeScannerCrypter-bundled version of CryptoNG.au3
  • replace all occurrences of "$tUlong.value" with
    DllStructGetData($tUlong,"value")

and save the file. That's all.

Edited by RTFC
Link to comment
Share on other sites

Thanks for your time, thanks for your patience, thanks for your answers.
Sorry to forced you to return to the finished code.
The solution that you suggested, works and solves the main problem - line 587.
And if you release a new version, correct the cosmetic problem with "ByRef" in Func _VarIsVar function.

 

Link to comment
Share on other sites

13 hours ago, Lion66 said:

correct the cosmetic problem with "ByRef" in Func _VarIsVar function.

Please elaborate.

Link to comment
Share on other sites

One could argue that this is an AutoIt limitation, in that it doesn't distinguish between read-only ByRef and read/write ByRef parameters (although one could also argue that specifying ByRef implies that one desires the option of R/W access). You could say that Scite is premature in flaggging this as an error rather than a warning, because if a Const is parsed as 2nd parameter only, Const is not violated at all. IMHO it would be better if the interpreter were to flag an error when a Const is actually about to be overwritten.

The easiest way to fix this is in MCFinclude.au3, #region Indirection,  to remove the second ByRef specifier here:

Func _VarIsVar(ByRef $a, $b)

before running CodeScanner on your scripts. When copying large arrays, this would of course incur a significant extra performance cost (which is why the 2nd param was ByRef in the first place). It will be fixed in the next full release.

Edited by RTFC
Link to comment
Share on other sites

So cleaner and does not require additional corrections from the user.
I want to experience the option of encryption only several lines.
I read the instructions from the "CodeCrypterFAQ.pdf" and get an empty array "$phrasesEncryp".

I tried to change the separator  from "|" to "\n", but it did not help.

#include <Array.au3>
#include <File.au3>
#include <readCSdatadump.au3>
FileCopy("test.au3.CS_DATA\phrasesUsed.txt", "test.au3.CS_DATA\phrasesNew.txt",1)
_readCSdatadump("test.au3.CS_DATA\phrasesNew.txt")
_ArrayDisplay($phrasesEncryp, True, "\n")

Maybe I do not exactly understand the instructions.

Spoiler

Q. I want to encrypt only some specific individual lines, not entire UDFs.
How do I do that?
A. This will require some effort on your part. First Run Codecrypter with full
encryption, with subsets disabled. You now have two same-sized arrays:
$phrasesUsed and $phrasesEncryp. Then you figure out at which line of
phrasesUsed.txt your important code begins, and at which line it ends. Now you
write a tiny script that:
 copies text file phrasesUsed.txt to file phrasesNew.txt
 calls _readCSdatadump() to load all arrays in memory
 fills array $phrasesNew from array $phrasesEncryp, but only from the first
to the last phrase of your important code!
 calls _FileWriteFromArray("phrasesNew.txt",$phrasesNew,1) (you need
#include <File.au3> for that) to write out array $phrasesNew to file
phrasesNew.txt (don't forget the third parameter "1", or everything will be
misaligned and fail).
Then you fire up CodeCrypter, enable CreateNew, and press <Run>. You're
done.


What am I doing wrong?
Thanks.  

Link to comment
Share on other sites

NB that ByRef edit I suggested would only be necessary if you use indirection, which does incur an additional performance penalty at runtime.

Yes, your target's $phrasesEncryp is empty until you run CodeCrypter at least once on your target with encryption enabled. Ensure the encrypted version works as expected before proceeding.

To do what you want (assuming that placing your desired to-be-encrypted lines in a single UDF and enabling encryption only for that function is not an option (see tick-box list under Encrypt Tab)), you'll need to:

  • write a small script yourself that loads the phrasesUsed and phrasesEncryp arrays (just include readCSdatadump.au3 in your own utility and call _ReadCSDataDump(<full CS output subdir path>)),
  • copy phrasesUsed to phrasesNew array,
  • replace the desired lines only from phrasesEncryp into phrasesNew,
  • write phrasesNew to file (ensure no lines are misaligned with respect to phrasesUsed!), then
  • restart CodeCrypter and select Main option "Create New". See the Remarks in the CodeCrypter header:
Spoiler

; * _CreateNewScript() should be used ONLY if you wish to replace MetaCode tags
;        entirely by yourself, based on content YOU change in the *New[] arrays
;        (pre-filled with *Used[] arrays by _CreateSingleBuild()).
;        If you make no changes, the output is as when calling _BackTranslate().

And in the FAQ:

Spoiler

Q. When would I be using "Create New"?
A. This option allows you to create a new script directly from the *New content arrays, without any alterations by MCF or CodeCrypter. You need it if you develop some new way to change the content arrays, and want to build a new script that incorporates those changes. Of course, you still need to start by creating the Single Build MCF0.txt

 

Edited by RTFC
Link to comment
Share on other sites

Version 3.4 of the bundle has been released, with some significant upgrades; with special thanks to Partner-in-Crypt TheXman, and a fond farewell to Ward's AES UDF, which is now no longer part of the bundle.

Edited by RTFC
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...