Pull to refresh

Расшифровываем Javascript на примере файлового хостинга mediafire.com

Website development *
В настоящее время набирает популярность способ шифрования javascript на сайтах с помощью вложенных команд eval. Недавно я столкнулся с таким шифрованием на файловом хостинге mediafire.com. Шифрование было необычное, меня это заинтересовало и я решил понять, насколько хорошо данный метод работает.

Сайт mediafire.com позволяет скачивать файлы без каптчи и при этом, с недавнего времени, стал достаточно успешно защищаться от всевозможных автоматических роботов. Делает он это с помощью встроенного генератора кода javascript. Причем, код каждый раз создается новый, что затрудняет его эмуляцию автоматическими средствами.

В этой статье я расскажу о том, как можно очень легко обойти такую защиту без глубокого анализа шифрованного кода и создать автоматический скрипт загрузки файлов с mediafire.com.

Для начала покажу как выглядит такой код:
Copy Source | Copy HTML
  1. var h5u='';
  2. var ybb=unescape('rev%24l%7Djg9%23%23%3Frev%24swhsp4l9qjawgeta%2C%23%213Bl%213F%216%3Da4c0%2A%2A6%213Bl%<<<тут был длинный код шифрованных символов>>>Z%3D--%3Fareh%2Cl%7Djg-%3F');
  3. for(i=0;i<1324;i++)h5u=h5u+(String.fromCharCode(ybb.charCodeAt(i)^4));
  4. eval(h5u);

Как видно из примера, код шифруется. Также при каждом обращении к странице, код меняется: изменяются коды шифрования (XOR), изменяется вложенность eval, изменяются названия переменных и функций.

Код вызывает одну из N функций (генерируются в html), которая в свою очередь включает на экране один из N блоков (тоже генерируются в html) и показывает его на экране. Потом, загружается дополнительный скрипт (тоже шифрованный), который записывает во все блоки ссылки на псевдо-правильный путь к загрузке файла и только в один их этих блоков записывает правильный путь.

Итак, нам надо решить задачу автоматической загрузки файлов с такой
системы.

Составим план действий.

1. Загрузить главную страницу, расшифровать и определить какая именно из N функций вызывается и в какой именно из N блоков она включает (узнать ключ)
2. Загрузить файл со ссылками по ключу, расшифровать и определить какая из N ссылок реальная (определить по ключу)
3. Скачать файл

Честно говоря, идею с разбором кода и метода шифрования я отмел сразу, так как код постоянно меняется смысла в этом нет никакого. Поэтому я предлагаю вашему вниманию другой способ, а именно эмуляция некоторых функций браузера.

Решать эту задачу будем с привлечением подручных средств: spidermonkey.

Установим spidermonkey в систему (в моем примере FreeBSD):

cd /usr/ports/lang/spidermonkey
make install clean

Самая большая проблема, с которой я столкнулся, это то, что заранее неизвестно куда именно исполняемый код будет сохранять ссылки и какую именно функцию он будет вызывать. Для того, чтобы не разбирать сам код, я создал некоторое подобие функции getElementById(), функция используется для загрузки значений в конкретный элемент HTML. Сделал я это вот так:
Copy Source | Copy HTML
  1. var element = new Object();
  2. element.innerHTML = "";
  3. var parent = new Object();
  4. parent.document = new Object();
  5. parent.document.getElementById = functiontheGetElementByID(x) {
  6.  print("HTML:" + element.innerHTML);
  7.  print("\n");
  8.  print("ELEMENT:" + x + ":");
  9.  return element;
  10. };
  11.  
  12. // INSERT CODE HERE
  13.  
  14. print("HTML:" + element.innerHTML);

Сам код, в неизменном виде вставляется внутрь этой обертки и исполняется. Если код вызывает функию getElementById(), мой код выведет на экран все, что сохранится в innerHTML.

Таким образом, без изменения кода, появляется возможность определять что и куда сохраняет скрипт.

И в заключении предлагаю вам ознакомиться с работающим примером загрузки файлов с ресурса mediafire.com:
Copy Source | Copy HTML
  1. /*<br/> * Copyright (C) AIG<br/> * aignospam at gmail.com<br/> *<br/> * Redistribution and use in source and binary forms, with or without<br/> * modification, are permitted provided that the following conditions<br/> * are met:<br/> * 1. Redistributions of source code must retain the above copyright<br/> *    notice, this list of conditions and the following disclaimer.<br/> * 2. Redistributions in binary form must reproduce the above copyright<br/> *    notice, this list of conditions and the following disclaimer in the<br/> *    documentation and/or other materials provided with the distribution.<br/> *<br/> * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br/> * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br/> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br/> * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE<br/> * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br/> * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br/> * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br/> * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br/> * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br/> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br/> * SUCH DAMAGE.<br/> */
  2.  
  3. function jsDecode($code)
  4. {
  5.   $fh = fopen('./code.js', 'w');
  6.   fwrite($fh, 'var element = new Object();element.innerHTML = "";');
  7.   fwrite($fh, 'var parent = new Object();parent.document = new Object();');
  8.   fwrite($fh, 'parent.document.getElementById = function theGetElementByID(x) {print("HTML:" + element.innerHTML);print("\n");print("ELEMENT:" + x + ":");return element;};');
  9.   fwrite($fh, $code);
  10.   fwrite($fh, 'print("HTML:" + element.innerHTML);');
  11.   fclose($fh);
  12.   return `js ./code.js 2>&1`;
  13. }
  14.  
  15. function downloadMediafire($url)
  16. {
  17.   $cookie_file = './cookie.mediafire.txt';
  18.   @unlink($cookie_file);
  19.  
  20.   $user_agent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
  21.  
  22.   $ch = curl_init($url);
  23.   curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
  24.   curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
  25.   curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  26.   curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
  27.   curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
  28.   $result_parent = curl_exec($ch);
  29.  
  30.   $referer = $url;
  31.  
  32.   // search all functions
  33.   if (!preg_match_all("/function\s+([a-z0-9]+)\(qk\,pk\,r\)/", $result_parent, $match_function_names)) {
  34.     print "unable to find generated functions\n";
  35.     print $result_parent;
  36.     return false;
  37.   }
  38.  
  39.   $code_header = '';
  40.   foreach ($match_function_names[1] as $function_name) {
  41.     $code_header .= 'function ';
  42.     $code_header .= $function_name;
  43.     $code_header .= '(qk,pk,r)';
  44.     $code_header .= '{print("KEY:" + qk + ":" + pk + ":" + r + ":" + "' . $function_name . '" + ":");};';
  45.   }
  46.  
  47.   if (!preg_match('/Eo\(\);(.*?eval.*?)if/', $result_parent, $match_code)) {
  48.     print "unable to find key code\n";
  49.     print $result_parent;
  50.     return false;
  51.   }
  52.  
  53.   // decode eval functions...
  54.   $code = jsDecode($code_header . $match_code[1]);
  55.  
  56.   if (!preg_match('/KEY:(.*?):(.*?):(.*?):(.*?):/', $code, $match_key)) {
  57.     print $code;
  58.     return false;
  59.   }
  60.  
  61.   $qk = $match_key[1];
  62.   $pk = $match_key[2];
  63.   $r = $match_key[3];
  64.  
  65.   $valid_function_name = $match_key[4];
  66.  
  67.   // search for visible element...
  68.   if (!preg_match('/function ' . $valid_function_name . '\(.*?document.getElementById\(\'(.{32})\'\)/', $result_parent, $match_id)) {
  69.     print $result_parent;
  70.     return false;
  71.   }
  72.  
  73.   $element_id = $match_id[1];
  74.  
  75.   $url = 'http://www.mediafire.com/dynamic/download.php?qk=' . $qk . '&pk=' . $pk . '&r=' . $r;
  76.  
  77.   print "URL=$url\n";
  78.  
  79.   curl_setopt($ch, CURLOPT_URL, $url);
  80.   curl_setopt($ch, CURLOPT_REFERER, $referer);
  81.   $result_fetch = curl_exec($ch);
  82.   curl_close($ch);
  83.  
  84.   if (!preg_match('/(var\s+et\s*=\s*15.*?)function/', $result_fetch, $match_header)) {
  85.     print "unable to find link header\n";
  86.     print $result_fetch;
  87.     return false;
  88.   }
  89.  
  90.   $code_header = $match_header[1];
  91.  
  92.   if (!preg_match('/case\s+15:(.*?)break;/', $result_fetch, $match_code)) {
  93.     print "unable to find link code\n";
  94.     print $result_fetch;
  95.     return false;
  96.   }
  97.  
  98.   // decode eval functions...
  99.   $code = jsDecode($code_header . $match_code[1]);
  100.  
  101.   if (!preg_match('/' . $element_id . '.*?href="http:\/\/([^"]+)"/', $code, $match_url)) {
  102.     print "unable to find element url\n";
  103.     print $code;
  104.     return false;
  105.   }
  106.  
  107.   $file_url = $match_url[1];
  108.  
  109.   print "URL=$file_url\n";
  110.  
  111.   $file = basename($file_url);
  112.   $url = "http://$file_url";
  113.  
  114.   if (file_exists($file)) {
  115.     return true;
  116.   }
  117.  
  118.   $fp = fopen($file, 'w');
  119.  
  120.   $ch = curl_init($url);
  121.   curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
  122.   curl_setopt($ch,CURLOPT_USERAGENT, $user_agent);
  123.   curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
  124.   curl_setopt($ch,CURLOPT_COOKIEJAR, $cookie_file);
  125.   curl_setopt($ch,CURLOPT_COOKIEFILE, $cookie_file);
  126.   curl_setopt($ch,CURLOPT_REFERER, $referer);
  127.   curl_setopt($ch, CURLOPT_FILE, $fp);
  128.   $result = curl_exec($ch);
  129.   $info = curl_getinfo($ch);
  130.   curl_close($ch);
  131.  
  132.   fclose($fp);
  133.  
  134.   if ($info['http_code'] != 200) {
  135.     print_r($info);
  136.     return false;
  137.   }
  138.  
  139.   return true;
  140. }
  141.  
Tags:
Hubs:
Total votes 39: ↑35 and ↓4 +31
Views 4.7K
Comments Comments 18