Łata pliku binarnego za pomocą dd


32

Przeczytałem ten cytat (poniżej) kilka razy, ostatnio tutaj , i ciągle zastanawiam się, jak ddmożna go użyć do łatania czegokolwiek, nie mówiąc już o kompilatorze:

System uniksowy, z którego korzystałem w szkole 30 lat temu, był bardzo ograniczony pod względem pamięci RAM i miejsca na dysku. Szczególnie /usr/tmpsystem plików był bardzo mały, co spowodowało problemy, gdy ktoś próbował skompilować duży program. Oczywiście studenci i tak nie powinni pisać „dużych programów”; duże programy były zwykle kodami źródłowymi kopiowanymi „gdzieś”. Wielu z nas kopiowane /usr/bin/ccdo /home/<myname>/cci używane ddzałatać binarny do używania /tmpzamiast/usr/tmp , który był większy. Oczywiście tylko pogorszyło to problem - przestrzeń dyskowa zajmowana przez te kopie miała znaczenie w tych dniach, a teraz /tmpregularnie się zapełnia, uniemożliwiając innym użytkownikom nawet edytowanie swoich plików. Po dowiedzeniu się, co się stało, sysadmins zrobilichmod go-r /bin/* /usr/bin/* co „naprawiło” problem i usunęło wszystkie nasze kopie kompilatora C.

(Moje podkreślenie)

ddCzłowiek-strona nie mówi nic o łatanie i nie sądzę, żeby to mogło być ponownie postanowił zrobić to w każdym razie.

Czy naprawdę można załatać pliki binarne dd? Czy ma to jakieś znaczenie historyczne?


3
Jasne - tylko odplik bajtowych kodów szesnastkowych, znajdź potrzebne przesunięcie, zdecyduj o swojej edycji i bs=$patchsize count=1 seek=$((offset/bs)) conv=notrunc
łatce

3
Ktoś nigdy nie nadpisał sektora rozruchowego. ;)
Parthian Shot

@ParthianShot Właściwie to raz nadpisałem pierwsze ~ 260 MB mojego napędu rozruchowego (+ root) częścią LiveCD Debiana. O_o Ale nie sądzę, że to naprawdę łatanie, hehehe ...
Amziraro

1
A raczej takie jest oczekiwane i całkowicie normalne zachowanie Disk Destroyer: D
Amziraro

Odpowiedzi:


73

Spróbujmy. Oto trywialny program C:

#include <stdio.h>
int main(int argc, char **argv) {
    puts("/usr/tmp");
}

Zbudujemy to w test:

$ cc -o test test.c

Jeśli go uruchomimy, wyświetli „/ usr / tmp”.

Dowiedzmy się, gdzie „ /usr/tmp” znajduje się w pliku binarnym:

$ strings -t d test | grep /usr/tmp
1460 /usr/tmp

-t d wypisuje przesunięcie dziesiętne do pliku każdego znalezionego ciągu.

Teraz zróbmy plik tymczasowy z po prostu „ /tmp\0”:

$ printf "/tmp\x00" > tmp

Teraz mamy plik binarny, wiemy, gdzie znajduje się ciąg, który chcemy zmienić, i mamy plik z ciągiem zastępującym.

Teraz możemy użyć dd:

$ dd if=tmp of=test obs=1 seek=1460 conv=notrunc

Odczytuje dane z tmp(naszego „ /tmp\0” pliku), zapisuje je do naszego pliku binarnego, używając rozmiaru bloku wyjściowego 1 bajt, przeskakując do przesunięcia, które znaleźliśmy wcześniej, zanim coś zapisuje, i jawnie nie obcinając pliku, gdy jest gotowy.

Możemy uruchomić załatany plik wykonywalny:

$ ./test
/tmp

Dosłowny ciąg znaków, który program wypisuje, został zmieniony, więc zawiera teraz „ /tmp\0tmp\0”, ale funkcje ciągów zatrzymują się, gdy zobaczą pierwszy bajt zerowy. Ta łatka pozwala tylko na skrócenie lub taką samą długość łańcucha, ale nie dłużej, ale jest wystarczająca do tych celów.

Więc nie tylko możemy łatać rzeczy za pomocą dd, ale właśnie to zrobiliśmy.


1
Jest to doskonałe ... i mam nadzieję, że nigdy nie spotkam się w środowisku produkcyjnym! W przeszłości używałem podobnych metod, aby przekształcić numery seryjne w obrazy szesnastkowe dla mikrokontrolerów, jednak zdecydowanie łatwiej jest strzelać sobie w stopę.
Michael Shaw,

Gdybym chciał przekazać komuś pisemne instrukcje, jak załatać określony plik binarny, wolę dać mu wiersz poleceń do skopiowania / wklejenia niż powiedzieć mu: „otwórz plik w edytorze szesnastkowym, znajdź /usr/tmpciąg, zamień go na /tmp, don nie zapomnij końcowego \0bajtu, zapisz plik i trzymaj kciuki ". Lub nawet lepiej, skrypt powłoki, który najpierw sprawdza poprawność poczytalności, a następnie wywołuje dd. Niestety, potrzeba takich rzeczy pojawia się często, gdy stare oprogramowanie nieistniejącego już dostawcy musi zostać migrowane do nowego systemu.
Guntram Blohm wspiera Monikę

Tak, sed jest lepszy do tego rodzaju rzeczy. Ale nie do końca masz rację co do całości „Ta łatka pozwala tylko na skrócenie lub taką samą długość sznurka, a nie dłużej”. Zakładasz, że troszczysz się o dane bezpośrednio po ciągu, który chcesz zmodyfikować, lub że nie możesz mieć tego, aby następny ciąg był po prostu podciągiem oryginalnego ciągu. Innymi słowy, jeśli jesteś w sekcji .strings pamięci i masz „/ usr \ 0 / bin / bash \ 0”, możesz zmienić to w / usr / bin / bash, po prostu zmieniając to pierwsze zerowy bajt i uczynienie go „/ usr // bin / bash” (na przykład).
Parthian Shot

2
@ParthianShot - sed„s nie lepiej dla tego rodzaju rzeczy - nie można więc expliciltly i precyzyjnie granica sed” s odczytu / zapisu buforów w sposób, w jaki może z dd- co jest przyczyną tego, że cały kiedykolwiek użyto w tym w pierwszej kolejności. Za pomocą ddmożesz dowolnie umieścić dowolną liczbę dowolnych bajtów. Tego też nie można powiedzieć sed. Jeśli ddużyjesz go tutaj jak skalpela, zastosujesz się sedjak kula rozbijająca.
mikeserv

To uczciwa (choć dość rzadka!) Kwestia - zdarzają się sytuacje, w których możesz wydłużyć ciąg, nie dbając o wynik ani o inną dowolną, ale konkretną, część danych. Będę jednak przestrzegać ogólnego stwierdzenia.
Michael Homer,

9

Zależy to od tego, co rozumiesz przez „łatanie pliku binarnego”.

ddCzasami zmieniam pliki binarne . Oczywiście nie ma takiej funkcji dd, ale może otwierać pliki oraz czytać i pisać rzeczy z określonymi przesunięciami, więc jeśli wiesz, gdzie pisać, voila jest łatka.

Na przykład miałem ten plik binarny, który zawierał pewne dane PNG. Użyj, binwalkaby znaleźć odsunięcie, ddaby go wyodrębnić (zwykle binwalk również wyodrębnia rzeczy, ale moja kopia była wadliwa), edytuj za pomocą gimp, upewnij się, że edytowany plik ma taki sam rozmiar lub jest mniejszy niż oryginalny (zmiana przesunięcia nie jest czymś, co możesz zrobić łatwo ), a następnie użyj, ddaby przywrócić zmieniony obraz na swoim miejscu.

$ binwalk thebinary
[…]
4194643    0x400153     PNG image, 800 x 160, 8-bit/color RGB, non-interlaced
[…]
$ dd if=nickel bs=1 skip=4194641 count=2 conv=swab | od -i
21869 # file size in this case - depends on the binary format
$ dd if=thebinary bs=1 skip=4194643 count=21869 of=theimage.png
$ gimp theimage.png
$ pngcrush myimage.png myimage.crush.png
# make sure myimage.crush.png is smaller than the original
$ dd if=myimage.crush.png of=thebinary bs=1 seek=4194643 conv=notrunc

Czasami chcę również zastąpić ciągi w plikach binarnych (takich jak nazwy ścieżek lub zmiennych). Chociaż można to również zrobić za pomocą dd, łatwiej jest to zrobić za pomocą sed. Musisz tylko upewnić się, że łańcuch, który zamieniasz, ma taką samą długość jak łańcuch oryginalny, abyś nie zmienił przesunięć.

sed -e s@/the/old/save/path@/the/new/save/path@ -i thebinary

lub pobrać przykład @ MichaelHomer z dodanym 0-bajtem:

sed -e 's@/usr/tmp@/tmp\x00tmp@' -i test

Oczywiście musisz sprawdzić, czy to rzeczywiście działa później.


... zakładając, że masz seddobrą obsługę plików binarnych, co wydaje się mieć miejsce w przypadku GNU sed, ale nie w przypadku wielu starszych seds, które działały tylko na plikach ASCII, pomylił się z czymkolwiek innym (szczególnie \0s na wejściu), i miał ograniczenia dotyczące maksymalnej długości linii.
Guntram Blohm wspiera Monikę

1
busybox sedwydaje się być w stanie dobrze zmieniać pliki binarne, ale \x00w łańcuchu zastępującym nie rozumie tak, jak sedrobi to GNU . Wymaga testowania, ale myślę, że warto o tym wspomnieć, ponieważ jest o wiele prostsze niż dd- w niektórych przypadkach. Łatowanie plików binarnych to i tak płatna sprawa.
frostschutz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.