I want a "Red Teaming"
Michael Schneider
Here is what Adobe has to say about JSXBIN files:
The .jsxbin files are compiled JavaScript; they are in binary format so the source code is not exposed…
According to that document, the use of JSXBIN happens for two reasons:
This labs will demonstrate, that JSXBIN files are nothing but source code obfuscated JSX files. With some effort the source is recognizable and with some more effort it might even be possible to completely reverse the JSXBIN to a JSX.
After installing the ESTK, let’s have a look at how to create a binary version of a JSX file.
Ctrl + S
(optional).Open your newly created JSXBIN file in a file editor (e.g. notepad or notepad++). The first thing for you to notice: It’s not really binary in the sense of a compiled executionable. In fact, it’s all ASCII limited to the characters [A-Za-z0-9]. It might remind you of base64 encoding. If you like, go on and try to decode it as base64. Because if we look at the meaning and method of the code, it is somewhat similar to base64. It uses the same character set to represent the original JSX file. It is definitively not binary.
Like I said, a JSXBIN is nothing but code obfuscation. For those of you interested in code obfuscation, there are contests to write the best obfuscated code or break a piece of obfuscated code. However, it is now clear, that the first purpose – to protect the source code from exposure – is certainly not true. It only takes time to crack the obfuscation.
The good news for us, we have the ESTK to create the obfuscation in any plaintext we like. That’s exactly what my first approach was in reversing a JSXBIN. And here are the results.
Let’s forget about the previously created JSXBIN file for a second and start from scratch. The first script we’re going to export is an empty JSX file. This gives us information about possible static content.
The following is all the content of a JSXBIN from an empty JSX script.
@JSXBIN@ES@2.0@MyBn0DzABByB
For a next export, enter a single letter (e.g. the lower case a) in the JSX script file and export that script. You will receive the following JSXBIN content:
@JSXBIN@ES@2.0@MyBbyBn0ABJAnAjzBjBBf0DzACByB
Repeat this by yourself and after many more JSXBIN files, we are able to identify somewhat static parts.
MyB
ByB
, that end any JSXBIN file so farWe have identified what seems to be a description header and a possible static three letter block at the beginning and end of the JSXBIN file. The next steps are to identify the representation of different characters and symbols, and their combinations.
For example extend the above one letter script to with an additional lower case a and export the script aa, followed by aaa and so on. After that, create the same for any other letter, and then write each on a different line and so on. After identifying the character representation, start identifying objects, variables, functions, control structures etc. And then the combination of all of those.
Having exported many scripts of various combinations of letters, the following letter representation characteristic was identified. A lower case letter (not as a data type string) is represented by j[B-Za]
. Starting with a = jB
and ending with z = ja
. The upper case letters differ only in the leading value. Instead of j
, a lower case i
is used. This gives A = iB
and Z = ia
.
In addition to the representation of lower and upper case letters, a leading value that represents the number of letters was identified. For a single letter like a, that was a B
, for two letters such as aa, that was a C
. This goes on, up the alphabet and will be discussed in more details in the section about counter values.
Lower Case Letter | Representation | Upper Case Letter | Representation |
---|---|---|---|
a | jB | A | iB |
b | jC | B | iC |
c | jD | C | iD |
d | jE | D | iE |
e | jF | E | iF |
f | jG | F | iG |
g | jH | G | iH |
h | jI | H | iI |
i | jJ | I | iJ |
j | jK | J | iK |
k | jL | K | iL |
l | jM | L | iM |
m | jN | M | iN |
n | jO | N | iO |
o | jP | O | iP |
p | jQ | P | iQ |
q | jR | Q | iR |
r | jS | R | iS |
s | jT | S | iT |
t | jU | T | iU |
u | jV | U | iV |
v | jW | V | iW |
w | jX | W | iX |
x | jY | X | iY |
y | jZ | Y | iZ |
z | ja | Z | ia |
The table is true for variable names, function names etc. In case of the data type string, the letters are represented in the same form. Before the leading letter counter value, a new identifier is inserted – Fe
– to represent that the next letters and characters are part of a string. We are now able to translate the value Test to the JSXBIN representation EiUjFjTjU
(including the counter value E
). The same value as a data type string “Test” is represented as FeEiUjFjTjU
(including string marker Fe
and counter E
).
The table below shows some special characters recognised during the analysis.
Special Character (in string) | Description | Representation |
---|---|---|
“ “ | Space | hA |
“ | Quotation Mark | hC |
‘ | Apostrophe | hH |
& | Ampersand | hG |
\ | Backslash | ic |
: | Colon | ha |
. | Period | hO |
– | Dash | hN |
_ | Underscore | if |
? | Question Mark | hf |
^ | Caret | ie |
` | Accent Grave | ja |
~ | Tilde | je |
´ | Accent Aigu | lU |
+ | Plus | hL |
* | Asterisk | hK |
# | Hash | hD |
% | Percentage sign | hF |
/ | Slash | hP |
| | Pipe | jc |
( | Parenthesis Open | hI |
) | Parenthesis Close | jJ |
> | Is Greater Than | hc |
< | Is Less Than | he |
We are now able to represent the string “Test Value” in JSXBIN as FeKiUjFjTjUhAiWjBjMjVjF
.
We have identified lower and upper case letters and special characters, as well as the difference between functional strings (variable, function etc. names) and the data type strings. In a next step, we are going to analyse the representation of digits and numbers as numerical values and as part in the data type string.
The procedure is same as the process to identify the letter values. First, there’s an export of a JSX script with a single digit, then multiple digits on the same line and the same digit on different lines.
The first export is of the script with a single digit 1 (remember, we’re removing the static description header from the output).
MyBbyBn0ABJAnAFdB0EzABByB
In the above export, the digit 1 is represented by dB
. Different than with the upper and lower case letters, the string “1” is represented by a different value, hR
. The table below shows the digit, its representation as number and its representation in a string data type.
Digit Character | Representation | Numerical String | Representation |
---|---|---|---|
0 | d (dA – unbestätigt) | “0” | hQ |
1 | dB | “1” | hR |
2 | dC | “2” | hS |
3 | dD | “3” | hT |
4 | dE | “4” | hU |
5 | dF | “5” | hV |
6 | dG | “6” | hW |
7 | dH | “7” | hX |
8 | dI | “8” | hY |
9 | dJ | “9” | hZ |
10 | dK | “10” | hRhQ |
11 | dL | “11” | hRhR |
12 | dM | “12” | hRhS |
13 | dN | “13” | hRhT |
14 | dO | “14” | hRhU |
15 | dP | “15” | hRhV |
16 | dQ | “16” | hRhW |
17 | dR | “17” | hRhX |
18 | dS | “18” | hRhY |
19 | dT | “19” | hRhZ |
20 | dU | “20” | hShQ |
21 | dV | “21” | hShR |
22 | dW | “22” | hShS |
23 | dX | “23” | hShT |
24 | dY | “24” | hShU |
25 | dZ | “25” | hShV |
26 | dga | “26” | hShW |
27 | dgb | “27” | hShX |
28 | dgc | “28” | hShY |
29 | dgd | “29” | hShZ |
30 | dge | “30” | hShQ |
31 | dgf | “31” | hShR |
32 | dhA | “32” | hShS |
33 | dhB | “33” | hShT |
Note: The table only lists the values for the digits/numbers and does not contain any form of counter value.
We can see a clear difference between the digit character and the numerical string equivalent. The latter is just a combination of the string values from 0-9. This means the string “22192” is represented as FeFhShShZhRhS
(including string marker Fe
and counter value F
). The number 22192 as a number acts like a counter (see section below) and is represented as d2kAiZ
.
Counters are found in different functions. They may count the number of characters used in the name of a variable of function, the length of a string, there might even exist some sort of line numbers/counters. To my understanding, not all counters have the same starting value. What all have in common is the overflow after a multiple of 32.
We have already introduced the counter value in this article. Time to expand on that. A single lowercase letter is substituted with j[A-Za]
, excluding the counter value. If we add said counter value to it – the character indicating how long the string that follows is – the single lowercase letter a will appear in the JSXBIN as BjB
. Let’s have a look at an example, namely the word Test, which is a functional string or a string data type. The word Test is a four-letter word and we have deduced that the leading counter value for four-letter-words is E
. Therefore, we can state that the leading counter value character of a single-letter string is B
and if we are trying to decode a four-letter character combination, then it’s E
.
Now let’s try something else. Write the same characters on multiple lines, create a JSXBIN and try to find the value that represents a line break.
Here is an example of a multi-line file:
"line1" "line2" "line3"
And its JSXBIN representation (some form formatting was applied to outline the different lines and blocks):
MyBbyBn0AD ("line1") JAnA Fe FjMjJjOjFhR ("line2") JBnA Fe FjMjJjOjFhS ("line3") JCnA Fe FjMjJjOjFhT 0DzABByB
Let’s ignore the first and the last line and concentrate on the three lines in between. The string representation of “line[1-3]” is FeFjMjJjOjFh[R-T]
. In order to identify the line counter, we can focus on the first four characters. The first four characters are of the form J[A-C]nA
. If there is a line counter or line number value, it has to be the second value of that four character block.
The next example is an export of a file with 33 lines. We are only looking at the last four identified lines of the JSXBIN string (it is only an excerpt of the important lines to express the overflow happening between 26 and 27, and 32 and 33. Plus some formatting is applied for better explanation).
("line26") J Z nA Fe GjMjJjOjFhShW ("line27") J ga nA Fe GjMjJjOjFhShX ("line32") J gf nA Fe GjMjJjOjFhThS ("line33") J hA nA Fe GjMjJjOjFhThT
Again, focusing on the characters from the beginning to the string data type delimiter (Fe
), we are able to see that the first letter (J
) remains static. It is followed by the counter value that can be comprised of either one or two characters. The block is ended with two static characters (nA
).
We are able to identify that after the number 26 two characters are used to represent 27 and from line 32 to 33 an overflow occurs.
Here is what’s happening if we only look at the binary representation of the counters:
Z 01011010 ga 01100111 01100001 gf 01100111 01100110 hA 01101000 01000001
But why isn’t it just 01011011
followed by 01011100
after Z? The first byte represents [ in ASCII, the second represents \. So it is for the simple reason that only [A-Za-z0-9] are used in the JSXBIN file.
In the following table, you will find the counter values until the first overflow and some more overflow examples.
Counter Value | Representation |
---|---|
0 | A (only an assumption) |
1 | B |
2 | C |
3 | D |
4 | E |
5 | F |
6 | G |
7 | H |
8 | I |
9 | J |
10 | K |
11 | L |
12 | M |
19 | T |
20 | U |
21 | V |
22 | W |
23 | X |
24 | Y |
25 | Z |
26 | ga |
27 | gb |
28 | gc |
29 | gd |
30 | ge |
31 | gf |
32 | hA |
63 | hf |
64 | iA |
95 | if |
96 | jA |
127 | jf |
128 | kA |
In the previous section, we identified the representation of different characters, the representation in different cases (string data type or not) and we identified possible numbering structures or counters.
In this section, we are going to look at variable declaration. You could start again and build up the declaration. It’s what was done for this article, but we skip that and go straight to a more complex example.
var a=2; a=1; a; var b=null; b=1; var test=1; test = a;
The JSX script is represented (in a formatted form to identify elements) below.
MyB byB n0AG a) JAnA Sz BjB ByB ndCft b) JBnA S ByB ndBff c) JCnA V BfyB d) JDnA Sz BjC CyB nbft e) JEnA S CyB ndBff f) JFnA Sz EjUjFjTjU DyB ndBft g) JGnA S DyB V BfyB nff AD B40Bi AC 4B0Ai AD 4C0Ai AAD AzAE ByB
Line | Block #1 | Block #2 | Block #3 | Block #4 | Block #5 | Block #6 |
---|---|---|---|---|---|---|
a) | JAnA | Sz | BjB | ByB | ndCft | |
A (see section Counter Values) | Sz observed when variable is declared and defined in one construct | see section Alphabet Representation and Counter Values | ByB possibly a reference | dC represents the digit 2 | ||
b) | JBnA | S | ByB | ndBff | ||
B (see section Counter Values) | S observed when a declared variable is assigned a new value | ByB possibly a reference | dB represents the digit 1 | |||
c) | JCnA | V | BfyB | |||
C (see section Counter Values) | V observed when a variable is referenced | BfyB is very similar to ByB this could possibly be a reference to the variable data | ||||
g) | JGnA | S | DyB | V | BfyB | nff |
G (see section Counter Values) | S observed when a declared variable is assigned a new value | DyB possibly the reference to the variable test | V observed when a variable is referenced | ByfB could possibly be a reference to the variable data | nff remains unknown, but very close to the last block in line b) (if dB is removed) |
The line below g) (AD B40Bi AC 4B0Ai AD 4C0Ai AAD
) is of importance, but it’s meaning is unknown as of yet. A similar line always appears in the case of variable usage.
We are going to analyse functions in this section. Beginning with empty functions, and adding more context later in the analysis.
We start with empty, one-liner functions.
function a(){} function b(){} function c(){}
This is the converted JSXBIN content.
MyB byB nAD MAn0 Dz BjB B0A MBn0 Dz BjC CAB MCn0 Dz BjD DAC 0EzAE ByB
Looking at this example, we might be able to identify some of the elements.
M[A-C]n0
is very similar to the line numbering scheme (see Counter Values).Dz
is observed as some sort of key indicator to address the declaration of a function. Similar to Sz
(see Variables).Bj[B-D]
is clearly the name of the function.Next, we will have a look at two empty functions, but this time declared over multiple lines.
1) function a(){ 2) 3) 4) 5) 6) } 7) function b(){ 8) 9) 10) 11) 12) }
Note: The line numbers are added for visibility and not part of the JSX script.
The JSX script is represented in JSXBIN by (Line designations a) and b) are added for visibility):
MyB byB nAC a) MAn0 Dz BjB BAF b) MGn0 Dz BjC CAL 0EzAD ByB
If we compare line a) with the first function line (MAn0 Dz BjB B0A
) of the first example, we see that the last two letters changed. If we compare line b) and the second function line (MBn0 Dz BjC CAB
) of the first example, we see the second and the last letter changed. The only difference in the source code is that there are empty lines.
Hence, the second letter might declare the line number where the function declaration starts (function a(){
and the last letter defines the line number where the function declaration ends (}
).
Before looking to more complex function definitions, here is an example with multiple examples and that calls more than one function.
function xxa(){} xxa(); function bbb(){} bbb(); function ccc(){} ccc(); function ddd(){} eee(); function eee(){} ddd(); xxa(); bbb(); ccc(); ddd(); eee(); xxa(); bbb(); ccc(); ddd(); eee(); xxa(); bbb(); ccc(); ddd(); eee();
The converted JSXBIN string:
MyB byB nAF MAn0 Dz DjYjYjB B0A MCn0 Dz DjCjCjC CAC MEn0 Dz DjDjDjD DAE MGn0 Dz DjEjEjE EAG MIn0 Dz DjFjFjF FAI U JBnA EjB fnf JDnA EjC fnf JFnA EjD fnf JHnA EjF fnf JJnA EjE fnf JKnA EjB fnf JLnA EjC fnf JMnA EjD fnf JNnA EjE fnf JOnA EjF fnf JPnA EjB fnf JQnA EjC fnf JRnA EjD fnf JSnA EjE fnf JTnA EjF fnf JUnA EjB fnf JVnA EjC fnf JWnA EjD fnf JXnA EjE fnf JYnA EjF fnf 0DzAG ByB
By analysing the JSXBIN string, we are able to identify that the function calls between the function declarations are shifted down. As a consequence all function declarations are bundled at the beginning of the JSXBIN string (have a look at the second letter after M
or J
indicating the line number).
We are also able to identify the structure of a function call.
J[counterValue]nA
.Ej[reference]
).U
is also unknown.If we have a closer look at the second block and take the first function call (xxa()
) as example. The definition of the function xxa()
equals the line MAn0 Dz DjYjYjB B0A
and the call of the function xxa()
equals the line JBnA EjB fnf
. Note that the first letter of the last block in the function declaration line equals the last letter in the second block of the function calling line (here B
). Therefore that seems to be the reference value and Ej
must be some sort of generic function call operation.
As outlined in the beginning of this section, we will now analyse functions with more context. We will see that certain elements from the section above are changing and new elements are inserted.
1) function a(){ 2) //test1 3) "alpha" 4) //test2 5) }
Note: The numbers 1-5 are inserted for visibility reasons and not part of the actual content.
This is the (slightly formatted) JSXBIN output string:
MyB byB nAB a) MA byB n0 AB b) JCnA FeFjBjMjQjIjB 0 c) Dz BjB BAE 0EzACByB
If we compare line a) with the equivalent line of the first example (MAn0 Dz BjB BAF
) we are able to identify quite some strong differences.
A
) a triple (byB
) is inserted.AB
is new.Two other details to note:
Line c) contains the remaining parts of the function declaration of the first example (MAn0 Dz BjB BAF
). The last letter F
is equivalent with the number 5, which equals the line number where the function declaration is finished.
Now let’s look at an example where the function is called on a different line below the declaration.
1) function a(){ 2) //test1 3) "alpha" 4) //test2 5) } 6) 7) a();
Note: The number 1-5 are inserted for visibility reasons and not part of the actual content
Transformed to JSXBIN:
MyB byB nAB a) MA byB n0 AB b) JCnA FeFjBjMjQjIjB 0 c) Dz BjB BAE d) B e) JGnA EjB fnf 0DzAC ByB
B
in the last block equals again the first letter of the last block on line c).So far our examples are very easy and don’t have a lot of content. We will now extend the function by a variable declaration.
1) function a(){ 2) //test1 3) var non=null; 4) //test2 5) }
The converted JSXBIN:
MyB byB nAB a) MA byB n0 AB b) JCnA Sz DjOjPjO BA nbft c) AB B40Bi AAB d) Az BjB CAE 0EzAD ByB
The line b) equals the variable declaration (see section Variables for more details). As mentioned at the end of the section Variables, there is a line that is still unknown in functionality. A similar line appears here as line c). Another difference could be seen in line d), what before was Dz
turned into Az
with the declaration of a variable.
We extend the last example and add another variable to the function.
1) function a(){ 2) //test1 3) var non=null; 4) var alpha="alpha"; 5) //test2 6) }
The converted JSXBIN:
MyB byB nAB a) MA byB n0AC b) JCnA Sz DjOjPjO BA nbft c) JDnA Sz FjBjMjQjIj BCB neFjBjMjQjIjB ft d) AC C 4B0Ai A B40Bi AAC e) Az BjB DAF 0EzAE ByB
In this example, the line c) is the newly added variable alpha
with the assigned value “alpha”. The added variable also affects line d), the old one was AB B40Bi AAB
and the new one is AC C 4B0Ai A B40Bi AAC
.
B
to C
, could also be some sort of counter.C 4B0Ai A
.B
to C
, could have a connection to the first point of this list.There is certainly much going on in the conversion of a function from JSX to JSXBIN. Reversing the full algorithm would take much more time. This is especially because of the unrecognized parts in the variable declaration.
To summarize what I have got so far:
M[A-Z]
shows where in the source the declaration starts.Ej[referenceLetter]
.Some parts are not represented specifically represented in a JSXBIN string. Among others such values are:
For the time being, this is the end of the reversing of the JSX to JSXBIN export functionality. With the functionality described in this article, it is possible to write a simple script converting the identified elements back into JSX. It may be possible that some elements are replaced with the wrong values. This is due to the script being more of something that identifies strings rather than a complete re-converter.
This article was posted as detailed as necessary to leave it open for anyone to contribute their own analysis. There is still much to do, apart form the variable and function declaration. For example: control structures (for
, while
etc.) and mathematical operations.
Our experts will get in contact with you!
Michael Schneider
Marisa Tschopp
Michèle Trebo
Andrea Covello
Our experts will get in contact with you!