কোনও ফাইলে বাইট সিক্যুয়েন্সের সংখ্যাটি আমি কীভাবে গণনা করতে পারি?


16

আমার কাছে থাকা ফাইলের মধ্যে বাইটের একটি নির্দিষ্ট ক্রম কতবার ঘটে তা আমি গণনা করতে চাই। উদাহরণস্বরূপ, আমি \0xdeadbeefনির্বাহযোগ্য ফাইলের মধ্যে সংখ্যাটি কতবার ঘটে তা সন্ধান করতে চাই । এই মুহূর্তে আমি গ্রেপ ব্যবহার করে এটি করছি:

#/usr/bin/fish
grep -c \Xef\Xbe\Xad\Xde my_executable_file

(বাইটগুলি বিপরীত ক্রমে লিখিত কারণ আমার সিপিইউ স্বল্প-এডিয়ান

তবে আমার পদ্ধতির সাথে আমার দুটি সমস্যা রয়েছে:

  • যারা \Xnnপালানোর ক্রমগুলি কেবল ফিশ শেলের মধ্যে কাজ করে।
  • গ্রেপ আসলে আমার যাদু নম্বর ধারণ করে এমন লাইনগুলির সংখ্যা গণনা করছে। যদি প্যাটার্ন একই লাইনে দু'বার ঘটে তবে এটি কেবল একবার গণনা করা হবে।

এই সমস্যাগুলি সমাধান করার কোনও উপায় আছে? আমি কীভাবে এই এক লাইনারটিকে বাশ শেলের মধ্যে রান করতে পারি এবং সঠিকভাবে ফাইলের অভ্যন্তরে যে প্যাটার্নটি ঘটে তা গণনা করতে পারি?


কিছু সহায়তা: unix.stackexchange.com/q/231213/117549 - বিশেষভাবেgrep -o
জেফ

1
গ্রেপ ব্যবহারের জন্য ভুল সরঞ্জাম। বিগ্রিপ বা বিগ্রেপ 2 বিবেচনা করুন।
এফএমপুরফি

3
যদি অনুসন্ধানের ক্রমটি হয় তবে কোনও ইনপুটটিতে 11221122কী ফিরিয়ে দেওয়া উচিত 112211221122? 1 বা 2?
স্টাফেন চেজেলাস

সেক্ষেত্রে 2 বা 3 ম্যাচের প্রতিবেদন দিয়ে আমি ঠিক আছি। যেগুলি কার্যকর করা সহজ হবে।
hugomg

উত্তর:


15

এটি অনুরোধ করা ওয়ান-লাইনারের সমাধান (সাম্প্রতিক শেলগুলির জন্য যা "প্রক্রিয়া প্রতিস্থাপন" রয়েছে):

grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l

যদি কোনও "প্রক্রিয়া বিকল্প" <(…)উপলব্ধ না হয় তবে কেবল গ্রেটারকে ফিল্টার হিসাবে ব্যবহার করুন:

hexdump -v -e '/1 "%02x "' infile.bin  | grep -o "ef be ad de" | wc -l

নীচে সমাধানের প্রতিটি অংশের বিশদ বিবরণ দেওয়া হল।

হেক্স নম্বর থেকে বাইট মান:

আপনার প্রথম সমস্যা সমাধান করা সহজ:

\ এক্সএনএন এস্কেপ সিকোয়েন্সগুলি কেবল ফিশ শেলটিতে কাজ করে।

উপরেরটিকে Xনীচের দিকে পরিবর্তন করুন xএবং প্রিন্টফ ব্যবহার করুন (বেশিরভাগ শাঁসের জন্য):

$ printf -- '\xef\xbe\xad\xde'

বা ব্যবহার করুন:

$ /usr/bin/printf -- '\xef\xbe\xad\xde'

যে শেলগুলি '\ x' উপস্থাপনাটি বাস্তবায়ন করতে পছন্দ করে না তাদের জন্য।

অবশ্যই, হেক্সকে অষ্টালে অনুবাদ করলে কোনও শেল (প্রায়) কার্যকর হবে:

$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'

যেখানে "$ sh" হ'ল কোনও (যুক্তিসঙ্গত) শেল। তবে এটি সঠিকভাবে উদ্ধৃত করা বেশ কঠিন is

বাইনারি ফাইল।

সর্বাধিক দৃ solution় সমাধান হ'ল ফাইল এবং বাইট সিকোয়েন্স (উভয়) কে এমন কিছু এনকোডিংয়ে রূপান্তর করা যা (নতুন লাইন) 0x0Aবা (নাল বাইট) এর সাথে বিজোড় চরিত্রের মানগুলির কোনও সমস্যা নেই 0x00। উভয়ই "টেক্সট ফাইলগুলি" প্রক্রিয়াকরণের জন্য ডিজাইন করা এবং অভিযোজিত সরঞ্জামগুলির সাথে সঠিকভাবে পরিচালনা করা বেশ কঠিন।

বেস 64৪ এর মতো রূপান্তরটি একটি বৈধ মনে হতে পারে তবে এটি প্রতিটি ইনপুট বাইটের তিনটি আউটপুট উপস্থাপনা থাকতে পারে যদি এটি মোড 24 (বিট) অবস্থানের প্রথম, দ্বিতীয় বা তৃতীয় বাইট হয় depending

$ echo "abc" | base64
YWJjCg==

$ echo "-abc" | base64
LWFiYwo=

$ echo "--abc" | base64
LS1hYmMK

$ echo "---abc" | base64        # Note that YWJj repeats.
LS0tYWJjCg==

হেক্স রূপান্তর

সবচেয়ে শক্তিশালী রূপান্তরটি হ'ল সহজ এইচএক্স উপস্থাপনার মতো প্রতিটি বাইট সীমানায় শুরু হওয়া উচিত ts
আমরা এই সরঞ্জামগুলির যে কোনওটির মাধ্যমে ফাইলের হেক্স উপস্থাপনের সাথে একটি ফাইল পেতে পারি:

$ od -vAn -tx1 infile.bin | tr -d '\n'   > infile.hex
$ hexdump -v -e '/1 "%02x "' infile.bin  > infile.hex
$ xxd -c1 -p infile.bin | tr '\n' ' '    > infile.hex

এই ক্ষেত্রে সন্ধানের বাইট ক্রমটি ইতিমধ্যে হেক্সে রয়েছে।
:

$ var="ef be ad de"

তবে এটি রূপান্তরিতও হতে পারে। রাউন্ড ট্রিপ হেক্স-বিন-হেক্সের উদাহরণ অনুসরণ করে:

$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de

বাইনারি উপস্থাপনা থেকে অনুসন্ধান স্ট্রিং সেট করা যেতে পারে। ওড, হেক্সডাম্প বা এক্সএক্সডিডি উপরে উপস্থাপিত তিনটি বিকল্পের যেকোনটি সমতুল্য। বাইট সীমানায় ম্যাচটি নিশ্চিত হওয়ার জন্য ফাঁকা স্থানগুলি অন্তর্ভুক্ত করার বিষয়টি নিশ্চিত করুন (কোনও ছোঁয়াচে শিফ্ট অনুমোদিত নয়):

$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de

যদি বাইনারি ফাইলটি দেখতে এমন হয়:

$ cat infile.bin | xxd
00000000: 5468 6973 2069 7320 efbe adde 2061 2074  This is .... a t
00000010: 6573 7420 0aef bead de0a 6f66 2069 6e70  est ......of inp
00000020: 7574 200a dead beef 0a66 726f 6d20 6120  ut ......from a 
00000030: 6269 0a6e 6172 7920 6669 6c65 2e0a 3131  bi.nary file..11
00000040: 3232 3131 3232 3131 3232 3131 3232 3131  2211221122112211
00000050: 3232 3131 3232 3131 3232 3131 3232 3131  2211221122112211
00000060: 3232 0a

তারপরে, একটি সাধারণ গ্রেপ অনুসন্ধানে মিলিত ক্রমের তালিকা দেবে:

$ grep -o "$a" infile.hex | wc -l
2

এক লাইন?

এটি সমস্তই এক লাইনে সম্পাদন করা যেতে পারে:

$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l

উদাহরণস্বরূপ, 11221122একই ফাইলে অনুসন্ধান করতে এই দুটি পদক্ষেপের প্রয়োজন হবে:

$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4

ম্যাচগুলি "দেখতে":

$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232

$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')

… 0a 3131323231313232313132323131323231313232313132323131323231313232 313132320a


বাফারিং

একটি উদ্বেগ রয়েছে যে গ্রেপ পুরো ফাইলটি বাফার করবে এবং যদি ফাইলটি বড় হয় তবে কম্পিউটারের জন্য ভারী বোঝা তৈরি করে। তার জন্য, আমরা একটি আনফার্ডড সেড সলিউশন ব্যবহার করতে পারি:

a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin  | 
    sed -ue 's/\('"$a"'\)/\n\1\n/g' | 
        sed -n '/^'"$a"'$/p' |
            wc -l

প্রথম সেডটি আনফারড করা হয় না ( -u) এবং প্রতি ম্যাচিং স্ট্রিং প্রতি স্ট্রিমে দুটি নতুন লাইন ইনজেক্ট করতে ব্যবহৃত হয়। দ্বিতীয়sed (সংক্ষিপ্ত) মিলের লাইনগুলি মুদ্রণ করবে। ডাব্লুসি-এল মিলবে লাইন গণনা করবে।

এটি কেবল কয়েকটি সংক্ষিপ্ত রেখা বাফার করবে। দ্বিতীয় সেডের সাথে ম্যাচিং স্ট্রিং (গুলি)। ব্যবহৃত সম্পদগুলিতে এটি বেশ কম হওয়া উচিত।

বা, বুঝতে আরও কিছুটা জটিল, তবে একই ধরণের ধারণাটি একটি সেডে:

a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin  |
    sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
        wc -l

2
মনে রাখবেন যে আপনি যদি সমস্ত পাঠ্যকে একটি লাইনে রাখেন, তার অর্থ grepএটি পুরো মেমরির লোড হয়ে যাবে (এখানে হেক্স এনকোডিংয়ের কারণে মূল ফাইল + 1 এর দ্বিগুণ), সুতরাং শেষ পর্যন্ত এটি আরও বেশি হয়ে যায় ওভারহেড চেয়ে pythonপদ্ধতির বা perlসঙ্গে এক -0777। আপনার এমন একটি grepবাস্তবায়নও দরকার যা স্বেচ্ছাসেবী দৈর্ঘ্যের লাইনগুলিকে সমর্থন করে (যারা সমর্থনগুলি -oসাধারণত এটি করে) অন্যথায় ভাল উত্তর।
স্টাফেন চেজেলাস

1
আপনার হেক্স সংস্করণগুলি কচুর স্থানান্তরিত মানগুলির সাথে মেলে? E fb ea dd e? কাঙ্ক্ষিত বাইট ছাড়াও। od -An -tx1 | tr -d '\n'বা hexdump -v -e '/1 " %02x"'কোনও অনুসন্ধান স্ট্রিংয়ের সাথে স্পেস থাকা এড়াতে পারে তবে আমি এর জন্য কোনও ঠিক করি না xxd
dave_thompson_085

@ dave_thompson_085 উত্তর সম্পাদিত। আমি বিশ্বাস করি যে উত্তরটি এখন কেবলমাত্র বাইট সীমানার সাথে মিলবে, আবারও ধন্যবাদ।
sorontar

@ স্টাফেনচাজলাস আপনি কি অবিশক্ত শেড ব্যবহারের প্রস্তাবিত বিকল্পটি পর্যালোচনা করতে পারবেন? ধন্যবাদ।
sorontar

sed -u(যেখানে উপলভ্য) আনবুফারের জন্য। তার মানে এটি ইনপুটটিতে একবারে একটি বাইট পড়বে এবং বাফারিং ছাড়াই সরাসরি তার আউটপুট আউটপুট দেবে। যেকোন ক্ষেত্রে, এটি এখনও প্যাটার্ন স্পেসে পুরো লাইনটি লোড করতে হবে, সুতরাং এখানে সাহায্য করবে না।
স্টাফেন চেজেলাস

7

সঙ্গে গনুহ grepএর -P(Perl-regexp) পতাকা

LC_ALL=C grep -oaP '\xef\xbe\xad\xde' file | wc -l

LC_ALL=C মাল্টি-বাইট লোকেলগুলিতে সমস্যা এড়ানো is grep অন্যথায় বাইটগুলির ক্রমগুলি অক্ষর হিসাবে ব্যাখ্যা করার চেষ্টা করবে।

-aবাইনারি ফাইলগুলি পাঠ্য ফাইলের সমতুল্য আচরণ করে (সাধারণ আচরণের পরিবর্তে, যেখানে grepকেবল কমপক্ষে একটি মিল আছে কিনা তা কেবল প্রিন্ট করে)


এই সমাধানটি সর্বদা আমাকে সঠিক সংখ্যার পরিবর্তে 0 টি ম্যাচ দিচ্ছে।
hugomg

@ হুগমগ, এটি কি হতে পারে যে grep ম্যাচটি পেতে আপনার পাস করা বাইটগুলি রিভার্স করা দরকার ?
ইরুভর

আমি মনে করি না এটি আদেশ। এই প্রশ্নের অন্য দুটি উত্তর সঠিকভাবে কাজ করে।
hugomg

2
@ হুগমগ, এটি লোকাল। সম্পাদনা দেখুন।
স্টাফেন চেজেলাস

2
আমি -aবিকল্পটি অন্তর্ভুক্ত করার পরামর্শ দেব , অন্যথায় গ্রেপ উত্তর দিবে Binary file file.bin matchesযে কোনও ফাইলের জন্য গ্রেপ বাইনারি হিসাবে সনাক্ত করে।
sorontar

6
PERLIO=:raw perl -nE '$c++ while m/\xef\xbe\xad\xde/g; END{say $c}' file

যা ইনপুট ফাইল (গুলি) কে বাইনারি হিসাবে বিবেচনা করে ( লাইনফিড বা এনকোডিংগুলির জন্য কোনও অনুবাদ নয়, পার্লারুন দেখুন ) তারপরে ইনপুট ফাইলগুলি লুপ করে প্রদত্ত হেক্সের সমস্ত ম্যাচের (বা যা কিছু ফর্ম, পার্লার দেখুন ) ছাঁটাই করছে না printing


2
নোট করুন যে সন্ধানের ক্রমটিতে বাইট 0xa থাকলে আপনি এটি ব্যবহার করতে পারবেন না। সেক্ষেত্রে আপনি একটি ভিন্ন রেকর্ড বিভাজক (সহ -0ooo) ব্যবহার করতে পারেন ।
স্টাফেন চেজেলাস

1
@ স্টাফেনচাজেলাস আপনি $/কিছুটা আলাদা ট্রেড perl -nE 'BEGIN { $/ = "\xef\xbe\xad\xde" } chomp; $c++ unless eof && length; END { say $c }'
অফের

@ স্টাফেনচাজেলাস দয়া করে কোনও বাইট মানগুলির সমাধানের জন্য আমার উত্তরটি পড়ুন।
sorontar

1
@ হোবস, যে কোনও ক্ষেত্রে, এমনকি এখানে, মেমরির ব্যবহার দুটি 0xa বাইটের মধ্যে সর্বাধিক দূরত্বের সমানুপাতিক হবে যা অ-পাঠ্য ফাইলগুলির জন্য নির্বিচারে বড় হতে পারে।
স্টাফেন চেজেলাস

5

জিএনইউ দিয়ে awkআপনি এটি করতে পারেন:

LC_ALL=C awk -v 'RS=\xef\xbe\xad\xde' 'END{print NR - (NR && RT == "")}'

বাইটগুলির মধ্যে যদি কোনও ইআরআর অপারেটর হয় তবে তাদের (যদিও \\) সাথে পালাতে হবে । ভালো লেগেছে 0x2eযা .যেমন প্রবেশ করানো হবে \\.বা \\\x2e। তা ছাড়া, এটি 0 এবং 0xa সহ নির্বিচারে বাইট মানগুলির সাথে কাজ করা উচিত।

মনে রাখবেন যে এটি বেশ NR-1কয়েকটি সাধারণ ক্ষেত্রে রয়েছে বলে ঠিক এতটা সহজ নয় :

  • যখন ইনপুটটি খালি থাকে, এনআর 0 হয়, এনআর -1 দেয় -1 দেয়।
  • যখন ইনপুটটি রেকর্ড বিভাজকটিতে শেষ হয়, তার পরে একটি খালি রেকর্ড তৈরি হয় না। আমরা এটির জন্য পরীক্ষা করি RT==""

আরও মনে রাখবেন যে সবচেয়ে খারাপ ক্ষেত্রে (যদি ফাইলটিতে অনুসন্ধানের শব্দটি না থাকে), ফাইলটি স্মৃতিতে লোড হয়ে যায়)


5

আমি দেখতে সবচেয়ে সোজা-এগিয়ে অনুবাদটি হ'ল:

$ echo $'\xef\xbe\xad\xde' > hugohex
$ echo $'\xef\xbe\xad\xde\xef\xbe\xad\xde' >> hugohex
$ grep -F -a -o -e $'\xef\xbe\xad\xde' hugohex|wc -l
3

আমি কোথা থেকে ব্যবহার করেছি $'\xef'যেমন ব্যাশ ANSI-উদ্ধৃত (মূলত একটি ksh93বৈশিষ্ট্য, এখন দ্বারা সমর্থিত zsh, bash, mksh, ফ্রিবিএসডি sh) মাছের সংস্করণ \Xef, এবং ব্যবহৃত grep -o ... | wc -lদৃষ্টান্ত গণনা।grep -oপ্রতিটি ম্যাচ পৃথক লাইনে আউটপুট করে। -aপতাকা বাইনারি ফাইল একই ভাবে এটা টেক্সট ফাইল আছে, grep আচরণ করে তোলে। -Fস্থির স্ট্রিংগুলির জন্য তাই আপনার রেজিেক্স অপারেটরদের পালানোর দরকার নেই।

আপনার fishক্ষেত্রে মত, আপনি এই পদ্ধতির ব্যবহার করতে পারবেন না যদিও সন্ধানের ক্রমটিতে বাইট 0 বা 0xa (এএসসিআইআইতে নতুন লাইন) অন্তর্ভুক্ত রয়েছে।


ব্যবহার করা printf '%b' $(printf '\\%o ' $((0xef)) $((0xbe)) $((0xad)) $((0xde))) > hugohex'হবে সবচেয়ে বহনযোগ্য "খাঁটি শেল" পদ্ধতি। অবশ্যই: printf "efbeadde" | xxd -p -r > hugohexমনে হয় সবচেয়ে ব্যবহারিক পদ্ধতির মতো।
sorontar

4

bytes.countবাইস্ট্রিংয়ে মোট নন-ওভারল্যাপিং সাবস্ট্রিংগুলির সংখ্যা পাওয়ার জন্য আপনি পাইথনের পদ্ধতিটি ব্যবহার করতে পারেন ।

python -c "print(open('./myexecutable', 'rb').read().count(b'\xef\xbe\xad\xde'))"

এই ওয়ান-লাইনারটি পুরো ফাইলটিকে মেমরিতে লোড করবে, তাই সবচেয়ে দক্ষ নয়, তবে এটি কাজ করে এবং পার্লের চেয়ে আরও সুস্পষ্ট;


'পার্লের চেয়ে আরও সুস্পষ্ট' টিইসিও থেকে কেবল এক ধাপ উপরে - যা আইআইএনএম হ'ল: 239I$ 190I$ 173I$ 222I$ HXA ERfile$Y 0UC <:S^EQA$; %C$> QC=(জিডি ও আর)
ডেভ_্থম্পসন_085

আপনি mmap()পাইথনে ফাইল করতে পারেন ; যে স্মৃতিবদ্ধতা কমিয়ে আনতে হবে।
টবি স্পিড


1

আমি মনে করি আপনি পার্ল ব্যবহার করতে পারেন, একবার চেষ্টা করে দেখুন:

perl -0777ne 'CORE::say STDOUT s/\xef\xbe\xad\xde//g' file_name  

রিপ্লেস কমান্ডটি sপ্রতিস্থাপনের সংখ্যা দেয়, -0777 এর অর্থ নতুন লাইনটিকে বিশেষ চরিত্র হিসাবে বিবেচনা করবেন না, e- কমান্ড এক্সিকিউট করুন, sayপরবর্তীটি প্রিন্ট করতে তারপরে নতুন লাইন অক্ষর মুদ্রণ করুন,n আমি পুরোপুরি আঁকড়ে ধরেছিলাম না, তবে w / আউট কাজ করে না - থেকে দস্তাবেজ:

পার্লকে আপনার প্রোগ্রামের চারপাশে নীচের লুপটি ধরে নিয়েছে, যা ফাইল নাম যুক্তিগুলিকে কিছুটা সেড-এন বা অ্যাজকের মতো পুনরাবৃত্তি করে তোলে: লাইন: যখন (<>) {... # আপনার প্রোগ্রামটি এখানে যায়}

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.