Jump to content

Recommended Posts

Posted

RTFC, 

Thanks for all the help.  I got it to obfuscate my code and it compiled without error.  Just have to test it out now and make sure everything is good.  Thanks for continuing to support obfuscation, I know the writers for AutoIT don't believe in it but I do.  

Posted

Excellent, jack71! :dance:

Note: If you're really concerned about protecting your work you should consider encryption too.

Best of luck with your projects,

RT

Posted

Okay, then I have some questions for you, legend:

  1. does Ward's AEStest run?
  2. If you include AES.au3 directly in your own script and call _AES_Startup(), does that work without error?
  3. From what I can see from your screengrab, your subdirectory contents do not appear to contain your own test script. I cannot be sure, it's difficult to make out (but easy for you to check). Since the #include path in MCFinclude just states "AES.au3", if you include #MCFinclude.au3 in your script and that script sits in a different directory, it may not be able to find AES.au3 locally. Just as a test, try moving your test script into the subdirectory where AES.au3 sits. Still the same error?
  4. Try adding explicit full paths to both your #include "MCFincude.au3" line in your own script and the line #include "AES.au3" inside MCFinclude.au3. Does that solve it?
  5. Still no joy, then please post the smallest possible script that reproduces the error, and I'll see if I can figure out what's failing.
  • 1 month later...
Posted (edited)

Hello RTFC I am able to obfuscate and encrypt my autoit flawless and works perfectly on my computer. But I am noticing on someone else computer it doesn't run properly. Could this be because I have using $CCKey[3] which uses my computer username? So I am guessing it only decrypts on my computer with that option? How could I set the encryption so any computer can use the file without a  prompt?

Edited by CodeFOB
Posted

@CodeFOB: Now that is a good question! :blink:

You're quite right, that's exactly what's happening, and it's exactly what is supposed to happen to protect your script from being run in unauthorised environments. I'd never really considered the possibility that users might just want encryption without a defined targeted environment. :shocked:

However, the solution is actually quite simple. B)  You need to follow these simple steps:

1) open MCFinclude.au3 and define an encryption key as macro: @Scriptname (you can just replace an existing one, for example, number 4 (@LogonDomain). Remember/write down the key ID number you're using for later.

2) ensure your script includes the line: #include "MCFinclude.au3" (all code below it will be encrypted)

2) delete any existing CodeScanner datadump subdirectory for your script

3) Run CodeScanner on your script with WriteMetaCode=On (I'll presume no major problems are identified)

4) Start CodeCrypter, load your script, and navigate to Tab Encrypt. Select the key ID you just defined as @scriptname in MCFinclude.au3

5) Press the <Decryptor> button to redefine the expected response. As you're currently running CodeCrypter, the macro's current response is "CodeCrypter.au3". In the bottom two boxes, type the final name of your script (the name you'll use when renaming MCF0.au3 or MCF0test.au3) BEWARE: if you will be compiling your script later, then @scriptname will return <scriptname>.EXE in the compiled version (but <scriptname>.AU3 in the original version); you cannot test/use both at the same time, so the .exe name will fail to decrypt properly in the original version, and the .au3 in the compiled version!

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

7) rename MCF0.au3/MCF0test.au3 to the scriptname you defined earlier (and compile if you used the .exe variant)

The result should work anywhere, whereas the contents are still encrypted.

However, know that this solution is less secure than an environment-dependent or password encryption, because any hacker that is able to analyse the content of $CCkey will be able to discover that you're actually using a fixed response rather than an environment-dependent one. So you're basically circumventing the main protective feature of CodeCrypter. I guess that's not an issue for casual use, but I wouldn't recommend this approach for any commercial or sensitive material. :whistle:

Posted

@CodeFOB: Now that is a good question! :blink:

You're quite right, that's exactly what's happening, and it's exactly what is supposed to happen to protect your script from being run in unauthorised environments. I'd never really considered the possibility that users might just want encryption without a defined targeted environment. :shocked:

However, the solution is actually quite simple. B)  You need to follow these simple steps:

1) open MCFinclude.au3 and define an encryption key as macro: @Scriptname (you can just replace an existing one, for example, number 4 (@LogonDomain). Remember/write down the key ID number you're using for later.

2) ensure your script includes the line: #include "MCFinclude.au3" (all code below it will be encrypted)

2) delete any existing CodeScanner datadump subdirectory for your script

3) Run CodeScanner on your script with WriteMetaCode=On (I'll presume no major problems are identified)

4) Start CodeCrypter, load your script, and navigate to Tab Encrypt. Select the key ID you just defined as @scriptname in MCFinclude.au3

5) Press the <Decryptor> button to redefine the expected response. As you're currently running CodeCrypter, the macro's current response is "CodeCrypter.au3". In the bottom two boxes, type the final name of your script (the name you'll use when renaming MCF0.au3 or MCF0test.au3) BEWARE: if you will be compiling your script later, then @scriptname will return <scriptname>.EXE in the compiled version (but <scriptname>.AU3 in the original version); you cannot test/use both at the same time, so the .exe name will fail to decrypt properly in the original version, and the .au3 in the compiled version!

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

7) rename MCF0.au3/MCF0test.au3 to the scriptname you defined earlier (and compile if you used the .exe variant)

The result should work anywhere, whereas the contents are still encrypted.

However, know that this solution is less secure than an environment-dependent or password encryption, because any hacker that is able to analyse the content of $CCkey will be able to discover that you're actually using a fixed response rather than an environment-dependent one. So you're basically circumventing the main protective feature of CodeCrypter. I guess that's not an issue for casual use, but I wouldn't recommend this approach for any commercial or sensitive material. :whistle:

Thank you so much for the quick response! I will definitely try this method, it is exactly what I was looking for.

Posted

If I use $CMDLineRaw in my script then I get a problem with undeclared global variable.

But this is a built in variable.  Is there some way that I need to declare this variable or is this a bug in this script?

Also... is there a simple way for me to exclude obfuscation of specific Funcs or Variables?

I know in the obfuscator that used to be in scite it had a limitation that you could not obfuscate certain things that used "Call" or "Execute".  But from what I see... you have found a way around this?  Would AdlibRegister also need a workaround?  Or are there certain udf's that are similar that we would need to exclude strings?

Thanks for putting this together for everyone.  I can see it being very handy. :)

Posted (edited)

Questions, questions, so many questions... :ermm:

1) $cmdlineraw

Oversight on my part. Next version of MCF.au3 will deal with this properly. In the meantime, you can patch this yourself:

  • open MCF.au3, navigate to UDF _ObfuscateNames, then find the line
  • If $inputarray[$rc]="$cmdline" Then ContinueLoop    ; special case (keep intact)
  • duplicate it (Ctrl-D in Scite) and add "raw" to string "$cmdline". Done.

 

2) A simple way to exclude obfuscation of specific Funcs or Variables?

Obfuscation alternatives to * Used content are stored in arrays *Transl, so:

  • Run a regular full obfuscation pass first
  • If most content is to be obfuscated, Copy *Transl to *New, otherwise Copy *Used to *New
  • Copy whatever you wish to keep as cleartext c.q. obfuscated text to * New, from *Used or *Transl respectively.
  • Run CodeCrypter with CreateNew (without obfuscation); this replace MC tags with the *New content directly

So basically you build your own replacement template in the *New arrays, taking the original content in *Used, and the obfuscated content in *Transl as you see fit. Please make absolutely sure all *New arrays are still properly aligned (that is, each line still matches the one in *Used, even though its content may have been changed now). CodeCrypter's CreateNew option then builds the new script directly from the *New arrays without any further changes.

NB Creating the UDF selection option for encryption proved very complicated and time-consuming. I won't be implementing a separate function to handle obfuscation. I've always considered it an on-off proposition, especially since an obfuscated script runs exactly as fast as a cleartext one.

 

3) Limitations

This has got nothing to wth obfuscation proper, but with CodeScanner writing MetaCode. There are two separate issues here.

A. The parsing of function names to other functions

As you can see for yourself in CodeScanner's UDF: _Scan4Func(), it can deal with the following special cases:

Switch $previousword
                Case "AdlibEnable"      ; no func params allowed
                    $funcparamID=1
                Case "AdlibRegister"        ; no func params allowed
                    $funcparamID=1
                Case "AdlibUnRegister"  ; no func params allowed
                    $funcparamID=1
                Case "Call"                 ; UDF only, unknown number of func params may follow
                    $funcparamID=1
                Case "GUICtrlSetOnEvent"; no func params allowed
                    $funcparamID=2
                Case "GUIRegisterMsg"   ; UDF only, <=4 predefined func params, none is parsed
                    $funcparamID=2
                Case "GUISetOnEvent"        ; no func params allowed
                    $funcparamID=2
                Case "HotKeySet"            ; no func params allowed
                    $funcparamID=2
                Case "OnAutoItExitRegister"         ; no func params allowed
                    $funcparamID=1
                Case "OnAutoItExitUnRegister"           ; no func params allowed
(...)
                   Endswitch

Strings parsed to these functions should be replaced by MetaCode {func*} tags, and these can be replaced by obfuscated or encrypted names, as per usual.

B. self-referencing/modifying code

As you can see from MCF.au3 UDF _EncodeMCF, the following commands (there may be additonal ones) can all cause serious problems:

Switch $realcode    ; self-modifying code or indirect variable-name referencing
    Case "Assign"
        $errorcountSMC+=1
    Case "Eval"
        $errorcountSMC+=1
    Case "Execute"
        $errorcountSMC+=1
    Case "IsDeclared"
        $errorcountSMC+=1
EndSwitch

Now, it's not guaranteed to fail; I remember various (highly artificial) test scenarios where a nested Execute call still worked even after doubly-nested encryption on top of that. All I'm saying is that you should start from the assumption that it won't work, and test your new script thoroughly to ascertain whether that is indeed the case. See also my final remarks in the MCFQA.pdf FAQ doc, where I give an example of a dynamically built Execute construct that completely fails (because the function names it creates no longer exist in the new script). An ounce of forethought here may save you a ton of grief later. You know what parts of the content will be affected by MetaCode processing (you control this yourself), so if any of those parts are used as arguments to one of the functions listed above, expect the worst. :x

Re. thanks: You're very welcome; I find it quite handy too. ;)

Edited by RTFC
Posted

@CodeFOB:

When you rurn your script or "compiled" exe, it is allocated in RAM, still encrypted. As each line is processed, each Execute(_MCFCC(<encrypted string>)) call first decrypts the encrypted string to a memory location that AutoIt allocates, after which the Execute-wrapping call executes its content. I think the same memory location is re-used immediately for consecutive lines (although I have not personally verified this with a step-debugger), so the decrypted line would only ever exist for a few milliseconds, but a step-debugger could of course freeze this process anywhere.

But I fear you're missing the point. :ermm:  The decryption is (meant to be) environment-dependent; the decryption key is retrieved from the work environment at runtime, using either a macro or a UDF (or combination thereof) that is supposed to be different depending on where (or by whom) the script is run. So if someone steals your script and tries to run it somewhere else, the returned decription key from that different environment will differ from the one in the valid enivronment, and thus the decryption will invariably return total garbage, and your script will either stop or crash immediately trying to execute that garbage. So even if a hacker were to monitor your script as it is executing step-by-step in a debugger, that still won't reveal anything, because the key is not stored in the script, and without access to the original environment, no amount of trace debugging in any other environment will ever reveal the key.

Now, given your earlier question, you wanted to circumvent this mechanism by creating an encrypted script that would run anywhere. That's fine, of course, but it implies using some type of fixed decryption key, so a step-debugger monitoring the right location in RAM would be able to capture this at runtime (and maybe even statically) . This is why I mentioned that the notion of an encrypted script that runs anywhere is inherently less secure than using CodeCrypter's (or your own) environment--dependent options.

Hope this clarifies matters. ;)

Posted (edited)

Thankyou for response, last question. Lets say a "heavy" encryption method is used to only run on a certain computer(Enviroment-Dependent). And somehow someone gets a hold of that .exe. Would the data still be injected in memory when that person trys to run it?

Also is there a way to exclude a certain function from encryption? I notice functions that use Writeprocessmemory that are encrypted slow its function or gives it a delay

Edited by CodeFOB
Posted (edited)

@CodeFOB:

Let's start with your last question, which is easy to answer: Yes, you have extensive control over which parts of your script get encrypted. You can either:

  • select specific UDFs to encrypt/keep clear; to do this, run CodeCrypter, select your CodeScanned target file, press Tab <Encrypt> , press button <UDFs> and you'll get a list of all UDFs whose encryption status (on/off) can be user-defined (some UDFs are always encrypted, anything preceding the line  #include "MCFinclude.au3" is never encrypted). Simply (un)tick the checkboxes to suit your needs before encrypting; OR,
  • define a subset to be encrypted (by ticking the "subset def" checkbox under the same <Encrypt> Tab; the number field can be either a proportion between 0 and 1, an integer percentage (<value>%) between 1-100, or an integer larger than 1; the first two cases will encrypt random lines throughout your script to match the proportion/percentage you defined on average, whereas the last option simply cycles through N lines (where N is your integer >1) and encrypts the first line of each cycle. Subset encryption is useful if your script runs tight loops, has time-dependent processing (streaming sound or video, for example) or incorporates rapid "on event" responses to keep going. If you encrypt a few percent, the script will still fail when run outside of its sanctioned environment, but in the valid environment, the delay due to the extra decryption processing is minimal.

 

Re. your first question: maybe I wasn't sufficiently clear in my previous answer... :ermm:  The decryption engine itself always runs when the exe is run, regardless of where or by whom it is run, but this does not matter! The beauty of this decryption is that an attacker can study the decryption engine for a lifetime, and still be unable to discover either the decryption key or your plaintext script, providing they do not have access to the original environment where the encrypted script or .exe is supposed to run. In the worst-case scenario, a determined hacker might be able to determine the type(s) of information your programme queries from its environment to obtain one or more decryption keys, but their content (user password, user name, drive serial number, fixed IP address, any AutoIt macro or UDF you write yourself) will be different when the attacker runs their stolen .exe elsewhere. So each decrption step is still 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.

Okay, an example. :think:

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.

The above analogy thus highlights the importance of choosing a sufficiently strong key; a user password can be strong protection unless the user's notebook with their list of passwords was also physcially stolen; many people will have the same username, and so forth, so it makes sense to use several keys (either strung together or used cyclically (CodeCrypter allows you to select this option too), because the chances of another house having a black pet with the same name AND a red book on the top shelf next to the window AND a woollen bedspread in the guest room are fairly remote. :lol:

I hope it's clear now that low-level debugging, or access to RAM or your encrypyed exe is totally insufficient; the only way to break the encryption is to gain access to the original environment to determine those actual bits of information that your exe extracts from it at runtime to build the decryption key.

I don't know how to make it any clearer. :sweating::x

Edited by RTFC
Posted (edited)

RTFC,

Any idea what in the code supplied below would cause your obfuscation to make it act differently?  I need to check to see if a recording is new (less than an hour old) and if it is I want my script to sleep until it is 1 hour old before continuing.  When I use your obfuscation on the script, it doesn't sleep and wait.  When I don't obfuscate it works fine.  Any ideas?

IsNew()
 
Func IsNew()
Local $folder = "c:\test"
Local $farray, $date, $createtime, $createtimearray, $diff, $sleeptime
 
$farray = _FileListToArrayRec($folder, "*.mpg", 1, 0, 0)
$date = _NowCalc()
If IsArray($farray) Then
For $i = 1 To $farray[0]
$createtime = FileGetTime($folder & $farray[$i], 1)
$createtimearray = $createtime[0] & "/" & $createtime[1] & "/" & $createtime[2] & " " & $createtime[3] & ":" & $createtime[4] & ":" & $createtime[5]
If _DateDiff('n', $createtimearray, $date) < 60 Then
TraySetToolTip("Detected New Recording, Waiting For a Bit...")
$diff = _DateDiff('n', $createtimearray, $date)
$sleeptime = (60 - $diff) * 60000
sleep($sleeptime)
IsNew()
EndIf
Next
EndIf
EndFunc
Edited by jack71
Posted (edited)

@jack71:

Thanks for your query.

First off, if you encounter problems such as these (and this goes for everyone posting here), I'd appreciate it if you did your homework first. :angry:  Just dumping a complete UDF stating "it doesn't work" is not helpful to me. As the MCF FAQ clearly states, you should systematically narrow down the issue as far as you can yourself, and only then post a far more specific question than the example above. In your case, jack71, you could have tried running the obfuscation affecting only the variables, and only the UDF names respectively. Then you would have discovered that the problem occurs only in the former case, not in the latter. Next, you could have disabled various lines in your example, to discover that the problem has nothing to do with your file creation time evaluation or sleep cycle, but with the initial call _FileListToArrayRec. If you had posted a query along the lines of "function FileListToArrayRec fails when obfuscating variables" I wouldn't have wasted a significant amount of time and effort ruling out various other possibilities. So next time, please try a little harder before you post.

Okay, grumbling session is over. :lol:  the problem was due to a RegExp pattern string containing "$" followed by a digit, which the MetaCode processor wrongly interpreted as being a variable that Codescanner had missed, so it was added to the list, and obfuscated within the pattern string, causing the RegExp to fail, causing the filename to be skipped, so your list always returned empty.

To solve this, please download the latest version of the MCF library, version 1.3. Do not download the complete CodeScannerCrypter bundle, that hasn't been updated yet, just MCF.v1.3.7z. The new version contains a filter for RegExp pattern strings that kicks in in several places to avoid these misinterpretations from happening in future. That ought to fix it (it does at my end).

Thanks for identifying this issue.

Edited by RTFC
Posted

@jack71:

Thanks for your query.

First off, if you encounter problems such as these (and this goes for everyone posting here), I'd appreciate it if you did your homework first. :angry:  Just dumping a complete UDF stating "it doesn't work" is not helpful to me. As the MCF FAQ clearly states, you should systematically narrow down the issue as far as you can yourself, and only then post a far more specific question than the example above. In your case, jack71, you could have tried running the obfuscation affecting only the variables, and only the UDF names respectively. Then you would have discovered that the problem occurs only in the former case, not in the latter. Next, you could have disabled various lines in your example, to discover that the problem has nothing to do with your file creation time evaluation or sleep cycle, but with the initial call _FileListToArrayRec. If you had posted a query along the lines of "function FileListToArrayRec fails when obfuscating variables" I wouldn't have wasted a significant amount of time and effort ruling out various other possibilities. So next time, please try a little harder before you post.

Okay, grumbling session is over. :lol:  the problem was due to a RegExp pattern string containing "$" followed by a digit, which the MetaCode processor wrongly interpreted as being a variable that Codescanner had missed, so it was added to the list, and obfuscated within the pattern string, causing the RegExp to fail, causing the filename to be skipped, so your list always returned empty.

To solve this, please download the latest version of the MCF library, version 1.3. Do not download the complete CodeScannerCrypter bundle, that hasn't been updated yet, just MCF.v1.3.7z. The new version contains a filter for RegExp pattern strings that kicks in in several places to avoid these misinterpretations from happening in future. That ought to fix it (it does at my end).

Thanks for identifying this issue.

 

RTFC,

I'm sorry :(.  I'm honestly not the greatest coder in the world and am still learning.  I just knew after 4 hours of going back and forth that either 1) I was going insane or 2) Something was different on the machines I was testing the script on and maybe that was causing the problem.  Then I remembered 3) I was obfuscating and maybe something was happening...

So sure enough I tried the original script without obfuscating it and it worked as expected...

I appreciate your continual support!  Thanks for the update.  I'm not sure when I'll have access to those machines again but when I do I will test it again and report back.

TY!! 

Posted

Uh oh.... :o

I updated the MCF files then went to run codecrypter after codescanner....pressed Go and then:

"C:Program Files (x86)AutoIt3Codecryptercodecrypter.au3"(1956,40) : error: _HandleEnteredSubsetDef() already defined.
Func _HandleEnteredSubsetDef($newvalue)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
C:Program Files (x86)AutoIt3Codecryptercodecrypter.au3 - 1 error(s), 0 warning(s)
!>09:48:52 AU3Check ended. Press F4 to jump to next error.rc:2
+>09:48:52 AutoIt3Wrapper Finished.
>Exit code: 2    Time: 0.8273
Posted (edited)

Oops, my bad. I'd forgotten that I moved that function, :oops:  so you need to update your codecrypter to version 1.3 as well (freshly uploaded just now).

Apologies for the confusion. Please retry.

RE. going insane, I can definitely relate, having lost my marbles a long time ago :wacko: . It's got nothing to with being less (or more) experienced, the most baffling things go wrong for me too (Example from yesterday: Stringlen(_StringRepeat(" ",0)) produces 1, not 0 :o; in this case, due to a genuine AutoIt bug IMHO). But the only way to regain control of your sanity is by methodically breaking down the big monolithic "it no longer works" into more manageable chunks such as: specific function X no longer returns the expected output.

Did you ever watch "Apollo 13"? Remember Gene Kranz's sage advice (when everyone else is going berserk): "Let's work the problem, people. Let's not make things worse by guessing." It can be a long and tedious process, but it helps you develop your analytical skills, and in the end it all boils down to asking exactly the right question. You had a great lab setup: one version that worked, and one slightly altered version that did not work. So then you could start replacing code sections in one version with their duplicates from the other to narrow down what bit is actually failing. In this particular case, I had to burrow deep into the standard <File.au3> include to figure out that RegExp was to blame, which is not surprising in hindsight because those pattern strings it works with have virtually no fault tolerance.

Anyway, see if it works for you with the correct CodeCrypter version 1.3...

Edited by RTFC
Posted

Oops, my bad. I'd forgotten that I moved that function, :oops:  so you need to update your codecrypter to version 1.3 as well (freshly uploaded just now).

Apologies for the confusion. Please retry.

RE. going insane, I can definitely relate, having lost my marbles a long time ago :wacko: . It's got nothing to with being less (or more) experienced, the most baffling things go wrong for me too (Example from yesterday: Stringlen(_StringRepeat(" ",0)) produces 1, not 0 :o; in this case, due to a genuine AutoIt bug IMHO). But the only way to regain control of your sanity is by methodically breaking down the big monolithic "it no longer works" into more manageable chunks such as: specific function X no longer returns the expected output.

Did you ever watch "Apollo 13"? Remember Gene Kranz's sage advice (when everyone else is going berserk): "Let's work the problem, people. Let's not make things worse by guessing." It can be a long and tedious process, but it helps you develop your analytical skills, and in the end it all boils down to asking exactly the right question. You had a great lab setup: one version that worked, and one slightly altered version that did not work. So then you could start replacing code sections in one version with their duplicates from the other to narrow down what bit is actually failing. In this particular case, I had to burrow deep into the standard <File.au3> include to figure out that RegExp was to blame, which is not surprising in hindsight because those pattern strings it works with have virtually no fault tolerance.

Anyway, see if it works for you with the correct CodeCrypter version 1.3...

 

Hrm...getting this error now when I hit "Run" on codecrypter:

"C:Program Files (x86)AutoIt3CodecrypterMCF.au3" (2766) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
$split=StringSplit(StringTrimLeft($references[$regexplist[$rc]][5],StringInStr($references[$regexplist[$rc]][5],",")),"{string",1)
$split=StringSplit(StringTrimLeft($references[^ ERROR

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
×
×
  • Create New...