[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Лечение флешек с помощью PHP
I++
В этой статье я опишу простой способ обход любых вид защит swf файлов, применимо к любым флеш файлам даже при использовании защит от дизасемблеров.

Для начала нам понадобится:

Спецификация формата.
http://www.adobe.com/content/dam/Adobe/en/...at_spec_v10.pdf

Пример флешки:

Обычный проект AS3:

import fl.controls.Label;

var InfoLabel:Label = new Label();
InfoLabel.move(20, 20);

if (check_state())
{
InfoLabel.text = "Protected";
}
else
{
InfoLabel.text = "DeProtected";
}
addChild(InfoLabel);

function check_state()
{
return 1;
}


Данная флешка показывается простой пример защиты, используются во множестве коммерческих проектах, функция check_state проверяет состояние например лицензионных кодов, в случае правильного кода включается функционал, иначе выводится предупреждение, в данном примере будет показано лишь Protected и DeProtected, таким образом можно обойти защиту и флешка будет валида, в случае не правильного кода.

Для изучения уже готовой флешки использовался Sothink SWF Decompiler он достаточно прост в использовании и имеет визуальный интерфейс, что упрощает анализ.

Предварительный анализ:

user posted image

Исходный код нормально отображается, так как не используется защита от подобных методов, в случае если используются методы защиты, программа не сможет обработать корректно файл и вылетит с fatal error'ом.

Для обхода зищит используем показ P-кода.

user posted image

Из спецификации мы узнаем, что последовательность 12 E0 00 00 означает:

user posted image

Где 12 непосредственно команда, E0 смещение.

Нам нужно обойти данное ограничение, для этого мы меняем условие, напримере скрипта:


if(check_state())
{

}



мы заменяем на


if(!check_state())
{

}



Для этого мы узнаем из спецификации о такой конструкции:

user posted image

Что по сути будет означать обратное значение _as3_iffalse т.е as3_iftrue

Т.е значение 12 E0 00 00 нам нужно изменить на 11 E0 00 00

Для этого можно применить вот этот PHP код:

class SWFCrack
{
private $file_buffer;

/**
* Main Crack function
*
* Use this method to crack SWF files
*
*
@access public
*
@param string $file_name
*
@param string|array $search_hex
*
@param string|array $replace_hex
*
@example void crackit(string $file_name, mixed $search_hex, mixed $search_hex, bool $enable_debug = false)
*/

public function crackit($file_name, $search_hex, $replace_hex, $enable_debug = false)
{
$time_start_script = microtime(1);
$params_checks = array(0,0);
$debug_string = '';

if(is_array($search_hex))
$params_checks[0] = 1;
else
$search_hex = array($search_hex);

if(is_array($replace_hex))
$params_checks[1] = 1;
else
$replace_hex = array($replace_hex);

$search_hexcount = count($search_hex);
$replace_hexcount = count($replace_hex);

if($params_checks[0] != $params_checks[1])
{
die('"Search" and "Replace" not arrays or strings');
}
else
{
if($search_hexcount != $replace_hexcount)
die('Different number of parameters "Search" and "Replace"');
}

if(!file_exists($file_name))
die('File not found');

$this->file_buffer = file_get_contents($file_name) or die ('Can\'t open file');
$this->swf_unpack();
$this->bin_to_hex();

for($i=0 ; $i < $search_hexcount ; $i++)
{
$replace_hexlen = strlen($replace_hex[$i]);

if($replace_hexlen !== strlen($search_hex[$i]))
die('"Search" and "Replace" Hex strings not the same length: Debug (Search string: '.$search_hex[$i].' Reaplace string: '.$replace_hex[$i]);

$search_hex[$i] = strtolower($search_hex[$i]);
$replace_hex[$i] = strtolower($replace_hex[$i]);

$hexpos = strpos($this->file_buffer, $search_hex[$i]);

if($hexpos === false)
die('Damn! Search string not found: Debug (Search string: '.$search_hex[$i].')');

for($i2 = 0 ; $i2 < $replace_hexlen ; $i2++)
{
$this->file_buffer[$hexpos+$i2] = $replace_hex[$i][$i2];
}

if($enable_debug)
{
$debug_range_start = $hexpos-50;
$debug_range_end = $hexpos+50+$replace_hexlen;
$debug_info = '';

for($i2 = $debug_range_start ; $i2 < $debug_range_end ; $i2++)
{
$debug_info .= $this->file_buffer[$i2];
}

$debug_string .=
"--------[ DEBUG ]--------<br>\n"
.'Position: '.$hexpos."<br>\n"
.'Search string: '.chunk_split(strtoupper($search_hex[$i]), 2, ' ')."<br>\n"
.'Replace string: '.chunk_split(strtoupper($replace_hex[$i]), 2, ' ')."<br>\n"
.'Debug info: '.chunk_split(strtoupper($debug_info), 2, ' ')."<br>\n";
}
}


$this->hex_to_bin();
$this->swf_pack();
file_put_contents('cracked_'.$file_name, $this->file_buffer);
$this->file_buffer = NULL;

echo 'Cracked successful, time: '.(microtime(1) - $time_start_script)." seconds<br />\n".$debug_string;
}

private function bin_to_hex()
{
$this->file_buffer = bin2hex($this->file_buffer);
}

private function hex_to_bin()
{
$this->file_buffer = pack("H*", $this->file_buffer);
}

private function swf_pack()
{
if(substr($this->file_buffer, 0, 3) != 'FWS')
return;

$swf_header = substr($this->file_buffer, 0, 8);
$swf_header[0] = 'C';
$this->file_buffer = $swf_header.gzcompress(substr($this->file_buffer, 8));
}

private function swf_unpack()
{
if(substr($this->file_buffer, 0, 3) != 'CWS')
return;

$swf_header = substr($this->file_buffer, 0, 8);
$swf_header[0] = 'F';
$this->file_buffer = $swf_header.gzuncompress(substr($this->file_buffer, 8));
}
}


Для начала, нужно выделить все нужные рядом последовательности, чтобы не заменить случайно другие опкоды, из скриншота:

user posted image

Я взял широкий набор, чтобы точно знать, что заменю только то, что надо, а именно:

46e40100120e0000d0 мы меняем на 46e40100110e0000d0

Используя выше PHP скрипт это просто:

$obj = new SWFCrack();
$obj->crackit('protected.swf', '46e40100120e0000d0', '46e40100110e0000d0', true);


На выходе получаем файл cracked_protected.swf

user posted image

И все, флешка вылечивается от жадности :)

При запуске cracked_protected.swf мы получим текст: DeProtected

Т.е код:

import fl.controls.Label;

var InfoLabel:Label = new Label();
InfoLabel.move(20, 20);

if (check_state())
{
InfoLabel.text = "Protected";
}
else
{
InfoLabel.text = "DeProtected";
}
addChild(InfoLabel);

function check_state()
{
return 1;
}


заменится на:

import fl.controls.Label;

var InfoLabel:Label = new Label();
InfoLabel.move(20, 20);

if (!check_state())
{
InfoLabel.text = "Protected";
}
else
{
InfoLabel.text = "DeProtected";
}
addChild(InfoLabel);

function check_state()
{
return 1;
}


Peace of cake

Данному виду атаки подвержены любые флешь приложения, всякие флипбуки, и остальные прелести.



Спустя 4 минуты, 35 секунд (24.04.2012 - 23:25) m4a1fox написал(а):
Специфично

Спустя 10 часов, 5 минут, 17 секунд (25.04.2012 - 09:30) bodja написал(а):
I++

Интересный способ.
Но тут играет человеческий фактор.
Дело в том ,что в крупном проекте без коментирования вы вряд ли найдете нужные функции,да и не факт ,что именно так будет проверка проходить.
В проектах более 1000 строк кода теряется уже сам разработчик,а глубокий анализ чужого кода практически равнозначно разработке с нуля своего.

Спустя 1 час, 31 минута, 35 секунд (25.04.2012 - 11:02) killer8080 написал(а):
I++
держи плюсик за статью smile.gif

Спустя 17 минут, 44 секунды (25.04.2012 - 11:20) vital написал(а):
Интересно. Но снова гвозди микроскопом.

Спустя 3 часа, 44 минуты, 16 секунд (25.04.2012 - 15:04) I++ написал(а):
Цитата (bodja @ 25.04.2012 - 10:30)
I++

Интересный способ.
Но тут играет человеческий фактор.
Дело в том ,что в крупном проекте без коментирования вы вряд ли найдете нужные функции,да и не факт ,что именно так будет проверка проходить.
В проектах более 1000 строк кода теряется уже сам разработчик,а глубокий анализ чужого кода практически равнозначно разработке с нуля своего.

Отчасти согласен, особенно когда разработчики используют защиты в виде обфускации кода, но это лишь оттягивает неизбежное. В любом случае на экране показывается, что не зарегистрированная версия или например слово DEMO и тд, вот с этого и начинается поиск, что очень сильно приближает к нахождению нужного участка кода.

В большинстве флешек используется консктрукция:

if(check_state())

И достаточно изменить лишь условие и все. В некоторых флешках встречается проверка ключа, этот часток кода при должном знании можно использовать для генерации кода и в этом случае вообще не нужно патчить флешку, а так же программу exeшную не приходится дизасемблировать и выискивать нужный участок, с опкодами намного проще работать чем с асмом =)

Спустя 44 минуты, 50 секунд (25.04.2012 - 15:49) bodja написал(а):
I++
Ваши слова ,да богу в уши.
Тут народ в 10 строчках JS не может разобратся...какие там опкоды smile.gif
Так же останется актуальной привязка к домену и погрузка файлов.

Спустя 8 минут, 13 секунд (25.04.2012 - 15:57) I++ написал(а):
Цитата (bodja @ 25.04.2012 - 16:49)
I++
Ваши слова ,да  богу в уши.
Тут народ в 10 строчках JS не может разобратся...какие там опкоды :)
Так же останется актуальной привязка к домену и погрузка файлов.

Файлы подгружаемые можно скачать, а привязка к домену...

if($this_domain == 'example.com')


меняется на

if($this_domain != 'example.com')


:lol:

Цитата
Тут народ в 10 строчках JS не может разобратся...какие там опкоды :)


Ну я не заявлял, что щелкнул пальцем и всё хорошо

Спустя 4 месяца, 6 дней, 23 часа, 35 минут, 56 секунд (1.09.2012 - 15:33) elvira_live написал(а):
Цитата (m4a1fox @ 25.04.2012 - 00:25)
Специфично
телефон ретро

Я с вами полностью согласна. Необычно как то
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.