# Originally written by Brian Baskin (@bbaskin):
# https://github.com/Rurik/Java_IDX_Parser
# See the file 'LICENSE' for copying permission.


import os
import getopt
import struct
import sys
import time
import zlib

from viper.common.out import *
from viper.common.abstracts import Module
from viper.core.session import __sessions__

class Idx(Module):
    cmd = 'idx'
    description = 'Parse Java idx files'
    authors = ['Kevin Breen']

    def run(self):

        def sec2_parse():
            """Parse Section Two from 6.03 and greater files.

            Section two contains all download history data
            """
            sec_two = []
            data.seek(128)
            len_URL = struct.unpack('>l', data.read(4))[0]
            data_URL = data.read(len_URL)
            len_IP = struct.unpack('>l', data.read(4))[0]
            data_IP = data.read(len_IP)
            sec2_fields = struct.unpack('>l', data.read(4))[0]

            sec_two.append(['URL', data_URL])
            sec_two.append(['IP', data_IP])
            for i in range(0, sec2_fields):
                len_field = struct.unpack('>h', data.read(2))[0]
                field = data.read(len_field)
                len_value = struct.unpack('>h', data.read(2))[0]
                value = data.read(len_value)
                sec_two.append([field, value])
            return sec_two

        def sec2_parse_602():
            """Parse Section Two from 6.02 files.

            Section two contains all download history data. However, this version
            does not store IP addresses.
            """
            sec_two = []
            data.seek(32)
            len_URL = struct.unpack('b', data.read(1))[0]
            data_URL = data.read(len_URL)
            namespace_len = struct.unpack('>h', data.read(2))[0]
            namespace = data.read(namespace_len)
            sec2_fields = struct.unpack('>l', data.read(4))[0]
            sec_two.append(['URL', data_URL])

            for i in range(0, sec2_fields):
                len_field = struct.unpack('>h', data.read(2))[0]
                field = data.read(len_field)
                len_value = struct.unpack('>h', data.read(2))[0]
                value = data.read(len_value)
                sec_two.append([field, value])

            return sec_two

        def sec3_parse():
            """Parse Section three of the file.

            Section three contains a copy of the JAR manifest data.
            """
            sec_three = []
            data.seek (128+sec2_len)
            sec3_data = data.read(sec3_len)

            if sec3_data[0:3] == '\x1F\x8B\x08': # Valid GZIP header
                sec3_unc = zlib.decompress(sec3_data, 15+32) # Trick to force bitwindow size
                sec_split = sec3_unc.strip().split('\n')
                for line in sec_split:
                    k, v = line.split(':')
                    sec_three.append([k,v.replace('\x0d', '')])
            return sec_three

        def sec4_parse():
            """Parse Section four of the file.

            Section four contains Code Signer details
            Written from docs at:
            http://docs.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html
            """

            # ToDo Export any found data blocks or objects
            sec_four = []
            unknowns = 0
            data.seek (128 + sec2_len + sec3_len)
            sec4_magic, sec4_ver = struct.unpack('>HH', data.read(4))