Misja Gynvaela 013 cd.

{Kontynuacja posta Misja Gynvaela 013}

 

Prostsze rozwiązanie

Rozwiązanie tej misji mogło potoczyć się trochę inaczej, gdybym po rozpakowaniu obrazu przez binwalka, najpierw zajrzał do środka za pomocą jakiegoś HEX Edytora. Możliwe, że zauważyłbym występujące w niektórych miejscach bajty 01.

Pojawiają się one na początku wiersza obrazu, a właściwie przed pierwszym pixelem wiersza. Jeśli podzielimy rozpakowany rozmiar pliku 1920800 / 800 otrzymiemy 2401. Wynika z tego, że każdy wiersz poprzedzony jest jednym bajtem 2401=800*3+1.

Kod rozwiązania misji mógłby wyglądać wtedy jeszcze prościej:

Oczywiście przesunięcie bitowe b>>3 jest równoważne z dzieleniem b/8, a b&0x7 z resztą z dzielenia b%8, jednak pomimo tego, że w C# programuję już ponad 2 lata to jakoś mu nie ufam. W C++ to wiadomo, że kompilator takie oczywiste operacje jak dzielenie przez potęgę dwójki zamienia na przesunięcia bitowe. To jest dobre bo operacja dzielenia jest bardzo kosztowna. W C# tego już nie jestem pewien, no w każdym bądź razie, gdy mamy operacje dzielenia i reszty, a następnie otworzymy okienko Disassembly to widzimy dwa razy idiv, zamiast sar i and. Może dopiero przy release takie optymalizacje robi.

Muszę przyznać, że to zwięzłe rozwiązanie przyszło mi do głowy po tym, jak przeczytałem sposób rozwiązania, który opisuje Lucas Geras na swoim blogu. On także skorzystał z binwalka, a następnie zamienił wszystkie białe piksele na czarne. To pozwoliło mu zobaczyć wystąpienie “dziwnej linii”, której piksele były oddalone od siebie o 2401. Zamienił piksele na bity, bity na bajty i wyszło rozwiązanie.

 

Porządny HEX Edytor

Mieć porządny Hex Edytor naprawdę warto. Zobaczyłem to dopiero teraz, kiedy znalazłem przyjemny i darmowy Hex Editor Neo. Wersja darmowa jest mocno okrojona, ale podstawowe funkcje są dostępne i co było dla mnie dużym zaskoczeniem jest też dostępy Structure Viewer. Pozwala on na wyświetlenie struktury pliku w przyjazny sposób (rysunek 1). Rozpoznaje 20 różnych typów plików. Jeśli wersja free nie będzie wystarczająca to można zakupić wersję standard za $24,99 (około 91 zł) lub wyższe wersje. Mając taki edytor nie trzeba się tak męczyć z analizowaniem struktury pliku. Teraz dokładnie wiać gdzie siedzą dane obrazu. (Edit: Po 30 dniach Structure Viewer przestał działać. Jednak to była wersja 30-dniowa… ale i tak dużo w nim można zrobić)

Rysunek 1

No dobrze, mamy blok ImageData, ale więcej informacji o tym, co to są za dane, już nie mamy. Teraz trzeba zajrzeć do specyfikacji (Portable Network Graphics (PNG) Specification), ale żeby się nie przestraszyć, to proponuję najpierw zajrzeć do plakatów corkami.

Dane są zapisane w formacie zlib. Mógłbym podać rozwiązanie korzystając z jakiegoś NuGeta np. zlib.net, ale na blogu, który prowadzi Czang zobaczyłem ciekawsze rozwiązanie. Skoro dane są spakowane algorytmem Deflate to można skorzystać z dostępnej klasy DeflateStream. Trzeba tylko pominąć pierwsze 2 bajty informujące o metodzie kompresji i flagach.

Rozkompresowanie danych obrazu w C# będzie wyglądać tak:

No i to by było na tyle.

Chciałbym jeszcze tutaj wspomnieć o dwóch rozwiązaniach w JavaScript uruchamianych na Node.js. Wielki szacun dla argeento, który przeanalizował krok po kroku strukturę pliku PNG i opisał w jaki sposób dobrać się do danych obrazu. Rozwiązanie misji też ma ciekawe, bo zrobił to prawie identycznie jak ja. Zinterpretował czarne i białe linie jako bity. Ciekawe jest to, że udało mu się to zrobić z obrazu wczytanego do formatu RGB, czyli tego przekrzywionego. Polecam tam zajrzeć.

Drugie rozwiązanie JavaScriptowe napisane zostało przez Sceptero. Krótkie zwięzłe i na temat. Po rozkompresowaniu danych obrazu przechodzi po wszystkich blokach (wierszach) i zczytuje pierwszy bajt, a następnie zamienia na tekst. Podobne jest do rozwiązania Lucasa Gerasa.

To może teraz w JavaScripcie spróbujemy to skrócić.

 

Perfekcyjna steganografia

Ta misja to idealny przykład steganografii. Tajna informacja została zaszyta w obrazie, ale wynikowy obraz nie został naruszony. Gdzie siedziały więc informacje?

Każdy wiersz danych obrazu PNG, poprzedzony jest dodatkowym bajtem informującym o filtrze zastosowanym na wierszu (specyfikacja PNG – Filtry). Filtr modyfikuje bajty w taki sposób, żeby można było odwrócić jego działanie podczas otwierania obrazu. Takie modyfikacje umożliwiają polepszenie kompresji, jest to pole do popisu dla algorytmu kompresującego.

Pole filtra jest zatem miejscem gdzie można ukryć informacje. Jeśli mamy władzę nad sposobem generowania pliku, to możemy zastosować dowolny filtr i przygotować dane w taki sposób, aby wynikowy obraz nie został zmieniony.

W misji 013 użyty jest filtr 0 oraz 1. Filtr 0 nie modyfikuje danych, natomiast 1 działa w taki sposób, że kolor pixela w wierszu obliczany jest przez odjęcie koloru poprzedniego pixela. Dlatego właśnie na rozkompresowanych danych pojawiały się czarne paski.

Rysunek 2

Na rysunku 2 znajduje się początkowy fragment obrazu po rozkompresowaniu (Indexed). Pierwsze wiersze są białe, czyli wypełnione wartościami FF. Zastosowany jest filtr 0 czyli dane pozostają bez zmian.

W czwartym wierszu użyty jest filtr 1 (czyli odejmowanie koloru poprzedniego). Pierwszy piksel pix1 pozostaje bez zmian, bo poprzedzającego go piksela nie ma. Następny piksel pix2_new powstaje przez odjęcie:

Kolejny piksel także ma wartość 0, bo do odejmowania bierzemy wartości przed modyfikacją. Obliczamy tak samo do końca wiersza. Te operacje należy wykonać osobno na każdym kanale, a także na kanale alfa jeśli jest dostępny.

Podczas otwierania obrazu wykonywana jest operacja odwrotna, czyli tak jak w dokumentacji pisze, poprzedni piksel dodawany jest do odczytanego. W tym wypadku obliczenie pix2 wygląda następująco:

Różnica jest tutaj taka, że do sumowania bierzemy piksel poprzedni po modyfikacji.

Teraz już widać dlaczego w GIMPie po wczytaniu surowych danych pojawiły się czarne linie na obrazku. Pojawiają się one tam, gdzie filtrowanie ustawione jest na 1. Z tego powodu właśnie, misję można było rozwiązać także interpretując czarne i białe linie jako bity.

 

Wniosek do zapamiętania:

Jeśli algorytm otwierający (dekodujący) dany format pliku umożliwia zdekodowanie tych samych danych dla różnych danych wejściowych, to można w takim pliku ukryć jakieś informacje.

Post Author: marbel82

1 thought on “Misja Gynvaela 013 cd.

    […] Editor Neo jest świetnym narzędziem do tego, o czym pisałem wcześniej (Misja Gynvaela 013 cd.), pomimo tego, iż skubany okazał się 30-dniową wersją pro i teraz ograniczył trochę swoją […]

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.