/usr/lib/python3/dist-packages/binwalk/modules/hexdiff.py is in python3-binwalk 2.1.1-16.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | import os
import sys
import string
import binwalk.core.common as common
from binwalk.core.compat import *
from binwalk.core.module import Module, Option, Kwarg
class HexDiff(Module):
COLORS = {
'red' : '31',
'green' : '32',
'blue' : '34',
}
SEPERATORS = ['\\', '/']
DEFAULT_BLOCK_SIZE = 16
SKIPPED_LINE = "*"
CUSTOM_DISPLAY_FORMAT = "0x%.8X %s"
TITLE = "Binary Diffing"
CLI = [
Option(short='W',
long='hexdump',
kwargs={'enabled' : True},
description='Perform a hexdump / diff of a file or files'),
Option(short='G',
long='green',
kwargs={'show_green' : True},
description='Only show lines containing bytes that are the same among all files'),
Option(short='i',
long='red',
kwargs={'show_red' : True},
description='Only show lines containing bytes that are different among all files'),
Option(short='U',
long='blue',
kwargs={'show_blue' : True},
description='Only show lines containing bytes that are different among some files'),
Option(short='w',
long='terse',
kwargs={'terse' : True},
description='Diff all files, but only display a hex dump of the first file'),
]
KWARGS = [
Kwarg(name='show_red', default=False),
Kwarg(name='show_blue', default=False),
Kwarg(name='show_green', default=False),
Kwarg(name='terse', default=False),
Kwarg(name='enabled', default=False),
]
RESULT_FORMAT = "%s\n"
RESULT = ['display']
def _no_colorize(self, c, color="red", bold=True):
return c
def _colorize(self, c, color="red", bold=True):
attr = []
attr.append(self.COLORS[color])
if bold:
attr.append('1')
return "\x1b[%sm%s\x1b[0m" % (';'.join(attr), c)
def _color_filter(self, data):
red = '\x1b[' + self.COLORS['red'] + ';'
green = '\x1b[' + self.COLORS['green'] + ';'
blue = '\x1b[' + self.COLORS['blue'] + ';'
if self.show_blue and blue in data:
return True
elif self.show_green and green in data:
return True
elif self.show_red and red in data:
return True
return False
def hexascii(self, target_data, byte, offset):
color = "green"
for (fp_i, data_i) in iterator(target_data):
diff_count = 0
for (fp_j, data_j) in iterator(target_data):
if fp_i == fp_j:
continue
try:
if data_i[offset] != data_j[offset]:
diff_count += 1
except IndexError as e:
diff_count += 1
if diff_count == len(target_data)-1:
color = "red"
elif diff_count > 0:
color = "blue"
break
hexbyte = self.colorize("%.2X" % ord(byte), color)
if byte not in string.printable or byte in string.whitespace:
byte = "."
asciibyte = self.colorize(byte, color)
return (hexbyte, asciibyte)
def diff_files(self, target_files):
last_line = None
loop_count = 0
sep_count = 0
# Figure out the maximum diff size (largest file size)
self.status.total = 0
for i in range(0, len(target_files)):
if target_files[i].size > self.status.total:
self.status.total = target_files[i].size
self.status.fp = target_files[i]
while True:
line = ""
done_files = 0
block_data = {}
seperator = self.SEPERATORS[sep_count % 2]
for fp in target_files:
block_data[fp] = fp.read(self.block)
if not block_data[fp]:
done_files += 1
# No more data from any of the target files? Done.
if done_files == len(target_files):
break
for fp in target_files:
hexline = ""
asciiline = ""
for i in range(0, self.block):
if i >= len(block_data[fp]):
hexbyte = "XX"
asciibyte = "."
else:
(hexbyte, asciibyte) = self.hexascii(block_data, block_data[fp][i], i)
hexline += "%s " % hexbyte
asciiline += "%s" % asciibyte
line += "%s |%s|" % (hexline, asciiline)
if self.terse:
break
if fp != target_files[-1]:
line += " %s " % seperator
offset = fp.offset + (self.block * loop_count)
if not self._color_filter(line):
display = line = self.SKIPPED_LINE
else:
display = self.CUSTOM_DISPLAY_FORMAT % (offset, line)
sep_count += 1
if line != self.SKIPPED_LINE or last_line != line:
self.result(offset=offset, description=line, display=display)
last_line = line
loop_count += 1
self.status.completed += self.block
def init(self):
# To mimic expected behavior, if all options are False, we show everything
if not any([self.show_red, self.show_green, self.show_blue]):
self.show_red = self.show_green = self.show_blue = True
# Always disable terminal formatting, as it won't work properly with colorized output
self.config.display.fit_to_screen = False
# Set the block size (aka, hexdump line size)
self.block = self.config.block
if not self.block:
self.block = self.DEFAULT_BLOCK_SIZE
# Build a list of files to hexdiff
self.hex_target_files = []
while True:
f = self.next_file(close_previous=False)
if not f:
break
else:
self.hex_target_files.append(f)
# Build the header format string
header_width = (self.block * 4) + 2
if self.terse:
file_count = 1
else:
file_count = len(self.hex_target_files)
self.HEADER_FORMAT = "OFFSET " + (("%%-%ds " % header_width) * file_count) + "\n"
# Build the header argument list
self.HEADER = [fp.name for fp in self.hex_target_files]
if self.terse and len(self.HEADER) > 1:
self.HEADER = self.HEADER[0]
# Set up the tty for colorization, if it is supported
if hasattr(sys.stderr, 'isatty') and sys.stderr.isatty() and not common.MSWindows():
import curses
curses.setupterm()
self.colorize = self._colorize
else:
self.colorize = self._no_colorize
def run(self):
if self.hex_target_files:
self.header()
self.diff_files(self.hex_target_files)
self.footer()
|