Jak zablokować skompilowane klasy Java, aby zapobiec dekompilacji?
Wiem, że to musi być bardzo dobrze omawiany temat w Internecie, ale nie mogłem dojść do żadnego wniosku po ich skierowaniu.
Wiele osób sugeruje obfuscator, ale po prostu zmieniają nazwy klas, metod i pól za pomocą trudnych do zapamiętania sekwencji znaków, ale co z wrażliwymi wartościami stałymi?
Na przykład opracowałeś komponent szyfrowania i deszyfrowania w oparciu o technikę szyfrowania opartą na hasłach. W tym przypadku każda przeciętna osoba korzystająca z języka Java może użyć JAD do dekompilacji pliku klasy i łatwego pobrania wartości hasła (zdefiniowanej jako stała), a także soli, a następnie może odszyfrować dane, pisząc mały niezależny program!
A może takie wrażliwe komponenty powinny być wbudowane w kod natywny (na przykład VC ++) i wywoływać je za pośrednictwem JNI ?
źródło
Odpowiedzi:
Niektóre z bardziej zaawansowanych obfuskatorów kodu bajtowego Java robią znacznie więcej niż tylko zniekształcanie nazw klas. Na przykład Zelix KlassMaster może również zakodować przepływ kodu w sposób, który sprawia, że jest naprawdę trudny do naśladowania i działa jako doskonały optymalizator kodu ...
Ponadto wielu obfuskatorów jest w stanie zaszyfrować stałe łańcuchowe i usunąć nieużywany kod.
Innym możliwym rozwiązaniem (niekoniecznie wykluczającym zaciemnianie) jest użycie zaszyfrowanych plików JAR i niestandardowego modułu ładującego klasy, który odszyfrowuje (najlepiej przy użyciu natywnej biblioteki wykonawczej).
Po trzecie (i prawdopodobnie zapewniające najsilniejszą ochronę) jest użycie natywnych kompilatorów wyprzedzających, takich jak na przykład GCC lub Excelsior JET , które kompilują kod Java bezpośrednio do natywnego pliku binarnego specyficznego dla platformy.
W każdym razie musisz o tym pamiętać, jak mówi estońskie przysłowie „Zamki są dla zwierząt”. Oznacza to, że każdy bit kodu jest dostępny (załadowany do pamięci) w czasie wykonywania i mając wystarczające umiejętności, determinację i motywację, ludzie mogą i będą dekompilować, rozszyfrować i zhakować Twój kod ... Twoim zadaniem jest po prostu uczynić proces tak niewygodnym jak możesz i nadal to działa ...
źródło
Dopóki mają dostęp zarówno do zaszyfrowanych danych, jak i do oprogramowania, które je odszyfrowuje, w zasadzie nie ma sposobu, aby uczynić to całkowicie bezpiecznym. Sposób, w jaki zostało to wcześniej rozwiązane, polega na użyciu jakiejś formy zewnętrznej czarnej skrzynki do obsługi szyfrowania / deszyfrowania, takiej jak klucze sprzętowe, zdalne serwery uwierzytelniające itp. Ale nawet wtedy, biorąc pod uwagę, że użytkownik ma pełny dostęp do własnego systemu, trudne, a nie niemożliwe - chyba że możesz powiązać swój produkt bezpośrednio z funkcjonalnością przechowywaną w „czarnej skrzynce”, jak na przykład serwery gier online.
źródło
Zastrzeżenie: nie jestem ekspertem w dziedzinie bezpieczeństwa.
To brzmi jak zły pomysł: pozwalasz komuś zaszyfrować rzeczy za pomocą „ukrytego” klucza, który mu dajesz. Nie sądzę, aby można to było zabezpieczyć.
Może klawisze asymetryczne mogą działać:
Nie jestem pewien, ale uważam, że klient może faktycznie zaszyfrować klucz licencyjny za pomocą klucza publicznego, który mu podałeś. Następnie możesz go odszyfrować za pomocą klucza prywatnego i ponownie zaszyfrować.
Możesz zachować oddzielną parę kluczy publiczny / prywatny dla każdego klienta, aby upewnić się, że faktycznie otrzymujesz dane od właściwego klienta - teraz jesteś odpowiedzialny za klucze ...
źródło
Bez względu na to, co robisz, można to „zdekompilować”. Heck, możesz go po prostu zdemontować. Lub spójrz na zrzut pamięci, aby znaleźć swoje stałe. Widzisz, komputer musi je znać, więc twój kod też będzie musiał.
Co z tym zrobić?
Staraj się nie wysyłać klucza jako stałej zakodowanej na stałe w kodzie: zachowaj go jako ustawienie dla użytkownika. Spraw, aby użytkownik był odpowiedzialny za opiekę nad tym kluczem.
źródło
@jatanp: lub jeszcze lepiej, mogą dekompilować, usuwać kod licencyjny i ponownie kompilować. Wydaje mi się, że w przypadku Javy nie ma odpowiedniego, odpornego na włamania rozwiązania tego problemu. W Javie nawet zły, mały klucz sprzętowy nie mógłby temu zapobiec.
Moi menedżerowie biznesu martwią się tym i myślę za dużo. Ale z drugiej strony sprzedajemy naszą aplikację dużym korporacjom, które zwykle przestrzegają warunków licencji - generalnie bezpiecznego środowiska dzięki licznikom fasoli i prawnikom. Sama dekompilacja może być nielegalna, jeśli twoja licencja jest napisana poprawnie.
Muszę więc zapytać, czy naprawdę potrzebujesz wzmocnionej ochrony, tak jak szukasz dla swojej aplikacji? Jak wygląda Twoja baza klientów? (Korporacje? Lub nastoletnie masy graczy, gdzie byłby to większy problem?)
źródło
Jeśli szukasz rozwiązania licencyjnego, możesz sprawdzić TrueLicense API . Opiera się na wykorzystaniu asymetrycznych klawiszy. Nie oznacza to jednak, że Twoja aplikacja nie może zostać złamana. Każda aplikacja może zostać złamana przy wystarczającym wysiłku. Jak odpowiedział Stu , naprawdę ważne jest ustalenie, jak silnej ochrony potrzebujesz.
źródło
Nie sądzę, aby istniała jakakolwiek skuteczna metoda antypiracka offline. Branża gier wideo próbowała to odkryć wiele razy, a ich programy zawsze były łamane. Jedynym rozwiązaniem jest to, że program musi być uruchomiony w trybie online i połączony z serwerami, aby można było zweryfikować klucz lincense i że w danym momencie istnieje tylko jedno aktywne połączenie licencjobiorcy. Tak działa World of Warcraft lub Diablo . Nawet jeśli istnieją prywatne serwery opracowane dla nich, aby ominąć zabezpieczenia.
Powiedziawszy to, nie wierzę, że średnie / duże korporacje używają nielegalnie kopiowanego oprogramowania, ponieważ koszt licencji dla nich jest minimalny (być może nie wiem, ile zamierzasz zapłacić za swój program) w porównaniu z koszt wersji próbnej.
źródło
Możesz bez obaw korzystać z szyfrowania bajtowego.
Faktem jest, że cytowany powyżej artykuł „Cracking Java Bte-Code Encryption” zawiera błąd logiczny. Głównym założeniem artykułu jest to, że przed uruchomieniem wszystkie klasy muszą zostać odszyfrowane i przesłane do
ClassLoader.defineClass(...)
metody . Ale to nieprawda.Założenie pominięte w tym miejscu zakłada , że działają one w autentycznym lub standardowym środowisku wykonawczym Java . Nic nie może zmusić chronionej aplikacji Java nie tylko do uruchomienia tych klas, ale nawet do odszyfrowania i przekazania ich do
ClassLoader
. Innymi słowy, jeśli pracujesz w standardowym środowisku JRE, nie możesz przechwycićdefineClass(...)
metody, ponieważ standardowa java nie ma do tego celu interfejsu API, a jeśli używasz zmodyfikowanego środowiska JRE z poprawionąClassLoader
lub inną „sztuczką hakerską”, nie możesz tego zrobić, ponieważ jest chroniona Aplikacja java w ogóle nie będzie działać, dlatego nie będziesz mieć nic do przechwycenia. I absolutnie nie ma znaczenia, który „wyszukiwarka łatek” jest używany lub jaką sztuczkę wykorzystują hakerzy. Te szczegóły techniczne to zupełnie inna historia.źródło
P: Czy jeśli zaszyfruję moje pliki .class i użyję niestandardowego modułu ładującego klasy do załadowania i odszyfrowania ich w locie, czy zapobiegnie to dekompilacji?
O: Problem z zapobieganiem dekompilacji kodu bajtowego Javy jest prawie tak stary jak sam język. Pomimo szeregu narzędzi zaciemniających dostępnych na rynku, początkujący programiści Java wciąż zastanawiają się nad nowymi i sprytnymi sposobami ochrony swojej własności intelektualnej. W tej części poświęconej pytaniom i odpowiedziom dotyczącym języka Java rozwiewam kilka mitów dotyczących pomysłu często powracającego na forach dyskusyjnych.
Niezwykła łatwość, z jaką pliki Java .class mogą być rekonstruowane do źródeł Java, które są bardzo podobne do oryginałów, ma wiele wspólnego z celami projektowania kodu bajtowego Java i kompromisami. Kod bajtowy Java został między innymi zaprojektowany z myślą o zwartości, niezależności platformy, mobilności sieci i łatwości analizy przez interpretery kodu bajtowego i dynamiczne kompilatory JIT (just-in-time) / HotSpot. Prawdopodobnie skompilowane pliki .class wyrażają intencje programisty tak wyraźnie, że mogą być łatwiejsze do przeanalizowania niż oryginalny kod źródłowy.
Można zrobić kilka rzeczy, jeśli nie całkowicie zapobiec dekompilacji, a przynajmniej utrudnić ją. Na przykład, jako krok po kompilacji, możesz wymasować dane .class, aby kod bajtowy był trudniejszy do odczytania po dekompilacji lub trudniejszy do dekompilacji do prawidłowego kodu Java (lub obu). Techniki takie jak wykonywanie ekstremalnego przeciążania nazw metod dobrze sprawdzają się w pierwszym przypadku, a manipulowanie przepływem sterowania w celu utworzenia struktur kontrolnych, których nie można przedstawić za pomocą składni języka Java, działają dobrze w przypadku drugiego. Bardziej udane komercyjne obfuskatory wykorzystują połączenie tych i innych technik.
Niestety, oba podejścia muszą faktycznie zmienić kod, który JVM będzie uruchamiać, i wielu użytkowników obawia się (słusznie), że ta transformacja może dodać nowe błędy do ich aplikacji. Ponadto zmiana nazw metod i pól może spowodować, że wywołania odbicia przestaną działać. Zmiana rzeczywistych nazw klas i pakietów może spowodować uszkodzenie kilku innych interfejsów API języka Java (JNDI (Java Naming and Directory Interface), dostawców adresów URL itp.). Oprócz zmienionych nazw, jeśli skojarzenie między przesunięciami kodu bajtowego klasy a numerami wierszy źródłowych zostanie zmienione, odzyskanie oryginalnych śladów stosu wyjątków może być trudne.
Następnie istnieje możliwość zaciemnienia oryginalnego kodu źródłowego Java. Ale zasadniczo powoduje to podobny zestaw problemów. Szyfruj, a nie zaciemniaj?
Być może powyższe sprawiło, że pomyślałeś: „A co jeśli zamiast manipulować kodem bajtowym, szyfruję wszystkie moje klasy po kompilacji i odszyfrowuję je w locie wewnątrz maszyny JVM (co można zrobić za pomocą niestandardowego modułu ładującego klasy)? Następnie JVM wykonuje moje oryginalny kod bajtowy, a mimo to nie ma co dekompilować ani odtwarzać kodu źródłowego, prawda? "
Niestety, byłbyś w błędzie, zarówno myśląc, że to ty wpadłeś na ten pomysł jako pierwszy, jak i myśląc, że to faktycznie działa. Przyczyna nie ma nic wspólnego z siłą twojego schematu szyfrowania.
źródło