Библиотека чтения ID брелков сигнализациий HCS301 KEELOQ
- Войдите на сайт для отправки комментариев
Вот накарябал свою первую библиотечку по чтению кодов с брелков на микросхеме HCS301 Keeloq
Целевое назначение - можно использовать в разных системах контроля доступа
Чип HCS301 Keeloq довольно часто используемый в брелках, отличается тем, что имеет "катящийся" код, т.е. постянно изменяемый. Расшифровку кода я не сделал, однако из передаваемых данных можно вытащить следующую инфу : блок кодированной инфы 32 бита, серийный номер брелка, нажатые кнопки, состояние батареи брелка
Помимо двух китайских брелков с ебея одолжил у соседа брелок сигнализации с названием KGB, оказалось что тоже великолепно работает.
"Катящийся код" позволяет делать систему с брелками, защищенную от клонирования и сканирования
Найти такие брелки на ебее можно по ключевым словам hcs 301
Например вот лот, который я использовал
Официально платка имеет 4 выхода, которые активируются при нажатии на одну из 4х кнопок брелка, но неофициально есть контакт "data" с которого можно считывать данные.
Подозреваю, что это можно делать любым приемником с соответствующей частотой
Не знаю, как тут прикрепить файлы, поэтому вот внешние ссылки
Библиотека
http://71reg.ru/HCS301.rar
Data sheet на HCS301
http://71reg.ru/hcs301.pdf
Ключевые слова:
Ардуино Arduino HCS301 KEELOQ Code Hopping rolling роллинг прыгающий код уникальный айди unique ID брелок KeyFob брелоков
Вот пример того, что читается с брелка
Зашифрованный постоянно меняющийся блок 1605787492
Серийный номер 223657
Нажата кнопка Close
Повтор =0
Батарея в норме
То есть если купить вот такой наборчик http://www.ebay.com/itm/433Mhz-RF-transmitter-and-receiver-link-kit-for-Arduino-ARM-MCU-WL-/140719918135?pt=LH_DefaultDomain_0&hash=item20c38f8c37, использовать из него приемник совместно с вашей библиотекой, то можно будет считывать коды с брелков автосигнализаций?
Скорее всего будет, но наборчик этот мне очень не понравился, есть у меня такой.
Еще один брелок протестировал, сига APS, тоже считывается
Проверил - работает.
Имея код брелка как при помощи Arduino воспроизвести его?
С какой целью ? Чтобы приемник KEELOQ типа сигнализации сигнал воспринял как родной ?
С какой целью ? Чтобы приемник KEELOQ типа сигнализации сигнал воспринял как родной ?
Открывать то, что по техпричинам временно не открывается. В законном понимание этого смысла)))
Сколько раз бывало, что ключи с брелками терялись. А так код имеешь пожалуйста открывай. Недавно у сестры на субарике пришлось сигналку переустанавливать из за того, что брел умер...
Вообще можно зашить код в брелок с Arduino без самой сигнализации?
Тут вся фишка в том, что HCS301 имеет "прыгающий" код. Каждая посылка уникальна в пределах что то около 65000 посылок.
Код формируется из кода производителя + серийный номер. Алгоритм KEELOQ вроде взломан, но настолько глубоко я не копал
Получается что даже если "подслушать" посылку и передать её это ничего не даст, второй раз эта посылка не пройдет
А для генерации корректной посылки нужно воспроизводить алгоритм Keeloq
Я думаю ты скоро до этого сам докопаешься. Посоветуй пожалуйста статью или топик по теме простых радио-пультов и их программирования.
По поводу простых радиопультов поищи по ключевому слову RCswitch это вроде библиотека для работы радиобрелками (но без прыгающего кода)
Я разбирался по даташиту HCS301
http://www.allcomponents.ru/pdf/microchip/hcs301.pdf
А теперь тоже самое, но на прерываниях
#define LED_PIN 13 #define HCS_RECIEVER_PIN 2 // пин к которому подключен приемник для брелков class HCS301 { public: unsigned BattaryLow : 1; // На брелке села батарейка unsigned Repeat : 1; // повторная посылка unsigned BtnNoSound : 1; unsigned BtnOpen : 1; unsigned BtnClose : 1; unsigned BtnRing : 1; unsigned long SerialNum; unsigned long Encript; void print(); }; volatile boolean HCS_Listening = true; byte HCS_preamble_count = 0; uint32_t HCS_last_change = 0; uint32_t HCS_start_preamble = 0; uint8_t HCS_bit_counter; // счетчик считанных бит данных uint8_t HCS_bit_array[66]; // массив считанных бит данных #define HCS_TE 400 // типичная длительность имульса Te #define HCS_Te2_3 600 // HCS_TE * 3 / 2 HCS301 hcs301; #define HCS_DEBUG_ #ifdef HCS_DEBUG uint16_t HCS_PulseDuration[12]; uint16_t HCS_BitDuration[66]; uint32_t HCS_msg_duration; struct dta_ { uint16_t delay; byte f; byte st; }; volatile dta_ arr[1000]; volatile int poz_a = 0,poz_b = 0; #endif void HCS301::print(){ String btn; if (BtnRing == 1) btn += "Ring"; if (BtnClose == 1) btn += "Close"; if (BtnOpen == 1) btn += "Open"; if (BtnNoSound == 1) btn += "NoSound"; String it2; it2 += "Encript "; it2 += Encript; it2 += " Serial "; it2 += SerialNum; it2 += " "; it2 += btn; it2 += " BattaryLow="; it2 += BattaryLow; it2 += " Rep="; it2 += Repeat; Serial.println(it2); } void setup() { Serial.begin(9600); attachInterrupt(0, HCS_interrupt, CHANGE); pinMode(LED_PIN, OUTPUT); pinMode(HCS_RECIEVER_PIN, INPUT); } void loop() { if(HCS_Listening == false){ HCS301 msg; memcpy(&msg,&hcs301,sizeof(HCS301)); msg.print(); #ifdef HCS_DEBUG if(msg.SerialNum != 639){ Serial.println("Raw >>>>>>>>>>>>>>>>>>>>>>>"); while(1){ if(poz_b == poz_a) break; Serial.println(String(poz_b)+String(" ")+String(arr[poz_b].delay)+String(" ")+String(arr[poz_b].f == 0 ? "LOW":"HIGH")+String(" ")+String(arr[poz_b].st)); poz_b++; } Serial.println("Data >>>>>>>>>>>>>>>>>>>>>>>"); for(int i = 0;i<66;i++){ Serial.println(HCS_bit_array[i]); } } else { } poz_a = 0,poz_b = 0; #endif HCS_Listening = true; } } // void HCS_interrupt(){ if(HCS_Listening == false){ return; } uint32_t cur_timestamp = micros(); uint8_t cur_status = digitalRead(HCS_RECIEVER_PIN); uint32_t pulse_duration = cur_timestamp - HCS_last_change; HCS_last_change = cur_timestamp; #ifdef HCS_DEBUG if(poz_a < 999){ arr[poz_a].delay = pulse_duration; arr[poz_a].f = cur_status == HIGH ? 0 : 1; poz_a++; } #endif // ловим преамбулу if(HCS_preamble_count < 12){ if(cur_status == HIGH){ if( ((pulse_duration > 200) && (pulse_duration < 400)) || HCS_preamble_count == 0){ // начало импульса преамбулы if(HCS_preamble_count == 0){ HCS_start_preamble = cur_timestamp; // Отметим время старта преамбулы } } else { // поймали какую то фигню, неправильная пауза между импульсами HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы goto exit; } } else { // конец импульса преамбулы if((pulse_duration > 400) && (pulse_duration < 600)){ #ifdef HCS_DEBUG HCS_PulseDuration[HCS_preamble_count] = pulse_duration; #endif // поймали импульс преамбулы HCS_preamble_count ++; #ifdef HCS_DEBUG arr[poz_a-1].st = HCS_preamble_count; #endif if(HCS_preamble_count == 12){ // словили преамбулу //HCS_Te = (cur_timestamp - HCS_start_preamble) / 23; // вычисляем длительность базового импульса Te //HCS_Te2_3 = HCS_Te * 3 / 2; HCS_bit_counter = 0; goto exit; } } else { // поймали какую то фигню HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы goto exit; } } } // ловим данные if(HCS_preamble_count == 12){ if(cur_status == HIGH){ if(((pulse_duration > 300) && (pulse_duration < 900)) || HCS_bit_counter == 0){ // начало импульса данных } else { // неправильная пауза между импульсами HCS_preamble_count = 0; goto exit; } } else { // конец импульса данных if((pulse_duration > 300) && (pulse_duration < 900)){ HCS_bit_array[65 - HCS_bit_counter] = (pulse_duration > HCS_Te2_3) ? 0 : 1; // импульс больше, чем половина от Те * 3 поймали 0, иначе 1 #ifdef HCS_DEBUG HCS_BitDuration[HCS_bit_counter] = pulse_duration; #endif HCS_bit_counter++; #ifdef HCS_DEBUG arr[poz_a-1].st = HCS_bit_counter; #endif if(HCS_bit_counter == 66){ // поймали все биты данных HCS_Listening = false; // отключем прослушку приемника, отправляем пойманные данные на обработку HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы #ifdef HCS_DEBUG HCS_msg_duration = cur_timestamp - HCS_start_preamble; #endif hcs301.Repeat = HCS_bit_array[0]; hcs301.BattaryLow = HCS_bit_array[1]; hcs301.BtnNoSound = HCS_bit_array[2]; hcs301.BtnOpen = HCS_bit_array[3]; hcs301.BtnClose = HCS_bit_array[4]; hcs301.BtnRing = HCS_bit_array[5]; hcs301.SerialNum = 0; for(int i = 6; i < 34;i++){ hcs301.SerialNum = (hcs301.SerialNum << 1) + HCS_bit_array[i]; }; uint32_t Encript = 0; for(int i = 34; i < 66;i++){ Encript = (Encript << 1) + HCS_bit_array[i]; }; hcs301.Encript = Encript; } } else { // поймали хрень какую то, отключаемся HCS_preamble_count = 0; goto exit; } } } exit:; //digitalWrite(LED_PIN,cur_status); }Тут вся фишка в том, что HCS301 имеет "прыгающий" код. Каждая посылка уникальна в пределах что то около 65000 посылок.
Код формируется из кода производителя + серийный номер. Алгоритм KEELOQ вроде взломан, но настолько глубоко я не копал
Получается что даже если "подслушать" посылку и передать её это ничего не даст, второй раз эта посылка не пройдет
А для генерации корректной посылки нужно воспроизводить алгоритм Keeloq
На самом деле никто не взламывал KEELOQ и любой другой шифр не взламывают, да этого и не нужно, плюс ко всему что бы взломать надо тыкать на брелок N сотен раз.
Все верно, что бы организовать защиту от клонирования (копирования) пакета существует счетчик синхранизации:
Данный счетчик (Sync Value) при каждом нажатии на кнопку брелка инкрементируется (увеличивается на 1). В сигнализации помимо серийного номера брелка хранится еще и значение этого счетчика и каждый последующий пакет должен иметь значение счетчика больше чем предыдущий, иначе сигнализация никак не отреагирует на пакет, а может даже и сирену включит "распознав" в этом попытку взлома.
То есть не получится в момент снятия с охраны просто записать пакет брелка и воспроизвести его когда нибудь потом.
Так как как же тогда взламывают? Да очень просто. Вся фича во взломе это - не техничекое оснащение и компьютерная мощь, а немного логики. Для взлома сигнализации вам понадобится естественно еще передатчик.
И так, рассмотрим как это делается на сигнализациях, которые на одну и ту же кнопку снимается и ставится на охрану.
Когда хозяин авто нажимает на кнопку считываем пакет, но при этом глушим его передатчиком, сигнализация данный пакет не принимает - то есть пакет прочитан только нами, сохраняем этот пакет. Далее хозяин авто (так как машина не закрылась) тыкает еще раз, а мы делаем тоже самое. И сразу же отправляем сохраненный ранее пакет. Все! Машина закрыта, хозяин авто уходит, а у нас есть сохраненый пакет от второго нажатия с инкрементированным счетчиком, который и снимет сигналку с охраны.
Тут есть небольшая сложность - это одновременное глушение и прием пакета. Я не знаю как это организованно в грабберах, но на дуине можно организовать так: при приеме части пакета включается передатчик например в момент передачи первых 8 бит серийного номера, а при следущем приеме пакета включается например в момент передачи последних 8 бит серийного номера. Тоесть сигналка не распознает ни одного пакета, а мы можем из двух пакетов собрать правильный серийный номер.
С сигналками, у которых сниятие и постановка на охрану осуществляется разными кнопками все тоже самое только нужно дождаться пока хозяин авто в непонятках начнет тыкать на все кнопки подряд и нажмет на снятие с охраны.
Вот как то так.
Кто-нить может поделиться библиотекой HCS301? Линк с поста 1 дохлый.
Поделюсь, отчего ж нет. Только я её на прерывания переписал и теперь это не библиотека, а просто функция.
#define LED_PIN 13 // Радиобрелки /////////////////////////////////////////////////////////////////////////////////////// #define HCS_RECIEVER_PIN 2 // пин к которому подключен приемник для брелков class HCS301 { public: unsigned BattaryLow : 1; // На брелке села батарейка unsigned Repeat : 1; // повторная посылка unsigned BtnNoSound : 1; unsigned BtnOpen : 1; unsigned BtnClose : 1; unsigned BtnRing : 1; unsigned long SerialNum; unsigned long Encript; void print(); }; volatile boolean HCS_Listening = true; byte HCS_preamble_count = 0; uint32_t HCS_last_change = 0; //uint32_t HCS_start_preamble = 0; uint8_t HCS_bit_counter; // счетчик считанных бит данных uint8_t HCS_bit_array[66]; // массив считанных бит данных #define HCS_TE 400 // типичная длительность имульса Te #define HCS_Te2_3 600 // HCS_TE * 3 / 2 HCS301 hcs301; void setup() { Serial.begin(9600); // Брелки pinMode(HCS_RECIEVER_PIN, INPUT); attachInterrupt(0, HCS_interrupt, CHANGE); Serial.println("Setup OK"); } void loop() { long CurTime = millis(); // проверяем наличие команды брелка if(HCS_Listening == false){ HCS301 msg; memcpy(&msg,&hcs301,sizeof(HCS301)); // включаем слушанье брелков снова HCS_Listening = true; Serial.println(String("KeyFb#")+String(msg.SerialNum)); } } // Функции класса HCS301 для чтения брелков void HCS301::print(){ String btn; if (BtnRing == 1) btn += "Ring"; if (BtnClose == 1) btn += "Close"; if (BtnOpen == 1) btn += "Open"; if (BtnNoSound == 1) btn += "NoSound"; String it2; it2 += "Encript "; it2 += Encript; it2 += " Serial "; it2 += SerialNum; it2 += " "; it2 += btn; it2 += " BattaryLow="; it2 += BattaryLow; it2 += " Rep="; it2 += Repeat; Serial.println(it2); } void HCS_interrupt(){ if(HCS_Listening == false){ return; } uint32_t cur_timestamp = micros(); uint8_t cur_status = digitalRead(HCS_RECIEVER_PIN); uint32_t pulse_duration = cur_timestamp - HCS_last_change; HCS_last_change = cur_timestamp; // ловим преамбулу if(HCS_preamble_count < 12){ if(cur_status == HIGH){ if( ((pulse_duration > 150) && (pulse_duration < 500)) || HCS_preamble_count == 0){ // начало импульса преамбулы //if(HCS_preamble_count == 0){ // HCS_start_preamble = cur_timestamp; // Отметим время старта преамбулы //} } else { // поймали какую то фигню, неправильная пауза между импульсами HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы goto exit; } } else { // конец импульса преамбулы if((pulse_duration > 300) && (pulse_duration < 600)){ // поймали импульс преамбулы HCS_preamble_count ++; if(HCS_preamble_count == 12){ // словили преамбулу //HCS_Te = (cur_timestamp - HCS_start_preamble) / 23; // вычисляем длительность базового импульса Te //HCS_Te2_3 = HCS_Te * 3 / 2; HCS_bit_counter = 0; goto exit; } } else { // поймали какую то фигню HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы goto exit; } } } // ловим данные if(HCS_preamble_count == 12){ if(cur_status == HIGH){ if(((pulse_duration > 250) && (pulse_duration < 900)) || HCS_bit_counter == 0){ // начало импульса данных } else { // неправильная пауза между импульсами HCS_preamble_count = 0; goto exit; } } else { // конец импульса данных if((pulse_duration > 250) && (pulse_duration < 900)){ HCS_bit_array[65 - HCS_bit_counter] = (pulse_duration > HCS_Te2_3) ? 0 : 1; // импульс больше, чем половина от Те * 3 поймали 0, иначе 1 HCS_bit_counter++; if(HCS_bit_counter == 66){ // поймали все биты данных HCS_Listening = false; // отключем прослушку приемника, отправляем пойманные данные на обработку HCS_preamble_count = 0; // сбрасываем счетчик пойманных импульсов преамбулы hcs301.Repeat = HCS_bit_array[0]; hcs301.BattaryLow = HCS_bit_array[1]; hcs301.BtnNoSound = HCS_bit_array[2]; hcs301.BtnOpen = HCS_bit_array[3]; hcs301.BtnClose = HCS_bit_array[4]; hcs301.BtnRing = HCS_bit_array[5]; hcs301.SerialNum = 0; for(int i = 6; i < 34;i++){ hcs301.SerialNum = (hcs301.SerialNum << 1) + HCS_bit_array[i]; }; uint32_t Encript = 0; for(int i = 34; i < 66;i++){ Encript = (Encript << 1) + HCS_bit_array[i]; }; hcs301.Encript = Encript; } } else { // поймали хрень какую то, отключаемся HCS_preamble_count = 0; goto exit; } } } exit:; //digitalWrite(LED_PIN,cur_status); }Спасибки огромное!!!
Не за что, если ошибки какие нароешь или доработаешь, скинь сюда пожалуйста
Но в принципе ошибки маловероятны, код уже скоро полгода в работе
Круто, не думали добавить поддержку этих чипов в RCSwitch?
всем привет ! начну свой вопрос с того,что задался целью зделать брелок СЕЗАМ откройся !ну и как обычно это бывает у начинающего,я много и по долгу гуглил И прихожу к такому мнению,что не стоит настолько углубляться ,ВЕДЬ истина лежит на поверхности !мне сегодня приносили пацаны одну такую на ПЯТЁРОЧКИ и я посмотрев повнимательнее понял что к ней в домашних условиях не прикосались !но вот интерестная штука - кварц в ней на 21.4 Мгц в противоположность стандарту 433.92 !,так-жэ некоторые умельцы ставят на 1.0 Мгц ! Вопрос :достаточно ли в брелках замены кварца чтобы из него вышел кодграббер ?
Конечно не достаточно!
Параллельно кварцу нужно еще подстроечный резистор поставить на 100 кОм. Вот именно этим резистором и граббить код
АЛЛЕЛУЯ ! друг скинь схемку а ? я паяльным ремеслом занялся недавно и первое что зделал-жучок !нехочу останавливаться !в инете помоему банят подобные темы-очень трудно чтолибо найти !но я знал что есть пацаны которые не оставят без хлеба других пацанов ! то есть в любом брелке накинуть кудато лапы резистра параллельно любому кварцу ??? вот блин надо было брелок у себя оставить,но и звонить пока не хочу,пока с уверенностью не скажу им что да смогу зделать !
вот чтото наподобие такой схемы да ?
очень нужны любые коментарии к вышепроэллюстрированным схемам !любая инфа !!!!
Клевые схемы, бро!
А если серьезно, то
1. Дело не в схеме, а в "мозгах", т.е. программе
2. Взлом HCS не тривиальная задача, тут описывался способ, но к нему есть серьезные вопросы.
3. Эта задача не для твоего уровня квалификации, это 100%
ну даже если мне придётся взятся за программатор,то посоветуй какой нужен !научимся ёпты .....
а у заводских ведь мозги есть ?!
почитайте http://phreakerclub.com/
satai явно не ваша квалификация, либо вы просто народ троллите...
Какой интересный сайт. И прямо сходу там нашел алгоритм дешифрации посылки Keeloq
http://phreakerclub.com/forum/showthread.php?t=1094
Спасибо за ссылку.
ну да я понимаю ! вы ведь уже родились такими-с програматором в голове !когда права получали вспомните ка с каким призрением на вас автолюбители смотрели-тоже наверное с рулём родились !)))я не оскорбляю,а констатирую факт !полгода назад купил себе ноут и не знал как его включить,а сейчас уже не пользуюсь антивирусами !всё в этом мире познаётся ребята и для вас это может и хобби,но для меня жэ хлеб насущный-от практики перехожу к теорий!я ещё с линеички начинал(40см.)!не ну я конечно жэ понимаю,что можно открыть и прописать ключь !вот только работёнка эта при котороой можно и получить,да хотябы и срок !,да короче давайте расказывайте и объясняйте что по чём.при себе имею комп и паяльник !)))
Не вопрос. Для начала подключи к Ардуине светодиод и попробуй им помигать. Как осилишь - приходи, подскажем дальше
не вопрос !я микроконтроллер сниму с игрушки,у которой светодиоды мигают )))
http://rsataev2014.wordpress.com - я всёравно найду единомышленников !
satai, судя по вашим ответам, вам паяльник эффективней будет для терморектального крипто анализа использовать. Эффективность, в вашем случае, выше будет. А ноут рядом поставте
не ну я могу конечно проАНАЛлизировать ваш внутренний мир глубоко уважаемый roman,но боюсь что вам это может понравится,а я не хотел бы заводить себе поклонников !а то время ,когда пояльником вымогали деньги безвозратно прошло !да и я не из категории быдла,если я иду на преступление,то только от голода и только в адрес тех,кто не прочухает пропажу части денег ! я джентельмен ))) вы лучше просветите меня об новшествах в сфере защиты новых сигналок !
Все привет!
Вскрыл брелок и обнаружил что чип там HCS 201. Подскажите в чем разница между 201 и 301?
Все привет!
Вскрыл брелок и обнаружил что чип там HCS 201. Подскажите в чем разница между 201 и 301?
а Datasheet на чипы что говорит, смотрели?
посмотрел, для меня это пока темный лес, вот к вам и обращаюсь))))), просто хотел узнать можно ли использовать данный брелок с этой библиотекой
да и я не из категории быдла,если я иду на преступление,то только от голода
От нехватки мозгов это. Отсюда и проблемы с чтением даташитов и чувство голода. Поди в вашем голоде и виноват кто угодно, но только не вы (общество, судьба, правильтельство, родители, "жизнь такая")
А "прочухают/не прочухают" - оставте эти самооправдания для себя. Задумали вы гадость и хотите что-бы вам кто-то помогал.
Просветить вас? Да запросто: http://www.youtube.com/watch?v=3qaDlS-EC2w
да 12,6 отсидел и не жалуюсь !вы эту хрень учите учите а я взял и сделал !и мало того завёл свой блог по данной теме
rsataev2014.wordpress.com
здесь инфу черпать бесполезно !эти очкарики научились пользоваться программатором и думают что судьбу за яйца поймали !)))
удачи вам лошары со своими ардуинами !
Нет, недостаточно. Граб это отдельное устройство, которое из общего с брелком имеет только трансивер. НО: трансивер занимается передачами полезной нагрузки, т. о. собственно приёмом/отправкой кода. Принцип граба заключается в приёме открывающего кода, с одновременным недопущением приёма машиной закрывающего кода. Поэтому кроме трансивера ещё нужна глушилка. Так что топаем на http://phreaker.us/ и вдумчиво читаем статьи о кодграбберах, ибо граб - это граб. А брелок - это брелок. И наивно полагать что из одного получится другое. Хотя есть оговорка - из граба, в принципе, возможно сделать брелок. Но процессоров там тогда, скорее всего, будет два.
Нет, недостаточно. Граб это отдельное устройство, которое из общего с брелком имеет только трансивер.
Вы еще не поняли что это просто малолетний троль который только учится "мурчать по понятиям" (или бездарно пытается изобразить подобную роль)?
А ссылки, на сайты.... ну не нужно, а? Ведь действительно для подростков это "заманчиво и романтично", а способности предвидеть последствия - еще ослаблены. Понятно, что "кто хочет тот найдет", только зачем же "вводить во искушение?" :) Разве без этого нет интерестных применений контроллерым знаниям?
Нет, недостаточно. Граб это отдельное устройство, которое из общего с брелком имеет только трансивер.
Вы еще не поняли что это просто малолетний троль который только учится "мурчать по понятиям" (или бездарно пытается изобразить подобную роль)?
А ссылки, на сайты.... ну не нужно, а? Ведь действительно для подростков это "заманчиво и романтично", а способности предвидеть последствия - еще ослаблены. Понятно, что "кто хочет тот найдет", только зачем же "вводить во искушение?" :) Разве без этого нет интерестных применений контроллерым знаниям?