Версия для печати
Почти всё, что вы хотели узнать, но боялись спросить о Crc32. Продолжение
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=431Andrew Rybin
дата публикации 12-07-2001 15:54Почти всё, что вы хотели узнать, но боялись спросить о Crc32. Продолжение
После написания данной статьи я перебирал старые архивы и наткнулся на описание программы Locker разработанной в Институт математики АН Молдовы, Колесниковым Александром Евгеньевичем. Самой программы и алгоритмов её функционирования представлено не было. Далее приводится оригинальный текст описания:Традиционное использование CRC, в том числе и в области персо-нальных компьютеров - в контроллерах дисков, коммуникационных (XMODEM) и сетевых (Ethernet, Token Ring и др.) протоколах, предполагает размещение (передачу) значения CRC ПОСЛЕ блока информа-ции. Такой метод позволяет обнаружить практически все виды ЕСТЕСТВЕННЫХ ошибок в канале (физический сбой, помеха и пр.), но совершен-но не помогает в случае ошибок ИСКУССТВЕННЫХ (злонамеренные действия ПЕРЕХВАТЧИКА, например). Действительно, применительно к безопасности данных в файловой системе персонального компьютера, можно представить себе следующую ситуацию. Пусть фирма-разработчик пакета программ сопровождает свой пакет файлом типа README, в котором приведены значения CRC для всех исполняемых файлов пакета. Такая информация позволит однозначно определить, например, факт поражения вирусом по неизбежному изменению реальной CRC файла по отношению к приведенной в README. Однако обна-ружить злонамеренные действия пионера, сажающего в тело файла шутки ради вирус или троянскую компоненту и РЕДАКТИРУЮЩЕГО соответствующее значение CRC в README, таким способом не удастся принципиально. Если же предположить, что значение CRC блока данных находится ВНУТРИ этого блока (не рассматривая пока вопрос о том, как это сделать), то подобные действия пионера будут серьезно затруднены: при попытке редактирования блока произойдет рассогласование реальной CRC и записанного внутри блока значения, причем согласовать их снова (в случае использования достаточно мощного CRC алгоритма, например, CRC32) будет практически невозможно. Как поместить в тело файла значение его CRC32? Пусть дан исход-ный файл. Определим его CRC32 и попытаемся добавить полученное зна-чение к исходному файлу. Это получится, однако при редактировании значение CRC файла безнадежно изменится. Из теоретических соображе-ний, приведенных в литературе, следует, что для согласования ("балансирования") в этом случае достаточно 64 бит или 8 байт (удвоенная длина используемого сдвигового регистра), однако теория ничего не говорит о том, как эти 8 байт определить. Несмотря на то, что психологически 8 байт выглядят как ерунда, найти нужное значение прямым перебором всех 2^64 возможных комбинаций в течение ближайших пятилеток не представляется возможным.Происходило это всё в воскресный день, и я решил развлечения ради написать программу с аналогичными функциями. Рассмотрев что дано и что требуется мною была написана процедура:procedure Crc32UpdateDelta (CrcFrom, CrcTo: LongWord; lpData: Pointer);гдеСначала я написал процедуру генерирующую 8 байт, но немного подумав сократил количество корректирующих CRC32 байт до 4х. После этого я перепробовал её на разных файлах и разных поверяльщиках CRC32. Итоги были одинаковы - сгенерированные процедурой байты приводят CRC32 к нужному. Существенным ограничением является то, что образующий полином для процедуры Crc32UpdateDelta и поверяльщика должны (скорее всего ;-) совпадать, НО учитывая то что стандартом де-факто во всех программах считающих CRC32 (пр: RAR и pkZIP) является $EDB88320, то ограничение почти не существенно. Исходный код (распространяется по принципу GratitudeWare - если вы имеете с этого выгоду, автор хочет получить презент ;-).
- CrcFrom - CRC32 файла испорченного хакером
- CrcTo - CRC32 оригинального файла, т.е. то к которому надо привести
- LpData - указатель на область памяти в которую будут занесены корректировочные байты
function StepBack (Crc: LongWord): LongWord;//>Index var i: Integer; Begin Result:=0; for i:=0 to 255 do if ((CRC32Table[i] xor Crc) shr 24)=0 then begin Result:=i; EXIT; end; End;//StepBack - индекс элемента массива с HiByte=Crc var Crc,A,B,C,D: LongWord; P: PChar; Begin P:=lpData; CrcFrom:=Crc32Done(CrcFrom);//привести к истинному виду CrcTo:=Crc32Done(CrcTo); //1.DCBA - поиск в таблице индексов элементов со старшими байтами образующими новый CRC32 D:=StepBack(CrcTo); CrcTo:=(CrcTo xor Crc32Table[D]) shl 8; C:=StepBack(CrcTo); CrcTo:=(CrcTo xor Crc32Table[C]) shl 8; B:=StepBack(CrcTo); CrcTo:=(CrcTo xor Crc32Table[B]) shl 8; A:=StepBack(CrcTo); //2. (X xor Crc) xor Crc = X - зная какие элементы таблицы формируют // нужный CRC - просто подставляем их Crc:=CrcFrom; P^:=chr(A xor Crc); Crc:=(Crc shr 8) xor Crc32Table[A]; //*Crc32Table[Crc]; inc(P); P^:=chr(B xor Crc); Crc:=(Crc shr 8) xor Crc32Table[B]; inc(P); P^:=chr(C xor Crc); Crc:=(Crc shr 8) xor Crc32Table[C]; inc(P); P^:=chr(D xor Crc); End;//Crc32UpdateDeltaAndrew P.Rybin
Специально для Королевства Delphi