ICO Parser. Closes #2407

This commit is contained in:
Ujjwal Verma 2017-06-24 03:11:59 +05:30
parent ba38a120e4
commit e81144e26b
5 changed files with 122 additions and 1 deletions

View File

@ -6,6 +6,7 @@ from kaitaistruct import KaitaiStream
from mitmproxy.contrib.kaitaistruct import png from mitmproxy.contrib.kaitaistruct import png
from mitmproxy.contrib.kaitaistruct import gif from mitmproxy.contrib.kaitaistruct import gif
from mitmproxy.contrib.kaitaistruct import jpeg from mitmproxy.contrib.kaitaistruct import jpeg
from mitmproxy.contrib.kaitaistruct import ico
Metadata = typing.List[typing.Tuple[str, str]] Metadata = typing.List[typing.Tuple[str, str]]
@ -78,3 +79,24 @@ def parse_jpeg(data: bytes) -> Metadata:
if field.data is not None: if field.data is not None:
parts.append((field.tag._name_, field.data.decode('UTF-8').strip('\x00'))) parts.append((field.tag._name_, field.data.decode('UTF-8').strip('\x00')))
return parts return parts
def parse_ico(data: bytes) -> Metadata:
img = ico.Ico(KaitaiStream(io.BytesIO(data)))
parts = [
('Format', 'ICO'),
('Number of images', str(img.num_images)),
]
for i, image in enumerate(img.images):
parts.append(
(
'Image {}'.format(i), "Size: {} x {}\n "
"Bits per pixel: {}\n "
"PNG: {}".format(256 if not image.width else image.width,
256 if not image.height else image.height,
image.bpp, image.is_png)
)
)
return parts

View File

@ -5,6 +5,13 @@ from mitmproxy.types import multidict
from . import image_parser from . import image_parser
def test_ico(h, f):
if h.startswith(b"\x00\x00\x01\x00"):
return "ico"
imghdr.tests.append(test_ico)
class ViewImage(base.View): class ViewImage(base.View):
name = "Image" name = "Image"
prompt = ("image", "i") prompt = ("image", "i")
@ -27,6 +34,8 @@ class ViewImage(base.View):
image_metadata = image_parser.parse_gif(data) image_metadata = image_parser.parse_gif(data)
elif image_type == 'jpeg': elif image_type == 'jpeg':
image_metadata = image_parser.parse_jpeg(data) image_metadata = image_parser.parse_jpeg(data)
elif image_type == 'ico':
image_metadata = image_parser.parse_ico(data)
else: else:
image_metadata = [ image_metadata = [
("Image Format", image_type or "unknown") ("Image Format", image_type or "unknown")

View File

@ -0,0 +1,90 @@
# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
from pkg_resources import parse_version
from kaitaistruct import __version__ as ks_version, KaitaiStruct, KaitaiStream, BytesIO
import struct
if parse_version(ks_version) < parse_version('0.7'):
raise Exception("Incompatible Kaitai Struct Python API: 0.7 or later is required, but you have %s" % (ks_version))
class Ico(KaitaiStruct):
"""Microsoft Windows uses specific file format to store applications
icons - ICO. This is a container that contains one or more image
files (effectively, DIB parts of BMP files or full PNG files are
contained inside).
.. seealso::
Source - https://msdn.microsoft.com/en-us/library/ms997538.aspx
"""
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self._read()
def _read(self):
self.magic = self._io.ensure_fixed_contents(struct.pack('4b', 0, 0, 1, 0))
self.num_images = self._io.read_u2le()
self.images = [None] * (self.num_images)
for i in range(self.num_images):
self.images[i] = self._root.IconDirEntry(self._io, self, self._root)
class IconDirEntry(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self._read()
def _read(self):
self.width = self._io.read_u1()
self.height = self._io.read_u1()
self.num_colors = self._io.read_u1()
self.reserved = self._io.ensure_fixed_contents(struct.pack('1b', 0))
self.num_planes = self._io.read_u2le()
self.bpp = self._io.read_u2le()
self.len_img = self._io.read_u4le()
self.ofs_img = self._io.read_u4le()
@property
def img(self):
"""Raw image data. Use `is_png` to determine whether this is an
embedded PNG file (true) or a DIB bitmap (false) and call a
relevant parser, if needed to parse image data further.
"""
if hasattr(self, '_m_img'):
return self._m_img if hasattr(self, '_m_img') else None
_pos = self._io.pos()
self._io.seek(self.ofs_img)
self._m_img = self._io.read_bytes(self.len_img)
self._io.seek(_pos)
return self._m_img if hasattr(self, '_m_img') else None
@property
def png_header(self):
"""Pre-reads first 8 bytes of the image to determine if it's an
embedded PNG file.
"""
if hasattr(self, '_m_png_header'):
return self._m_png_header if hasattr(self, '_m_png_header') else None
_pos = self._io.pos()
self._io.seek(self.ofs_img)
self._m_png_header = self._io.read_bytes(8)
self._io.seek(_pos)
return self._m_png_header if hasattr(self, '_m_png_header') else None
@property
def is_png(self):
"""True if this image is in PNG format."""
if hasattr(self, '_m_is_png'):
return self._m_is_png if hasattr(self, '_m_is_png') else None
self._m_is_png = self.png_header == struct.pack('8b', -119, 80, 78, 71, 13, 10, 26, 10)
return self._m_is_png if hasattr(self, '_m_is_png') else None

View File

@ -6,6 +6,6 @@ wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master
wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/gif.ksy wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/gif.ksy
wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/jpeg.ksy wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/jpeg.ksy
wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/png.ksy wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/png.ksy
wget -N https://raw.githubusercontent.com/mitmproxy/mitmproxy/master/mitmproxy/contrib/tls_client_hello.py wget -N https://raw.githubusercontent.com/kaitai-io/kaitai_struct_formats/master/image/ico.ksy
kaitai-struct-compiler --target python --opaque-types=true *.ksy kaitai-struct-compiler --target python --opaque-types=true *.ksy