Страницы

Поиск по вопросам

четверг, 26 декабря 2019 г.

Отличие “картинок с сюрпризом” от обычных изображений.

#изображения


На создание данного поста меня вдохновило это, это и это.
Если эти rarjpeg'и можно создать, значит можно и определить их среди обычных "невинных"
изображений. Под подозрение сразу попадают .jpg и .png. А как же отличить раржпег от
обычной картинки? 
Банальное сравнение размера (если, например, картинка больше 10 Мб, то она может
быть раржпегом) не поможет - могут быть разные размеры: картинка 10Кб с спрятанным
в ней однострочным текстовиком или большая фотография с довольно большим аудиофайлом
внутри. Как бы вы отличили?
Я бы сделал так: расчитываем размер изображения (высота*ширина*глубина_цвета) и сравниваем
его с настоящим размером файла. Не сошлось - значит раржпег. Но как же тогда расчитать
размер EXIF и сжатие (у jpg), они же тоже часть изображения?
UPDATE Написал рабочий (довольно шустрый) алгоритм на Java (проверял на Android'e).
Спокойно работает с png+zip/rar, jpg+zip/rar.
//Определим заголовки файлов
String HEADER_RAR = "Rar!"; //Для .rar это будет Rar!
String HEADER_ZIP = new String(new BigInteger("504B0304", 16).toByteArray()); //а
для .zip будет "PK" и ещё два нечитаемых символа, поэтому мы получим их из HEX-кода

//создаём массив строк с путями к нужным изображениям (ArrayList mImages)
ArrayList mRarjpegs = new ArrayList(); //массив с путями к раржпегам

for (String path : mImages) { //проверяем каждый файл
    try {
        BufferedReader br = new BufferedReader(new FileReader(path));
        String line;
        while ((line = br.readLine()) != null) //открываем файл построчно...
            {
                if (line.contains(HEADER_RAR) || line.contains(HEADER_ZIP)) // ...если
в строке нашёлся заголовок одного из архивов...
                    {
                        mRarjpegs.add(path); // ...то добавим его в список раржпегов
                        break; // ...и выйдем из цикла, чтобы не считывать остальную
часть файла
                    }
                }
    } catch (Exception ex) { /* что-то своё */ }
}
//На выходе получим mRarjpegs, наполненный путями
    


Ответы

Ответ 1



Я когда-то писал для себя подобное. Вроде работает. enum RJClassification { NotJpeg, JustJpeg, JpegWithUnrecognizedTail, JpegWithRarTail } static class RJClassifier { public static RJClassification Classify(byte[] data, out long payloadIndex) { payloadIndex = 0; JpegParser jpp = new JpegParser(data, 0); if (!jpp.HasJpegHeader()) return RJClassification.NotJpeg; var jpegEnd = jpp.SkipJpegHeader(); if (!jpegEnd.HasValue) return RJClassification.NotJpeg; var rrp = new RarParser(data, jpegEnd.Value); var rarStart = rrp.FindRarHeader(); if (!rarStart.HasValue) return RJClassification.JpegWithUnrecognizedTail; payloadIndex = rarStart.Value; return RJClassification.JpegWithRarTail; } } class RarParser { byte[] data; long startIndex; public RarParser(byte[] data, long startIndex) { this.data = data; this.startIndex = startIndex; } byte[] signature = { 0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00 }; public long? FindRarHeader() { // state machine int state = 0; for (long i = startIndex; i < data.LongLength; i++) { if (data[i] == signature[state]) { state++; if (state == signature.Length) return i + 1 - state; } else { if (state > 0) i--; // need to recheck the current byte state = 0; } } return null; } } JPEG parser чересчур длинный, положил сюда. Для других форматов картинок нужен, понятно, другой картиночный парсер. Или можно вообще без него, если скармливать RarParser'у ноль в качестве startIndex (но будет дольше и менее надёжно). Упс, кажется, код никогда не возвращает JustJpeg. Нужна ещё проверка после var jpegEnd = jpp.SkipJpegHeader();.

Комментариев нет:

Отправить комментарий