Dd के साथ एक बाइनरी पैचिंग


32

मैंने यह उद्धरण (नीचे) कई बार पढ़ा है, हाल ही में यहाँ , और लगातार इस बात पर हैरान हूँ कि ddकिसी भी चीज़ को अकेले संकलित करने के लिए कैसे इस्तेमाल किया जा सकता है ?

30 साल पहले मैंने स्कूल में जो यूनिक्स सिस्टम इस्तेमाल किया था, वह रैम और डिस्क स्पेस में बहुत सीमित था। विशेष रूप से, /usr/tmpफ़ाइल सिस्टम बहुत छोटा था, जिसके कारण किसी को एक बड़े कार्यक्रम को संकलित करने की कोशिश करने पर समस्या होती थी। बेशक, छात्रों को "बड़े कार्यक्रमों" को वैसे भी लिखना नहीं चाहिए था; बड़े कार्यक्रम आम तौर पर "कहीं" से कॉपी किए गए स्रोत कोड थे। हम में से कई की नकल की /usr/bin/ccकरने के लिए /home/<myname>/cc, और इस्तेमाल किया ddद्विआधारी उपयोग करने के लिए पैच करने के लिए /tmpके बजाय/usr/tmp , जो बड़ा था। बेशक, इसने समस्या को और भी बदतर बना दिया है - इन प्रतियों पर कब्जा कर लिया गया डिस्क स्थान उन दिनों में मायने रखता था, और अब /tmpनियमित रूप से भरा हुआ था, अन्य उपयोगकर्ताओं को अपनी फ़ाइलों को संपादित करने से रोक रहा था। जब उन्हें पता चला कि क्या हुआ था, तब सीसडैमिन ने एchmod go-r /bin/* /usr/bin/* जो समस्या को "ठीक" कर देता है, और सी कंपाइलर की हमारी सभी प्रतियां हटा देता है।

(जोर मेरा)

ddमानव पेज पैचिंग बारे में कुछ नहीं कहना है और एक नहीं लगता कि यह वैसे भी ऐसा करने के लिए सोद्देश्य यह हो सकता है।

क्या वास्तव में बायनेरिज़ के साथ समझौता किया जा सकता है dd? क्या इसका कोई ऐतिहासिक महत्व है?


3
ज़रूर - odबाइट हेक्स कोड्स के लिए सिर्फ एक फ़ाइल, आपको जो ऑफ़सेट चाहिए, उसे bs=$patchsize count=1 seek=$((offset/bs)) conv=notrunc
ढूंढिए

3
किसी ने कभी बूट सेक्टर को अधिलेखित नहीं किया। ;)
पार्थियन ने

@ParthianShot वास्तव में मैंने एक बार डेबियन लाइवसीडी के हिस्से के साथ अपने बूट ड्राइव (रूट) के पहले ~ 260MB को ओवररोट किया। O_o लेकिन मुझे नहीं लगता कि यह वास्तव में पैचिंग है,
हेहे

1
या यों कहें कि डिस्क डिस्ट्रॉयर का अपेक्षित और पूरी तरह से सामान्य व्यवहार है: D
Amziraro

जवाबों:


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 बाइट करें और इसे "/ usr // bin / bash" (उदाहरण के लिए) बनाएं।
पार्थियन ने

2
@ParthianShot - sed's नहीं बेहतर बात इस तरह का के लिए - आप नहीं कर सकते तो expliciltly और ठीक सीमा sedके पढ़ने / जिस तरह से आप के साथ हो सकता है में लिखने बफ़र्स dd- जो पूरी कारण यह कभी पहली जगह में इस के लिए इस्तेमाल किया गया था। साथ ddआप मनमाने ढंग से मनमाने ढंग से बाइट्स की एक मनमाना गिनती रख सकते हैं। यह भी नहीं कहा जा सकता है sed। अगर ddयहाँ एक स्केलपेल की तरह उपयोग किया जाता है, तो आप sedएक गेंद की तरह लागू होते हैं।
मोकेसर

यह एक उचित (यद्यपि काफी दुर्लभ है!) बिंदु - ऐसे मौके होंगे जब आप परिणाम या किसी अन्य के बारे में परवाह न करके स्ट्रिंग को लंबे समय तक बना सकते हैं, लेकिन विशिष्ट, डेटा का टुकड़ा। मैं सामान्य कथन द्वारा खड़ा हूँ, यद्यपि।
माइकल होमर

9

यह इस बात पर निर्भर करता है कि आप "बाइनरी पैच" से क्या मतलब है।

मैं ddकभी-कभी बायनेरिज़ का उपयोग करता हूं । बेशक इसमें ऐसी कोई सुविधा नहीं है dd, लेकिन यह फाइलों को खोल सकता है, और विशिष्ट कार्यालयों में चीजों को पढ़ और लिख सकता है, इसलिए यदि आप जानते हैं कि क्या लिखना है, तो वसीला आपके पैच है।

उदाहरण के लिए मेरे पास यह बाइनरी है जिसमें कुछ पीएनजी डेटा था। 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

या 0-बाइट के साथ @ माइकलहोमर का उदाहरण लेने के लिए इसमें जोड़ा गया:

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

बेशक आपको यह सत्यापित करना होगा कि यह वास्तव में बाद में काम करता है या नहीं।


... मान लें कि आपके पास एक sedअच्छी तरह से बाइनरी फाइलें हैं, जो कि गन्नू के साथ मामला है sed, लेकिन कई पुराने sedएस के साथ नहीं है, जो केवल एएससीआई फाइलों पर काम करते हैं, कुछ और (विशेष रूप \0से इनपुट में एस) के साथ भ्रमित हो गए , और अधिकतम लाइन लंबाई पर प्रतिबंध था।
गुंटराम ब्लोह

1
बिजीबॉक्स sedबाइनरी फ़ाइलें ठीक बदलने में सक्षम हो रहा है, लेकिन यह नहीं समझती \x00प्रतिस्थापन स्ट्रिंग में जिस तरह से जीएनयू sedकरता है। इसके परीक्षण की आवश्यकता है लेकिन फिर भी मुझे लगता है कि यह ध्यान देने योग्य है क्योंकि यह ddकुछ मामलों के लिए बहुत सरल है । पैचिंग बायनेरी एक तरह से परतदार व्यवसाय है।
frostschutz
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.