Виправлення бінарного файлу з dd


32

Я читав цю цитату (нижче) декілька разів, останнім часом тут , і я постійно спантеличений тим, як ddможна використовувати патч що- небудь, не кажучи вже про компілятор:

Система Unix, якою я користувалася в школі, 30 років тому, була дуже обмежена в оперативній пам’яті та на диску. Тим більше, що /usr/tmpфайлова система була дуже маленькою, що призводило до проблем, коли хтось намагався скласти велику програму. Звичайно, студентам все одно не слід було писати "великих програм"; великі програми, як правило, були вихідними кодами, скопійованими звідкись. Багато з нас скопіювали /usr/bin/ccв /home/<myname>/cc, і використовуються ddдля виправлення виконуваного файлу використовувати /tmpзамість/usr/tmp , який був більше. Звичайно, це тільки погіршило проблему - дисковий простір, зайнятий цими копіями, мав значення в ті дні, і тепер /tmpрегулярно заповнюється, не даючи іншим користувачам навіть редагувати свої файли. Після того як вони дізналися, що сталося, сисадміни зробилиchmod go-r /bin/* /usr/bin/* що "виправило" проблему та видалило всі наші копії компілятора C.

(Наголос мій)

Сторінка ddлюдини нічого не говорить про виправлення, і не думаю, що це все-таки можна було б зробити заново.

Чи справді бінарні файли можуть бути виправлені dd? Чи є в цьому історичне значення?


3
Звичайно - просто odфайл для байт-шістнадцяткових кодів, знайдіть потрібне зміщення, визначтесь із редагуванням та bs=$patchsize count=1 seek=$((offset/bs)) conv=notruncсвоїм патчем прямо.
mikeserv

3
Хтось ніколи не перезаписує завантажувальний сектор. ;)
Парфянський розстріл

@ParthianShot Насправді я перезаписав перший ~ 260 Мб свого завантажувача (+ root) з частиною Debian LiveCD один раз. O_o Але я не думаю, що це насправді виправлення,
хе-хе

1
А точніше, така очікувана і абсолютно нормальна поведінка
Disc

Відповіді:


73

Давайте спробуємо. Ось тривіальна програма С:

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

Ми вбудуємо це в test:

$ cc -o test test.c

Якщо ми запустимо його, він надрукує "/ usr / tmp".

Давайте дізнаємось, де " /usr/tmp" знаходиться у двійковому:

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

-t d друкує зміщення у десятковій формі у файл кожного знайденого рядка.

Тепер давайте зробимо тимчасовий файл з просто " /tmp\0" у ньому:

$ printf "/tmp\x00" > tmp

Отже, тепер у нас є двійковий файл, ми знаємо, де знаходиться рядок, який ми хочемо змінити, і у нас є файл із рядком заміни.

Тепер ми можемо використовувати dd:

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

Це зчитує дані з tmpнашого " /tmp\0" файлу), записуючи їх у наш двійковий файл, використовуючи вихідний блок розміром 1 байт, переходячи до зрушення, яке ми знайшли раніше, перш ніж він щось пише, і явно не обрізує файл, коли це буде зроблено.

Ми можемо запустити виконувану версію:

$ ./test
/tmp

Буквальний рядок, який виводить програма, був змінений, тому він містить " /tmp\0tmp\0", але функції рядка припиняються, як тільки вони бачать перший нульовий байт. Цей виправлення дозволяє лише зробити рядок коротшою або однакової довжини, і не довше, але це адекватно для цих цілей.

Тож ми не лише можемо виправити речі за допомогою dd, але ми це зробили.


1
Це чудово ... і те, що я дуже сподіваюся, що ніколи не зіткнуся у виробничих умовах! У минулому я використовував подібні методи, щоб отримувати серійні номери в шестигранних зображеннях для мікроконтролерів, хоч і занадто просто знімати себе в ногу.
Майкл Шоу

Якщо я хотів дати комусь письмові вказівки, як виправити певний двійковий файл, я б краще дати їм командний рядок скопіювати / вставити, ніж сказати їм "відкрийте файл у шестигранному редакторі, знайдіть /usr/tmpрядок, замініть його на /tmp, не "не забудьте остаточний \0байт, збережіть файл і схрестіть пальці". Або, ще краще, сценарій оболонки, який спочатку робить перевірку правильності, а потім дзвінки dd. На жаль, потреба в таких речі , як це часто виникає , коли стара частина програмного забезпечення на нині неіснуючим постачальник тільки повинна бути перенесена на нову систему.
Гунтрам Блом підтримує Моніку

Так, сед краще для подібних речей. Але ви не зовсім праві в цілому "Цей виправлення дозволяє лише зробити рядок коротшим або однаковим, а не довшим". Ви припускаєте, що ви дбаєте про дані, що безпосередньо слідують за рядком, який ви хочете змінити, або що наступна рядок не може бути просто підрядкою вихідної рядки. Іншими словами, якщо ви перебуваєте в розділі пам'яті .strings, і у вас є "/ usr \ 0 / bin / bash \ 0", ви можете перетворити це на / usr / bin / bash, просто змінивши це спочатку null byte та робить його "/ usr // bin / bash" (наприклад).
Парфянський розстріл

2
@ParthianShot - sed«S НЕ краще для такого роду речі - ви не можете так expliciltly і точно межа sed» s для читання / запису буфера в тому , як ви могли б з dd- що вся причина , вона була колись - або використовували для цього в першу чергу. За допомогою ddвас можна довільно розмістити довільну кількість довільних байтів. Про це також не можна сказати sed. Якщо ddтут використовується як скальпель, ви б застосували, sedяк куля-шкода.
mikeserv

Це справедливий (хоч і досить рідкісний!) Пункт - будуть випадки, коли ви можете продовжити рядок довше, не піклуючись ні про результат, ні про іншу довільну, але конкретну інформацію. Я, однак, буду стояти за загальним твердженням.
Майкл Гомер

9

Це залежить від того, що ви маєте на увазі під "виправлення двійкового".

Я змінюю двійкові файли, використовуючи ddіноді. Звичайно, такої функції немає dd, але вона може відкривати файли та читати та записувати речі з певними зрушеннями, тож якщо ви знаєте, що писати куди, вуаля є ваш патч.

Наприклад, у мене був цей двійковий файл, який містив деякі дані PNG. Використовуйте, binwalkщоб знайти зсув, ddвитягнути його (як правило, під час перегляду також витягуються речі, але моя копія була помилкова), відредагуйте її gimp, переконайтесь, що відредагований файл має розмір або менший, ніж вихідний (зміна компенсацій - це не те, що ви можете легко зробити ), а потім скористайтеся, ddщоб повернути змінене зображення на місце.

$ 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

Іноді я також хочу замінити рядки у бінарних файлах (наприклад, імена шляху або змінних). Хоча це також можна зробити за допомогою dd, простіше зробити це за допомогою sed. Вам просто потрібно переконатися, що рядок, яку ви замінюєте, має таку ж довжину, що і вихідна рядок, щоб ви не змінили зрушення.

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

або взяти приклад @ MichaelHomer з додаванням 0-байт у:

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

Звичайно, ви повинні перевірити, чи працює він насправді згодом.


... припускаючи, що у вас є, sedщо добре обробляє бінарні файли, що, мабуть, має місце з gnu sed, але не з багатьма старими seds, які працювали лише на файли ascii, заплуталися в чому-небудь іншому (особливо \0s у вході), і мали обмеження щодо максимальної довжини лінії.
Guntram Blohm підтримує Моніку

1
sedСхоже, що зайнятий вміє добре змінювати бінарні файли, але \x00в рядку заміни не розуміє, як це робить GNU sed. Це вимагає тестування, але навіть я вважаю, що це варто згадати, оскільки це набагато простіше, ніж dd- у деяких випадках. Виправлення бінарних файлів - це будь-яка робота, яка є чітким.
frostschutz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.