Using grep to search for hex strings in a file

120,728

Solution 1

We tried several things before arriving at an acceptable solution:

xxd -u /usr/bin/xxd | grep 'DF'
00017b0: 4010 8D05 0DFF FF0A 0300 53E3 0610 A003  @.........S.....


root# grep -ibH "df" /usr/bin/xxd
Binary file /usr/bin/xxd matches
xxd -u /usr/bin/xxd | grep -H 'DF'
(standard input):00017b0: 4010 8D05 0DFF FF0A 0300 53E3 0610 A003  @.........S.....

Then found we could get usable results with

xxd -u /usr/bin/xxd > /tmp/xxd.hex ; grep -H 'DF' /tmp/xxd

Note that using a simple search target like 'DF' will incorrectly match characters that span across byte boundaries, i.e.

xxd -u /usr/bin/xxd | grep 'DF'
00017b0: 4010 8D05 0DFF FF0A 0300 53E3 0610 A003  @.........S.....
--------------------^^

So we use an ORed regexp to search for ' DF' OR 'DF ' (the searchTarget preceded or followed by a space char).

The final result seems to be

xxd -u -ps -c 10000000000 DumpFile > DumpFile.hex
egrep ' DF|DF ' Dumpfile.hex

0001020: 0089 0424 8D95 D8F5 FFFF 89F0 E8DF F6FF  ...$............
-----------------------------------------^^
0001220: 0C24 E871 0B00 0083 F8FF 89C3 0F84 DF03  .$.q............
--------------------------------------------^^

Solution 2

This seems to work for me:

LANG=C grep --only-matching --byte-offset --binary --text --perl-regexp "<\x-hex pattern>" <file>

short form:

LANG=C grep -obUaP "<\x-hex pattern>" <file>

Example:

LANG=C grep -obUaP "\x01\x02" /bin/grep

Output (cygwin binary):

153: <\x01\x02>
33210: <\x01\x02>
53453: <\x01\x02>

So you can grep this again to extract offsets. But don't forget to use binary mode again.

Note: LANG=C is needed to avoid utf8 encoding issues.

Solution 3

There's also a pretty handy tool called binwalk, written in python, which provides for binary pattern matching (and quite a lot more besides). Here's how you would search for a binary string, which outputs the offset in decimal and hex (from the docs):

$ binwalk -R "\x00\x01\x02\x03\x04" firmware.bin
DECIMAL     HEX         DESCRIPTION
--------------------------------------------------------------------------
377654      0x5C336     Raw string signature

Solution 4

grep has a -P switch allowing to use perl regexp syntax the perl regex allows to look at bytes, using \x.. syntax.

so you can look for a given hex string in a file with: grep -aP "\xdf"

but the outpt won't be very useful; indeed better do a regexp on the hexdump output;

The grep -P can be useful however to just find files matrching a given binary pattern. Or to do a binary query of a pattern that actually happens in text (see for example How to regexp CJK ideographs (in utf-8) )

Solution 5

I just used this:

grep -c $'\x0c' filename

To search for and count a page control character in the file..

So to include an offset in the output:

grep -b -o $'\x0c' filename | less

I am just piping the result to less because the character I am greping for does not print well and the less displays the results cleanly. Output example:

21:^L
23:^L
2005:^L
Share:
120,728
user650649
Author by

user650649

Updated on January 31, 2021

Comments

  • user650649
    user650649 over 3 years

    I have been trying all day to get this to work. Does anyone know how to get grep, or something of the like, to retrieve offsets of hex strings in a file?

    I have a bunch of hexdumps that I need to check for strings and then run again and check if the value has changed.

    I have tried hexdump and dd, but the problem is because it's a stream, I lose my offset for the files.

    Someone must have had this problem and a workaround. What can I do?

    To clarify, I have a series of dumped memory regions from GDB.

    I am trying to narrow down a number by searching out all the places the number is stored, then doing it again and checking if the new value is stored at the same memory location.

    I cannot get grep to do anything because I am looking for hex values so all the times I have tried (like a bazillion, roughly) it will not give me the correct output.

    The hex dumps are just complete binary files, the paterns are within float values at larges so 8? bytes?

    The patterns are not wrapping the lines that I am aware of. I am aware of the what it changes to, and I can do the same process and compare the lists to see which match. The hex dumps normally end up (in total) 100 megs-ish.

    Perl COULD be a option, but at this point, I would assume my lack of knowledge with bash and its tools is the main culprit.

    Its a little hard to explain the output I am getting since I really am not getting any output..

    I am anticipating (and expecting) something along the lines of:

    <offset>:<searched value>
    

    Which is the pretty well standard output I would normally get with grep -URbFo <searchterm> . > <output>

    Problem is, when I try to search for hex values, I get the problem of if just not searching for the hex values, so if I search for 00 I should get like a million hits, because thats always the blankspace, but instead its searching for 00 as text, so in hex, 3030. Any idea's?

    I CAN force it through hexdump or something of the link but because its a stream it will not give me the offsets and filename that it found a match in.

    Using grep -b option doesnt seem to work either, I did try all the flags that seemed useful to my situation, and nothing worked.

    Using xxd -u /usr/bin/xxd as an example I get a output that would be useful, but I cannot use that for searching..

    0004760: 73CC 6446 161E 266A 3140 5E79 4D37 FDC6  s.dF..&j1@^yM7..
    0004770: BF04 0E34 A44E 5BE7 229F 9EEF 5F4F DFFA  ...4.N[."..._O..
    0004780: FADE 0C01 0000 000C 0000 0000 0000 0000  ................
    

    Nice output, just what I wana see, but it just doesnt work for me in this situation..

    This is some of the things i've tried since posting this:

    xxd -u /usr/bin/xxd | grep 'DF'
    00017b0: 4010 8D05 0DFF FF0A 0300 53E3 0610 A003  @.........S.....
    
    root# grep -ibH "df" /usr/bin/xxd
    Binary file /usr/bin/xxd matches
    xxd -u /usr/bin/xxd | grep -H 'DF'
    (standard input):00017b0: 4010 8D05 0DFF FF0A 0300 53E3 0610 A003  @.........S.....
    
  • user650649
    user650649 almost 13 years
    I looked at bgrep, its not printable stings im looking for.. a lot of the time I am trying to find think that are unprintable and its certainly possible to end up with values in hex that end up being backspaces etc. I will try the bgrep and see if it works for me.
  • user650649
    user650649 almost 13 years
    What I actually ended up using for xxd was: xxd -ps -u -c 100000000000000000000 input.file > output.file in order to get rid of the excess information and give me raw hex. This gave me a way to use grep to search the hex itself, but when it returns a offset, remember to divide the offset by 2 to get the actual offset. Thank you so much for your help! Oh, and I cant vote up yet..
  • Calaf
    Calaf over 9 years
    Caveat: Darwin's (OS X's) and hence presumably also BSD's grep does not have the --perl-regexp option.
  • bmaupin
    bmaupin almost 9 years
    What am I missing? xxd -u system.raw.img.tmp | grep 53EF | wc -l gives me 2105, grep -obUaP "\x53\xEF" system.raw.img.tmp | wc -l gives me 18
  • bmaupin
    bmaupin almost 9 years
    Got it; UTF8 messes this up. This works: LANG=C grep -obUaP "\x53\xEF" system.raw.img.tmp
  • Japanish
    Japanish almost 9 years
    Mr.bmaupin. Worked for me. Thanks!
  • Fran Marzoa
    Fran Marzoa over 8 years
    Just to point out this doesn't seem to work in OSX, and maybe not in FreeBSD either, but it does it just replacing the simple quotes by double ones like in: grep -c $"\x0c" filename
  • JPT
    JPT over 7 years
    you may pipe the result through hexdump, this will deal with non printable chars
  • Ruslan
    Ruslan over 7 years
    xxd has -g option which will help you prevent matching across two bytes. I.e. use xxd -g1 instead of xxd.
  • Pedro Gimeno
    Pedro Gimeno almost 7 years
    Unfortunately I can't use this to search hex strings that have \x0A in them. I had to write my own hex search tool.
  • Cameron
    Cameron over 6 years
    Wow, this actually works with the Windows port of grep out of the box ^^
  • uldics
    uldics about 4 years
    Had almost same issue - to extract a zip file list of files, but could not get the part of file directly into a variable, as the null bytes were removed. So my solution is to find byte offset of start and stop of that part, store in a variable, increase the address to appropriate place, then extract that part with dd. grep -boaP "\x50\x4b\x05\x06" weirdfiles.zip | cut -d: -f1 Result: 100483 Parameters: b gives byte offsett, o shows only match and gets match start instead of line start, a will search in binary files - ones with non printable characters, P Perl regex
  • truthadjustr
    truthadjustr over 3 years
    Thanks it works! I am able to find every file that has the hex byte sequence 46 41 43 00 using this command: find . -type f -exec grep -q -obUaP "\x46\x41\x43\x00" {} \; -exec echo {} \;
  • Robert Calhoun
    Robert Calhoun almost 3 years
    You should get double points for "LANG=C", since otherwise grep can't find bytes that are plain as day in hexdump.
  • bebbo
    bebbo over 2 years
    NOTE: this does not work reliably!!! I'm searching .o files plus the resulting files. Only some .o files show up but the the resulting file. So there are still some issues. \x04\xe7\x88\x2f\x00\x2f\x2a does not work, but \xe7\x88\x2f\x00\x2f\x2a finds more results, despite the \x04 is present.