создание своей nulled CMS на примере DLE На сегодняшний день существует множество популярных коммерческих CMS: DLE , SLAED CMS Pro, bitrix и др. Я не буду сейчас подробно разъяснять чем отличаются коммерческие движки от открытых, скажу лишь только, что поддержка у них намного лучше, да и безопасность тоже - хотя это мое личное мнение. Отдельной стороной стоят нуленые cкрипты. Статус Nulled данные скрипты получают после исключения из их кода защит и систем контроля, оставленных разработчиками, к примеру привязка к домену, запрос ключа регистрации при установке, ограничение времени использования и тп… Вопрос стоит ли использовать Nulled движки зависит от самого пользователя, если вы хотите безопасный скрипт на неограниченном количестве сайтов - дерзайте. При этом правда потеряется непосредственное обновление с сайта разработчиков, но это не сильно страшно, всегда можно и вручную заплатки ставить или скачать новую зануленую версию. К тому же если вы решите напичкать свой двиг модулями, то обновления затрут их, так что добрая половина пользователей вообще не используют эту функцию, а остальная часть использует лицензию В последнее время участилось распространение фейковых дистрибутивов, с бекдором внутри. Собственно добрые дядьки нулили нулили, а злые впихивали туда свой код и распространяли на файлообменниках. В принципе, чтобы самому создать Nulled версию - достаточно хорошо знать PHP, ну и плюс пару тройку часов свободного времени и несколько банок пива. А что что делать тем кто плохо знает PHP и не хочет левый "null"? - читать дальше. Есть еще один способ эффективного понимания процесса нуления. Многие движки распространяются в исходниках, некоторые с закрытыми или шифрованными исходниками ( к примеру DLE Demo). И так, рассмотрим "чистый" способ создания nulled скриптов на примере DLE 7.0. Для этого лицензию всетаки надо приобрести, чтоб получить открытый код CMS, ну можно также скачать в инете или, что еще лучше спросить у друга, который эту лицензию приобрел (без ключа-то она такое же демо) : еще нужна программа для визуального сравнения текстовых документов на предмет изменений в них - подойдет WinMerge (аналогичные есть и под линь, к примеру KDiff3), собственно сама нуленая версия для сравнения ( использовалась от MID team) и кой-какое знание PHP. И так, приступим: Открываем WinMerge - создаем новый проект, в левой стороне указываем папку с "демо" версией DLE (допустим C:\temp\dle\demo\), в правой c нуленой версией от МИДа (C:\temp\dle\nulled\). Как видно изменений много, но если присмотреться львиная чать изменена не намного, вставлен копирайт от MID. Значительному изменению подверглись только несколько файлов: в папке \upgrade\index.php, addnews.php, dboption.php, functions.inc.php, \engine\inc\init.php, main.php, options.php, updates.php. Рассмотрим их содержимое более подробней. 1. \upgrade\index.php - тут надо удалить строчку с двумя переменными - PHP: $_D = ROOT_DIR; $_F = ENGINE_DIR; - они не нужны. 2. addnews.php - тут убрать ограничение на добавление новостей (просто удалить этот кусок) PHP: if ($lic_tr) { $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_post"); $stats_news = $row['count']; $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_comments"); $count_comments = $row['count']; if ($stats_news > 200) die("Licence not Found!"); if ($count_comments > 500) die("Licence not Found!"); } 3. dboption.php - убираем условие, отвечающее за привязку к домену PHP: if ($domen_hash == "" OR $domen_hash != $config['key']) {$row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_comments");if ($row['count'] > 555) die("\114\151\143\455\156\455\145\40\156\157\164\40\106\157\165\156\144!");} 4. в functions.inc.php - удаляем переменные $_F, $_D и условие PHP: if(!$_F OR !$_D) exit(); function echoheader($image, $header_text){ global $PHP_SELF, $skin_header, $member_db, $user_group, $_F, $_D; $skin_header = preg_replace("/{header-text}/", $header_text, $skin_header); $skin_header = preg_replace("/{user}/", $member_db[2], $skin_header); $skin_header = preg_replace("/{group}/", $user_group[$member_db[1]]['group_name'], $skin_header); if(!$_F OR !$_D) exit(); echo $skin_header; } Должно получиться следующие PHP: function echoheader($image, $header_text){ global $PHP_SELF, $skin_header, $member_db, $user_group; $skin_header = preg_replace("/{header-text}/", $header_text, $skin_header); $skin_header = preg_replace("/{user}/", $member_db[2], $skin_header); $skin_header = preg_replace("/{group}/", $user_group[$member_db[1]]['group_name'], $skin_header); echo $skin_header; } 5. main.php - изменяем переменную $licence PHP: $licence = ($lic_tr) ? $lang['licence_trial'] : $lang['licence_full']; На PHP: $licence = "Nulled by NickName"; Далее удаляем условие, когда активируется ключ. PHP: if ($lic_tr) { echo <<<HTML <SCRIPT LANGUAGE="JavaScript"> function dle_activation (){ document.getElementById( 'result_info' ).innerHTML = '{$lang['nl_sinfo']}'; var dle_key = ajax.encodeVAR( document.getElementById('sitekey').value ); var varsString = "dle_key=" + dle_key; ajax.setVar("activation", 'yes'); ajax.requestFile = "{$config['admin_path']}"; ajax.element = 'dle-activation'; ajax.method = 'POST'; ajax.sendAJAX(varsString); return false; } </script> HTML; echo"<br /><table width=\"100%\"align=center><tr><td style='padding:3px; border:1px dashed rgb(190,190,190); background-color:lightyellow;' class=main> <div id=\"dle-activation\">$lang[trial_info]<br /><br /><b>$lang[trial_key]</b><span style=\"padding-left:7px;\"><input class=\"edit\" type=\"text\" size=\"55\" name=\"sitekey\" id=\"sitekey\"> <input class=\"edit\" type=\"button\" onClick=\"dle_activation(); return false;\" value=\"$lang[trial_act]\"></span><div id=\"result_info\" style=\"color:red;\"><br /></div></div> </td></tr><tr><td> </td></tr></table>"; } 6. Ковыряем options.php Удаляем условие, отвечающее за ограничение на комментарии и новости PHP: if ($lic_tr) { $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_post"); $stats_news = $row['count']; $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_comments"); $count_comments = $row['count']; if ($stats_news > 501) die("Licence not Found!"); if ($count_comments > 1001) die("Licence not Found!"); } 7. updates.php - убираем функцию обновления скрипта заменяем PHP: $data = @file_get_contents("http://www.dle-news.ru/extras/updates.php?version_id=".$_REQUEST['versionid']."&key=".$config['key']); if (!strlen($data)) echo $lang['no_update']; else echo $data; на PHP: $data = "нельзя - движок нуленый"; echo $data; 8. и самый большой подводный камень - это init.php. Этот файлик очень хитрожо…в общем зашифрован он. Тестить бум на сервере, копируем весь "мусор" в index.php и будем запускать из браузера (я использовал денвер). Посмотрев теперь index.php по внимательней можно найти строчку PHP: $_D=strrev('edoced_46esab');eval($_D( "тут какой-то код") если ее прочитать задом наперед то получится base64_decoded : вот тут то и начинает попахивать жареным. Копаем дальше… Функция strrev переводит сроку в обратном направлении. Расшифровываем переменную $_D в BASE64 (использовал онлайн дешифратор, таких скриптов куча)- получилось: PHP: $_X=base64_decode($_X);$_X=strtr($_X,'O/bpuw3kM6B2txD1.RoX]lVY >JAEGTfz7K QH=js}ZqUce8v5nm<[9a4i0CrW{NghdILPySF','iC vfF>zeSE7P5nqlAt.wWDOmKubdU}=3M{Rkcx92JhLZgX06yrpQTG< VajIB1][Y48sH/oN');$_R=ereg_replace('__FILE__',"'".$_F."'",$_X);eval($_R);$_R=0;$_X=0; что видим… переворачивается 'edoced_46esab' слева направо, таким образом получая 'base64_decode', выполняется переменная под eval, собственно это и есть ключ к расшифровке. Таксь, уже близко - чую запашок горелого, если это не на кухне - тогда скрипт наш скроро сдастся. Видно, что нешифрованный код будет находиться в переменной $_X, а не в $_R. Поэтому изменим его: eval($_R); заменим на print base64_encode($_X); Должно получиться следующее: PHP: $_X=base64_decode($_X);$_X=strtr($_X,'O/bpuw3kM6B2txD1.RoX]lVY >JAEGTfz7K QH=js}ZqUce8v5nm<[9a4i0CrW{NghdILPySF','iC vfF>zeSE7P5nqlAt.wWDOmKubdU}=3M{Rkcx92JhLZgX06yrpQTG< VajIB1][Y48sH/oN');$_R=ereg_replace('__FILE__',"'".$_F."'",$_X);print base64_encode($_X);$_R=0;$_X=0; Шифруем в BASE64 и вставляем обратно, потом запускаем скрипт из браузера, нам выдаст опять шифровку в BASE64, вставляем ее в декодер и видим примерно тот же исходник которой был до этого, кроме одного но - ключ уже будет другой. Копируем дешифрованный код в наш скрипт полностью все заменяя (возможно придется убрать знак "?>" вначале), далее делаем такие же манипуляции с $_D как и выше, раскодируем - заменяем eval($_R); на print base64_encode($_X); -кодируем, заменяем в файле, запускаем в браузере - нам опять выдает закодированный код - только теперь если его раскодировать получим наш исходник : Вот такая у него мега кул защита… Если скачать демо версию, то большинство файлов (если не все) там закодированы также, так что если есть энтузиазм и банка пива - дерзайте, возможно превратить demo в полноценную версию (можно написать скрипт, чтоб все это вручную не проделывать), ну или использовать готовый null. Приступим непосредственно к ковырянию в коде и извлечению ненужных функций. Удаляем ограничение на новости: PHP: if (($mod != "editnews" AND $mod != "main" AND $mod != "") AND $lic_tr) { $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_post"); $stats_news = $row['count']; $row = $db->super_query("SELECT COUNT(*) as count FROM " . PREFIX . "_comments"); $count_comments = $row['count']; if ($stats_news > 100) msg("info","error", $lang['trial_limit']); if ($count_comments > 200) msg("info","error", $lang['trial_limit']); } Удаляем ограничения на домен: PHP: $domen_hash = explode('.', $_SERVER['HTTP_HOST']); $count_key = count($domen_hash) - 1; unset ($domen_hash[$count_key]); if (end($domen_hash) == "com" OR end($domen_hash) == "net") $count_key --; $domen_hash = $domen_hash[$count_key-1]; $domen_hash = md5(md5($domen_hash."780918")); $lic_tr = true; if ($domen_hash == $config['key']) $lic_tr = false; if ($_REQUEST['activation'] == "yes") { dle_activation (convert_unicode($_REQUEST['dle_key']), $domen_hash, $config); exit;} и Удаляем активацию скрипта на сервере: PHP: function convert_unicode($t, $to = 'windows-1251') { $t = preg_replace( '#%u([0-9A-F]{1,4})#ie', "'&#' . hexdec('\\1') . ';'", $t ); $t = urldecode ($t); $t = @html_entity_decode($t, ENT_NOQUOTES, $to); return $t; } function send_activation ($query,$others=''){ $host='dle-news.ru'; $path='/extras/activate.php'; $post="POST $path HTTP/1.1\r\nHost: $host\r\nContent-type: application/x-www-form-urlencoded\r\n{$others}User-Agent: Mozilla 4.0\r\nContent-length: ".strlen($query)."\r\nConnection: close\r\n\r\n$query"; $h=@fsockopen($host,80, $errno, $errstr, 30); if (!$h) { $r = @file_get_contents("http://".$host.$path."?".$query); } else { fwrite($h,$post); for($a=0,$r='';!$a;){ $b=fread($h,8192); $r.=$b; $a=(($b=='')?1:0); } fclose($h); } if (stristr( $r, "antw:activated" )) return "1"; if (stristr( $r, "antw:denied" )) return "0"; return "-1"; } function dle_activation($key, $domen_hash, $config){ include (ROOT_DIR.'/language/'.$config['langs'].'/adminpanel.lng'); $config['charset'] = ($lang['charset'] != '') ? $lang['charset'] : $config['charset']; $domain = urlencode(strip_tags ($_SERVER['HTTP_HOST'])); $key = strip_tags ($key); $buffer = send_activation ("domain={$domain}&key={$key}&site_key={$domen_hash}&c_id=5411"); switch ($buffer) { case "-1" : $buffer = $lang['trial_act1']; break; case "0" : $buffer = $lang['trial_act2']; break; case "1" : $config['key'] = $domen_hash; $handler = fopen(ENGINE_DIR.'/data/config.php', "w"); fwrite($handler, "<?PHP \n\n//System Configurations\n\n\$config = array (\n\n"); foreach($config as $name => $value) { fwrite($handler, "'{$name}' => \"{$value}\",\n\n"); } fwrite($handler, ");\n\n?>"); fclose($handler); $buffer = $lang['trial_act3']; break; default: $buffer = $lang['trial_act4']; } @header("Content-type: text/css; charset=".$config['charset']); echo $buffer; die (); } extract($_REQUEST, EXTR_SKIP); замечания: вышеописанный способ работает с версией 7.0, для версии 7.2 нужно подправить init.php - там привязка к домену запихана в функцию. еще 2 файла редактировать необязательно - это editnews.php и editusers.php. тут нужно убрать условие также отвечающее за привязку к домену и проверке ключа, в принципе и с этим нормально работает... PHP: if ($domen_hash == "" OR $domen_hash != ........................);} но я за чистоту кода Данный способ позволяет лишний раз убедится в чистоте занулленого движка и по возможности создать свою версию nulled, к тому же приведенный выше способ подойдет наверняка и к другой версии, не думаю что разработчики каждый раз переписывают модули лицензии . Вся описанная информация предоставляется исключительно к ознакомлению и размышлению. Никакая часть данного материала не может быть использована во вред, в обратном случае, автор не несет какой-либо ответственности за возможный ущерб, причиненный материалами статьи. спициально для antichat.ru
только в личку, и наверно послезавтра, потому что у тебя уже превышен лимит сообщений там, у меня инета 5 минут осталось на этот месяц...
Автору спасибо. Только немного ошибся... сложно уложится в этот строк и тем более в это количество пива
SchmeL, выложи линк на скачку двига, плз... Без данного линка твоя статья лишена какого-либо смысла. Потому как платить 40 Евро за двиг, чтобы потом его же зачем-то занулить, согласись, нет никакого смысла...
Ну в целом, молодец.. только начинать надо было не с а с того откуда эти переменные, что значат и почему их надо удалять.. имхо
можно и демо версию превратьтить в полноценную версию, принцип кодирования тотже... архив с дле выложить тут не могу, я его не покупал, а кто покупал не хочет распространения, так как боится что его забанить могут... а переменные $D и $F если мне память не ошибает служат для проверки активации... вот видео http://webfile.ru/2151127
статенька норм,вот тока название темы - создание своей nulled CMS на примере DLE мона проста было назвать Нуление движка cms но эт нетак важно