Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
binwalk
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fact-gitdep
binwalk
Commits
ae122ee8
Commit
ae122ee8
authored
Dec 13, 2013
by
devttys0
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial move of hexdiff.py/plotter.py to modules.
parent
1a117715
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
380 additions
and
38 deletions
+380
-38
binvis.py
src/binwalk/modules/binvis.py
+310
-0
hexdiff.py
src/binwalk/modules/hexdiff.py
+70
-38
No files found.
src/binwalk/modules/binvis.py
0 → 100644
View file @
ae122ee8
import
os
import
binwalk.module
from
binwalk.compat
import
*
from
binwalk.common
import
BlockFile
class
Plotter
(
object
):
'''
Base class for plotting binaries in Qt.
Other plotter classes are derived from this.
'''
VIEW_DISTANCE
=
1024
MAX_2D_PLOT_POINTS
=
12500
MAX_3D_PLOT_POINTS
=
25000
NAME
=
"Binary Visualization"
CLI
=
[
binwalk
.
module
.
ModuleOption
(
short
=
'3'
,
long
=
'3D'
,
kwargs
=
{
'axis'
:
3
,
'enabled'
:
True
},
description
=
'Generate a 3D binary visualization'
),
binwalk
.
module
.
ModuleOption
(
short
=
'2'
,
long
=
'2D'
,
kwargs
=
{
'axis'
:
2
,
'enabled'
:
True
},
description
=
'Project data points onto 3D cube walls only'
),
binwalk
.
module
.
ModuleOption
(
short
=
'Z'
,
long
=
'max-points'
,
type
=
int
,
kwargs
=
{
'max_points'
:
0
},
nargs
=
1
,
description
=
'Set the maximum number of plotted data points'
),
binwalk
.
module
.
ModuleOption
(
short
=
'V'
,
long
=
'show-grids'
,
kwargs
=
{
'show_grids'
:
True
},
description
=
'Display the x-y-z grids in the resulting plot'
),
]
KWARGS
=
[
binwalk
.
module
.
ModuleKwarg
(
name
=
'axis'
,
default
=
3
),
binwalk
.
module
.
ModuleKwarg
(
name
=
'max_points'
,
default
=
0
),
binwalk
.
module
.
ModuleKwarg
(
name
=
'show_grids'
,
default
=
False
),
]
def
__init__
(
self
,
**
kwargs
):
'''
Class constructor.
@axis - Set to 2 for 2D plotting, 3 for 3D plotting.
@max_points - The maximum number of data points to display.
@show_grids - Set to True to display x-y-z grids.
Returns None.
'''
import
pyqtgraph.opengl
as
gl
from
pyqtgraph.Qt
import
QtGui
binwalk
.
module
.
process_kwargs
(
self
,
kwargs
)
self
.
verbose
=
self
.
config
.
verbose
self
.
files
=
self
.
config
.
target_files
self
.
offset
=
self
.
config
.
offset
self
.
length
=
self
.
config
.
length
self
.
plane_count
=
-
1
self
.
plot_points
=
None
if
self
.
axis
==
2
:
self
.
MAX_PLOT_POINTS
=
self
.
MAX_2D_PLOT_POINTS
self
.
_generate_data_point
=
self
.
_generate_2d_data_point
elif
self
.
axis
==
3
:
self
.
MAX_PLOT_POINTS
=
self
.
MAX_3D_PLOT_POINTS
self
.
_generate_data_point
=
self
.
_generate_3d_data_point
else
:
raise
Exception
(
"Invalid Plotter axis specified:
%
d. Must be one of: [2, 3]."
%
self
.
axis
)
if
not
self
.
max_points
:
self
.
max_points
=
self
.
MAX_PLOT_POINTS
self
.
app
=
QtGui
.
QApplication
([])
self
.
window
=
gl
.
GLViewWidget
()
self
.
window
.
opts
[
'distance'
]
=
self
.
VIEW_DISTANCE
if
len
(
self
.
files
)
==
1
:
self
.
window
.
setWindowTitle
(
self
.
files
[
0
])
def
_print
(
self
,
message
):
'''
Print console messages. For internal use only.
'''
if
self
.
verbose
:
print
(
message
)
def
_generate_plot_points
(
self
,
data_points
):
'''
Generates plot points from a list of data points.
@data_points - A dictionary containing each unique point and its frequency of occurance.
Returns a set of plot points.
'''
total
=
0
min_weight
=
0
weightings
=
{}
plot_points
=
{}
# If the number of data points exceeds the maximum number of allowed data points, use a
# weighting system to eliminate data points that occur less freqently.
if
sum
(
data_points
.
itervalues
())
>
self
.
max_points
:
# First, generate a set of weight values 1 - 10
for
i
in
range
(
1
,
11
):
weightings
[
i
]
=
0
# Go through every data point and how many times that point occurs
for
(
point
,
count
)
in
iterator
(
data_points
):
# For each data point, compare it to each remaining weight value
for
w
in
get_keys
(
weightings
):
# If the number of times this data point occurred is >= the weight value,
# then increment the weight value. Since weight values are ordered lowest
# to highest, this means that more frequent data points also increment lower
# weight values. Thus, the more high-frequency data points there are, the
# more lower-frequency data points are eliminated.
if
count
>=
w
:
weightings
[
w
]
+=
1
else
:
break
# Throw out weight values that exceed the maximum number of data points
if
weightings
[
w
]
>
self
.
max_points
:
del
weightings
[
w
]
# If there's only one weight value left, no sense in continuing the loop...
if
len
(
weightings
)
==
1
:
break
# The least weighted value is our minimum weight
min_weight
=
min
(
weightings
)
# Get rid of all data points that occur less frequently than our minimum weight
for
point
in
get_keys
(
data_points
):
if
data_points
[
point
]
<
min_weight
:
del
data_points
[
point
]
for
point
in
sorted
(
data_points
,
key
=
data_points
.
get
,
reverse
=
True
):
plot_points
[
point
]
=
data_points
[
point
]
total
+=
1
if
total
>=
self
.
max_points
:
break
return
plot_points
def
_generate_data_point
(
self
,
data
):
'''
Subclasses must override this to return the appropriate data point.
@data - A string of data self.axis in length.
Returns a data point tuple.
'''
return
(
0
,
0
,
0
)
def
_generate_data_points
(
self
,
file_name
):
'''
Generates a dictionary of data points and their frequency of occurrance.
@file_name - The file to generate data points from.
Returns a dictionary.
'''
i
=
0
data_points
=
{}
self
.
_print
(
"Generating data points for
%
s"
%
file_name
)
with
BlockFile
(
file_name
,
'r'
,
offset
=
self
.
offset
,
length
=
self
.
length
)
as
fp
:
fp
.
MAX_TRAILING_SIZE
=
0
while
True
:
(
data
,
dlen
)
=
fp
.
read_block
()
if
not
data
or
not
dlen
:
break
i
=
0
while
(
i
+
(
self
.
axis
-
1
))
<
dlen
:
point
=
self
.
_generate_data_point
(
data
[
i
:
i
+
self
.
axis
])
if
has_key
(
data_points
,
point
):
data_points
[
point
]
+=
1
else
:
data_points
[
point
]
=
1
i
+=
3
return
data_points
def
_generate_plot
(
self
,
plot_points
):
import
numpy
as
np
import
pyqtgraph.opengl
as
gl
nitems
=
float
(
len
(
plot_points
))
pos
=
np
.
empty
((
nitems
,
3
))
size
=
np
.
empty
((
nitems
))
color
=
np
.
empty
((
nitems
,
4
))
i
=
0
for
(
point
,
weight
)
in
iterator
(
plot_points
):
r
=
0.0
g
=
0.0
b
=
0.0
pos
[
i
]
=
point
frequency_percentage
=
(
weight
/
nitems
)
# Give points that occur more frequently a brighter color and larger point size.
# Frequency is determined as a percentage of total unique data points.
if
frequency_percentage
>
.
005
:
size
[
i
]
=
.
20
r
=
1.0
elif
frequency_percentage
>
.
002
:
size
[
i
]
=
.
10
g
=
1.0
r
=
1.0
else
:
size
[
i
]
=
.
05
g
=
1.0
color
[
i
]
=
(
r
,
g
,
b
,
1.0
)
i
+=
1
scatter_plot
=
gl
.
GLScatterPlotItem
(
pos
=
pos
,
size
=
size
,
color
=
color
,
pxMode
=
False
)
scatter_plot
.
translate
(
-
127.5
,
-
127.5
,
-
127.5
)
return
scatter_plot
def
plot
(
self
,
wait
=
True
):
import
pyqtgraph.opengl
as
gl
self
.
window
.
show
()
if
self
.
show_grids
:
xgrid
=
gl
.
GLGridItem
()
ygrid
=
gl
.
GLGridItem
()
zgrid
=
gl
.
GLGridItem
()
self
.
window
.
addItem
(
xgrid
)
self
.
window
.
addItem
(
ygrid
)
self
.
window
.
addItem
(
zgrid
)
# Rotate x and y grids to face the correct direction
xgrid
.
rotate
(
90
,
0
,
1
,
0
)
ygrid
.
rotate
(
90
,
1
,
0
,
0
)
# Scale grids to the appropriate dimensions
xgrid
.
scale
(
12.8
,
12.8
,
12.8
)
ygrid
.
scale
(
12.8
,
12.8
,
12.8
)
zgrid
.
scale
(
12.8
,
12.8
,
12.8
)
for
file_name
in
self
.
files
:
data_points
=
self
.
_generate_data_points
(
file_name
)
self
.
_print
(
"Generating plot points from
%
d data points"
%
len
(
data_points
))
self
.
plot_points
=
self
.
_generate_plot_points
(
data_points
)
del
data_points
self
.
_print
(
"Generating graph from
%
d plot points"
%
len
(
self
.
plot_points
))
self
.
window
.
addItem
(
self
.
_generate_plot
(
self
.
plot_points
))
if
wait
:
self
.
wait
()
def
wait
(
self
):
from
pyqtgraph.Qt
import
QtCore
,
QtGui
t
=
QtCore
.
QTimer
()
t
.
start
(
50
)
QtGui
.
QApplication
.
instance
()
.
exec_
()
def
_generate_3d_data_point
(
self
,
data
):
'''
Plot data points within a 3D cube.
'''
return
(
ord
(
data
[
0
]),
ord
(
data
[
1
]),
ord
(
data
[
2
]))
def
_generate_2d_data_point
(
self
,
data
):
'''
Plot data points projected on each cube face.
'''
self
.
plane_count
+=
1
if
self
.
plane_count
>
5
:
self
.
plane_count
=
0
if
self
.
plane_count
==
0
:
return
(
0
,
ord
(
data
[
0
]),
ord
(
data
[
1
]))
elif
self
.
plane_count
==
1
:
return
(
ord
(
data
[
0
]),
0
,
ord
(
data
[
1
]))
elif
self
.
plane_count
==
2
:
return
(
ord
(
data
[
0
]),
ord
(
data
[
1
]),
0
)
elif
self
.
plane_count
==
3
:
return
(
255
,
ord
(
data
[
0
]),
ord
(
data
[
1
]))
elif
self
.
plane_count
==
4
:
return
(
ord
(
data
[
0
]),
255
,
ord
(
data
[
1
]))
elif
self
.
plane_count
==
5
:
return
(
ord
(
data
[
0
]),
ord
(
data
[
1
]),
255
)
def
run
(
self
):
self
.
plot
()
return
self
.
plot_points
src/binwalk/hexdiff.py
→
src/binwalk/
modules/
hexdiff.py
View file @
ae122ee8
#!/usr/bin/env python
#!/usr/bin/env python
# TODO: Use sane defaults for block size and file size, if not specified.
# Handle header output for multiple files.
import
os
import
os
import
sys
import
sys
import
curses
import
curses
import
platform
import
platform
import
binwalk.module
import
binwalk.common
as
common
import
binwalk.common
as
common
from
binwalk.compat
import
*
from
binwalk.compat
import
*
...
@@ -22,23 +26,43 @@ class HexDiff(object):
...
@@ -22,23 +26,43 @@ class HexDiff(object):
'blue'
:
'34'
,
'blue'
:
'34'
,
}
}
def
__init__
(
self
,
binwalk
=
None
):
NAME
=
"Binary Diffing"
CLI
=
[
binwalk
.
module
.
ModuleOption
(
short
=
'W'
,
long
=
'hexdump'
,
kwargs
=
{
'enabled'
:
True
},
description
=
'Perform a hexdump / diff of a file or files'
),
binwalk
.
module
.
ModuleOption
(
short
=
'G'
,
long
=
'green'
,
kwargs
=
{
'show_green'
:
True
,
'show_blue'
:
False
,
'show_green'
:
False
},
description
=
'Only show lines containing bytes that are the same among all files'
),
binwalk
.
module
.
ModuleOption
(
short
=
'i'
,
long
=
'red'
,
kwargs
=
{
'show_red'
:
True
,
'show_blue'
:
False
,
'show_green'
:
False
},
description
=
'Only show lines containing bytes that are different among all files'
),
binwalk
.
module
.
ModuleOption
(
short
=
'U'
,
long
=
'blue'
,
kwargs
=
{
'show_blue'
:
True
,
'show_red'
:
False
,
'show_green'
:
False
},
description
=
'Only show lines containing bytes that are different among some files'
),
binwalk
.
module
.
ModuleOption
(
short
=
'w'
,
long
=
'terse'
,
kwargs
=
{
'terse'
:
True
},
description
=
'Diff all files, but only display a hex dump of the first file'
),
]
KWARGS
=
[
binwalk
.
module
.
ModuleKwarg
(
name
=
'show_red'
,
default
=
True
),
binwalk
.
module
.
ModuleKwarg
(
name
=
'show_blue'
,
default
=
True
),
binwalk
.
module
.
ModuleKwarg
(
name
=
'show_green'
,
default
=
True
),
binwalk
.
module
.
ModuleKwarg
(
name
=
'terse'
,
default
=
False
),
]
def
__init__
(
self
,
**
kwargs
):
binwalk
.
module
.
process_kwargs
(
self
,
kwargs
)
self
.
block_hex
=
""
self
.
block_hex
=
""
self
.
printed_alt_text
=
False
self
.
printed_alt_text
=
False
if
binwalk
:
self
.
_pprint
=
binwalk
.
display
.
_pprint
self
.
_show_header
=
binwalk
.
display
.
header
self
.
_footer
=
binwalk
.
display
.
footer
self
.
_display_result
=
binwalk
.
display
.
results
self
.
_grep
=
binwalk
.
filter
.
grep
else
:
self
.
_pprint
=
sys
.
stdout
.
write
self
.
_show_header
=
self
.
_print
self
.
_footer
=
self
.
_simple_footer
self
.
_display_result
=
self
.
_print
self
.
_grep
=
None
if
hasattr
(
sys
.
stderr
,
'isatty'
)
and
sys
.
stderr
.
isatty
()
and
platform
.
system
()
!=
'Windows'
:
if
hasattr
(
sys
.
stderr
,
'isatty'
)
and
sys
.
stderr
.
isatty
()
and
platform
.
system
()
!=
'Windows'
:
curses
.
setupterm
()
curses
.
setupterm
()
self
.
colorize
=
self
.
_colorize
self
.
colorize
=
self
.
_colorize
...
@@ -57,15 +81,28 @@ class HexDiff(object):
...
@@ -57,15 +81,28 @@ class HexDiff(object):
return
"
\x1b
[
%
sm
%
s
\x1b
[0m"
%
(
';'
.
join
(
attr
),
c
)
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
if
self
.
show_green
and
green
in
data
:
return
True
if
self
.
show_red
and
red
in
data
:
return
True
return
False
def
_print_block_hex
(
self
,
alt_text
=
"*"
):
def
_print_block_hex
(
self
,
alt_text
=
"*"
):
printed
=
False
printed
=
False
if
self
.
_
grep
is
None
or
self
.
_grep
(
self
.
block_hex
):
if
self
.
_
color_filter
(
self
.
block_hex
):
self
.
_pprin
t
(
self
.
block_hex
)
self
.
config
.
display
.
resul
t
(
self
.
block_hex
)
self
.
printed_alt_text
=
False
self
.
printed_alt_text
=
False
printed
=
True
printed
=
True
elif
not
self
.
printed_alt_text
:
elif
not
self
.
printed_alt_text
:
self
.
_pprin
t
(
"
%
s
\n
"
%
alt_text
)
self
.
config
.
display
.
resul
t
(
"
%
s
\n
"
%
alt_text
)
self
.
printed_alt_text
=
True
self
.
printed_alt_text
=
True
printed
=
True
printed
=
True
...
@@ -82,33 +119,29 @@ class HexDiff(object):
...
@@ -82,33 +119,29 @@ class HexDiff(object):
else
:
else
:
self
.
block_hex
+=
c
self
.
block_hex
+=
c
def
_simple_footer
(
self
):
def
run
(
self
):
print
(
""
)
def
_header
(
self
,
files
,
block
):
header
=
"OFFSET "
for
i
in
range
(
0
,
len
(
files
)):
f
=
files
[
i
]
header
+=
"
%
s"
%
os
.
path
.
basename
(
f
)
if
i
!=
len
(
files
)
-
1
:
header
+=
" "
*
((
block
*
4
)
+
10
-
len
(
os
.
path
.
basename
(
f
)))
self
.
_show_header
(
header
=
header
)
def
display
(
self
,
files
,
offset
=
0
,
size
=
DEFAULT_DIFF_SIZE
,
block
=
DEFAULT_BLOCK_SIZE
,
show_first_only
=
False
):
i
=
0
i
=
0
total
=
0
total
=
0
fps
=
[]
fps
=
[]
data
=
{}
data
=
{}
delim
=
'/'
delim
=
'/'
offset
=
self
.
config
.
offset
size
=
self
.
config
.
length
block
=
self
.
config
.
block
files
=
self
.
config
.
target_files
self
.
config
.
display
.
format_strings
(
"
\n
%
s
\n
"
,
"
%
s
\n
"
)
# If negative offset, then we're going that far back from the end of the file
# If negative offset, then we're going that far back from the end of the file
if
offset
<
0
:
if
offset
<
0
:
size
=
offset
*
-
1
size
=
offset
*
-
1
if
show_first_only
:
# TODO: Display all file names in hexdump
self
.
_header
([
files
[
0
]],
block
)
if
self
.
terse
:
self
.
config
.
display
.
header
(
files
[
0
])
else
:
else
:
self
.
_header
(
files
,
block
)
self
.
config
.
display
.
header
(
files
[
0
]
)
if
common
.
BlockFile
.
READ_BLOCK_SIZE
<
block
:
if
common
.
BlockFile
.
READ_BLOCK_SIZE
<
block
:
read_block_size
=
block
read_block_size
=
block
...
@@ -169,7 +202,7 @@ class HexDiff(object):
...
@@ -169,7 +202,7 @@ class HexDiff(object):
diff_same
[
j
]
=
self
.
SOME_DIFF
diff_same
[
j
]
=
self
.
SOME_DIFF
for
index
in
range
(
0
,
len
(
files
)):
for
index
in
range
(
0
,
len
(
files
)):
if
s
how_first_only
and
index
>
0
:
if
s
elf
.
terse
and
index
>
0
:
break
break
f
=
files
[
index
]
f
=
files
[
index
]
...
@@ -194,7 +227,7 @@ class HexDiff(object):
...
@@ -194,7 +227,7 @@ class HexDiff(object):
except
:
except
:
self
.
_build_block
(
' '
)
self
.
_build_block
(
' '
)
if
index
==
len
(
files
)
-
1
or
(
s
how_first_only
and
index
==
0
):
if
index
==
len
(
files
)
-
1
or
(
s
elf
.
terse
and
index
==
0
):
self
.
_build_block
(
"|
\n
"
)
self
.
_build_block
(
"|
\n
"
)
else
:
else
:
self
.
_build_block
(
'|
%
s '
%
delim
)
self
.
_build_block
(
'|
%
s '
%
delim
)
...
@@ -211,8 +244,7 @@ class HexDiff(object):
...
@@ -211,8 +244,7 @@ class HexDiff(object):
for
fp
in
fps
:
for
fp
in
fps
:
fp
.
close
()
fp
.
close
()
self
.
_
footer
()
self
.
config
.
display
.
footer
()
if
__name__
==
"__main__"
:
return
True
HexDiff
()
.
display
(
sys
.
argv
[
1
:])
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment