.
675 |
676 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP JavaScript unpacker
2 | This a ported unpacker for JavaScript files that were packed with Dean Edwards JavaScript's Packer. This package includes a testpage "index.php" and the actual JavaScriptUnpacker class "JavaScriptUnpacker.php".
3 |
4 | ## Basic usage
5 |
6 | 1. You can use the packer tool on [Dean Edwards Packer](http://dean.edwards.name/packer/) page to create a packed JavaScript
7 | 2. Pate the generated (packed) code into the textarea of the testpage.
8 | 3. Hit on submit to get the unpacked JavaScript
9 |
10 | ## Class usage
11 | Actually the purpose of this script is not to unpack userinputs, it makes more sense to
12 | use it for automation, e.g. site scraping, where you need to get the unpacked version of
13 | a packed JavaScript to parse out link or something like that.
14 |
15 | And here is how you can use the class
16 | ```
17 | // where $packedJS is the packed JavaScript that begins with
18 | // eval(p,a,c,k,e,d) or eval(p,a,c,k,e,r)
19 |
20 | $unpacker = new JavaScriptUnpacker();
21 | $unpacked = $myPacker->Unpack($packedJs);
22 | ```
--------------------------------------------------------------------------------
/inc/JavaScriptUnpacker.php:
--------------------------------------------------------------------------------
1 | .
18 | *
19 | * Ported to PHP from:
20 | * https://github.com/Eldorados/script.module.urlresolver/blob/master/lib/urlresolver/plugins/lib/jsunpack.py
21 |
22 | *
23 | * ----------------------------------------------------------------------
24 | * changelog:
25 | * 1.0 : Initial Release.
26 | * 1.1 : Fixed the if-statements within the Unbaser constructor
27 | * ----------------------------------------------------------------------
28 | *
29 | * examples of usage :
30 | * $unpacker = new JavaScriptUnpacker();
31 | * $unpacker = $myPacker->Unpack($packedJs);
32 | * *
33 | * The unpack() method returns the uncompressed JavasScript, as a string
34 | * that was packed with Dean Edwards JavaScript's Packer method.
35 | *
36 | * Notes :
37 | * # need PHP 5 . Tested with PHP 5.4.7 and 5.5.21
38 | */
39 |
40 | class JavaScriptUnpacker
41 | {
42 | private $unbaser;
43 | private $payload;
44 | private $symtab;
45 | private $radix;
46 | private $count;
47 |
48 | function Detect($source)
49 | {
50 | $source = preg_replace("/ /","",$source);
51 | preg_match("/eval\(function\(p,a,c,k,e,[r|d]?/", $source, $res);
52 |
53 | Debug::Write($res,"detection result");
54 |
55 | return (count($res) > 0);
56 | }
57 |
58 | function Unpack($source)
59 | {
60 | preg_match_all("/}\('(.*)', *(\d+), *(\d+), *'(.*?)'\.split\('\|'\)/",$source,$out);
61 |
62 | Debug::Write($out,"DOTALL", false);
63 |
64 | // Payload
65 | $this->payload = $out[1][0];
66 | Debug::Write($this->payload,"payload");
67 | // Words
68 | $this->symtab = preg_split("/\|/",$out[4][0]);
69 | Debug::Write($this->symtab,"symtab");
70 | // Radix
71 | $this->radix = (int)$out[2][0];
72 | Debug::Write($this->radix,"radix");
73 | // Words Count
74 | $this->count = (int)$out[3][0];
75 | Debug::Write($this->count,"count");
76 |
77 | if( $this->count != count($this->symtab)) return; // Malformed p.a.c.k.e.r symtab !
78 |
79 | //ToDo: Try catch
80 | $this->unbaser = new Unbaser($this->radix);
81 |
82 | $result = preg_replace_callback(
83 | '/\b\w+\b/',
84 | array($this, 'Lookup')
85 | ,
86 | $this->payload
87 | );
88 | $result = str_replace('\\', '', $result);
89 | Debug::Write($result);
90 | $this->ReplaceStrings($result);
91 | return $result;
92 | }
93 |
94 | function Lookup($matches)
95 | {
96 | $word = $matches[0];
97 | $ub = $this->symtab[$this->unbaser->Unbase($word)];
98 | $ret = !empty($ub) ? $ub : $word;
99 | return $ret;
100 | }
101 |
102 | function ReplaceStrings($source)
103 | {
104 | preg_match_all("/var *(_\w+)\=\[\"(.*?)\"\];/",$source,$out);
105 | Debug::Write($out);
106 | }
107 |
108 | }
109 |
110 | class Unbaser
111 | {
112 | private $base;
113 | private $dict;
114 | private $selector = 52;
115 | private $ALPHABET = array(
116 | 52 => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP',
117 | 54 => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR',
118 | 62 => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
119 | 95 => ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
120 | );
121 |
122 |
123 | function __construct($base)
124 | {
125 | $this->base = $base;
126 |
127 | if($this->base > 62) $this->selector = 95;
128 | else if($this->base > 54) $this->selector = 62;
129 | else if($this->base > 52) $this->selector = 54;
130 | }
131 |
132 | function Unbase($val)
133 | {
134 | if( 2 <= $this->base && $this->base <= 36)
135 | {
136 | return intval($val,$this->base);
137 | }else{
138 | if(!isset($this->dict)){
139 |
140 | $this->dict = array_flip(str_split($this->ALPHABET[$this->selector]));
141 | }
142 | $ret = 0;
143 | $valArray = array_reverse(str_split($val));
144 |
145 | for($i = 0; $i < count($valArray) ; $i++)
146 | {
147 | $cipher = $valArray[$i];
148 | $ret += pow($this->base, $i) * $this->dict[$cipher];
149 | }
150 | return $ret;
151 | // UnbaseExtended($x, $base)
152 | }
153 | }
154 |
155 | }
156 |
157 |
158 | class Debug
159 | {
160 | public static $debug = false;
161 | public static function Write($data, $header = "", $mDebug = true)
162 | {
163 | if(!self::$debug || !$mDebug) return;
164 |
165 | if(!empty($header))
166 | echo "".$header."
";
167 |
168 | echo "";
169 | print_r($data);
170 | echo "
";
171 | }
172 |
173 | }
174 | ?>
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | Javascript unpacker testpage
11 |
12 |
13 |
14 |
15 | Javascript unpacker testpage
16 |
35 |
36 |
--------------------------------------------------------------------------------