Показать сообщение отдельно

  #32  
Старый 31.05.2009, 16:03
.:EnoT:.
Постоянный
Регистрация: 29.05.2007
Сообщений: 852
Провел на форуме:
4832771

Репутация: 1916


По умолчанию

Парсинг страниц с защитой на JavaScript


[INTRO]
Многие начинающие и не очень начинающие кодеры при написании парсеров/грабберов сталкиваются с проблемой, что вывод
данных на страницу производится яваскриптом, да ещё и с динамическими именами переменных, массивов и т.д.
Собственно решил написать эту статейку.

[Способ решения]
Вот так недавно наткнулся на один код.
На странице выводилась прокся (IP : Port). Но выводилось при помощи JS.
Наша задача - получить адрес и порт прокси при помощи PHP, не прибегая к каким-либо выполнениям на стороне клиента.
Код страницы выглядел примерно вот так:

Код:
<HTML><BODY>
<script>
lXaLNu = new Array(742,62,948,760,41,960,48);
auAQmk = parseInt((((500+lXaLNu[0])*lXaLNu[1]+lXaLNu[2]+lXaLNu[3])*lXaLNu[4]-lXaLNu[5]-lXaLNu[6])*10)/10-3226178;

jmJZrOkTxr = new Array(351,30,25,715,874);
JACwFMTS = parseInt((((109+jmJZrOkTxr[0])*jmJZrOkTxr[1])*jmJZrOkTxr[2]+jmJZrOkTxr[3]+jmJZrOkTxr[4])*10)/10-346439;

pYSHW = new Array(425,482,67,716,370,432);
nlM = parseInt(((843+pYSHW[0]+pYSHW[1])*pYSHW[2]+pYSHW[3]-pYSHW[4]+pYSHW[5])*10)/10-105771;

CIjU = new Array(374,514,208);
NCfWOOCO = parseInt((424+CIjU[0]+CIjU[1]-CIjU[2])*10)/10-894;

ZuIGvQrzIMTS = new Array(112,185,735,61,91);
myiDrcfCi = parseInt(((287+ZuIGvQrzIMTS[0]-ZuIGvQrzIMTS[1]-ZuIGvQrzIMTS[2])*ZuIGvQrzIMTS[3]+ZuIGvQrzIMTS[4])*10)/10+31828;

TMUuMPjfRhm = parseInt(NCfWOOCO)+'.'+parseInt(auAQmk)+'.'+parseInt(myiDrcfCi)+'.'+parseInt(JACwFMTS)+':'+parseInt(nlM);

</script>

Proxy IP:PORT : <script>document.write(TMUuMPjfRhm);</script>
Имена переменных, массивов были динамическими, последовательности и величины математических операций так же были различными при
каждой перезагружке страницы.
Казалось бы сложно, на самом деле нет
Рассмотрим код:
Каждая переменная формирует кусок ip прокси, а одна из них содержит порт. Этот алгоритм не меняется.
Далее переменная TMUuMPjfRhm содержит конечный результат (адрес разделённый точками и через двоеточие порт).
Следовательно нам нужно получить результат этой переменной.
В принципе есть множество способов решения данной проблемы, в целом всё зависит от воображения программиста.
Сейчас мы рассмотрим один из способов - преобразование JS кода в PHP и выполнение.
И так пошагово:
  1. Отпарсить кусок нужного JavaScript
  2. Заменить JS переменные и массивы на PHP
  3. Заменить JS функции на эквивалентные PHP
  4. Выполнить полученный код через eval() и создать переменную, содержащую конечный результат

Всё, что для этого нужно это знание регулярных выражений, ну и синтаксиса PHP (как бы банально это не звучало),
иначе eval() код с ошибками кушать не будет


[Поехали]


1. Парсим код.


Всё, что нам нужно для счастья это код между <script></script>.
PHP код:
preg_match('#<script>(.+)</script>#Uis'$source$out); 
В $out[1] теперь содержится нужный нам код.


2. Парсим имена массивов и переменных


PHP код:
preg_match_all('#([a-z]+)\s=\snew#i'$out[1], $arrs);
preg_match_all('#([a-z]+)\s=\sparse#i'$out[1], $vars); 
Получаем

Код:
Переменные
Array
(
    [0] => auAQmk
    [1] => JACwFMTS
    [2] => nlM
    [3] => NCfWOOCO
    [4] => myiDrcfCi
    [5] => TMUuMPjfRhm
)


Массивы
Array
(
    [0] => lXaLNu
    [1] => jmJZrOkTxr
    [2] => pYSHW
    [3] => CIjU
    [4] => ZuIGvQrzIMTS
)
Теперь преобразуем все переменные в PHP путём добавления знака доллара. Для этого напишем небольшую функцию
обратного вызова, чтобы применить её ко всем элементам массивов $arrs[1] и $vars[1].

PHP код:
function add_dollar($elem) {
    return 
'$' $elem;

Применяем:
PHP код:
$php_arrs array_map('add_dollar'$arrs[1]);
$php_vars array_map('add_dollar'$vars[1]); 
Далее заменяем преобразованные имена в нашем коде
PHP код:
$out[1] = str_replace($arrs[1], $php_arrs$out[1]);
$out[1] = str_replace($vars[1], $php_vars$out[1]); 
Заменили, едем дальше.


3. Меняем JS функции на эквивалентные PHP


Здесь используется всего-лишь одна функция parseInt. Эквиватент ей в PHP - intval() или в данном примере
даже подойдёт abs().
Заменим на intval():
PHP код:
$out[1] = str_replace('parseInt''intval'$out[1]); 
Далее смотрим на массивы, видим new Array(). Но так как в PHP массив не является объектом, а простой функцией array()
заменим это дело, просто убрав new:

PHP код:
$out[1] = str_replace('new '''$out[1]); 
В последней переменной, которая формирует результат мы видим JS-конкатенацию (знак плюса).
Заменяем ёё на PHP-конкатенацию (точка)

PHP код:
$out[1] = str_replace(
    array(
"'+""+'"),
    array(
"' . "" . '"),
    
$out[1]); 

Хитрый финт ушами и у нас уже готовый PHP-код:

PHP код:
$lXaLNu = Array(742,62,948,760,41,960,48);
$auAQmk intval((((500+$lXaLNu[0])*$lXaLNu[1]+$lXaLNu[2]+$lXaLNu[3])*$lXaLNu[4]-$lXaLNu[5]-$lXaLNu[6])*10)/10-3226178;

$jmJZrOkTxr = Array(351,30,25,715,874);
$JACwFMTS intval((((109+$jmJZrOkTxr[0])*$jmJZrOkTxr[1])*$jmJZrOkTxr[2]+$jmJZrOkTxr[3]+$jmJZrOkTxr[4])*10)/10-346439;

$pYSHW = Array(425,482,67,716,370,432);
$nlM intval(((843+$pYSHW[0]+$pYSHW[1])*$pYSHW[2]+$pYSHW[3]-$pYSHW[4]+$pYSHW[5])*10)/10-105771;

$CIjU = Array(374,514,208);
$NCfWOOCO intval((424+$CIjU[0]+$CIjU[1]-$CIjU[2])*10)/10-894;

$ZuIGvQrzIMTS = Array(112,185,735,61,91);
$myiDrcfCi intval(((287+$ZuIGvQrzIMTS[0]-$ZuIGvQrzIMTS[1]-$ZuIGvQrzIMTS[2])*$ZuIGvQrzIMTS[3]+$ZuIGvQrzIMTS[4])*10)/10+31828;

$TMUuMPjfRhm intval($NCfWOOCO) . '.' intval($auAQmk) . '.' intval($myiDrcfCi) . '.' intval($JACwFMTS) . ':' intval($nlM); 
4. Выполняем полученный код


Для начала создадим переменную, которая будет содержать результат. Ведь к переменной $TMUuMPjfRhm мы не можем обращаться постоянно,
так как имя её меняется.
Поэтому, чтоб код был постоянно рабочим при любых изменениях переменных достанем имя последней переменной из массива (того, когда парсили)
имена переменных. И создадим независимую переменную, содержащую результат.

PHP код:
$out[1] .= '$proxy = ' array_pop($php_vars) . ';'
Осталось лишь выполнить наш PHP-код через eval()
PHP код:
eval($out[1]); 
Теперь адрес проксика будет в переменной $proxy
PHP код:
echo $proxy

[Вывод]
Как все знают, идеальной защиты не существует и JS тому не исключение
Был продемонстрирован всего один из тысячи способов получения контента страницы с казалось бы такой крутой защитой.
В общем удачных кодесов

В аттаче весь код этой статьи с комментариями
Вложения
Тип файла: rar js2php.rar (1.2 Кб, 5 просмотров)

Последний раз редактировалось .:EnoT:.; 31.05.2009 в 16:41..
 
Ответить с цитированием