Для начала нам понадобится:
Спецификация формата.
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 он достаточно прост в использовании и имеет визуальный интерфейс, что упрощает анализ.
Предварительный анализ:
Исходный код нормально отображается, так как не используется защита от подобных методов, в случае если используются методы защиты, программа не сможет обработать корректно файл и вылетит с fatal error'ом.
Для обхода зищит используем показ P-кода.
Из спецификации мы узнаем, что последовательность 12 E0 00 00 означает:
Где 12 непосредственно команда, E0 смещение.
Нам нужно обойти данное ограничение, для этого мы меняем условие, напримере скрипта:
if(check_state())
{
}
мы заменяем на
if(!check_state())
{
}
Для этого мы узнаем из спецификации о такой конструкции:
Что по сути будет означать обратное значение _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));
}
}
Для начала, нужно выделить все нужные рядом последовательности, чтобы не заменить случайно другие опкоды, из скриншота:
Я взял широкий набор, чтобы точно знать, что заменю только то, что надо, а именно:
46e40100120e0000d0 мы меняем на 46e40100110e0000d0
Используя выше PHP скрипт это просто:
$obj = new SWFCrack();
$obj->crackit('protected.swf', '46e40100120e0000d0', '46e40100110e0000d0', true);
На выходе получаем файл cracked_protected.swf
И все, флешка вылечивается от жадности :)
При запуске 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 строк кода теряется уже сам разработчик,а глубокий анализ чужого кода практически равнозначно разработке с нуля своего.
Интересный способ.
Но тут играет человеческий фактор.
Дело в том ,что в крупном проекте без коментирования вы вряд ли найдете нужные функции,да и не факт ,что именно так будет проверка проходить.
В проектах более 1000 строк кода теряется уже сам разработчик,а глубокий анализ чужого кода практически равнозначно разработке с нуля своего.
Спустя 1 час, 31 минута, 35 секунд (25.04.2012 - 11:02) killer8080 написал(а):
I++
держи плюсик за статью
держи плюсик за статью
Спустя 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 не может разобратся...какие там опкоды
Так же останется актуальной привязка к домену и погрузка файлов.
Ваши слова ,да богу в уши.
Тут народ в 10 строчках JS не может разобратся...какие там опкоды
Так же останется актуальной привязка к домену и погрузка файлов.
Спустя 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) |
Специфично телефон ретро |
Я с вами полностью согласна. Необычно как то