Rodzaj konwersji kodu stosowany w plikach wykonywalnych systemu Linux

13

Chcę zapytać, jaki rodzaj kodowania jest używany do tworzenia plików wykonywalnych systemu Linux, np. Hexadecemal, binarny lub cokolwiek innego. jak jest konwertowany? Czy jest jakiś sposób na odzyskanie oryginalnego kodu z tego pliku wykonywalnego?

Oto trochę kodu, który mam:

ELF���������>�����%|�����@�������������������@�8��@���������������������@�������@�����7<�����7<������� ������������������f�����f���������������������� ������[�UPX!L
h�h�8����������?�E�h=��ڊ̓�N�    4���9ISloB�q�w�]ȉ.��,ς��Q䝦����#e��-�N����/�b,���d<��'��-E��6E�s�/�U���ly�V�Y2]"a��S�.�hU�|�S�J�I�2���X}
�G0�;���5d�$���.)

co to ma znaczyć?

redchief
źródło
Chociaż nie pomoże ci to odzyskać niczego, warto zauważyć, że stringsprogram filtrujący może być bardzo przydatny w identyfikowaniu konkretnego programu binarnego, ponieważ drukuje wszystkie osadzone ciągi tekstowe dłuższe niż określona długość w plik binarny i przeglądanie wiadomości w programie czasami mówi wiele o tym, co to jest i co robi.
Joe
Możliwy / częściowy duplikat? stackoverflow.com/questions/193896/whats-a-good-c-decompiler
arielf

Odpowiedzi:

29

To jest binarne. Kod źródłowy został skompilowany. Możesz go wyświetlić w edytorze (edytor szesnastkowy blessmoże wymagać bardziej dopracowanych zmian), ale naprawdę musisz wiedzieć, co robisz. Prawdopodobnie nadaje się tylko do wprowadzania zmian w łańcuchach.

Aby uzyskać coś bardziej hardkorowego, możesz zacząć przekształcać kod binarny w kod asemblera . Jest to często uważane za język komputerowy najniższego poziomu, który jest możliwy do analizy przez człowieka.

objdump -d helloworld | less

Ale będzie też zawierać wiele bzdur kompilatora. Na przykład, jeśli skompilujesz najprostszyhelloworld.cpp z G ++, a następnie objdumpto, otrzymasz 226 linii (208 pozbawionych) fuj. Możesz napisać „witaj świecie” w zaledwie 15 liniach asemblacji , skompiluj go i objdumpto, ale nadal kwitnie w 166 liniach (pozbawionych).

Jeśli jesteś wystarczająco dobry w montażu, może to dać ci wystarczający dostęp do zrozumienia, co się dzieje, a nawet pozwolić ci to zmienić ... Ale aby odpowiedzieć na twoje pierwotne pytanie:

Nie można zamienić skompilowanego kodu z powrotem w oryginalny kod źródłowy.

Przepraszam. Jest to jednokierunkowa transformacja, która traci informacje (komentarze, formatowanie, czytelne koncepcje algorytmów itp.), Jest statycznie powiązana z innymi rzeczami i jest generalnie zoptymalizowana w taki sposób, aby uczynić ją niezrozumiałą dla niczego poza najlepszymi i najbardziej doświadczonymi programistami.

Aby dać wyobrażenie o skali problemu, cała idea oprogramowania do inżynierii odwrotnej ma własną stronę Stack Exchange .

Oli
źródło
Czy możesz mi powiedzieć, w jaki sposób mogę go odtworzyć i odzyskać maksymalną ilość kodu, ponieważ zgubiłem źródło
redchief,
7
Zobacz moją ostatnią edycję. Nie ma powrotu do oryginalnego źródła. Mając dużo nauki i dużo czasu, możesz być w stanie przepisać kod źródłowy na podstawie zdemontowanego kodu asemblera, ale w większości przypadków byłoby to tańsze (chyba że twój czas jest bezwartościowy) i łatwiejsze było przepisanie go od zera.
Oli
1
Sposobem na odzyskanie maksymalnej ilości kodu jest przywrócenie najnowszej kopii zapasowej. Jest to, nawiasem mówiąc, jedyny sposób, aby niezawodnie odzyskać coś przypominającego oryginalny kod źródłowy.
CVn
1
W ogóle nie zgadzając się z ostatnim akapitem, tylko na marginesie: niektóre dekompilatory IME wykonują świetną robotę w przywracaniu dokładnej struktury kodu (oczywiście poza tym, jak powiedziałeś komentarze, formatowanie, nazwy symboli ...). Jeśli nie napisałeś programu na pierwszym miejscu, odzyskany kod źródłowy może być nadal niezrozumiały, jednak uważam, że to świetna opcja, aby odzyskać (przynajmniej częściowo) utracony kod źródłowy / nieznany kod źródłowy (z przynajmniej częściami) właściwie zrozumiałe, w zależności od konkretnego kodu i tego, czy masz szczęście)
kosztują
1
Tak mówią wszystkie EULA w świecie prawnie zastrzeżonego oprogramowania, że ​​nie wolno ci - inżynierii wstecznej / dezasemblacji. Zawierają takie klauzule, ponieważ można to zrobić - ale na pewno nie jest to łatwe! Ale jak mówi @ MichaelKjörling, jedynym dobrym sposobem na odzyskanie rzeczy jest wielopoziomowa kopia zapasowa dla wszystkiego, co jest dla Ciebie ważne.
Joe
7

Nie mam wystarczającej liczby punktów reputacji dla komentarza, więc jest to odpowiedź:

Nie, nie można przekonwertować go „z powrotem”. Wspomniałeś o pakiecie UPX, czy kiedykolwiek czytałeś instrukcję UPX?

Jeśli straciłeś źródło lub nie masz dostępu do kodu innej osoby, to nie ma znaczenia, po prostu nie jest to możliwe.

Binarny plik wykonywalny został stworzony przy użyciu kompilatora, nie wierz w nic, co znajduje się na tej stronie, po prostu przeczytaj instrukcję tego kompilatora. Następnie możesz dodać tutaj, w jakim języku został napisany oryginalny kod, który kompilator został użyty, a następnie możesz zauważyć, że te kroki (wstępne przetwarzanie, kompilowanie, łączenie, może pakowanie) nie są odwrócone jako całość, ale mogą tylko przeanalizować, co zamierzał i napisał oryginalny autor.

justabot
źródło
3

Jak zauważył już Oli w swojej odpowiedzi, nie można uzyskać bardzo oryginalnego kodu źródłowego pliku wykonywalnego.

Podczas kompilacji kodu źródłowego (kompilacja ma charakter typowy dla szerszej akceptacji, stąd cały proces, który „przekształca” kod źródłowy w plik wykonywalny), wiele informacji zostaje utraconych.

Na przykład preprocesor C wykona (między innymi):

  • Interpretuj, wykonuj i usuwaj dyrektywy preprocesora ( #instrukcje)
  • Usuń komentarze
  • Usuń niepotrzebne białe znaki

Z drugiej strony to, co nie zostało utracone podczas kompilacji kodu źródłowego, jest technicznie odwracalne do funkcjonalnie równoważnego kodu źródłowego.

To dlatego, że:

  • Instrukcje binarne wykazują zgodność 1: 1 z instrukcjami montażu; asemblowanie kodu źródłowego asemblera jest po prostu konwersją instrukcji asemblera na instrukcje binarne oparte na tabeli korelencji; pojedyncza instrukcja binarna jest zawsze możliwa do zidentyfikowania i przywracania do pojedynczej instrukcji asemblacji ;
  • Instrukcje montażu nie mają związku 1: 1 z instrukcjami C; kompilacja kodu źródłowego C zwykle nie jest zwykłą konwersją instrukcji C do instrukcji asemblera opartych na tabeli korelencji, w rzeczywistości często jest odwrotnie; zwykle instrukcja C jest konwertowana na wiele (często różniących się w zależności od kompilatora) instrukcji montażu; jednakże wzory wielu instrukcji asemblacji są zwykle identyfikowalne i odwracalne do pojedynczej instrukcji C ;

Istnieją narzędzia zwane dekompilatorami, których celem jest próba przywrócenia pliku wykonywalnego na funkcjonalnie równoważny kod źródłowy; jednak wynik jest zwykle czymś dalekim od bardzo oryginalnego kodu źródłowego (i zwykle również nie do skompilowania);

Rozważ ten program:

#include <stdio.h>

#define MESSAGE "Literal strings will be recovered" // This preprocessor directive won't be recovered

/*

This comment and the comment above won't be recovered

*/

int main(int argc, char* argv[]) {
    printf(MESSAGE);
    return 0;
}

Kompilując go do pliku wykonywalnego i ponownie dekompilując do kodu źródłowego, jest to mniej więcej to, co zwykle otrzymujesz (w tym konkretnym przypadku użyłem gcc/ Boomerang ):

// address: 0x80483fb
int main(int argc, char **argv, char **envp) {
    printf("Literal strings will be recovered");
    return 0;
}

Jak przewidziano:

  • Brakuje dyrektyw preprocesora
  • Brak komentarzy (oprócz tego // address: 0x80483fb, który został dodany przez dekompilator)
  • Brakuje niepotrzebnych białych znaków (oprócz nowych linii i tabel, które zostały dodane przez dekompilator)

To także całkiem niezły wynik; nierzadko umieszcza się w kodzie instrukcje montażu w wierszu:

asm("assembly_instruction");
__asm__("assembly_instruction");

Najważniejsze jest (jak wskazano już w innych odpowiedziach): nie można uzyskać bardzo oryginalnego źródła pliku wykonywalnego *.

* Jednak w zależności od pliku wykonywalnego i na szczęście, to może być w stanie uzyskać coś za pomocą decompiler.

kos
źródło
2

Pliki wykonywalne są zwykle binarne, jeśli mówimy o skompilowanych programach. Możesz znaleźć więcej informacji za pomocą file path/to/executable. Możesz wyświetlać binarne pliki wykonywalne w systemie szesnastkowym, używając np. hexdump -C path/to/executable | less(Cokolwiek by to zrobiło). Jeśli chcesz „przekonwertować go z powrotem do pierwotnej postaci”, musisz użyć odpowiedniego dekompilatora, zobacz ten post, np. Chociaż da ci to dość nieczytelny kod, a nie oryginał, z którego został skompilowany. Jeśli nie jest to skompilowany plik binarny, byłby to jakiś skrypt wykonywalny, który powinien być łatwo czytelny w dowolnym edytorze tekstu. To, co nam tutaj pokazałeś, jest prawdopodobnie skompilowanym plikiem wykonywalnym. ELF oznacza „Format wykonywalny i łączący”, który jest powszechnym formatem binarnym w systemach Linux / Unix. Tam'strings path/to/executable, jeśli tego potrzebujesz.

Hinz
źródło
Próbowałem odtworzyć to z pakerem upx, ale nie działałem, a także z postem, który zasugerowałeś. Więc proszę powiedz mi, czy jest inny sposób.
redchief
Bardzo przepraszam, ale nie mogę powiedzieć nic więcej niż to, co napisano w znakomitym poście @ Oli.
Hinz