Code Crypter FAQ
Code Crypter FAQ
© by RTFC, 2013-21.
1
filename. CodeCrypter doesn't actually load your original target file at all, it just
needs its name to find the associated CS_data subdirectory.
2
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
Q. I've done a string Translation, and now my script can't find any of its
work files anymore. What gives?
A. Be careful which strings you translate, and always check the output of
whatever automatic translator you use. Google Translate, for example, may
insert an additional space before/after a (back)slash, so any string specifying a
directory path will be mangled. Same with filenames without extension that are
3
also valid English words. Ditto for strings such as "\\PhysicalDrive0". See the
earlier rule: never change more than you have to.
Q. I've done a string Translation, and now all my DllCalls fail. WTF?
A. Be careful which strings you translate. Dll calls require string parameters that
define the next parsed parameter type, strings such as "short," "long," and
"word" that are also normal words in English. So if you translate the entire
stringsTransl.txt file, those words may end up as "kurz," or "longue," or
"palabra," depending on your chosen language. And the dll that is handling your
call is probably none too happy about that.
4
Q. What happens if my keytype definition returns an empty string in the
user's environment?
A. An empty string will trigger a password user query dialog at startup. Unless
the user knows the expected response (unlikely), the script won't proceed.
5
3. Indirection adds extra calls to a few tiny, one-line UDFs, so the overhead
of indirection proper (or combined with obfuscation) will be negligible.
4. Decryption, however, is a different matter. Not only is the original code
replaced with a decryption step, but the decrypted "code as string" then
has to be executed (indirect call), so that's at least twice as much work as
before, possibly more. If you decide to nest your encryption (fixed-key
encryption of your dynamic key encryption, to hide your parsed keytype),
you add a whole second decryption step plus "Execute" call. Furthermore,
If you change the code structure through indirection prior to encryption,
you add many more calls that are all going to be encrypted. All of this
adds up. Only you can decide how much slowdown is acceptable.
Unfortunately, some scripts (with tight event loops, or timed calls, like
games and media players) cannot tolerate much delay.
On the positive side, you can adjust the proportion of encrypted code down to
any percentage, reducing the amount of extra processing again. Also, there's no
additional overhead for using multiple dynamic keys instead of one.
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 (so encrypting all lines). 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 (or collect the line numbers of the isolated lines you wish to encrypt). Now
you write a tiny script that:
6
copies text file phrasesUsed.txt to file phrasesNew.txt
calls _readCSdatadump(<{yourtarget}.CS_DATA subdir>) 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.
Q. How secure is the encryption when you store the fixed key that
encrypts MCFinclude.au3 inside MCFinclude.au3 itself? Won't an
attacker just bootstrap-decrypt the script in two passes instead of one?
A. Not possible. The fixed-key encryption is to prevent casual inspection to
reveal the keytype definitions, that is, how you obtain your decryption key at
runtime. A determined attacker will be able to figure out that you are, for
example, using keytype 1, which means a password user query dialog box will
be triggered at runtime (which is obvious to figure out anyway). But that's it.
The password is itself never stored anywhere (other than existing briefly in RAM
memory while CodeCrypter is encrypting).
The crucial safety factor is access, not to the programme but to the user
environment. For example, if you choose to encrypt with the C-drive serial
number of your end user's machine, and the attacker is able to log in to that
machine in secret and obtain that serial number, all bets are off. The same goes
for user names, IP addresses, stored signature files, Registry key, etc. And a
user password is only as safe as the user keeps it; if they have it written down
on a note on their keyboard and they keep their office door unlocked when
they're gone, game over. You'll have to be creative, and tailor a solution to the
specific circumstances of your target environment. Perhaps a combination of
something user-specific, something machine-specific, and your own web server's
response to the programme's unique serial number?
7
executed anywhere, but (providing you select or define your decryption key
wisely) only a single machine and/or user will produce the decryption key with
which the script was originally encrypted.
Example:
You can think of the array $CCkey in MCFinclude.au3 as a list of instructions to
construct a secret phrase (the decryption key). For example:
go to the library, find the first red book on the top shelf in the cabinet left
of the largest window, take the 7th word of the 3rd paragraph on page
123;
use the name of the only black pet in the house;
take the first letter of each word of the saying on the plaque over the
kitchen door
take the word for the material of the bedspread in the main guest room
etcetera (you can define these instructions yourself, adding as many as
you like)
When your proverbial hacker steals your executable, even though this list is
itself also encrypted (with a fixed key; there's no other way), they may be able
to decipher the list itself, or monitor the location in RAM where the result of
these instructions is stored. But such an instruction itself no longer makes sense
if it's referenced in any other house! There, the guestroom bedspread may be a
different type of cloth, there may not be any house pet, let alone a black one, or
even if so, it's name is likely different. Thus your hacker can monitor all they
want, but garbage in = garbage out, meaning the decryption key does not
match, therefore no sensible AutoIt code comes out of the decrpytor, just
gibberish that causes the programme to halt immediately. So yes, "the data"
(that is, the encrypted line and the "secret phrase" as extracted locally from the
work environment) are indeed "injected in memory", but this information is
completely useless when the secret phrase is different because the environment
is different. There is no hint whatsoever inside your script what name your black
pet actually has; there never was, and never will be. What is absent to begin
with cannot ever be extracted. Your only responsibility is to select or define
an instruction (or combination of several) that is unique (or very rare), and
unobtainable without access to the original environment.
8
Q. My new script does not work. How can I identify the cause?
A. Methodically eliminate all factors, dear Watson:
Start with CodeScanner. Were any issues identified that might affect the script's
proper functioning? Does the original script actually run?
Next up: BackTranslation. If the BackTranslated script does not work, the
problem likely lies in the initial MetaCode translation step. Create a new MCF0
while retaining all supposedly "redundant" parts (disable the Single-Build code-
pruning options), and see if that works when BackTranslated (if not, you're in
trouble).
All content alterations involve array manipulation. Check all array text files on
length; the number of lines should be equal for all files with the same prefix.
Even a single entry lost or added causes misalignment, often with disastrous
consequences. For strings, ensure they are all enclosed in single- or double
quotes. For variables, ensure that all names are prefixed with "$". For macros,
ensure that all names are prefixed with "@".
If none of this resolves the issue, then the most likely cause for failure is
encryption. Switch off nested keys and multikeys, and keep them off. Now try
and encrypt strings only (if enabled previously), then phrases only (if enabled
previously). If that does not narrow down the problem, enable Subset encryption
and encrypt only a tiny fraction of the code, such as 1 line in 100, or a few
percent. This should tell you whether the extra processing load is to blame. (If
so, gradually increase the proportion up to the point where the script starts
failing again, then maybe use half that proportion).
If you're still no nearer to a solution, it's time for more drastic measures. Create
a working BackTranslated script and a non-working encrypted one in the same
directory. Open both files in Scite and run AU3Check to see whether there are
any syntax errors. If not, run the encrypted version to check whether it starts up
at all, and if so, how far it gets. Alternatively, you can start replacing parts; first
the main code section, then each clear-code (working) UDF definition with their
encrpyted counterpart, one at a time. If the problem is localised, it should be
identifiable this way, although it may take time.
Finally, some valid AutoIt code simply does not work after passing through
MCF's digestive tract. A real example: Suppose a script compares the speed of
different sorting algorithms. Each algorithm has its own UDF, called from the
main script. Each of the UDF names ends in "Sort" ("BubbleSort", "QuickSort",
"MoronSort", etc.). The main script defines an array filled only with the prefix,
that is, the part that is different for each name ($name[1]="Bubble",
$name[2]="Quick", ...) and calls each in turn in a For-Next loop (with counter
$n) that calls each UDF like this: Execute($name[$n] & "Sort"). Now
suppose we obfuscate the UDF names. Neither the strings in array $name[] nor
string "Sort" in the Execute call will match the original UDF names, so they are
all kept as strings instead of being replaced by {funcU#} MetaCode tags.
Worse, to CodeCrypter it will appear as if the main script never calls any of the
9
defined *Sort functions, so unless prevented, it won't even include them in the
Single-Build (MCF0). Of course, once this problem is identified, we can easily fix
it by storing the full names in the array instead and removing the "Sort" suffix
from the string parsed to Execute(). That way, the strings will be recognised as
UDF names, the UDF definitions will be retained as active, and obfuscation will
replace the original name both in the UDF definition and in array $name.
10