import math from .method import GlimpseMethod class ShannonEntropy(GlimpseMethod): def __init__(self, builder): """Prepare a Shannon entropy display.""" super(ShannonEntropy, self).__init__(builder) button = builder.get_object('shannon_color') button.connect('color-set', self._on_color_set) self._on_color_set(button) self._step = 0x80 self._v_legend = 'Entropy' self._h_legend = 'Byte offsets' self._x_range = [ 0, 1024, 10240 ] self._y_range = [ 0.0, 0.25, 1.0 ] self._size = None self._values = [] def _on_color_set(self, button): """React on color chosen for the rendering.""" color = button.get_rgba() self._color = [ color.red, color.green, color.blue, color.alpha ] self._shadow_color = [ color.red * 0.5, color.green * 0.5, color.blue * 0.5, color.alpha ] def format_legend(self, value, vert): """Build the label used for a rule.""" if vert: text = str(value) else: scale = [ ' kb', ' Mb', ' Gb', ' Tb' ] suffix = '' for i in range(len(scale)): if value < 1024: break value /= 1024 suffix = scale[i] text = '%u%s' % (value, suffix) return text def update(self, data): """Provide a description for the method.""" self._size = len(data) step = 2 ** math.ceil(math.log(self._size / 10, 2)) self._x_range = [ 0, step, 10 * step ] self._values = [] for i in range(0, self._size, self._step): counter = [ 0 for i in range(256) ] start = i end = i + self._step if end > self._size: end = self._size for b in data[start : end]: counter[b] += 1 ent = 0.0 for c in counter: if c > 0: freq = c / (end - start) ent += freq * math.log(freq, 256) self._values.append(-ent) def render(self, cr, area): """Draw the bytes distribution for the current binary, if any.""" step = 2 ** math.ceil(math.log(self._size / 10, 2)) if self._size % step == 0: full_size = self._size else: full_size = (self._size + step - 1) & ~(step - 1) start = 0 last_x = area[0] last_y = area[1] + area[3] - (area[3] * self._values[0]) cr.move_to(last_x, last_y + 2) for i in range(0, self._size, self._step): end = i + self._step if end > self._size: end = self._size x = area[0] + ((end - start) * area[2]) / full_size y = area[1] + area[3] - (area[3] * self._values[int(i / self._step)]) if last_y != y: cr.line_to(last_x, y + 2) cr.line_to(x, y + 2) last_x = x cr.set_source_rgba(*self._shadow_color) cr.set_line_width(4) cr.stroke() last_x = area[0] last_y = area[1] + area[3] - (area[3] * self._values[0]) cr.move_to(last_x, last_y) for i in range(0, self._size, self._step): end = i + self._step if end > self._size: end = self._size x = area[0] + ((end - start) * area[2]) / full_size y = area[1] + area[3] - (area[3] * self._values[int(i / self._step)]) if last_y != y: cr.line_to(last_x, y) cr.line_to(x, y) last_x = x cr.set_source_rgba(*self._color) cr.set_line_width(2) cr.stroke()