Vá một nhị phân với dd


32

Tôi đã đọc trích dẫn này (bên dưới) nhiều lần, gần đây nhất ở đây , và liên tục bối rối về cách ddcó thể được sử dụng để vá bất cứ thứ gì chứ đừng nói đến trình biên dịch:

Hệ thống Unix tôi đã sử dụng ở trường, 30 năm trước, rất hạn chế về dung lượng RAM và ổ đĩa. Đặc biệt, /usr/tmphệ thống tập tin rất nhỏ, dẫn đến sự cố khi ai đó cố gắng biên dịch một chương trình lớn. Tất nhiên, dù sao đi nữa, sinh viên không nên viết "chương trình lớn"; các chương trình lớn thường là mã nguồn được sao chép từ "một nơi nào đó". Nhiều người trong chúng sao chép /usr/bin/ccđến /home/<myname>/cc, và dùng ddđể đắp vá các nhị phân để sử dụng /tmpthay vì/usr/tmp , đó là lớn hơn. Tất nhiên, điều này chỉ làm cho vấn đề trở nên tồi tệ hơn - không gian đĩa bị chiếm giữ bởi những bản sao này đã trở thành vấn đề trong những ngày đó, và hiện được /tmplấp đầy thường xuyên, ngăn người dùng khác thậm chí chỉnh sửa tệp của họ. Sau khi họ phát hiện ra chuyện gì đã xảy ra, các sysadins đã làm mộtchmod go-r /bin/* /usr/bin/* đã "khắc phục" sự cố và xóa tất cả các bản sao của trình biên dịch C.

(Nhấn mạnh của tôi)

Trang ddcon người không nói gì về việc vá và đừng nghĩ rằng nó có thể được tái định hướng để làm điều này.

Nhị phân thực sự có thể được vá với dd? Có bất kỳ ý nghĩa lịch sử cho điều này?


3
Chắc chắn - chỉ là odmột tệp cho mã hex byte, tìm phần bù bạn cần, quyết định chỉnh sửa và bs=$patchsize count=1 seek=$((offset/bs)) conv=notruncbản vá của bạn ngay trong đó
mikeerv

3
Ai đó không bao giờ ghi đè lên một khu vực khởi động. ;)
Bắn Parthian

@ParthianShot Trên thực tế, tôi đã ghi đè lên ~ 260 MB ổ đĩa khởi động (+ root) đầu tiên của mình bằng một phần của Debian LiveCD một lần. O_o Nhưng tôi không nghĩ điều đó thực sự đang vá, hehehe ...
Amziraro 10/07/2015

1
Hay đúng hơn, đó là hành vi được mong đợi và hoàn toàn bình thường của Kẻ hủy diệt đĩa: D
Amziraro

Câu trả lời:


73

Hãy thử nó. Đây là một chương trình C tầm thường:

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

Chúng tôi sẽ xây dựng nó thành test:

$ cc -o test test.c

Nếu chúng ta chạy nó, nó sẽ in "/ usr / tmp".

Hãy tìm xem " /usr/tmp" nằm ở đâu trong nhị phân:

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

-t d in phần bù theo số thập phân vào tệp của mỗi chuỗi mà nó tìm thấy.

Bây giờ, hãy tạo một tệp tạm thời chỉ với " /tmp\0" trong đó:

$ printf "/tmp\x00" > tmp

Vì vậy, bây giờ chúng ta có tệp nhị phân, chúng ta biết chuỗi chúng ta muốn thay đổi ở đâu và chúng ta có một tệp có chuỗi thay thế trong đó.

Bây giờ chúng ta có thể sử dụng dd:

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

Điều này đọc dữ liệu từ tmp( /tmp\0tệp " " của chúng tôi ), ghi nó vào tệp nhị phân của chúng tôi, sử dụng kích thước khối đầu ra là 1 byte, bỏ qua phần bù mà chúng tôi tìm thấy trước đó trước khi ghi bất cứ điều gì và rõ ràng không cắt bớt tệp khi hoàn tất.

Chúng tôi có thể chạy thực thi được vá:

$ ./test
/tmp

Chuỗi ký tự mà chương trình in ra đã được thay đổi, vì vậy giờ đây nó chứa " /tmp\0tmp\0", nhưng các hàm chuỗi dừng lại ngay khi chúng thấy byte null đầu tiên. Bản vá này chỉ cho phép làm cho chuỗi ngắn hơn hoặc cùng độ dài, và không dài hơn, nhưng nó phù hợp cho các mục đích này.

Vì vậy, chúng tôi không chỉ có thể vá mọi thứ bằng cách sử dụng dd, chúng tôi đã thực hiện nó.


1
Điều này thật tuyệt vời ... và một điều tôi cực kỳ hy vọng tôi không bao giờ gặp phải trong môi trường sản xuất! Tôi đã sử dụng các phương pháp tương tự trong quá khứ để lấy số sê-ri thành hình lục giác cho vi điều khiển, mặc dù vậy thật dễ dàng để tự bắn vào chân mình.
Michael Shaw

Nếu tôi muốn đưa ra hướng dẫn bằng văn bản cho ai đó cách vá một nhị phân cụ thể, tôi muốn cung cấp cho họ một dòng lệnh để sao chép / dán hơn là nói với họ "mở tệp trong trình soạn thảo hex, tìm /usr/tmpchuỗi, thay thế bằng /tmp, don Đừng quên \0byte theo dõi , lưu tệp và vượt qua các ngón tay của bạn ". Hoặc, thậm chí tốt hơn, một kịch bản shell thực hiện kiểm tra sự tỉnh táo trước, sau đó gọi dd. Thật không may, sự cần thiết của những thứ như thế này phát sinh thường xuyên khi một mảnh cũ của phần mềm bằng cách một nhà cung cấp bây giờ không còn tồn tại chỉ được di chuyển sang một hệ thống mới.
Guntram Blohm hỗ trợ Monica

Vâng, sed là tốt hơn cho loại điều này. Nhưng bạn không hoàn toàn đúng về toàn bộ "Việc vá này chỉ cho phép làm cho chuỗi ngắn hơn hoặc cùng độ dài chứ không dài hơn". Bạn đang giả định rằng bạn quan tâm đến dữ liệu ngay sau chuỗi bạn muốn sửa đổi hoặc bạn không thể có chuỗi tiếp theo đơn giản là chuỗi con của chuỗi gốc. Nói cách khác, nếu bạn đang ở trong phần .strings của bộ nhớ và bạn đã có "/ usr \ 0 / bin / bash \ 0", bạn có thể biến nó thành / usr / bin / bash bằng cách thay đổi trước null byte và làm cho nó "/ usr // bin / bash" (ví dụ).
Bắn Parthian

2
@ParthianShot - sedkhông tốt cho các loại hình điều - bạn có thể không quá expliciltly và chính xác giới hạn sed's đọc / ghi bộ đệm trong cách có lẽ bạn có dd- đó là toàn bộ lý do nó đã từng được sử dụng cho điều này ở nơi đầu tiên. Với ddbạn có thể tùy ý đặt một số lượng tùy ý các byte tùy ý. Điều này cũng không thể được nói về sed. Nếu ddđược sử dụng như dao mổ ở đây, bạn sẽ áp dụng sednhư một quả bóng phá hoại.
mikeerv

Đó là một điểm công bằng (mặc dù khá hiếm!) - sẽ có những lúc bạn có thể làm cho chuỗi dài hơn bằng cách không quan tâm đến kết quả hoặc một phần dữ liệu tùy ý, nhưng cụ thể. Mặc dù vậy, tôi sẽ đứng trước tuyên bố chung.
Michael Homer

9

Nó phụ thuộc vào những gì bạn có nghĩa là "vá nhị phân".

ddĐôi khi tôi thay đổi nhị phân bằng cách sử dụng . Tất nhiên không có tính năng như vậy trong dd, nhưng nó có thể mở các tệp, đọc và viết mọi thứ ở các độ lệch cụ thể, vì vậy nếu bạn biết phải viết gì ở đâu, thì đó là bản vá của bạn.

Ví dụ tôi có tệp nhị phân này chứa một số dữ liệu PNG. Sử dụng binwalkđể tìm phần bù, ddđể giải nén nó (thông thường binwalk cũng trích xuất mọi thứ nhưng bản sao của tôi bị lỗi), chỉnh sửa nó gimp, đảm bảo tệp đã chỉnh sửa có cùng kích thước hoặc nhỏ hơn bản gốc (thay đổi offset không phải là thứ bạn có thể làm dễ dàng ), và sau đó sử dụng ddđể đặt lại hình ảnh đã thay đổi.

$ 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

Đôi khi tôi cũng muốn thay thế các chuỗi trong nhị phân (chẳng hạn như tên đường dẫn hoặc tên biến). Trong khi điều này cũng có thể được thực hiện bằng cách sử dụng dd, nó đơn giản hơn để làm như vậy bằng cách sử dụng sed. Bạn chỉ cần đảm bảo chuỗi bạn thay thế có cùng độ dài với chuỗi ban đầu để cuối cùng bạn không thay đổi offset.

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

hoặc chọn ví dụ @ MichaelHomer với 0 byte được thêm vào:

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

Tất nhiên bạn phải xác minh xem nó thực sự hoạt động sau đó.


... giả sử bạn có một sedtệp xử lý tốt các tệp nhị phân, dường như là trường hợp của gnu sed, nhưng không phải với nhiều sedtệp cũ chỉ hoạt động trên các tệp ascii, bị nhầm lẫn với bất kỳ thứ gì khác (đặc biệt \0là trong đầu vào), có các hạn chế về chiều dài dòng tối đa.
Guntram Blohm hỗ trợ Monica

1
busybox seddường như có thể thay đổi các tệp nhị phân tốt nhưng nó không hiểu \x00trong chuỗi thay thế theo cách GNU sedlàm. Nó đòi hỏi phải thử nghiệm nhưng ngay cả tôi cũng nghĩ nó đáng được đề cập vì nó đơn giản hơn nhiều so với dd- đối với một số trường hợp. Vá nhị phân là một công việc hoàn hảo.
frostschutz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.