Obliczanie Podobieństwa Danych Binarnych

Widziałem tu kilka pytań związanych z określeniem podobieństwa plików, ale wszystkie są powiązane z konkretną domeną (obrazy, dźwięki, tekst itp.). Techniki oferowane jako rozwiązania wymagają znajomości podstawowego formatu plików porównywanych plików. To, czego szukam, to metoda bez tego wymogu, w której dowolne pliki binarne mogą być porównywane bez potrzeby rozumienia, jakiego typu dane zawierają. Czyli Szukam określenia procent podobieństwa danych binarnych dwóch plików .

Aby dać trochę więcej szczegółów, z którymi możesz pracować, mimo że potencjalnie dotyczy to wielu rzeczy, mam konkretny problem, nad którym pracuję. Obecnie również mam rozwiązanie działające, ale nie sądzę, że jest idealne. Prawdopodobnie istnieje wiele optymalizacji pod względem metody porównywania i przechowywania wyników. Mam nadzieję, że niektórzy ludzie tutaj będą mogli dać mi kilka nowych pomysłów. Prawdopodobnie będę edytował w niektórych informacjach o mojej obecnej metodzie po kilku dniach, ale nie chcę uprzedzać ludzi myśli o problemie, mówiąc, jak już to robię.

Problem, nad którym pracuję, to wykrywanie klonów dla obrazów ROM gier wideo. Dla tych, którzy nie mają doświadczenia z emulacją, ROM to zrzuty danych z kartridży z Grami. ROM "klon" jest zazwyczaj zmodyfikowaną wersją tej samej gry, najczęściej jest to wersja przetłumaczona. Na przykład Japońskie i angielskie wersje oryginalnego Final Fantasy dla NES są klonami. Gry dzielą prawie wszystkie swoje atuty (sprity, muzyka itp.), ale tekst został przetłumaczony.

Obecnie istnieje kilka grup, które pracują nad utrzymaniem list klonów dla różnych systemów, ale z tego co wiem, wszystko odbywa się ręcznie. Próbuję znaleźć metodę automatycznego i obiektywnego wykrywania podobnych obrazów ROM na podstawie podobieństwa danych z "these seem like the same game". Istnieje kilka powodów wykrywania klonów, ale jedną z głównych motywacji jest użycie kompresji stałej. Pozwala to na kompresję wszystkich klonów gry w jedno archiwum, przy czym cały skompresowany zestaw klonów często zajmuje tylko nieco więcej miejsca niż jeden z pojedynczych ROM-ów.

Niektóre obawy do rozważenia przy wymyślaniu potencjalnych podejść:

  • Romy różnią się wielkością, w zależności od system. Niektóre są małe, ale nowoczesne systemy mogą mieć duże, 256MB lub więcej. Niektóre (Wszystkie?) systemy mają tylko 2 Jak to możliwe rozmiary, gra 130MB na jednym z tych systemów miałaby 256MB rom, w dużej mierze pusty. Zauważ, że z tego powodu niektóre klony mogą mieć szalenie różne rozmiary, jeśli wersja gry przekracza próg i musi użyć kasety, która jest dwukrotnie większa.
  • obecnie istnieją tysiące znanych ROM-ów na wielu systemach, przy czym większość systemów wciąż ma nowe zwolniony stale. Nawet w przypadku starszych systemów istnieje duża społeczność hakerów ROM, która często produkuje zmodyfikowane Romy.
  • przechowywanie danych podobieństwa dla każdej możliwej pary ROM-ów skutkowałoby milionami wierszy danych dla każdego z bardziej popularnych systemów. System z 5000 ROM wymagałby 25 milionów wierszy danych podobieństwa, z jedną nową grą dodając kolejne 5000 wierszy.
  • Stan przetwarzania musi być możliwy do odzyskania, tak aby w przypadku jego przerwania mógł odebrać koniec. Przy każdej metodzie wymagane będzie dużo przetwarzania, a założenie, że całość będzie działać w jednej partii, nie jest bezpieczne.
  • nowe Romy mogą być dodane w dowolnym momencie, więc metoda nie powinna zakładać, że ma już" kompletny " zestaw. Oznacza to, że nawet po tym, jak już obliczyłeś podobieństwo dla wszystkich istniejących ROM-ów, jeśli zostanie dodany nowy (co może również wystąpić przed całkowitym zakończeniem poprzedniego przetwarzania), musi istnieć metoda porównywania go ze wszystkimi poprzednimi, aby określić, który (jeśli w ogóle) jest klonem.
  • wyższa prędkość przetwarzania powinna być traktowana priorytetowo nad dokładnością (do punktu). Wiedząc, czy dwa ROM są 94% lub 96% podobne nie jest szczególnie ważne, ale jeśli zajmie jeden dzień przetwarzania, aby porównać nowy ROM do wszystkich poprzednich, program prawdopodobnie nigdy naprawdę zakończyć.

To był ciekawy problem do pracy, czekam na to, co inni ludzie mogą wymyślić. Dajcie znać w komentarzach jeśli chcesz więcej szczegółów, postaram się je dostarczyć.

Author: Chad Birch, 2009-02-24

10 answers

Brzmi to tak, jakbyś chciał deltę binarną lub indeks pochodzący z zastosowania delty binarnej (jak jej rozmiar). Następnie możesz porównać ten indeks do jakiejś linii bazowej, którą ustalasz eksperymentalnie, aby zdecydować, czy jest to "klon", czy nie.

Istnieje wiele podobieństw między kompresją a tworzeniem delty, więc powiedziałbym, że nie jesteś daleko od obecnej implementacji.

Biorąc to pod uwagę, porównanie parami KAŻDEGO pliku binarnego w Twojej bazie danych jest prawdopodobnie zbyt drogie (O (n2), myślę). Chciałbym spróbować znaleźć prosty hash do identyfikacji potencjalnych kandydatów do porównania. Coś koncepcyjnie podobnego do tego, co sugerują spdenne i Eduard. Oznacza to, że znajdź hash, który można zastosować do każdego elementu raz, posortuj tę listę, a następnie użyj drobniejszego porównania dla elementów, których hasze są blisko siebie na liście.

Konstruowanie hashów przydatnych w ogólnym przypadku było aktywnie badanym tematem w CS dla kilka lat. Biblioteka lshkit implementuje niektóre algorytmy tego typu. Artykuł dostępny w Internecie znajdowanie podobnych plików w dużym systemie plików wydaje się być bardziej ukierunkowany na porównywanie plików tekstowych, ale może być dla Ciebie przydatny. Nowszy Artykuł multi-resolution similarion hashing opisuje potężniejszy algorytm. Nie wydaje się jednak, aby był dostępny bez subskrypcji. Prawdopodobnie chcesz zachować artykuł w Wikipedii NA local Sensitive Hashing przydatne podczas przeglądania innych zasobów. Wszystkie są dość techniczne, a sam wpis w Wikipedii jest dość ciężki matematycznie. Jako bardziej przyjazną dla użytkownika alternatywę możesz zastosować niektóre pomysły (a nawet pliki wykonywalne) z dziedziny Acoustic Fingerprinting.

Jeśli chcesz porzucić ogólny przypadek, prawdopodobnie znajdziesz znacznie prostszą (i szybszą) funkcję haszującą dla domeny, która działa tylko dla Twoich ROM-ów. Prawdopodobnie coś związanego z umieszczeniem standardowych lub wspólnych sekwencji bajtów i wartości wybranych bitów w pobliżu nich. Nie wiem zbyt wiele o Twoim formacie binarnym, ale wyobrażam sobie rzeczy, które sygnalizują początek sekcji w pliku, takich jak regiony dźwięku, obrazy lub tekst. Formaty binarne często przechowują adresy tego rodzaju sekcji w pobliżu początku pliku. Niektórzy używają również mechanizmu łańcuchowego, który przechowuje adres pierwszej sekcji w znanej lokalizacji wraz z to Rozmiar. Pozwala to przejść do następnej sekcji, która również zawiera rozmiar, itp. Małe dochodzenie prawdopodobnie pozwoli Ci odkryć odpowiednie formatowanie, jeśli nie jesteś jeszcze tego świadomy, i powinno cię dobrze przygotować do zbudowania użytecznego hasha.

Jeśli funkcje hashujące nie dają Ci pełnego dostępu (lub wymagają pewnego rodzaju danych wejściowych do zdefiniowania metryki/odległości), To istnieje kilka binarnych algorytmów i implementacji delta dostępnych w sieci. The one I ' m najbardziej znany jest używany przez system kontroli wersji subversion. Wykorzystuje binarny algorytm delta o nazwie xdelta do efektywnego przechowywania wersji plików binarnych. Oto link bezpośrednio do pliku w repozytorium, który go implementuje: xdelta.c . Prawdopodobnie w sieci jest narzędzie, które czyni to bardziej dostępnym.

 22
Author: Waylon Flinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-02 15:56:23

Warto przyjrzeć się bsdiff , który jest binarnym systemem różnicowania/łatania. Istnieje również teza z dużą ilością teorii.

 11
Author: jpalecek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 00:30:42

Użyj kilku pomysłów z algorytmów wykrywania Plagiatów .

Mój pomysł:

W celu stworzenia porównywalnej "sygnatury" dla każdego ROM, która zmienia się nieznacznie w miarę zmiany małych porcji, tworząc coś w rodzaju wykresu częstotliwości słów, ale zamiast rejestrować częstotliwości słów, możesz hashować bardzo krótkie sekcje ROM i rejestrować częstotliwości wartości skrótu.

Nie tylko hashować jedną sekcję, a następnie następną sekcję rozpoczynającą się od końca pierwszej sekcja, ale zamiast tego użyj przesuwanego okna, hashując sekcję począwszy od bajtu 1, następnie hashując sekcję tej samej wielkości począwszy od bajtu 2, potem od bajtu 3, itd. To zaneguje efekt zmiennych rozmiarów różnych części w Twoim ROM.

Jeśli użyłeś prostej funkcji skrótu, takiej jak xor każdego 8-bitowego bajtu, dzięki czemu możesz łatwo obliczyć hash następnej pozycji okna przez XOR bieżący hash z wychodzących 8 bitów i XOR przychodzących 8 bitów. Inna alternatywna funkcja hashowania może być po prostu użycie długości słowa kodu instrukcji. Może to wystarczyć do stworzenia statycznych wzorców dla kodów reprezentujących instrukcje maszynowe. Ważne jest to, że będziesz potrzebował funkcji skrótu, która powoduje wspólne krótkie sekwencje w kodzie instrukcji, co skutkuje tymi samymi wartościami skrótu.

Prawdopodobnie chcesz mniej wartości skrótu z wyższymi częstotliwościami każdego z nich, ale nie idź za daleko, bo twój wykres będzie zbyt płaski, co spowoduje trudności w porównaniu ich. Podobnie nie idź zbyt szeroko, bo będziesz miał wiele bardzo małych częstotliwości, co ponownie trudne porównanie.

Zapisz ten wykres na ROM. Porównaj wykresy częstotliwości dla dwóch różnych ROM, obliczając sumę kwadratów różnicy częstotliwości dla każdej wartości skrótu. Jeśli suma ta wynosi zero, to Rom prawdopodobnie będzie identyczny. Im dalej od zera, tym mniej podobne będą Romy.

 7
Author: Stephen Denne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-05 10:24:14

Choć minęło dużo więcej niż "kilka dni", pomyślałem, że powinienem dodać moje obecne rozwiązanie tutaj.

Nils Pipenbrinck szedł w tym samym kierunku, co moja obecna metoda. Ponieważ jednym z głównych wyników znajdowania klonów jest ogromne oszczędności dzięki solidnej archiwizacji, pomyślałem, że mogę po prostu spróbować skompresować dowolne dwa Romy razem i zobaczyć, ile miejsca zostało zaoszczędzone. Używam do tego algorytmu LZMA w 7zip .

Pierwszym krokiem jest skompresowanie każdego Pojedynczo i zanotuj rozmiar skompresowany, a następnie spróbuj zarchiwizować dowolne dwa Romy razem i zobacz, jak bardzo wynikowy rozmiar różni się od ich indywidualnych skompresowanych rozmiarów. Jeśli łączna wielkość jest taka sama jak suma poszczególnych rozmiarów, są one o 0% podobne, a jeśli wielkość jest taka sama jak jedna z nich (największa), są identyczne.

Teraz, jest to ogromna liczba prób kompresji wymagane, więc mam kilka optymalizacji do tej pory (i chciałbym dowiedzieć się więcej):

  1. Ustalanie priorytetów porównań na podstawie podobieństw skompresowanych rozmiarów. Jeśli ROM A ma skompresowany rozmiar 10MB, a ROM B ma skompresowany rozmiar 2MB, nie jest możliwe, aby były podobne o więcej niż 20%, więc porównanie ich w celu uzyskania rzeczywistego wyniku może zostać pozostawione na później. Uruchomienie tego samego algorytmu kompresji na bardzo podobnych plikach powoduje wyniki o podobnej wielkości, więc bardzo szybko znajduje to wiele klonów.

  2. W połączeniu z powyżej, zachowaj zarówno górną, jak i dolną "granicę" na możliwym podobieństwie między dowolną parą Romów. Pozwala to na dalsze ustalanie priorytetów. Jeśli ROM A i B są podobne w 95%, A ROM B I C są tylko 2% podobne, to już wiesz, że A I C są między 0% a 7%. Jest to zbyt niskie, aby być klonem, więc porównanie to można bezpiecznie odłożyć lub nawet całkowicie zignorować, chyba że naprawdę chcę znać dokładne podobieństwa wszystkiego.

 6
Author: Chad Birch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-03 15:35:01

Myślę, że niektóre techniki zapożyczone z kompresji danych mogą być tutaj interesujące:

Załóżmy, że masz dwa pliki, A I B.

Kompresuj każdy plik indywidualnie i dodaj skompresowane rozmiary razem. Następnie połącz oba pliki w jeden, duży plik i skompresuj go.

Różnica w rozmiarach da ci przybliżone oszacowanie, jak podobne są pliki.

Proponuję wypróbować transformację Burrowa Wheelera (bzip2), aby wykonać kompresję. Większość innych algorytmów kompresji ma tylko ograniczoną historię. Algorytm BWT otoh może pracować na bardzo dużych fragmentach danych. Algorytm "widzi" oba pliki w tym samym czasie, a każde podobieństwo spowoduje wyższy współczynnik kompresji.

 3
Author: Nils Pipenbrinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 02:54:00

XDelta jest całkiem przydatna do uzyskiwania porządnych binarnych diffów: http://xdelta.org

 2
Author: Rik Hemsley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 12:02:08

Możesz zacząć od przechowywania czegoś w rodzaju hash trees . Dla każdego ROM jest potrzebny tylko jeden taki zestaw skrótów, a wymagana przestrzeń dyskowa jest tylko proporcjonalna (ale znacznie mniejsza od) rozmiaru ROM, przy założeniu stałej wielkości bloku. Wybrany rozmiar bloku musi dawać wystarczającą ziarnistość, aby zapewnić dokładność, np.: dla minimalnego rozmiaru 128mib, ograniczenie dokładności 1% i Tiger-128 hash (podobny do tego, którego używają do sprawdzania plików przesyłanych przez DirectConnect), blok o rozmiarze 1mib działa dobrze i można przechowywać wszystkie hasze w 128 * 128 / 8 = 2048 bajtów! Tak więc robienie tego dla 10,000 ROM wymagałoby tylko około 20MB miejsca. Co więcej, możesz wybrać mniej bezpieczny, ale szybszy i/lub mniejszy hash. Dodawanie / sprawdzanie podobieństwa nowy ROM pociąga za sobą coś w stylu:

  1. podziel nowy ROM na bloki i hashuj każdy z nich.
  2. dla każdego ROM już w bazie danych, porównaj (patrz poniżej) jego skróty z nowymi ROM ' AMI hashes.

Funkcja porównywania powinna sprawdzać podobieństwo. Powinien jednak traktować każdy hash jako niepodzielną wartość, tzn. nie trudzić się szukaniem logicznie znaczącej funkcji różnicy między dwoma hashami. Tak długo, jak rozmiar bloku jest wystarczająco niski, a kolizje hashów są wystarczająco rzadkie, dokładność jest gwarantowana przez proste porównanie is-equal.

Jak widzisz, problem sprowadza się do prostszego pod względem wydajności: sprawdzania znacznie mniejszych zestawów danych pod kątem podobieństwa.

 1
Author: Eduard - Gabriel Munteanu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 02:45:12

Dwie myśli:

  • rozważ zorganizowanie pliku jako wykresu przepływu danych i dokonaj kanonicznej klasyfikacji tego represjonowania. Ponieważ znasz zestaw instrukcji, może to być wykonalne, może po prostu przywiązanie disassemblera i przetwarzanie tekstu.
  • klasyfikator trainable, taki jak CRM114 może się przydać, aby dać ci zwartą reprezentację, która daje ci pewne pojęcie, czy binaria mają wiele wspólnego.
 1
Author: Liudvikas Bukys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-24 03:09:54

Jak powiedział Waylon Flinn, możesz potrzebować binarnego algorytmu delta. Algorytm rsync jest dobry. Jest szybki i niezawodny. Zobacz także dokumentację narzędzia .

 1
Author: Yuval F,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-08 13:01:57

Trudność polega na tym, że ponieważ masz do czynienia z kodem wykonywalnym, proste zmiany mogą rozprzestrzeniać się w całej pamięci ROM. Adresy i przesunięcia dla wszystkich wartości mogą się zmieniać po dodaniu pojedynczej zmiennej lub instrukcji no-op. To uczyni nawet blokowe hashowanie bezwartościowym.

Szybkim i brudnym rozwiązaniem byłoby zhakowanie rozwiązania za pomocą difflib (lub równoważnego w / ulubionym języku), ponieważ daje Ci przesuwne porównanie, które może radzić sobie z danymi dodawanie lub usuwanie. Podziel ROM na sekcje wykonywalne i dane (jeśli to możliwe). Sekcja danych może być porównana bezpośrednio i współczynnik podobieństwa obliczony , choć nadal będziesz miał problemy z / adresami lub przesunięciami.

Sekcja wykonywalna jest ciekawsza. Odczytaj format ASM maszyny, weź plik wykonywalny i podziel go na sekwencję kodów opcodes. Pozostaw kod opcode i zarejestruj części, ale zamaskuj części "payload" / " immediate "(gdzie ładuje zmienne adresy). Podaj wynikowe informacje do kalkulatora współczynnika podobieństwa.

Niefortunną częścią jest to, że jest to nadal operacja O(n^2) na liczbie pamięci ROM, które śledzisz, ale można to złagodzić za pomocą (przyrostowego) klastrowania lub kolejności porównywania opartej na częstotliwości, aby zmniejszyć ilość potrzebnych porównań.

 1
Author: HUAGHAGUAH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-08 19:47:22