├── libzpy
├── libs
│ ├── __init__.py
│ ├── storage.py
│ ├── libucl_i368.so
│ ├── libucl_x64.so
│ ├── fmt.py
│ ├── ida.py
│ ├── UCL.py
│ ├── basecfg.py
│ ├── structure.py
│ ├── xstream.py
│ ├── cr_tools.py
│ ├── rtb.py
│ ├── binPCRE.py
│ └── vmzeus.py
├── README
├── fmt
│ ├── __init__.py
│ ├── powerzeus.py
│ ├── kins.py
│ ├── citadel.py
│ ├── citadel.py.1
│ ├── vmzeus2.py
│ ├── vmzeus20.py
│ ├── zeus.py
│ └── zeus.py.old
├── modules
│ ├── __init__.py
│ ├── conf.py
│ ├── misc.py
│ ├── powerzeus.py
│ ├── vmzeus2.py
│ ├── vmzeus20.py
│ ├── flokibot.py
│ ├── torment.py
│ ├── mmbb.py
│ ├── zeus.py
│ ├── kins.py
│ ├── chthonic.py
│ ├── vmzeus.py
│ ├── template.py
│ ├── citadel.py
│ └── p2p.py
├── structs
│ ├── __init__.py
│ ├── chthonic.py
│ ├── kins.py
│ ├── vmzeus2.py
│ ├── vmzeus20.py
│ ├── powerzeus.py
│ ├── citadel.py
│ └── zeus.py
├── .hgignore
└── __init__.py
├── .gitignore
└── setup.py
/libzpy/libs/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/libzpy/README:
--------------------------------------------------------------------------------
1 | read me
2 |
--------------------------------------------------------------------------------
/libzpy/fmt/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/libzpy/modules/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/libzpy/structs/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | .idea/
3 | dist/
4 | libzpy.egg*
--------------------------------------------------------------------------------
/libzpy/.hgignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 |
3 | *~
4 | *.pyc
5 | _local/*
6 |
--------------------------------------------------------------------------------
/libzpy/libs/storage.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class storageException(Exception):
4 | pass
5 |
6 |
--------------------------------------------------------------------------------
/libzpy/libs/libucl_i368.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mak/libzpy/HEAD/libzpy/libs/libucl_i368.so
--------------------------------------------------------------------------------
/libzpy/libs/libucl_x64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mak/libzpy/HEAD/libzpy/libs/libucl_x64.so
--------------------------------------------------------------------------------
/libzpy/libs/fmt.py:
--------------------------------------------------------------------------------
1 | import binascii
2 |
3 |
4 |
5 | def s2hex(s): return binascii.hexlify(s)
6 |
7 | def hex2s(s): return binascii.unhexlify(s)
8 |
9 |
10 | def NullTermStringList(data):
11 | return data.split(chr(0))
12 |
13 |
14 |
--------------------------------------------------------------------------------
/libzpy/modules/conf.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.zeus as z
2 |
3 |
4 | def pesettings(data,verb,type):
5 | p = z.PESettings(data)
6 | p._sep = "\n"
7 | print str(p)
8 | return p
9 |
10 | def get_pesettings_size(type,verb):
11 | return 0x1e6
12 |
13 | def pesettings_key(data,verb):
14 | p = z.PESettings(data)
15 | p._sep = "\n"
16 | print p.RC4KEY
17 |
--------------------------------------------------------------------------------
/libzpy/__init__.py:
--------------------------------------------------------------------------------
1 | import sys,os
2 | #from contextlib import contextmanager
3 |
4 | def get_mydir():
5 | p = os.path.abspath(__file__)
6 | dir_path = os.path.dirname(p)
7 | return dir_path
8 |
9 | #@contextmanager
10 | def get_parser(m):
11 |
12 | mod = __import__('.'.join(['libzpy.modules',m]))
13 | return getattr(mod.modules,m)
14 |
15 | def show_version(v):
16 | return "%02d.%02d.%02d.%02d"%(v>>24,(v>>16)&0xff,(v>>8)&0xff,v&0xff)
17 |
--------------------------------------------------------------------------------
/libzpy/modules/misc.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | def dumper(data,verb,byId='-1',mask=0,outfile=None):
5 | if not outfile:
6 | raise Exception("dumper: need outfile !")
7 |
8 | verb("Dumping items : %s " % byId )
9 | itemsId = map( int , byId.split(',') )
10 |
11 | for item in data['items']:
12 | if item['recId'] in itemsId :
13 | verb("Found record id=%d " % item['recId'])
14 | with open(outfile,'wb') as f:
15 | f.write(item['data'])
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | try:
4 | from setuptools import setup
5 | except ImportError:
6 | from distutils.core import setup
7 |
8 | setup(name="libzpy",
9 | version="0.0.6",
10 | description="zeus-like things",
11 | author="mak",
12 | packages=['libzpy', 'libzpy.fmt', 'libzpy.libs', 'libzpy.modules', 'libzpy.structs'],
13 | package_data={'libzpy.libs':['libucl_i368.so','libucl_x64.so']},
14 | include_package_data=True,
15 | install_requires=[
16 | "pycrypto",
17 | "mlib"
18 | ])
19 |
20 |
--------------------------------------------------------------------------------
/libzpy/fmt/powerzeus.py:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 |
3 |
4 | class fmt(zeus.fmt):
5 |
6 | def __init__(self,*args,**kwargs):
7 | super(fmt,self).__init__(*args,**kwargs)
8 | fmts = self._formats[:4]
9 | fmts += ['notify_srv','notify_list','captcha_srv','captcha_list']
10 | fmts += self._formats[4:]
11 | self._formats = fmts
12 |
13 |
14 | def notify_srv(self):
15 | return self._list('NOTIFY_SERVERS','notify_srv')
16 | def notify_list(self):
17 | return self._list('NOTIFY_LIST','notify_lst')
18 |
19 | def captcha_list(self):
20 | return self._list('CAPTCHA_LIST','captcha_lst')
21 |
22 | def captcha_srv(self):
23 | return self._list('CAPTCHA_SERVERS','captcha_srv')
24 |
--------------------------------------------------------------------------------
/libzpy/fmt/kins.py:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 |
3 |
4 | class fmt(zeus.fmt):
5 |
6 | # def __init__(self,*args,**kwargs):
7 | # super(fmt,self).__init__(*args,**kwargs)
8 | # self._wf_butify['$'] = 'NOTIFY'
9 | # self._wf_butify['|'] = 'UNKNOWN' ## TODO....
10 |
11 | def notify_srv(self):
12 | return self._list('{{NOTIFY_SERVERS}}','notify_srv','{{END_NOTIFY_SERVERS}}')
13 | def notify_list(self):
14 | return self._list('{{NOTIFY_LIST}}','notify_lst','{{END_NOTIFY_LIST}}')
15 |
16 | def captcha_list(self):
17 | return self._list('{{CAPTCHA_LIST}}','captcha_lst','{{END_CAPTCHA_LIST}}')
18 |
19 | def captcha_srv(self):
20 | return self._list('{{CAPTCHA_SERVERS}}','captcha_srv','{{END_CAPTCHA_SERVERS}}')
21 |
--------------------------------------------------------------------------------
/libzpy/modules/powerzeus.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.powerzeus as pz
2 | import libzpy.fmt.powerzeus as pzfmt
3 | from libzpy.modules import template as t
4 |
5 | from StringIO import StringIO
6 | from ctypes import sizeof
7 | import json
8 |
9 | def unpack(data,verb):
10 | return t.unpack(data,verb,pz)
11 |
12 | def parse(data,verb):
13 | return t.parse(data,verb,pz)
14 |
15 | def to_str(data,verb):
16 | if not isinstance(data,dict):
17 | verb('I need unpacked data')
18 | return
19 |
20 |
21 | fmt = pzfmt.fmt(data)
22 | fmt._ = 'PowerZeus'
23 | return fmt.format()
24 |
25 |
26 | def go(data,verb):
27 | data = unpack(data,verb)
28 | data = parse(data,verb)
29 | #print `data['injects']`
30 | print to_str(data,verb)
31 |
32 |
33 | def format(data,verb,type='pretty'):
34 | if type == 'pretty':
35 | return to_str(data,verb)
36 | elif type == 'json':
37 | return json.dumps(data)
38 |
--------------------------------------------------------------------------------
/libzpy/modules/vmzeus2.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.vmzeus2 as k
2 | import libzpy.fmt.vmzeus2 as pzfmt
3 | from libzpy.modules import template as t
4 |
5 |
6 | from ctypes import sizeof
7 | import json
8 | from struct import *
9 |
10 | def _print(data,ver):
11 | import pprint
12 | pprint.pprint(data)
13 |
14 | def do_print(data,verb):
15 | print data
16 |
17 |
18 | def unpack(data,verb):
19 | return t.unpack(data,verb,k)
20 | def parse(data,verb):
21 | return t.parse(data,verb,k)
22 |
23 | def json(data):
24 | verb=lambda x:x
25 | data = unpack(data,verb)
26 | data = parse(data,verb)
27 | return data
28 |
29 | def to_str(data,verb):
30 | if not isinstance(data,dict):
31 | verb('I need unpacked data')
32 | return
33 |
34 | fmt = pzfmt.fmt(data)
35 | fmt._name = 'VMZeus-2.0'
36 | return fmt.format()
37 |
38 | def go(data,verb):
39 | data = unpack(data,verb)
40 | data = parse(data,verb)
41 | #print `data['injects']`
42 | print to_str(data,verb)
43 |
--------------------------------------------------------------------------------
/libzpy/libs/ida.py:
--------------------------------------------------------------------------------
1 | import idc
2 |
3 |
4 | class ifile(object):
5 | def __init__(self,addr,use_debugger=False):
6 | self.off = 0
7 | self.addr = addr
8 | self.dbg = use_debugger
9 |
10 | def byte(self,a=None):
11 | if not a:
12 | a = sefl.addr + self.off
13 | self.off += 1
14 | return DbgByte(a) if self.dbg else Byte(a)
15 |
16 |
17 | def word(self,a=None):
18 | if not a:
19 | a = sefl.addr + self.off
20 | self.off += 2
21 | return DbgWord(a) if self.dbg else Word(a)
22 |
23 |
24 | def dword(self,a=None):
25 | if not a:
26 | a = sefl.addr + self.off
27 | self.off +=4
28 | return DbgDword(a) if self.dbg else Dword(a)
29 |
30 | def bytes(self,n,a=None):
31 | return map(ord,self.bytes(n,a))
32 |
33 | def read(self,n,a=None):
34 | if not a:
35 | a = sefl.addr + self.off
36 | self.off += n
37 | return ReadManyBytes(a,n,self.dbg)
38 |
--------------------------------------------------------------------------------
/libzpy/structs/chthonic.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_word
3 | import libzpy.structs.zeus as zeus
4 |
5 | class Header(zeus.Header):
6 | pass
7 |
8 |
9 | class Item(zeus.Item):
10 | def __init__(self,*args,**kwargs):
11 | super(Item,self).__init__(*args,**kwargs)
12 |
13 | self._cfgids['CFGID_OUTER_PAYLOAD'] = 12003
14 | self._cfgids['CFGID_INJECTS'] = 2541227442
15 | self._cfgids['CFGID_PAYLOAD'] = 12000
16 | self._flags['ITEMF_IS_PACKED_CONFIG'] = 0x10000000
17 |
18 |
19 | class HttpInject_HList(zeus.HttpInject_HList):
20 | struct = zeus.HttpInject_Header
21 |
22 | class HttpInject_BList(zeus.HttpInject_BList):
23 | pass
24 |
25 | class HttpInject_Captcha(DataStructure):
26 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
27 |
28 | class WebFilter(zeus.WebFilter):
29 | def __init__(self,*args,**kwargs):
30 | super(WebFilter,self).__init__(*args,**kwargs)
31 | self._wf['$'] = 'NOTIFY'
32 | self._wf['|'] = 'UNKNOWN' ## TODO....
--------------------------------------------------------------------------------
/libzpy/modules/vmzeus20.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.vmzeus20 as k
2 | import libzpy.fmt.vmzeus20 as pzfmt
3 | from libzpy.modules import template as t
4 |
5 |
6 | from ctypes import sizeof
7 | import json,struct
8 |
9 |
10 | def _print(data,ver):
11 | import pprint
12 | pprint.pprint(data)
13 |
14 | def unpack(data,verb):
15 | return t.unpack(data,verb,k)
16 | def parse(data,verb):
17 | return t.parse(data,verb,k)
18 |
19 | def to_str(data,verb):
20 | if not isinstance(data,dict):
21 | verb('I need unpacked data')
22 | return
23 |
24 | fmt = pzfmt.fmt(data)
25 | fmt._name = 'VMZeus-2.0'
26 | return fmt.format()
27 |
28 |
29 | def json(data):
30 | verb=lambda x:x
31 | data = unpack(data,verb)
32 | data = parse(data,verb)
33 | if 'CFGID_SIGNATURE' in data:
34 | data['CFGID_SIGNATURE'] =data['CFGID_SIGNATURE'].encode('hex')
35 | data['CFGID_CONFIG_CREATION_TIME'] = struct.unpack('I',data['CFGID_CONFIG_CREATION_TIME'])[0]
36 |
37 | return data
38 |
39 | def go(data,verb):
40 | data = unpack(data,verb)
41 | data = parse(data,verb)
42 | #print `data['injects']`
43 | print to_str(data,verb)
44 |
--------------------------------------------------------------------------------
/libzpy/fmt/citadel.py:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 |
3 |
4 | class fmt(zeus.fmt):
5 |
6 | def __init__(self,*args,**kwargs):
7 | super(fmt,self).__init__(*args,**kwargs)
8 | # self._wf_butify['#'] = 'MOVIE'
9 | fmts = self._formats[:4]
10 | fmts += ['webinj_url','cmds','keyloger','video','httpvip','dns_filter']
11 | fmts += self._formats[4:]
12 | self._formats = fmts
13 |
14 |
15 | def dns_filter(self):
16 | return self._list('DNS_FILTERS','dns_filter')
17 |
18 | def cmds(self):
19 | return self._list('COMANDS_LIST','cmds')
20 |
21 | def keyloger(self):
22 | if 'keyloger' in self.cfg:
23 | return '{{KEYLOGER}}\nTargets: %s\nTime: %d\n{{END_KEYLOGER}}' % (self.cfg['keyloger'],self.cfg['keyloger_time'])
24 | return ''
25 |
26 | def video(self):
27 | if 'video_qual' in self.cfg:
28 | return '{{VIDEO}}\nQuality: %d | Length: %d\n{{END_VIDEO}}' % (self.cfg['video_qual'],self.cfg['video_length'])
29 | return ''
30 |
31 | def httpvip(self):
32 | return self._field('HTTPVIPURLS','httpvi')
33 |
34 | def webinj_url(self):
35 | return self._field('WEBINJECT_URL','webinj_url')
36 |
--------------------------------------------------------------------------------
/libzpy/fmt/citadel.py.1:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 |
3 |
4 | class fmt(zeus.fmt):
5 |
6 | def __init__(self,*args,**kwargs):
7 | super(fmt,self).__init__(*args,**kwargs)
8 | self._wf_butify['#'] = 'MOVIE'
9 | fmts = self._formats[:4]
10 | fmts += ['webinj_url','cmds','keyloger','video','httpvip','dns_filter']
11 | fmts += self._formats[4:]
12 | self._formats = fmts
13 |
14 |
15 | def dns_filter(self):
16 | return self._list('DNS_FILTERS','dns_filter')
17 |
18 | def cmds(self):
19 | return self._list('COMANDS_LIST','cmds')
20 |
21 | def keyloger(self):
22 | if 'keyloger' in self.cfg:
23 | return '{{KEYLOGER}}\nTargets: %s\nTime: %d\n{{END_KEYLOGER}}' % (self.cfg['keyloger'],self.cfg['keyloger_time'])
24 | return ''
25 |
26 | def video(self):
27 | if 'video_qual' in self.cfg:
28 | return '{{VIDEO}}\nQuality: %d | Length: %d\n{{END_VIDEO}}' % (self.cfg['video_qual'],self.cfg['video_length'])
29 | return ''
30 |
31 | def httpvip(self):
32 | return self._field('HTTPVIPURLS','httpvi')
33 |
34 | def webinj_url(self):
35 | return self._field('WEBINJECT_URL','webinj_url')
36 |
--------------------------------------------------------------------------------
/libzpy/libs/UCL.py:
--------------------------------------------------------------------------------
1 | from ctypes import *
2 | import os
3 | from mlib.compression import lznt1
4 |
5 |
6 | class UCL(object):
7 | def decompress(self,data,size):
8 | try:
9 | return lznt1.decompress(data)
10 | except:
11 | return self.c_decompress(data,size)
12 |
13 | def c_decompress(self,data,size):
14 | compressed = c_buffer(data)
15 | decompressed = c_buffer(size)
16 | decompressed_size = c_int()
17 | result = self.get_ucl().ucl_nrv2b_decompress_le32(
18 | pointer(compressed),
19 | c_int(len(compressed.raw)),
20 | pointer(decompressed),
21 | pointer(decompressed_size))
22 | return decompressed.raw[:decompressed_size.value]
23 |
24 | def get_ucl(self):
25 | if hasattr(self,'_lib'):
26 | return self._lib
27 |
28 | MYSELF = os.path.abspath(os.path.expanduser(__file__))
29 | if os.path.islink(MYSELF):
30 | MYSELF = os.readlink(MYSELF)
31 | DIR = os.path.dirname(MYSELF)
32 | if sizeof(c_long) == 8:
33 | UCL = DIR + '/libucl_x64.so'
34 | else:
35 | UCL = DIR + '/libucl_i386.so'
36 | self._lib = cdll.LoadLibrary(UCL)
37 | return self._lib
38 |
--------------------------------------------------------------------------------
/libzpy/modules/flokibot.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.zeus as zeus
2 | import libzpy.fmt.zeus as zfmt
3 | from libzpy.modules import template as t
4 |
5 | from libzpy.libs.basecfg import BaseCfg
6 | import json
7 |
8 |
9 | def unpack(data,verb,verify=False):
10 | return t.unpack(data,verb,zeus,verify)
11 |
12 |
13 | def parse(data,verb):
14 | return t.parse(data,verb,zeus)
15 |
16 |
17 | def to_str(data,verb):
18 | if not isinstance(data,dict):
19 | verb('I need unpacked data')
20 | return
21 |
22 | fmt = zfmt.fmt(data)
23 | fmt._ = 'flokibot'
24 | return fmt.format()
25 |
26 |
27 | def json(data):
28 | verb=lambda x:x
29 | data = unpack(data,verb,True)
30 | data = parse(data,verb)
31 | return data
32 |
33 |
34 | def go(data,verb):
35 | data = unpack(data,verb)
36 | data = parse(data,verb)
37 | print to_str(data,verb)
38 |
39 |
40 | def format(data,verb,type='pretty'):
41 | if type == 'pretty':
42 | return to_str(data,verb)
43 | elif type == 'json':
44 | return json.dumps(data)
45 |
46 |
47 | def parse_basecfg(basecfg,args):
48 | bc = BaseCfg(basecfg)
49 | bc.get_rc4(581)
50 | res = bc.get_basics()
51 | return res
52 |
53 |
54 | def get_basecfg(d,*args):
55 | return d.decode('hex')
56 |
--------------------------------------------------------------------------------
/libzpy/fmt/vmzeus2.py:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 | from struct import unpack
3 | from datetime import datetime
4 |
5 | class fmt(zeus.fmt):
6 |
7 | def notify_srv(self):
8 | return self._list('{{NOTIFY_SERVERS}}','notify_srv')
9 | def notify_list(self):
10 | return self._list('{{NOTIFY_LIST}}','notify_lst')
11 |
12 |
13 | def captcha_list(self):
14 | return self._list('{{CAPTCHA_LIST}}','captcha_lst')
15 |
16 | def captcha_srv(self):
17 | return self._list('{{CAPTCHA_SERVERS}}','captcha_srv')
18 |
19 |
20 | def ctime(self):
21 | if 'CFGID_CONFIG_CREATION_TIME' in self.cfg:
22 | return 'Creation Time: %s\n' % datetime.fromtimestamp(unpack('I',self.cfg['CFGID_CONFIG_CREATION_TIME'])[0])
23 | return ''
24 |
25 | def modvnc(self):
26 | if 'CFGID_VNCDLL_URL' in self.cfg:
27 | return '{{VNCDLL_URL}}\n' +self.cfg['CFGID_VNCDLL_URL'] + "\n{{END_VNCDLL_URL}}\n"
28 | return ''
29 |
30 | def format(self):
31 | r = ''
32 | r += self.version()
33 | r += self.ctime()
34 | r += self.server()
35 | r += self.modvnc()
36 | r += self.binary()
37 | r += self.adv_server()
38 | r += self.notify_srv()
39 | r += self.notify_list()
40 | r += self.captcha_srv()
41 | r += self.captcha_list()
42 | r += self.webfilters()
43 | r += self.injects()
44 | r += self.captures()
45 | return r
46 |
--------------------------------------------------------------------------------
/libzpy/modules/torment.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import libzpy.fmt.zeus as zfmt
4 | import libzpy.structs.zeus as zeus
5 |
6 | import libzpy.libs.cr_tools as cry
7 | from libzpy.modules import template as t
8 |
9 |
10 | def unpack(data,verb,verify=False):
11 | return t.unpack(data,verb,zeus,verify)
12 |
13 | def parse(data,verb):
14 | return t.parse(data,verb,zeus)
15 |
16 | def to_str(data,verb):
17 | if not isinstance(data,dict):
18 | verb('I need unpacked data')
19 | return
20 |
21 | fmt = zfmt.fmt(data)
22 | fmt._ = 'PowerZeus'
23 | return fmt.format()
24 |
25 |
26 | def json(data):
27 | verb=lambda x:x
28 | data = unpack(data,verb,True)
29 | data = parse(data,verb)
30 | return data
31 |
32 | def go(data,verb):
33 | data = unpack(data,verb)
34 | data = parse(data,verb)
35 | #print `data['injects']`
36 | print to_str(data,verb)
37 |
38 |
39 | def format(data,verb,type='pretty'):
40 | if type == 'pretty':
41 | return to_str(data,verb)
42 | elif type == 'json':
43 | return json.dumps(data)
44 |
45 |
46 | def parse_basecfg(basecfg,args):
47 | data = unpack(basecfg,lambda x: x,verify=False)
48 | data = parse(data,lambda x:x)
49 | botname = data['unknown'][1].strip("\x00")
50 | rc4key = data['unknown'][3].strip("\x00")
51 | urls = data['unknown'][2].split('>')[2:-1]
52 | return {'botname': botname, 'rc4key':rc4key,'urls':urls,'cfg':urls[0]}
53 |
54 |
55 |
56 |
57 | ## we allready decode basecfg
58 | def get_basecfg(d,*args):
59 | # if not 'key' in args:
60 | # pass
61 |
62 | k = args[0]
63 | d = d.decode('hex')
64 | return cry.visDecry(cry.rc4decrypt(d,k,raw=True))
65 |
66 |
--------------------------------------------------------------------------------
/libzpy/fmt/vmzeus20.py:
--------------------------------------------------------------------------------
1 | import libzpy.fmt.zeus as zeus
2 | from struct import unpack
3 | from datetime import datetime
4 |
5 | class fmt(zeus.fmt):
6 |
7 | # def __init__(self,*args,**kwargs):
8 | # super(fmt,self).__init__(*args,**kwargs)
9 | # self._wf_butify['$'] = 'NOTIFY'
10 |
11 | def notify_srv(self):
12 | return self._list('{{NOTIFY_SERVERS}}','notify_srv')
13 | def notify_list(self):
14 | return self._list('{{NOTIFY_LIST}}','notify_lst')
15 |
16 |
17 | def captcha_list(self):
18 | return self._list('{{CAPTCHA_LIST}}','captcha_lst')
19 |
20 | def captcha_srv(self):
21 | return self._list('{{CAPTCHA_SERVERS}}','captcha_srv')
22 |
23 |
24 | def ctime(self):
25 | key = 'CFGID_CONFIG_CREATION_TIME'
26 | if key in self.cfg:
27 | d = unpack('I',self.cfg[key])[0] if type(self.cfg[key]) == str else self.cfg[key]
28 | return 'Creation Time: %s\n' % datetime.fromtimestamp(d)
29 | return ''
30 |
31 | def modvnc(self):
32 | return self._field('VNCDLL_URL','CFGID_VNCDLL_URL',lambda x:x)
33 |
34 | def signature(self):
35 | return self._field('SIGNATURE','CFGID_SIGNATURE',lambda x: x.encode('hex'))
36 |
37 | def format(self):
38 | r = ''
39 | r += self.version()
40 | r += self.ctime()
41 | r += self.server()
42 | r += self.modvnc()
43 | r += self.binary()
44 | r += self.adv_server()
45 | r += self.notify_srv()
46 | r += self.notify_list()
47 | r += self.captcha_srv()
48 | r += self.captcha_list()
49 | r += self.signature()
50 | r += self.webfilters()
51 | r += self.injects()
52 | r += self.captures()
53 | return r
54 |
--------------------------------------------------------------------------------
/libzpy/modules/mmbb.py:
--------------------------------------------------------------------------------
1 |
2 | import libzpy.structs.zeus as zeus
3 | import libzpy.fmt.zeus as zfmt
4 | from libzpy.modules import template as t
5 |
6 | from StringIO import StringIO
7 | from ctypes import sizeof
8 | from libzpy.libs.basecfg import BaseCfg
9 | import json
10 |
11 |
12 | class mmbbCfb(BaseCfg):
13 |
14 | def get_rc4(self,off):
15 | #(4,10,0)
16 | o=self.cfg.find('\x04\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00')
17 | self.aesKey = self.cfg[o+4+off:o+4+off+0x10]
18 | self.rc4sbox = self.cfg[o:]
19 | return self.rc4sbox
20 |
21 | def get_basics(self):
22 | st=super(mmbbCfb,self).get_basics()
23 | st['aes-key'] = self.aesKey.encode('hex')
24 | return st
25 |
26 | def unpack(data,verb,verify=False):
27 | return t.unpack(data,verb,zeus,verify)
28 |
29 | def parse(data,verb):
30 | return t.parse(data,verb,zeus)
31 |
32 | def to_str(data,verb):
33 | if not isinstance(data,dict):
34 | verb('I need unpacked data')
35 | return
36 |
37 | fmt = zfmt.fmt(data)
38 | fmt._ = 'PowerZeus'
39 | return fmt.format()
40 |
41 |
42 | def json(data):
43 | verb=lambda x:x
44 | data = unpack(data,verb,True)
45 | data = parse(data,verb)
46 | return data
47 |
48 | def go(data,verb):
49 | data = unpack(data,verb)
50 | data = parse(data,verb)
51 | #print `data['injects']`
52 | print to_str(data,verb)
53 |
54 |
55 | def format(data,verb,type='pretty'):
56 | if type == 'pretty':
57 | return to_str(data,verb)
58 | elif type == 'json':
59 | return json.dumps(data)
60 |
61 |
62 | def parse_basecfg(basecfg,args):
63 |
64 | off = args['aoff']#
65 | bc = mmbbCfb(basecfg)
66 | bc.get_rc4(off)
67 | return bc.get_basics()
68 |
69 |
70 | ## we allready decode basecfg
71 | def get_basecfg(d,*args):
72 | # print d
73 | return d.decode('hex')
74 |
--------------------------------------------------------------------------------
/libzpy/structs/kins.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_word
3 | import libzpy.structs.zeus as zeus
4 |
5 | class Header(zeus.Header):
6 | pass
7 |
8 | class Item(zeus.Item):
9 |
10 | def __init__(self,*args,**kwargs):
11 | super(Item,self).__init__(*args,**kwargs)
12 | self._flags['ITEMF_IS_ARGUMENT'] = 0x00100000
13 | self._flags['ITEMF_IS_MODULE_HASH'] = 0x00200000
14 | self._flags['ITEMF_IS_PROC_NAME_HASH'] = 0x00400000
15 | self._cfgids[20009] = 'CFGID_CAPTCHA_SERVER'
16 | self._cfgids[20010] ='CFGID_CAPTCHA_LIST'
17 | self._cfgids[20011] ='CFGID_NOTIFY_SERVER'
18 | self._cfgids[20012] ='CFGID_NOTIFY_LIST'
19 | # self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
20 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
21 |
22 |
23 | def is_captchasrv(self):
24 | return self.id == self._cfgids_n['CFGID_CAPTCHA_SERVER']
25 |
26 | def is_captchalist(self):
27 | return self.id == self._cfgids_n['CFGID_CAPTCHA_LIST']
28 | def is_notifysrv(self):
29 | return self.id == self._cfgids_n['CFGID_NOTIFY_SERVER']
30 |
31 | def is_notifylist(self):
32 | return self.id == self._cfgids_n['CFGID_NOTIFY_LIST']
33 |
34 |
35 | # class HttpInject_InjectBlock(zeus.HttpInject_InjectBlock):
36 | # pass
37 |
38 | class HttpInject_HList(zeus.HttpInject_HList):
39 | struct = zeus.HttpInject_Header
40 |
41 | class HttpInject_BList(zeus.HttpInject_BList):
42 | pass
43 |
44 | class HttpInject_Captcha(DataStructure):
45 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
46 |
47 | class WebFilter(zeus.WebFilter):
48 | def __init__(self,*args,**kwargs):
49 | super(WebFilter,self).__init__(*args,**kwargs)
50 | self._wf['$'] = 'NOTIFY'
51 | self._wf['|'] = 'UNKNOWN' ## TODO....
52 |
--------------------------------------------------------------------------------
/libzpy/libs/basecfg.py:
--------------------------------------------------------------------------------
1 | import re
2 | from struct import unpack
3 |
4 | import libzpy.libs.cr_tools as cry
5 |
6 |
7 | class BaseCfg(object):
8 |
9 | def __init__(self,cfg):
10 | self.cfg = cfg
11 | self.rc4sbox = None
12 |
13 | def get_strings(self):
14 | ss =map(lambda x: x.strip("\x00"),re.findall("[\x1f-\x7e]{6,}\x00", self.cfg))
15 | if self.urls:
16 | return list(set(ss).difference(set(self.urls)))
17 | return ss
18 |
19 | def get_botname(self):
20 | _max = lambda x : max(x,key=len) if x else ''
21 | return _max(filter(lambda x: x and not "\x00" in x,map(lambda x:x[0].decode('utf-16').strip("\x00"),re.findall("(([\x1f-\x7e]\x00)+)\x00\x00",self.cfg))))
22 |
23 |
24 |
25 | def get_urls(self):
26 | self.urls = map(lambda x:x.strip("\x00"),re.findall("https?://[\x1f-\x7e]{6,}\x00",self.cfg))
27 | return self.urls
28 |
29 | def rc4(self,d,k):
30 | return cry.rc4decrypt(d,k)
31 |
32 | def get_rc4(self,pes):
33 |
34 | if type(pes) == int:
35 | ## some time im off few byts, lets try to fix this
36 | rb = self.cfg[pes:pes+0x102]
37 | off1= pes - ( 0x102 - rb.rfind("\x00\x00") -2)
38 | self.rc4sbox = self.cfg[off1:off1+0x102]
39 | return self.rc4sbox
40 |
41 |
42 | mg = len(pes)
43 |
44 | for idx in xrange(len(self.cfg)-0x100):
45 | try:
46 | ss = unpack('I',self.rc4(pes,self.cfg[idx:idx+0x102])[0:4])[0]
47 |
48 | if ss == mg:
49 | print '[+] found rc4key'
50 | self.rc4sbox = self.cfg[idx:idx+0x102]
51 | return self.rc4sbox
52 |
53 | except Exception as e:
54 | print `e`
55 | pass
56 |
57 | def get_basics(self):
58 | if not self.rc4sbox:
59 | raise Exception('parse your shit bro')
60 |
61 | st = {}
62 | st['botname']=self.get_botname()
63 | st['rc4sbox']=self.rc4sbox.encode('hex')
64 | st['urls'] = self.get_urls()
65 | st['strings'] = self.get_strings()
66 | if not st['botname']:
67 | st['botname'] = '*default*'
68 | # if st['urls']:
69 | # st['cfg'] = st['urls'][0]
70 | # else:
71 | # st['cfg'] = ''
72 | return st
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/libzpy/modules/zeus.py:
--------------------------------------------------------------------------------
1 | import libzpy.structs.zeus as zeus
2 | import libzpy.fmt.zeus as zfmt
3 | from libzpy.modules import template as t
4 |
5 | from StringIO import StringIO
6 | from ctypes import sizeof,cast,c_byte
7 | from libzpy.libs.basecfg import BaseCfg
8 | import json
9 |
10 | def unpack(data,verb,verify=False):
11 | return t.unpack(data,verb,zeus,verify)
12 |
13 | def parse(data,verb):
14 | return t.parse(data,verb,zeus)
15 |
16 | def to_str(data,verb):
17 | if not isinstance(data,dict):
18 | verb('I need unpacked data')
19 | return
20 |
21 | fmt = zfmt.fmt(data)
22 | fmt._ = 'PowerZeus'
23 | return fmt.format()
24 |
25 |
26 | def json(data):
27 | verb=lambda x:x
28 | data = unpack(data,verb,True)
29 | data = parse(data,verb)
30 | return data
31 |
32 | def go(data,verb):
33 | data = unpack(data,verb)
34 | data = parse(data,verb)
35 | #print `data['injects']`
36 | print to_str(data,verb)
37 |
38 |
39 | def format(data,verb,type='pretty'):
40 | if type == 'pretty':
41 | return to_str(data,verb)
42 | elif type == 'json':
43 | return json.dumps(data)
44 |
45 |
46 | def parse_basecfg(basecfg,args):
47 |
48 | off = args['off']
49 | bc = BaseCfg(basecfg)
50 | bc.get_rc4(off)
51 | return bc.get_basics()
52 |
53 |
54 | ## we allready decode basecfg
55 | def get_basecfg(d,*args):
56 | return d.decode('hex')
57 |
58 | def pack(data,verb,rand=True):
59 | import hashlib
60 | import struct as s
61 | hdr = zeus.Header("\x00"*sizeof(zeus.Header))
62 | items = []
63 | for idx in data:
64 | d = data[idx]['data']
65 | if not isinstance(d,basestring):
66 | d= s.pack('I',d)
67 | itm = zeus.Item("\x00"*sizeof(zeus.Item))
68 | itm.id = idx
69 | itm.flags = data[idx]['flags']
70 | itm.size = len(d)
71 | itm.realSize = len(d)
72 | items.append(itm.pack() + d)
73 |
74 | with open('/dev/urandom') as f: rnd=f.read(20)
75 | cnt = ''.join(items)
76 | hsh = hashlib.md5(cnt).digest()
77 | hdr.count = len(data.keys())
78 | if rand:
79 | hdr.rand = (c_byte*20)(*map(ord,rnd))
80 |
81 | hdr.flags = 0
82 | hdr.size = len(cnt) + sizeof(zeus.Header)
83 | hdr.md5 =(c_byte*16)(*map(ord,hsh))
84 | # ctypes.cast(f.fileName, ctypes._char_p)
85 | return hdr.pack() + cnt
86 |
87 |
88 |
--------------------------------------------------------------------------------
/libzpy/modules/kins.py:
--------------------------------------------------------------------------------
1 | import json
2 | import sys,StringIO,re
3 | import libzpy.structs.kins as k
4 | import libzpy.fmt.powerzeus as pzfmt
5 | from libzpy.modules import template as t
6 | from libzpy.libs.vmzeus import VmContext as VM
7 | from libzpy.libs.basecfg import BaseCfg
8 | from ctypes import sizeof
9 | from struct import *
10 | from hashlib import md5
11 | from pprint import pprint
12 |
13 |
14 | class KinsCfg(BaseCfg):
15 | def get_rc4(self):
16 | self.rc4sbox = 'placeholder'
17 |
18 | def get_aes(self,off):
19 | self.get_rc4()
20 | self.aes = self.cfg[off:off+16]
21 | return self.aes
22 |
23 | def get_ua(self):
24 | self.ua = re.search("(Moz[^\x00]+)\x00",self.cfg).group(1)
25 | return self.ua
26 |
27 | def get_basics(self):
28 | st = super(KinsCfg,self).get_basics()
29 | del st['rc4sbox']
30 | st['aes-key']= self.aes.encode('hex')
31 | st['user-agent']=self.get_ua()
32 | return st
33 |
34 |
35 |
36 | def unpack(data,verb):
37 | return t.unpack(data,verb,k)
38 | def parse(data,verb):
39 | return t.parse(data,verb,k)
40 |
41 | def to_str(data,verb):
42 | if not isinstance(data,dict):
43 | verb('I need unpacked data')
44 | return
45 |
46 | fmt = pzfmt.fmt(data)
47 | fmt._name = 'KiNS'
48 | return fmt.format()
49 |
50 | def go(data,verb):
51 | data = unpack(data,verb)
52 | data = parse(data,verb)
53 | #print `data['injects']`
54 | r = to_str(data,verb)
55 | #print r
56 | return r
57 |
58 |
59 | def get_basecfg(data,verb,*args):
60 | oldstdout = sys.stdout
61 | #fd = open('/tmp/out','w')
62 | # print 'Code hash: ' + md5(data['code'].decode('hex')).hexdigest()
63 | # print 'Data hash: ' + md5(data['data'].decode('hex')).hexdigest()
64 | sys.stdout = StringIO.StringIO()
65 | cfg = None
66 | try:
67 | vmctx = VM(data['code'].decode('hex'),data['data'].decode('hex'))
68 | vmctx._fix_xors(data['magic'])
69 | vmctx.run()
70 | cfg = vmctx.config
71 |
72 | except Exception as e:
73 | import traceback
74 | sys.stdout = oldstdout
75 | print 'VMError: ' + `e`
76 | traceback.print_exc(file=sys.stdout)
77 |
78 | sys.stdout = oldstdout
79 | # fd.close()
80 | if not cfg:
81 | print 'Code hash: ' + md5(data['code'].decode('hex')).hexdigest()
82 | print 'Data hash: ' + md5(data['data'].decode('hex')).hexdigest()
83 | print 'Xors: ' + str(data['magic'])
84 | return cfg
85 |
86 |
87 |
88 |
89 |
90 | def parse_basecfg(basecfg,_args): #key,off,verb):
91 |
92 | # print `basecfg`
93 | off=_args['off']
94 | cfg = KinsCfg(basecfg)
95 | cfg.get_aes(off)
96 | return cfg.get_basics()
97 |
--------------------------------------------------------------------------------
/libzpy/libs/structure.py:
--------------------------------------------------------------------------------
1 | from ctypes import *
2 | #try:
3 | # from cStringIO import StringIO
4 | #except ImportError:
5 | from StringIO import StringIO
6 |
7 | c_word = c_uint16
8 | c_dword = c_uint32
9 | c_qword = c_uint64
10 |
11 | ## i need 32bit wchar...
12 | c_wchar = c_wchar if sizeof(c_wchar) == 2 else (2*c_char)
13 |
14 | class DataStructure(Structure):
15 | _flags = {}
16 | _have_data = True
17 | _sep = ' '
18 |
19 | def __init__(self,data):
20 | super(DataStructure,self).__init__()
21 | self.feed(data)
22 |
23 | def read(self,data):
24 | if isinstance(data,StringIO):
25 | self.data = data.read(self.size)
26 | else:
27 | self.data = data[sizeof(self):self.size]
28 |
29 | def pack(self):
30 | return buffer(self)[:]
31 |
32 | def feed(self, bytes):
33 | data = bytes
34 | if isinstance(data,StringIO):
35 | data = bytes.read(sizeof(self))
36 |
37 | memmove(addressof(self), c_char_p(data), sizeof(self))
38 | if self._have_data:
39 | self.read(bytes)
40 |
41 | def _str_field(self,args):
42 | if type(args) == str:
43 | args = (args,0)
44 | n,t = args
45 | if hasattr(self,'_print_%s' % n):
46 | return (n,getattr(self,'_print_%s' % n)())
47 | elif t == c_word:
48 | return (n,'0x%04x' % getattr(self,n))
49 | elif t == c_dword:
50 | return (n,'0x%08x' % getattr(self,n))
51 | elif getattr(self,n).__class__ == str:
52 | return (n,getattr(self,n).encode('string_escape'))
53 |
54 | def _p_field(self,a):
55 | return '%s: %s' % self._str_field(a)
56 |
57 | def _print_flags(self):
58 | ret = []
59 | for fl in self._flags:
60 | if self.flags & self._flags[fl]:
61 | ret.append(fl)
62 | try:
63 | return ' | '.join(ret) + "\n"
64 | except:
65 | return ''
66 |
67 | def __str__(self):
68 | return self._sep.join(map(self._p_field,self._fields_))
69 |
70 | def json(self):
71 | import json
72 | return json.dumps(dict(map(self._str_field,self._fields_)))
73 |
74 |
75 | class StructList(object):
76 | struct = None
77 |
78 | def __init__(self,data):
79 | self.data = data.data if isinstance(data,DataStructure) else data
80 | self.size = data.realSize if isinstance(data,DataStructure) else len(data)
81 | self.off = 0
82 |
83 | def __iter__(self):
84 | return self
85 |
86 | def next(self):
87 | if self.off >= self.size:
88 | raise StopIteration
89 | ib = self.struct(self.data[self.off:])
90 | self.off += ib.size
91 | return ib
92 |
--------------------------------------------------------------------------------
/libzpy/structs/vmzeus2.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_dword,c_word
3 | import libzpy.structs.zeus as zeus
4 |
5 |
6 | class Header(DataStructure):
7 | _have_data=False
8 | _fields_ = [ ('unk1',c_dword), ('size',c_dword), ('flags',c_dword), ('unk2',c_dword),('count',c_dword),('checksum',c_dword),('unk3',c_dword)]
9 |
10 |
11 |
12 | class Item(zeus.Item):
13 |
14 | def __init__(self,*args,**kwargs):
15 | super(Item,self).__init__(*args,**kwargs)
16 | self._flags['ITEMF_IS_ARGUMENT'] = 0x00100000
17 | self._flags['ITEMF_IS_MODULE_HASH'] = 0x00200000
18 | self._flags['ITEMF_IS_PROC_NAME_HASH'] = 0x00400000
19 | self._flags['ITEMF_IS_HTTP_INJECT'] = 8
20 | self._cfgids[20009] = 'CFGID_CAPTCHA_SERVER'
21 | self._cfgids[20010] ='CFGID_CAPTCHA_LIST'
22 | self._cfgids[20011] ='CFGID_NOTIFY_SERVER'
23 | self._cfgids[20012] ='CFGID_NOTIFY_LIST'
24 | self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
25 | self._cfgids[20014] ='CFGID_VNCDLL_URL'
26 | self._cfgids[20015] ='CFGID_MINERDLL_URL'
27 | self._cfgids[20018] ='CFGID_SPAM_TASK'
28 | self._cfgids[20019] ='CFGID_SPAM_TASK_STATUS'
29 | self._cfgids[20020] ='CFGID_SPAM_MODULE_URL'
30 | self._cfgids[20021] ='CFGID_CONFIG_CREATION_TIME'
31 | self._cfgids[20022] ='CFGID_P2P_NODE_INFO'
32 | self._cfgids[20023] ='CFGID_SIGNATURE'
33 | self._cfgids[20024] ='CFGID_FORCED_HOMEPAGE'
34 |
35 | # self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
36 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
37 | args[0].read(4)
38 |
39 | def is_captchasrv(self):
40 | return self.id == self._cfgids_n['CFGID_CAPTCHA_SERVER']
41 |
42 | def is_captchalist(self):
43 | return self.id == self._cfgids_n['CFGID_CAPTCHA_LIST']
44 | def is_notifysrv(self):
45 | return self.id == self._cfgids_n['CFGID_NOTIFY_SERVER']
46 |
47 | def is_notifylist(self):
48 | return self.id == self._cfgids_n['CFGID_NOTIFY_LIST']
49 |
50 | def is_ctime(self):
51 | return self.id == self._cfgids_n['CFGID_CONFIG_CREATION_TIME']
52 |
53 | # class HttpInject_InjectBlock(zeus.HttpInject_InjectBlock):
54 | # pass
55 |
56 | class HttpInject_HList(zeus.HttpInject_HList):
57 | struct = zeus.HttpInject_Header
58 |
59 | class HttpInject_BList(zeus.HttpInject_BList):
60 | pass
61 |
62 | class HttpInject_Captcha(DataStructure):
63 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
64 |
65 |
66 | class WebFilter(zeus.WebFilter):
67 | def __init__(self,*args,**kwargs):
68 | super(WebFilter,self).__init__(*args,**kwargs)
69 | self._wf['$'] = 'NOTIFY'
70 |
--------------------------------------------------------------------------------
/libzpy/structs/vmzeus20.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_dword,c_word
3 | import libzpy.structs.zeus as zeus
4 |
5 |
6 | class Header(DataStructure):
7 | _have_data=False
8 | _fields_ = [ ('unk1',c_dword), ('size',c_dword), ('flags',c_dword), ('unk2',c_dword),('count',c_dword),('checksum',c_dword),('unk3',c_dword)]
9 |
10 |
11 |
12 | class Item(zeus.Item):
13 |
14 | def __init__(self,*args,**kwargs):
15 | super(Item,self).__init__(*args,**kwargs)
16 | self._flags['ITEMF_IS_ARGUMENT'] = 0x00100000
17 | self._flags['ITEMF_IS_MODULE_HASH'] = 0x00200000
18 | self._flags['ITEMF_IS_PROC_NAME_HASH'] = 0x00400000
19 | self._flags['ITEMF_IS_HTTP_INJECT'] = 8
20 | self._cfgids[20009] = 'CFGID_CAPTCHA_SERVER'
21 | self._cfgids[20010] ='CFGID_CAPTCHA_LIST'
22 | self._cfgids[20011] ='CFGID_NOTIFY_SERVER'
23 | self._cfgids[20012] ='CFGID_NOTIFY_LIST'
24 | self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
25 | self._cfgids[20014] ='CFGID_VNCDLL_URL'
26 | self._cfgids[20015] ='CFGID_MINERDLL_URL'
27 | self._cfgids[20018] ='CFGID_SPAM_TASK'
28 | self._cfgids[20019] ='CFGID_SPAM_TASK_STATUS'
29 | self._cfgids[20020] ='CFGID_SPAM_MODULE_URL'
30 | self._cfgids[20021] ='CFGID_CONFIG_CREATION_TIME'
31 | self._cfgids[20022] ='CFGID_P2P_NODE_INFO'
32 | self._cfgids[20023] ='CFGID_SIGNATURE'
33 | self._cfgids[20024] ='CFGID_FORCED_HOMEPAGE'
34 |
35 | # self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
36 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
37 | args[0].read(4)
38 |
39 | def is_captchasrv(self):
40 | return self.id == self._cfgids_n['CFGID_CAPTCHA_SERVER']
41 |
42 | def is_captchalist(self):
43 | return self.id == self._cfgids_n['CFGID_CAPTCHA_LIST']
44 | def is_notifysrv(self):
45 | return self.id == self._cfgids_n['CFGID_NOTIFY_SERVER']
46 |
47 | def is_notifylist(self):
48 | return self.id == self._cfgids_n['CFGID_NOTIFY_LIST']
49 |
50 | def is_ctime(self):
51 | return self.id == self._cfgids_n['CFGID_CONFIG_CREATION_TIME']
52 |
53 | # class HttpInject_InjectBlock(zeus.HttpInject_InjectBlock):
54 | # pass
55 |
56 | class HttpInject_HList(zeus.HttpInject_HList):
57 | struct = zeus.HttpInject_Header
58 |
59 | class HttpInject_BList(zeus.HttpInject_BList):
60 | pass
61 |
62 | class HttpInject_Captcha(DataStructure):
63 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
64 |
65 |
66 | class WebFilter(zeus.WebFilter):
67 | def __init__(self,*args,**kwargs):
68 | super(WebFilter,self).__init__(*args,**kwargs)
69 | self._wf['$'] = 'NOTIFY'
70 |
--------------------------------------------------------------------------------
/libzpy/structs/powerzeus.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_word
3 | import libzpy.structs.zeus as zeus
4 |
5 | class Header(zeus.Header):
6 | pass
7 |
8 | class Item(zeus.Item):
9 |
10 | def __init__(self,*args,**kwargs):
11 | super(Item,self).__init__(*args,**kwargs)
12 | self._flags['ITEMF_IS_ARGUMENT'] = 0x00100000
13 | self._flags['ITEMF_IS_MODULE_HASH'] = 0x00200000
14 | self._flags['ITEMF_IS_PROC_NAME_HASH'] = 0x00400000
15 | self._cfgids[20009] = 'CFGID_CAPTCHA_SERVER'
16 | self._cfgids[20010] ='CFGID_CAPTCHA_LIST'
17 | self._cfgids[20011] ='CFGID_NOTIFY_SERVER'
18 | self._cfgids[20012] ='CFGID_NOTIFY_LIST'
19 | self._cfgids[20013] ='CFGID_REFRESH_BLOCK_LIST'
20 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
21 |
22 |
23 | def is_captchasrv(self):
24 | return self.id == self._cfgids_n['CFGID_CAPTCHA_SERVER']
25 |
26 | def is_captchalist(self):
27 | return self.id == self._cfgids_n['CFGID_CAPTCHA_LIST']
28 | def is_notifysrv(self):
29 | return self.id == self._cfgids_n['CFGID_NOTIFY_SERVER']
30 |
31 | def is_notifylist(self):
32 | return self.id == self._cfgids_n['CFGID_NOTIFY_LIST']
33 |
34 | _http_inj_flags = {
35 | 'FLAG_IS_INJECT' : 0x0001,
36 | 'FLAG_IS_CAPTURE' : 0x0002,
37 | 'FLAG_REQUEST_POST' : 0x0004,
38 | 'FLAG_REQUEST_GET' : 0x0008,
39 | 'FLAG_ONCE_PER_DAY' : 0x0010,
40 | 'FLAG_CAPTURE_NOTPARSE' : 0x0100,
41 | 'FLAG_CAPTURE_TOFILE' : 0x0200,
42 | 'FLAG_URL_CASE_INSENSITIVE' : 0x1000,
43 | 'FLAG_CONTEXT_CASE_INSENSITIVE' : 0x2000
44 | }
45 | class HttpInject_InjectBlock(zeus.HttpInject_InjectBlock):
46 | _flags = _http_inj_flags
47 |
48 | class HttpInject_Header(DataStructure):
49 | _pack_ = 1
50 | _fields_ = [('flags',c_word),('size',c_word),('urlMask',c_word),
51 | ('postDataBlackMask',c_word),('postDataWhiteMask',c_word),
52 | ('contextMask',c_word)
53 | ]
54 | _flags = _http_inj_flags
55 |
56 | def is_inject(self):
57 | return self.flags & self._flags['FLAG_IS_INJECT']
58 | def is_capture(self):
59 | return self.flags & self._flags['FLAG_IS_CAPTURE']
60 |
61 | class HttpInject_HList(zeus.HttpInject_HList):
62 | struct = HttpInject_Header
63 |
64 | class HttpInject_BList(zeus.HttpInject_BList):
65 | pass
66 |
67 | class HttpInject_Captcha(DataStructure):
68 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
69 |
70 |
71 | class WebFilter(zeus.WebFilter):
72 | def __init__(self,*args,**kwargs):
73 | super(WebFilter,self).__init__(*args,**kwargs)
74 | self._wf['$'] = 'NOTIFY'
75 |
--------------------------------------------------------------------------------
/libzpy/structs/citadel.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_word,c_dword,c_byte
3 | import libzpy.structs.zeus as zeus
4 |
5 | class Header(DataStructure):
6 | _have_data=False
7 | _fields_ = [ ('junk',c_byte*12), ('size',c_dword), ('flags',c_dword), ('count',c_dword),('md5',c_byte*0x10)]
8 |
9 |
10 | class Item(zeus.Item):
11 |
12 | def __init__(self,*args,**kwargs):
13 | super(Item,self).__init__(*args,**kwargs)
14 | self._flags['ITEMF_IS_ARGUMENT'] = 0x00100000
15 | self._flags['ITEMF_IS_MODULE_HASH'] = 0x00200000
16 | self._flags['ITEMF_IS_PROC_NAME_HASH'] = 0x00400000
17 | self._cfgids[20009] ='CFGID_DNS_FILTER'
18 | self._cfgids[20010] ='CFGID_CMD_LIST'
19 | self._cfgids[20011] ='CFGID_HTTP_MAGICURI_LIST'
20 | self._cfgids[20012] ='CFGID_FILESEARCH_KEYWORDS'
21 | self._cfgids[20013] ='CFGID_FILESEARCH_EXCLUDES_NAME'
22 | self._cfgids[20014] ='CFGID_FILESEARCH_EXCLUDES_PATH'
23 | self._cfgids[20015] ='CFGID_KEYLOGGER_PROCESSES'
24 | self._cfgids[20016] ='CFGID_KEYLOGGER_TIME'
25 | self._cfgids[20017] ='CFGID_FILESEARCH_MINYEAR'
26 | self._cfgids[20018] ='CFGID_WEBINJECTS_URL'
27 | self._cfgids[20019] ='CFGID_TOKENSPY_URL'
28 | self._cfgids[20020] ='CFGID_HTTPVIP_URLS'
29 | self._cfgids[20101] ='CFGID_VIDEO_QUALITY'
30 | self._cfgids[20102] ='CFGID_VIDEO_LENGTH'
31 | self._cfgids[20201] ='CFGID_MONEY_PARSER_ENABLED'
32 | self._cfgids[20202] ='CFGID_MONEY_PARSER_INCLUDE'
33 | self._cfgids[20203] ='CFGID_MONEY_PARSER_EXCLUDE'
34 |
35 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
36 |
37 |
38 | def is_captchasrv(self):
39 | return self.id == self._cfgids_n['CFGID_CAPTCHA_SERVER']
40 |
41 | def is_captchalist(self):
42 | return self.id == self._cfgids_n['CFGID_CAPTCHA_LIST']
43 | def is_notifysrv(self):
44 | return self.id == self._cfgids_n['CFGID_NOTIFY_SERVER']
45 |
46 | def is_notifylist(self):
47 | return self.id == self._cfgids_n['CFGID_NOTIFY_LIST']
48 |
49 | _http_inj_flags = {
50 | 'FLAG_IS_INJECT' : 0x0001,
51 | 'FLAG_IS_CAPTURE' : 0x0002,
52 | 'FLAG_REQUEST_POST' : 0x0004,
53 | 'FLAG_REQUEST_GET' : 0x0008,
54 | 'FLAG_ONCE_PER_DAY' : 0x0010,
55 | 'FLAG_CAPTURE_NOTPARSE' : 0x0100,
56 | 'FLAG_CAPTURE_TOFILE' : 0x0200,
57 | 'FLAG_URL_CASE_INSENSITIVE' : 0x1000,
58 | 'FLAG_CONTEXT_CASE_INSENSITIVE' : 0x2000
59 | }
60 | class HttpInject_InjectBlock(zeus.HttpInject_InjectBlock):
61 | _flags = _http_inj_flags
62 |
63 | class HttpInject_Header(DataStructure):
64 | _pack_ = 1
65 | _fields_ = [('flags',c_word),('size',c_word),('urlMask',c_word),
66 | ('postDataBlackMask',c_word),('postDataWhiteMask',c_word),
67 | ('contextMask',c_word)
68 | ]
69 | _flags = _http_inj_flags
70 |
71 | def is_inject(self):
72 | return self.flags & self._flags['FLAG_IS_INJECT']
73 | def is_capture(self):
74 | return self.flags & self._flags['FLAG_IS_CAPTURE']
75 |
76 | class HttpInject_HList(zeus.HttpInject_HList):
77 | struct = HttpInject_Header
78 |
79 | class HttpInject_BList(zeus.HttpInject_BList):
80 | pass
81 |
82 | class HttpInject_Captcha(DataStructure):
83 | _fields_ = [('size',c_word),('urlHostMask',c_word),('urlCaptcha',c_word)]
84 |
85 |
86 | class WebFilter(zeus.WebFilter):
87 | def __init__(self,*args,**kwargs):
88 | super(WebFilter,self).__init__(*args,**kwargs)
89 | self._wf['#'] = 'MOVIE'
90 |
--------------------------------------------------------------------------------
/libzpy/fmt/zeus.py:
--------------------------------------------------------------------------------
1 |
2 | class fmt(object):
3 | _name = 'ZeuS'
4 | _formats = ['version','server','adv_server','webfilters','injects','captures']
5 | def __init__(self,cfg):
6 | self.cfg = cfg
7 |
8 | # _wf_butify={
9 | # '@' : 'SCREENSHOT',
10 | # '!' : 'DONT-REPORT',
11 | # '-' : 'SAVE-COOCKIE',
12 | # '^' : 'BLOCK-ACCESS'
13 | # }
14 |
15 | def _butify_wf(self,d):
16 | if len(d['action']) > 3:
17 | return '{{' + d['action'] + '}} ' + d['target'].strip()
18 | return '{{' + 'UNKNOWN-ACCTION('+d['action'] + ')}} ' + d['target'].strip()
19 |
20 | def webfilters(self):
21 | if 'webfilters' in self.cfg:
22 | return "{{WEBFILTERS}}\n" + "\n".join(map(self._butify_wf,self.cfg['webfilters'])) + "\n{{END_WEBFILTERS}}\n\n"
23 | else:
24 | return ''
25 |
26 | def _field(self,name,fname,ppr=str):
27 | if not fname in self.cfg:
28 | return ''
29 | return '{{%s}}\n%s\n{{END_%s}}\n'%(name,ppr(self.cfg[fname]),name)
30 |
31 | def _list(self,name,fname):
32 | if not fname in self.cfg:
33 | return ''
34 | r = '{{%s}}\n'%name
35 | for c in self.cfg[fname]:
36 | if isinstance(c,str):
37 | r += c + "\n"
38 | elif isinstance(c,dict):
39 | for n in c:
40 | r += n.upper() + ':' + c[n] + " "
41 | r += "\n"
42 | return r + "{{END_%s}}\n"%name
43 |
44 | def version(self):
45 | if 'version' in self.cfg:
46 | return "\n\n" + self._name + ': ' + self.cfg['version'] + "\n\n\n"
47 | return ''
48 |
49 | def binary(self):
50 | return self._list('UPDATE_URLS','update')
51 | # def binary(self):
52 | # return self._list("{{UPDATE_URLS}}",'update',"{{END_UPDATE_URLS}}")
53 |
54 | def server(self):
55 | return self._list('SERVER_URLS','server')
56 |
57 | def adv_server(self):
58 | return self._list('ADV_SERVER_URLS','advance')
59 |
60 | def inject_flags(self,inj):
61 | pass
62 |
63 | def injects(self):
64 | r = self._injects_fmt('injects')
65 | return ('{{INJECTS}}' +r + "{{END_INJECTS}}\n") if r else ''
66 |
67 | def captures(self):
68 | r = self._injects_fmt('captures')
69 | return ('{{CAPTURES}}' +r + "{{END_CAPTURES}}\n") if r else ''
70 |
71 | def _injects_fmt(self,t):
72 | r = '' #
73 | for inject in self.cfg['injects']:
74 | if t in inject:
75 | r += '\nTarget: ' + inject['target']
76 | r += '\nFlags: ' + inject['flags']
77 | r += '\nMeta: '
78 | r += "\n"
79 | for inj in inject[t]:
80 |
81 | r += "{{DATA_BEFORE}}"+ (" {{FLAGS: %X}}" % inj['pre_flag']) +"\n"
82 | r += inj['pre'] + "\n"
83 | r += "{{END_DATA_BEFORE}}\n"
84 | r += "{{DATA_AFTER}}" + (" {{FLAGS: %X}}" % inj['post_flag']) + "\n"
85 | r += inj['post'] + "\n"
86 | r += "{{END_DATA_AFTER}}\n"
87 | r += "{{INJECT}}"+ (" {{FLAGS: %X}}" % inj['inj_flag']) +"\n"
88 | r += inj['inj'] + "\n"
89 | r += "{{END_INJECT}}\n\n"
90 | r += '-'*32
91 | r +="\n"
92 | r += '#' * 32
93 | r +="\n"
94 | return r
95 |
96 | def format(self):
97 | r = ''
98 | for fmt in self._formats:
99 | r+=getattr(self,fmt)()
100 |
101 | return r
102 |
--------------------------------------------------------------------------------
/libzpy/fmt/zeus.py.old:
--------------------------------------------------------------------------------
1 | from libs.rtb import check_url
2 |
3 | class fmt(object):
4 | _name = 'ZeuS'
5 | def __init__(self,cfg):
6 | self.cfg = cfg
7 |
8 | _wf_butify={
9 | '@' : 'SCREENSHOT',
10 | '!' : 'DONT-REPORT',
11 | '-' : 'SAVE-COOCKIE',
12 | '^' : 'BLOCK-ACCESS'
13 | }
14 |
15 | def _butify_wf(self,d):
16 | data = d.strip()
17 | if data[0] in self._wf_butify:
18 | return '{{' + self._wf_butify[data[0]] + '}} ' + data[1:]
19 | return data
20 |
21 | def webfilters(self):
22 | if 'webfilters' in self.cfg:
23 | return "{{WEBFILTERS}}\n" + "\n".join(map(self._butify_wf,self.cfg['webfilters'])) + "\n{{END_WEBFILTERS}}\n\n"
24 | else:
25 | return ''
26 |
27 | def _list(self,pre,name,post):
28 | if not name in self.cfg:
29 | return ''
30 | r = pre + "\n"
31 | for c in self.cfg[name]:
32 | if isinstance(c,str):
33 | r += c + "\n"
34 | elif isinstance(c,dict):
35 | for n in c:
36 | r += n.upper() + ':' + c[n] + " "
37 | r += "\n"
38 | return r + post + "\n"
39 |
40 | def version(self):
41 | if 'version' in self.cfg:
42 | return "\n\n" + self._name + ': ' + self.cfg['version'] + "\n\n\n"
43 | return ''
44 |
45 | def binary(self):
46 | return self._list("{{UPDATE_URLS}}",'update',"{{END_UPDATE_URLS}}")
47 |
48 | def server(self):
49 | return self._list("{{SERVER_URLS}}",'server',"{{END_SERVER_URLS}}")
50 |
51 | def adv_server(self):
52 | return self._list("{{ADV_SERVER_URLS}}",'advance',"{{ADV_END_SERVER_URLS}}")
53 |
54 | def inject_flags(self,inj):
55 | pass
56 |
57 | def injects(self):
58 | r = self._injects_fmt('injects')
59 | return ('{{INJECTS}}' +r + "{{END_INJECTS}}\n") if r else ''
60 |
61 | def captures(self):
62 | r = self._injects_fmt('captures')
63 | return ('{{CAPTURES}}' +r + "{{END_CAPTURES}}\n") if r else ''
64 |
65 | def _injects_fmt(self,t):
66 | r = '' #
67 | for inject in self.cfg['injects']:
68 | if t in inject:
69 | r += '\nTarget: ' + inject['target']
70 | r+= '\nHits: ' + check_url(inject['target'])
71 | r += '\nFlags: ' + inject['flags']
72 | r += '\nMeta: '
73 | r += "\n"
74 | for inj in inject[t]:
75 |
76 | r += "{{DATA_BEFORE}}"+ (" {{FLAGS: %X}}" % inj['pre_flag']) +"\n"
77 | r += inj['pre'] + "\n"
78 | r += "{{END_DATA_BEFORE}}\n"
79 | r += "{{DATA_AFTER}}" + (" {{FLAGS: %X}}" % inj['post_flag']) + "\n"
80 | r += inj['post'] + "\n"
81 | r += "{{END_DATA_AFTER}}\n"
82 | r += "{{INJECT}}"+ (" {{FLAGS: %X}}" % inj['inj_flag']) +"\n"
83 | r += inj['inj'] + "\n"
84 | r += "{{END_INJECT}}\n\n"
85 | r += '-'*32
86 | r +="\n"
87 | r += '#' * 32
88 | r +="\n"
89 | return r
90 |
91 | def format(self):
92 | r = ''
93 | r += self.version()
94 | r += self.server()
95 | r += self.binary()
96 | r += self.adv_server()
97 | # r += self.notify_srv()
98 | # r += self.notify_list()
99 | # r += self.captcha_srv()
100 | # r += self.captcha_list()
101 | r += self.webfilters()
102 | r += self.injects()
103 | r += self.captures()
104 | return r
105 |
--------------------------------------------------------------------------------
/libzpy/libs/xstream.py:
--------------------------------------------------------------------------------
1 | import StringIO
2 | import struct
3 | import string
4 | import os
5 |
6 |
7 | def glue(parts,delim='',preproc=None):
8 | if preproc:
9 | for fn in preproc:
10 | parts = map( fn , parts )
11 | return delim.join(parts)
12 |
13 | class streamError(Exception):
14 | msg=None
15 | def __init__(self,m=None):
16 | self.msg=m
17 | def __str__(self):
18 | if self.msg:
19 | return "Error: "+self.msg
20 | else:
21 | return "Error: unknow error "
22 |
23 | def unpackEx(fmt,data,into=None):
24 | #print "Will unpackt [%s] [%s]" % (fmt,`data`)
25 | t = struct.unpack(fmt,data)
26 | if not t :
27 | return None
28 | if not into:
29 | return t
30 | if len(t) != len(into):
31 | raise streamError("readFmt into values : size mismatch [%d != %d]" % (len(into),len(t)))
32 | return dict( (into[i],t[i]) for i in range(len(into)) )
33 |
34 | class xstream(StringIO.StringIO):
35 |
36 | def readN(self,n):
37 | d = self.read(n)
38 | if len(d) < n:
39 | raise streamError("Read error : need %d bytes, got %d " % ( n , len(d) ))
40 | return d
41 |
42 | def readFmt(self,fmt,into=None):
43 | n = struct.calcsize(fmt)
44 | d = self.readN(n)
45 | return unpackEx(fmt,d,into)
46 |
47 | # old code :
48 | t = struct.unpack(fmt,d)
49 | if not t:
50 | return None
51 | if not into:
52 | return t
53 | if len(into) != len(t):
54 | raise streamError("readFmt into values : size mismatch [%d != %d]" % (len(into),len(t)))
55 | D={}
56 | for i in range(len(into)):
57 | D[into[i]] = t[i]
58 | return D
59 |
60 |
61 | def readOne(self,fmt):
62 | d = self.readFmt(fmt)
63 | return None if d is None else d[0]
64 |
65 | def readAll(self):
66 | s = self.getLen()
67 | p = self.getPos()
68 | d = s - p
69 | return self.readN(d)
70 |
71 |
72 | def append(self,data):
73 | p = self.tell()
74 | self.seek(0, os.SEEK_END)
75 | self.write( data )
76 | self.seek(p)
77 |
78 | def appendFmt(self,fmt,*a):
79 | return self.append(struct.pack(fmt, *a) )
80 |
81 | def writeFmt(self,fmt,*a):
82 | return self.write( struct.pack(fmt , *a) )
83 |
84 | def writePascalData(self,data,fmt="!H"): # lol :D
85 | self.writeFmt(fmt,len(data))
86 | self.write(data)
87 |
88 | def readme(self):
89 | p = self.tell()
90 | self.seek(0)
91 | v = self.read()
92 | self.seep(p)
93 | return v
94 |
95 | def dump(self):
96 | return self.getvalue()
97 |
98 | def getLen(self):
99 | org = self.tell()
100 | self.seek(0, os.SEEK_END)
101 | end = self.tell()
102 | self.seek(org)
103 | return end
104 |
105 | def getPos(self):
106 | return self.tell()
107 |
108 | def availableLen(self):
109 | return self.getLen() - self.getPos()
110 |
111 | def printStatus(self):
112 | print " Len: %d Pos: %d " % ( self.getLen() , self.getPos() )
113 |
114 | def hexDump(self,inRow=16,title=None,head=True):
115 | S = ' \n'
116 | if head:
117 | if title:
118 | S += " .----[ %s ]----- \n" % title
119 | S += "| offset ascii hex \n"
120 | p = self.tell() # save
121 | self.seek(0) # rewind
122 | fmt = "| 0x%08X %-"+str(inRow)+"s \t %s\n"
123 | while True:
124 | of = self.tell()
125 | chunk = self.read(inRow)
126 | hx = ''
127 | ch = ''
128 | for c in list(chunk):
129 | ch+= c if ord(c)>=32 and ord(c)<127 else '.'
130 | hx += "%02X " % ord(c)
131 | S += fmt % (of,ch,hx)
132 | if len(chunk) < inRow:
133 | break
134 | S+= "| 0x%08X \n" % self.tell()
135 | S+= "`-- \n"
136 | self.seek(p)
137 | return S
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/libzpy/modules/chthonic.py:
--------------------------------------------------------------------------------
1 | from Crypto.Cipher import AES
2 | import libzpy.structs.chthonic as cht
3 | import libzpy.fmt.zeus as zeusfmt
4 | from libzpy.libs.basecfg import BaseCfg
5 | from libzpy.libs.vmzeus import VmContext as VM
6 | from libzpy.modules import template as t
7 | from libzpy.modules import zeus as zeus
8 | import mlib.crypto as mc
9 | import json
10 | import re
11 | import sys
12 | import StringIO
13 | import hashlib
14 | import struct
15 | import os
16 | import libzpy.structs.chthonic as chtstruct
17 |
18 | AES_BLOCK_SIZE = 16
19 |
20 | def aes_pad(s):
21 | return s + (AES_BLOCK_SIZE - len(s) % AES_BLOCK_SIZE) * chr(AES_BLOCK_SIZE - len(s) % AES_BLOCK_SIZE)
22 |
23 | def aes_decrypt(data, key):
24 | aes = AES.new(key, AES.MODE_ECB)
25 | data = aes.decrypt(data)
26 | data = mc.visDecry(data)
27 | return data
28 |
29 | def aes_encrypt(data, key):
30 | data = mc.visEncry(data)
31 | aes = AES.new(key, AES.MODE_ECB)
32 | data = aes.encrypt(aes_pad(data))
33 | return data
34 |
35 | def unpack(data, verb, key):
36 | if key is not None:
37 | data = aes_decrypt(data, key)
38 |
39 | data = t.unpack(data, verb, chtstruct)
40 |
41 | result = []
42 | items = data["items"]
43 |
44 | for item in items:
45 | if item.id == item._cfgids['CFGID_OUTER_PAYLOAD'] and not item.data.startswith("MZ"):
46 | try:
47 | nested = unpack(item.data, verb, key)
48 | result += nested["items"]
49 | except ValueError:
50 | nested = unpack(item.data, verb, None)
51 | result += nested["items"]
52 |
53 | elif item.id == item._cfgids['CFGID_PAYLOAD'] and item.flags & item._flags['ITEMF_IS_PACKED_CONFIG']:
54 | nested = unpack(item.data, verb, None)
55 | result += nested["items"]
56 | elif item.id == item._cfgids['CFGID_INJECTS']:
57 | nested = unpack(item.data, verb, None)
58 | result += nested["items"]
59 | else:
60 | result.append(item)
61 |
62 | data['items'] = result
63 |
64 | return data
65 |
66 | def pack(data, verb, aes_key):
67 | packet = zeus.pack(data, verb)
68 | packet = aes_encrypt(packet, aes_key)
69 |
70 | return packet
71 |
72 | def parse(data, verb):
73 | ret = t.parse(data, verb, cht)
74 |
75 | for i in data['items']:
76 | if i.data.startswith("MZ"):
77 | ret['PE'] = i.data
78 | return ret
79 |
80 |
81 | def to_str(data, verb):
82 | if not isinstance(data, dict):
83 | verb('I need unpacked data')
84 | return
85 |
86 | fmt = zeusfmt.fmt(data)
87 | fmt._ = 'Cthonic'
88 | return fmt.format()
89 |
90 | def format(data, verb, type='pretty'):
91 | if type == 'pretty':
92 | return to_str(data, verb)
93 | elif type == 'json':
94 | return json.dumps(data)
95 |
96 | def go(data, verb, aeskey):
97 | if not data:
98 | return ""
99 | if len(data) % 16 != 0:
100 | return ""
101 |
102 | data = unpack(data, verb, aeskey)
103 | data = parse(data, verb)
104 | return data
105 |
106 | def get_basecfg(data,verb,*args):
107 | oldstdout = sys.stdout
108 | sys.stdout = StringIO.StringIO()
109 | cfg = None
110 | try:
111 | vmctx = VM(data['code'].decode('hex'),data['data'].decode('hex'))
112 | vmctx._fix_xors(data['magic'])
113 | vmctx.run()
114 | cfg = vmctx.config
115 |
116 | except Exception as e:
117 | import traceback
118 | sys.stdout = oldstdout
119 | print 'VMError: ' + `e`
120 | traceback.print_exc(file=sys.stdout)
121 |
122 | sys.stdout = oldstdout
123 | if not cfg:
124 | print 'Code hash: ' + hashlib.md5(data['code'].decode('hex')).hexdigest()
125 | print 'Data hash: ' + hashlib.md5(data['data'].decode('hex')).hexdigest()
126 | print 'Xors: ' + str(data['magic'])
127 | return cfg
128 |
129 | class ChthonicCfg(BaseCfg):
130 | def __init__(self, cfg):
131 | super(ChthonicCfg, self).__init__(cfg)
132 | self.rc4sbox = 'huh'
133 |
134 | def get_ua(self):
135 | self.ua = re.search("(Moz[^\x00]+)\x00", self.cfg).group(1)
136 | return self.ua
137 |
138 | def get_basics(self):
139 | st = super(ChthonicCfg, self).get_basics()
140 | st['user-agent'] = self.get_ua()
141 | st['aes-key'] = self.aeskey
142 | del st['rc4sbox']
143 | return st
144 |
145 | def set_aes(self, aeskey):
146 | self.aeskey = aeskey
147 |
148 | def parse_basecfg(basecfg, _args):
149 | cfg = ChthonicCfg(basecfg)
150 | cfg.set_aes(_args['aes-key'])
151 | return cfg.get_basics()
152 |
--------------------------------------------------------------------------------
/libzpy/modules/vmzeus.py:
--------------------------------------------------------------------------------
1 | import sys,StringIO,re
2 | import libzpy.structs.kins as k
3 | import libzpy.fmt.powerzeus as pzfmt
4 | #import libzpy.libs.cr_tools as cry
5 | from libzpy.modules import template as t
6 | from libzpy.libs.vmzeus import VmContext as VM
7 | from libzpy.libs.basecfg import BaseCfg
8 | from ctypes import sizeof
9 | from struct import *
10 | from hashlib import md5
11 | from pprint import pprint
12 |
13 |
14 | class VMZCfg(BaseCfg):
15 | def _get_enc_urls(self,k=None):
16 | d = self.cfg
17 | k = k if k else self.rc4sbox
18 | rk = k[:-2][::-1]
19 | off = d.find(k)
20 | if off == -1:
21 | print 'No key... wrong baseconfig/key?'
22 | return
23 | i = 0
24 | ret =[];els = []
25 | while i < len(d):
26 | if i == off:
27 | i+= 0x102
28 | else:
29 | dec = self.rc4(d[i:i+0x66],rk)
30 | if dec.find('http') != -1:
31 | ret.append(dec.split("\x00")[0])
32 | elif re.search("[\x1f-\x7e]{6,}\x00",dec):
33 | els.append( re.search("([\x1f-\x7e]{6,})\x00",dec).group(1) )
34 | i+=1
35 | self.urls = ret
36 | return ret,els
37 |
38 | def get_urls(self):
39 | if not self.urls:
40 | self._get_enc_urls()
41 | return self.urls
42 |
43 | def get_rc4(self,ks):
44 | ## brutforece to find botnet rc4 key try to find baseurl
45 | ## if succeded its our key - should work well
46 | if type(ks) != list:
47 | self.rc4sbox = ks.decode('hex')
48 | return self.rc4sbox
49 |
50 | r = None
51 | for k in ks:
52 | try:
53 | temp = self._get_enc_urls(k)
54 | if temp and temp != ([],[]) and any(map(lambda u: u.find('http')!=-1,temp[0])):
55 | r = k
56 | except Exception as e:
57 | # import traceback
58 | # print `e`
59 | # traceback.print_exc(file=sys.stdout)
60 | pass
61 | self.rc4sbox = r
62 | return r
63 |
64 |
65 | def unpack(data,verb):
66 | return t.unpack(data,verb,k)
67 | def parse(data,verb):
68 | return t.parse(data,verb,k)
69 |
70 | def to_str(data,verb):
71 | if not isinstance(data,dict):
72 | verb('I need unpacked data')
73 | return
74 |
75 | fmt = pzfmt.fmt(data)
76 | fmt._name = 'VMZeus'
77 | return fmt.format()
78 |
79 | def do_print(data,verb):
80 | print data
81 |
82 | def json(data):
83 | return go(data,lambda x:x)
84 |
85 | def go(data,verb):
86 | data = unpack(data,verb)
87 | data = parse(data,verb)
88 | #print `data['injects']`
89 | return data
90 |
91 |
92 | def vmzeus_dga(key,suff,idx=0):
93 | key = key[::-1][2:]
94 | key = chr(ord(key[0]) + idx) + key[1:] + "\x00\x00"
95 | return 'http://' + md5(key).hexdigest()[:11] + suff
96 |
97 | def parse_basecfg(basecfg,data):
98 | # print `basecfg`
99 | key = data['key']
100 | rc6k = data.get('off',None)
101 |
102 | bc = VMZCfg(basecfg)
103 | bc.get_rc4(key)
104 | staticcfg = bc.get_basics()
105 | fakeurl = re.search('(http://[a-zA-Z0-9/.]*\x00)',bc.cfg).group(1)
106 | if rc6k:
107 | staticcfg['rc6sbox']= basecfg[rc6k:rc6k+0xb0].encode('hex')
108 | for u in filter(lambda x: x.endswith('.jpg'),bc.urls):
109 | staticcfg['cfg'] =u
110 |
111 | staticcfg['urls']
112 | staticcfg['fakeurl'] = (fakeurl if fakeurl else '*UNKNOWN*').strip("\x00")
113 | # staticcfg['OtherEncStrings'] = `els`
114 | # staticcfg['OtherStrings']= `othr`
115 | return staticcfg
116 |
117 | # print 'DGA: ' + `[ vmzeus_dga(key,els[0],i) for i in range(0,5)]`
118 |
119 |
120 | def get_basecfg(data,verb,*args):
121 | oldstdout = sys.stdout
122 | #fd = open('/tmp/out','w')
123 | sys.stdout = StringIO.StringIO()
124 | cfg = None
125 | try:
126 | vmctx = VM(data['code'].decode('hex'),data['data'].decode('hex'))
127 | vmctx._fix_xors(data['magic'])
128 | vmctx.run()
129 | cfg = vmctx.config
130 |
131 | except Exception as e:
132 | import traceback
133 | sys.stdout = oldstdout
134 | print 'VMError: ' + `e`
135 | traceback.print_exc(file=sys.stdout)
136 |
137 | sys.stdout = oldstdout
138 | # fd.close()
139 | if not cfg:
140 | print 'Code hash: ' + md5(data['code'].decode('hex')).hexdigest()
141 | print 'Data hash: ' + md5(data['data'].decode('hex')).hexdigest()
142 | print 'Xors: ' + str(data['magic'])
143 | # print `cfg`
144 | return cfg
145 |
146 | # def decrypt_cfg(data,key):
147 | # print 'Data: ' + `data`
148 | # print 'Key: ' + `key`
149 | # data = cry.rc4decrypt(data,key)
150 | # return cry.visDecry(data)
151 |
152 |
153 |
--------------------------------------------------------------------------------
/libzpy/modules/template.py:
--------------------------------------------------------------------------------
1 | from StringIO import StringIO
2 | from ctypes import sizeof
3 | from hashlib import md5
4 |
5 | def unpack(data,verb,mod=None,verify=None):
6 | data = StringIO(data)
7 | stor = mod.Header(data)
8 | hash = md5(data.read(stor.size - sizeof(mod.Header))).digest()
9 | data.seek(sizeof(mod.Header),0)
10 | if verify:
11 | # print str(bytearray(stor.md5)).encode('hex')
12 | # print hash.encode('hex')
13 | if hash != str(bytearray(stor.md5)):
14 | print '[-] Hash mismath -- corrupted binstor?'
15 | return None
16 | ret = {}
17 | ret['header'] = stor
18 | ret['items'] = []
19 | for idx in xrange(stor.count):
20 | itm = mod.Item(data)
21 | ret['items'].append(itm)
22 | return ret
23 |
24 | def string_list(d):
25 | return filter(None,d.split("\x00"))
26 |
27 |
28 |
29 | def parse(data,verb,mod=None):
30 | if not isinstance(data,dict):
31 | verb('I need unpacked data')
32 | return
33 | ret = {}
34 | ret['header'] = data['header']
35 | ret['unknown'] = {}
36 | injList = []
37 | injects = []
38 |
39 | for itm in data['items']:
40 | if itm.is_webfilter():
41 | if not 'webfilters' in ret:
42 | ret['webfilters'] = []
43 | for x in filter(None,itm.data.split("\x00")):
44 | ret['webfilters'].append(mod.WebFilter(x).json())
45 |
46 | elif itm.is_injectlist():
47 | injList.append(itm)
48 | elif itm.is_inject():
49 | injects.append(itm)
50 | elif itm.is_update():
51 | if not 'update' in ret:
52 | ret['update'] = []
53 | ret['update'].append(itm.data)
54 | elif itm.is_version():
55 | pv =lambda x:'.'.join(['%.2X'% ord(c) for c in reversed(x)])
56 | ret['version'] = pv(itm.data)
57 |
58 | elif (hasattr(itm,'is_captchasrv' ) and itm.is_captchasrv()):
59 |
60 | if not 'captcha_srv' in ret:
61 | ret['captcha_srv'] = []
62 | ret['captcha_srv'].append(itm.data)
63 |
64 | elif (hasattr(itm,'captchalist') and itm.is_captchalist()) :
65 |
66 | if not 'captcha_lst' in ret:
67 | ret['captcha_lst'] = []
68 |
69 | x = mod.HttpInject_Captcha(itm.data)
70 | u = x.data[x.urlCaptcha:].replace("w\x00\x00","www").strip("\x00")
71 | m = x.data.replace("w\x00\x00","www")
72 | m = m[x.urlHostMask:m.find("\x00")]
73 | ret['captcha_lst'].append({'mask':m,'url':u})
74 |
75 | elif (hasattr(itm,'notifysrv') and itm.is_notifysrv()):
76 |
77 | if not 'notify_srv' in ret:
78 | ret['notify_srv'] = []
79 | ret['notify_srv'].append(itm.data)
80 |
81 |
82 | elif itm.is_cfg_url():
83 |
84 | if not 'server' in ret:
85 | ret['server'] = []
86 | ret['server'].append(itm.data)
87 |
88 | elif itm.is_acfg_url():
89 | if not 'advance' in ret:
90 | ret['advance'] = []
91 | ret['advance'] += itm.data.split("\x00")
92 |
93 | elif itm._str_field('id')[1] != str(itm.id):
94 | # ## we know this type...
95 | ret[itm._str_field('id')[1]] = itm.data
96 | else:
97 | ret['unknown'][itm.id] = itm.data
98 | # ret['unknown'].append( str(itm) + "\n" + `itm.data`)
99 |
100 | ret['injects'] = []
101 | # print len(injects)
102 | for il in injList:
103 | idx = 0
104 | for ih in mod.HttpInject_HList(il.data):
105 |
106 | rr = {}
107 | rr['flags'] = ih._print_flags().strip()
108 | rr['flags_raw'] = ih.flags
109 | rr['meta'] = {} #{'flags': hex(ih.flags)}
110 | rr['target']=str(ih.data).strip().replace("\x00",'')
111 |
112 | if ih.is_inject():
113 | t = 'injects'
114 | elif ih.is_capture(): t = 'captures'
115 | else: t='unknown'
116 |
117 | rr[t]= []
118 | idx2= 0
119 | r = {}
120 | for inj in mod.HttpInject_BList(injects[idx].data):
121 | if idx2 % 3 == 0:
122 | r['pre'] = unicode(inj.data,'utf-8','replace').strip()
123 | r['pre_flag'] = inj.flags
124 | elif idx2 % 3 == 1:
125 | r['post'] = unicode(inj.data,'utf-8','replace').strip()
126 | r['post_flag'] = inj.flags
127 | else:
128 | r['inj'] = unicode(inj.data,'utf-8','replace').strip()
129 | r['inj_flag'] = inj.flags
130 | rr[t].append(r)
131 | r= {}
132 | idx2+=1
133 | idx += 1
134 | ret['injects'].append(rr)
135 | if len(injects) <= idx:
136 | break
137 | return ret
138 |
139 |
--------------------------------------------------------------------------------
/libzpy/modules/citadel.py:
--------------------------------------------------------------------------------
1 | import json
2 | from hashlib import md5
3 | from struct import unpack,pack
4 |
5 | import libzpy.fmt.citadel as cfmt
6 | import libzpy.structs.citadel as zeus
7 | from libzpy.libs.basecfg import BaseCfg
8 |
9 | import libzpy.libs.cr_tools as cry
10 | from libzpy.modules import template as t
11 |
12 |
13 | class CitaCfg(BaseCfg):
14 | def __init__(self,cfg,lk):
15 | self.lk = lk
16 | self.cfg = cfg
17 | self.rc4sbox = None
18 |
19 | def rc4(self,d,k):
20 | return cry.rc4decrypt(d,k,self.lk)
21 |
22 | def get_rc4(self,off):
23 | self.rc4sbox = self.cfg[off:off+0x102]
24 |
25 | def unpack(data,verb):
26 | return t.unpack(data,verb,zeus)
27 |
28 | def parse(data,verb):
29 | data = t.parse(data,verb,zeus)
30 | #print `data`
31 | for id in range(20009,20021) + range(20101,20204):
32 | if id in data and id == 20009:
33 | d = t.string_list(data[id].data)
34 | data['dns_filter'] =d
35 | del data[id]
36 |
37 | elif id in data and id == 20010:
38 | d = t.string_list(data[id].data)
39 | data['cmds'] =d
40 | del data[id]
41 | elif id in data and id == 20011:
42 | pass
43 |
44 | elif id in data and id == 20012:
45 | pass
46 | elif id in data and id == 20013:
47 | pass
48 | elif id in data and id == 20014:
49 | pass
50 |
51 | elif id in data and id == 20015:
52 | d = data[id].data.strip("\x00")
53 | data['keyloger'] = d
54 | del data[id]
55 |
56 | elif id in data and id == 20016:
57 | d = unpack('I',data[id].data)
58 | data['keyloger_time'] = d
59 | del data[id]
60 |
61 | elif id in data and id == 20017:
62 | pass
63 |
64 | elif id in data and id == 20018:
65 | d = data[id].data.strip("\x00")
66 | data['webinj_url'] = d
67 | del data[id]
68 |
69 | elif id in data and id == 20019:
70 | pass
71 |
72 | elif id in data and id == 20020:
73 | d = t.string_list(data[id].data)
74 | d['httpvip'] = d
75 | del data[id]
76 |
77 | elif id in data and id == 20101:
78 | d = unpack('I',data[id].data)
79 | data['video_length'] = d
80 | del data[id]
81 |
82 | elif id in data and id == 20102:
83 | d = unpack('I',data[id].data)
84 | data['video_qual' ] =d
85 | del data[id]
86 |
87 | return data
88 |
89 |
90 | def to_str(data,verb):
91 | if not isinstance(data,dict):
92 | verb('I need unpacked data')
93 | return
94 |
95 | fmt = cfmt.fmt(data)
96 | fmt._name = 'Citadel'
97 | return fmt.format() + '\n\nUNKNOWN_DATA:\n\n' + '\n'.join(data['unknown'])
98 |
99 |
100 | def json(data):
101 | verb=lambda x:x
102 | data = unpack(data,verb)
103 | data = parse(data,verb)
104 |
105 | return data
106 |
107 |
108 | def go(data,verb):
109 | data = unpack(data,verb)
110 | data = parse(data,verb)
111 |
112 | return to_str(data,verb)
113 |
114 |
115 | def format(data,verb,type='pretty'):
116 | if type == 'pretty':
117 | return to_str(data,verb)
118 | elif type == 'json':
119 | return json.dumps(data)
120 |
121 |
122 | def rc4_init_cit(key, magicKey):
123 | """ Initialize the RC4 keystate """
124 |
125 | hash = []
126 | box = []
127 | keyLength = len(key)
128 | if type(magicKey) == int:
129 | magicKey = pack('I',magicKey)
130 | magicKeyLen = len(magicKey)
131 |
132 | for i in range(0, 256):
133 | hash.append(ord(key[i % keyLength]))
134 | box.append(i)
135 |
136 | y = 0
137 | for i in range(0, 256):
138 | y = (y + box[i] + hash[i]) % 256
139 | tmp = box[i]
140 | box[i] = box[y]
141 | box[y] = tmp;
142 |
143 | y= 0
144 | for i in range(0, 256):
145 | magicKeyPart1 = ord(magicKey[y]) & 0x07;
146 | magicKeyPart2 = ord(magicKey[y]) >> 0x03;
147 | y += 1
148 | if (y == magicKeyLen):
149 | y = 0
150 |
151 | if (magicKeyPart1 == 0):
152 | box[i] = ~box[i]
153 | elif (magicKeyPart1 == 1):
154 | box[i] ^= magicKeyPart2
155 | elif (magicKeyPart1 == 2):
156 | box[i] += magicKeyPart2
157 | elif (magicKeyPart1 == 3):
158 | box[i] -= magicKeyPart2
159 | elif (magicKeyPart1 == 4):
160 | box[i] = box[i] >> (magicKeyPart2 % 8) | (box[i] << (8 - (magicKeyPart2 % 8)))
161 | elif (magicKeyPart1 == 5):
162 | box[i] = box[i] << (magicKeyPart2 % 8) | (box[i] >> (8 - (magicKeyPart2 % 8)))
163 | elif (magicKeyPart1 == 6):
164 | box[i] += 1
165 | elif (magicKeyPart1 == 7):
166 | box[i] -= 1
167 |
168 | box[i] = box[i] & 0xff
169 |
170 | return ''.join([chr(c) for c in box])
171 |
172 |
173 |
174 |
175 | def parse_basecfg(basecfg,args):
176 | login_key = args['lk']
177 | salt = args['s']
178 | off = args['off']
179 | bc = CitaCfg(basecfg,login_key)
180 | bc.get_rc4(off)
181 | st = bc.get_basics()
182 | aes = bc.rc4(md5(login_key).digest(),bc.rc4sbox)
183 |
184 | comm = rc4_init_cit(aes,salt)
185 |
186 | st['aes-key'] = aes.encode('hex')
187 | st['rc4cfg'] = bc.rc4sbox.encode('hex')
188 | st['rc4sbox'] = (comm+"\x00\x00").encode('hex')
189 | st['login_key'] = login_key
190 | st['cfg'] = st['urls'][0]
191 | if 'aes_xor' in args:
192 | st['aes_xor'] = args['aes_xor']
193 |
194 | return st
195 |
196 |
197 | ## we allready decode basecfg
198 | def get_basecfg(d,*args):
199 | return d.decode('hex')
200 |
201 |
--------------------------------------------------------------------------------
/libzpy/libs/cr_tools.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | from Crypto.Cipher import AES
3 | from Crypto.Cipher import ARC4
4 | import argparse,sys,struct
5 |
6 | aparse = argparse.ArgumentParser(description='RC4 decoder')
7 | aparse.add_argument('-f','--file')
8 | aparse.add_argument('-k','--key')
9 | aparse.add_argument('-d','--data')
10 | aparse.add_argument('-v','--visual',action='store_true')
11 | aparse.add_argument('-vv','--vvisual',action='store_true')
12 | aparse.add_argument('-t','--type',help='Type of encryptionk key: bin/string/hex')
13 | aparse.add_argument('-6',action='store_true',default=False,dest='v6')
14 |
15 |
16 | class RC6(object):
17 | def __init__(self, key):
18 | self.state = S = []
19 | key += "\0" * (4 - len(key) & 3) # pad key
20 |
21 | L = list(struct.unpack("<%sL" % (len(key) / 4), key))
22 |
23 | S.append(0xb7e15163)
24 | for i in range(43):
25 | S.append(_add(S[i], 0x9e3779b9))
26 |
27 | v = max(132, len(L) * 3)
28 |
29 | A = B = i = j = 0
30 |
31 | for n in range(v):
32 | A = S[i] = _rol(_add(S[i], A, B), 3)
33 | B = L[j] = _rol(_add(L[j] + A + B), _add(A + B))
34 | i = (i + 1) % len(S)
35 | j = (j + 1) % len(L)
36 |
37 | def encrypt(self, block):
38 | S = self.state
39 | A, B, C, D = struct.unpack("<4L", block.ljust(16, '\0'))
40 |
41 | B = _add(B, S[0])
42 | D = _add(D, S[1])
43 |
44 | for i in range(1, 21): # 1..20
45 | t = _rol(_mul(B, _rol(B, 1) | 1), 5)
46 | u = _rol(_mul(D, _rol(D, 1) | 1), 5)
47 | A = _add(_rol(A ^ t, u), S[2 * i])
48 | C = _add(_rol(C ^ u, t), S[2 * i + 1])
49 |
50 | A, B, C, D = B, C, D, A
51 |
52 | A = _add(A, S[42])
53 | C = _add(C, S[43])
54 |
55 | return struct.pack("<4L", A, B, C, D)
56 |
57 | def decrypt(self, block,state = None):
58 | S = state if state else self.state
59 | A, B, C, D = struct.unpack("<4L", block.ljust(16,"\0"))# * 16)
60 |
61 | C = _add(C, -S[43])
62 | A = _add(A, -S[42])
63 |
64 | for i in range(20,0,-1): # 20..1
65 | A, B, C, D = D, A, B, C
66 |
67 | u = _rol(_mul(D, _add(_rol(D, 1) | 1)), 5)
68 | t = _rol(_mul(B, _add(_rol(B, 1) | 1)), 5)
69 | C = _ror(_add(C, -S[2 * i + 1]), t) ^ u
70 | A = _ror(_add(A, -S[2 * i]), u) ^ t
71 |
72 | D = _add(D, -S[1])
73 | B = _add(B, -S[0])
74 |
75 | return struct.pack("<4L", A&0xffffffff, B&0xffffffff, C&0xffffffff, D&0xffffffff)#[A,B,C,D]
76 |
77 | # helper functions for rc6
78 |
79 | def _add(*args):
80 | return sum(args) % 4294967296
81 |
82 | def _rol(x, n):
83 | n = 31 & n
84 | return x << n | 2 ** n - 1 & x >> 32 - n
85 |
86 | def _ror(x, y): # rorororor
87 | return _rol(x, 32 - (31 & y))
88 |
89 | def _mul(a, b):
90 | return (((a >> 16) * (b & 65535) + (b >> 16) * (a & 65535)) * 65536 +
91 | (a & 65535) * (b & 65535)) % 4294967296
92 |
93 | def rc6decrypt(d,k):
94 | # if args.type == 'str':
95 | # rc = RC6(k)
96 | # ciph = lambda d,k: rc.decrypt(d)
97 | # else:
98 | if type(k) == str:
99 | k = struct.unpack('I'*(len(k)/4),k)
100 | ciph = lambda d,k:RC6('a'*16).decrypt(d,k)
101 | r = ''
102 | for i in range(0,len(d)>>4):
103 | r+=ciph(d[i*16:(i+1)*16],k)
104 | return r
105 |
106 |
107 | def aesdecrypt(d,k,xor):
108 | clean = AES.new(k,AES.MODE_ECB).decrypt(d)
109 | if xor:
110 | xor = map(ord,xor)
111 | lxor = len(xor)
112 | r = ''
113 | for i in xrange(0,len(clean),lxor):
114 | r += ''.join(map(lambda x: chr(ord(x[0])^x[1]),zip(clean[i:i+lxor],xor)))
115 | clean = r
116 | return clean
117 |
118 |
119 | #def rc4init(key,
120 |
121 | def rc4decrypt(data, key,xor=None,mod1=0,mod2=0,raw=False):
122 |
123 | if raw:
124 | cip = ARC4.new(key)
125 | return cip.decrypt(data)
126 |
127 | box = map(ord,key)
128 | x = 0
129 | y = 0
130 | out = []
131 | idx =0
132 | for byt in data:
133 | x = (x + 1 + mod1 ) % 256
134 | y = (y + box[x] + mod2) % 256
135 | box[x], box[y] = box[y], box[x]
136 | byt = ord(byt) ^ box[(box[x] + box[y]) % 256]
137 | if xor:
138 | byt ^= ord(xor[idx%len(xor)])
139 | idx+=1
140 | out.append(chr(byt))
141 |
142 | return ''.join(out)
143 |
144 | def visEncry(datA):
145 | i = len(datA)-1
146 | ret =map(ord,(datA))
147 | for idx in range(1,len(datA)):
148 | ret[idx] ^= ret[idx-1]
149 | return ''.join(map(chr,ret))
150 |
151 |
152 | def visDecry(datA):
153 | i = len(datA)-1
154 | ret =map(ord,(datA))
155 | for idx in range(len(datA)-1,0,-1):
156 | ret[idx] ^= ret[idx-1]
157 | return ''.join(map(chr,ret))
158 |
159 | def ppr(d):
160 | if args.visual:
161 | sys.stdout.write(visDecry(d))
162 | else:
163 | sys.stdout.write( d)
164 |
165 | def ciph(d,k):
166 | if args.v6:
167 | return rc6decrypt(d,k)
168 | else:
169 | return rc4decrypt(d,k)
170 |
171 | if __name__ == '__main__':
172 | args = aparse.parse_args()
173 | if args.type == 'bin':
174 | with open(args.key) as f: key = f.read()
175 | elif args.type == 'str':
176 | key = args.key
177 | elif args.type == 'hexstr':
178 | key = args.key.decode('hex')
179 | elif args.type == 'hex':
180 | with open(args.key) as f: key = f.read().replace(' ','').replace('\n','').replace('\r','').decode('hex')
181 | else:
182 | print "Unknown format"
183 | sys.exit(1)
184 | #print `key`
185 | #print len(key)
186 | if args.vvisual:
187 | key = visDecry(key)
188 |
189 | if args.file and args.file != '-':
190 | with open(args.file) as f:
191 | ppr(ciph(f.read(),key))
192 | elif args.file:
193 | ppr(ciph(sys.stdin.read(),key))
194 | else:
195 | ppr(ciph(args.data,key))
196 |
--------------------------------------------------------------------------------
/libzpy/structs/zeus.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.structure import DataStructure,StructList
2 | from libzpy.libs.structure import c_byte,c_word,c_dword,c_qword,c_wchar,c_char
3 | from libzpy.libs.UCL import UCL
4 | #from ctypes import bytearray
5 |
6 | _UCL = None
7 | def decompress(data,size):
8 | global _UCL
9 | if not _UCL:
10 | _UCL = UCL()
11 | return _UCL.decompress(data,size)
12 |
13 |
14 | class Header(DataStructure):
15 | _have_data = False
16 | _fields_ = [('rand',c_byte*20),('size',c_dword),('flags',c_dword),('count',c_dword),('md5',c_byte*0x10)]
17 |
18 | def _print_md5(self):
19 | ret =''
20 | for i in range(0,0x10):
21 | ret += '%02x' % self.md5[i]
22 | return ret
23 |
24 | class PESettings(DataStructure):
25 | compId = None
26 | _have_data = False
27 | _pack_ =1
28 | _fields_ = [('size',c_dword),('_compId',c_wchar*60),('guid',c_char*0x10),('_RC4KEY',c_byte*0x102),
29 | ('exeFile',c_char*20),('reportFile',c_char*20),('regKey',c_char*10),('regDynamicConfig',c_char*10),
30 | ('regLocalConfig',c_char*10),('regLocalSettings',c_char*10),('processInfectionId',c_dword),('storageArrayKey',c_dword)
31 | ]
32 |
33 | def _print__compId(self):
34 | return 'compId: ' + self.compId
35 | def _print__RC4KEY(self):
36 | b = bytearray(self._RC4KEY)
37 | return str(b).encode('hex')
38 |
39 | def __getattribute__(self,name):
40 | if name=='compId':
41 | return self._compId if self._compId[0].__class__ == unicode else ''.join(map(lambda x:x[0],self._compId)).strip("\x00")
42 | elif name == 'RC4KEY':
43 | return self._print__RC4KEY()
44 | else:
45 | return object.__getattribute__(self, name)
46 |
47 | class Item(DataStructure):
48 | _flags = {
49 | 'ITEMF_COMPRESSED': 0x00000001,
50 | 'ITEMF_COMBINE_ADD': 0x00010000,
51 | 'ITEMF_COMBINE_OVERWRITE': 0x00020000,
52 | 'ITEMF_COMBINE_REPLACE' : 0x00040000,
53 | 'ITEMF_COMBINE_DELETE' : 0x00080000,
54 | 'ITEMF_IS_OPTION' :0x10000000,
55 | 'ITEMF_IS_SETTING' :0x20000000,
56 | 'ITEMF_IS_HTTP_INJECT' :0x40000000
57 |
58 | }
59 |
60 | _cfgids = {
61 | 20001 :'CFGID_LAST_VERSION',
62 | 20002 :'CFGID_LAST_VERSION_URL',
63 | 20003 :'CFGID_URL_SERVER_0',
64 | 20004 :'CFGID_URL_ADV_SERVERS',
65 | 20005 :'CFGID_HTTP_FILTER',
66 | 20006 :'CFGID_HTTP_POSTDATA_FILTER',
67 | 20007 :'CFGID_HTTP_INJECTS_LIST',
68 | 20008 :'CFGID_DNS_LIST',
69 | }
70 |
71 | _fields_ = [ ('id',c_dword),('flags',c_dword),('size',c_dword),('realSize',c_dword)]
72 |
73 | def __init__(self,*args,**kwargs):
74 | super(Item,self).__init__(*args,**kwargs)
75 | self._cfgids_n = self._cfgids.__class__(map(reversed, self._cfgids.items()))
76 |
77 | def _print_id(self):
78 | if self.id in self._cfgids:
79 | return '%s' % self._cfgids[self.id]
80 | return '%d' % self.id
81 |
82 | def feed(self,data):
83 | super(Item,self).feed(data)
84 |
85 | ## apperently we ca have decompression without changed size...
86 | if self.flags & self._flags['ITEMF_COMPRESSED']:
87 | self.decompress()
88 |
89 | def decompress(self):
90 | self.data = decompress(self.data,self.realSize)#.run(1)
91 | # self.data = unrv2b(self.data,self.realSize).run(1)
92 |
93 |
94 | def is_compresed(self):
95 | return self.flags & self._flags['ITEMF_COMPRESSED']
96 |
97 | def is_option(self):
98 | return self.flags & self._flags['ITEMF_IS_OPTION']
99 |
100 | def is_inject(self):
101 | return self.flags & self._flags['ITEMF_IS_HTTP_INJECT']
102 |
103 | def is_setting(self):
104 | return self.flags & self._flags['ITEMF_IS_SETTING']
105 |
106 | def is_version(self):
107 | return self.id == self._cfgids_n['CFGID_LAST_VERSION']
108 |
109 | def is_update(self):
110 | return self.id == self._cfgids_n['CFGID_LAST_VERSION_URL']
111 |
112 | def is_injectlist(self):
113 | return self.id == self._cfgids_n['CFGID_HTTP_INJECTS_LIST']
114 |
115 | def is_webfilter(self):
116 | return self.id == self._cfgids_n['CFGID_HTTP_FILTER']
117 |
118 | def is_cfg_url(self):
119 | return self.id == self._cfgids_n['CFGID_URL_SERVER_0']
120 |
121 | def is_acfg_url(self):
122 | return self.id == self._cfgids_n['CFGID_URL_ADV_SERVERS']
123 |
124 | def is_dnslist(self):
125 | return self.id == self._cfgids_n['CFGID_DNS_LIST']
126 |
127 | def is_dnsfilter(self):
128 | return self.id == self._cfgids_n['CFGID_DNS_FILTER']
129 |
130 | def is_cmdlist(self):
131 | return self.id == self._cfgids_n['CFGID_CMD_LIST']
132 |
133 |
134 |
135 | _http_inj_Flags ={
136 | 'FLAG_IS_FAKE' : 0x0001,
137 | 'FLAG_IS_MIRRORFAKE' : 0x0002,
138 | 'FLAG_IS_INJECT' : 0x0004,
139 | 'FLAG_IS_CAPTURE' : 0x0008,
140 |
141 | 'FLAG_ONCE_PER_DAY' : 0x0010,
142 | 'FLAG_REQUEST_POST' : 0x0020,
143 | 'FLAG_REQUEST_GET' : 0x0040,
144 |
145 | 'FLAG_CAPTURE_NOTPARSE' : 0x0100,
146 | 'FLAG_CAPTURE_TOFILE' : 0x0200,
147 |
148 | 'FLAG_URL_CASE_INSENSITIVE' : 0x1000,
149 | 'FLAG_CONTEXT_CASE_INSENSITIVE' : 0x2000
150 | }
151 |
152 | class HttpInject_InjectBlock(DataStructure):
153 | _fields_ = [('size',c_word),('flags',c_word)]
154 | _flags = _http_inj_Flags
155 |
156 | def _print_flags(self):
157 | return '%x' % self.flags
158 |
159 | class HttpInject_BList(StructList):
160 | struct = HttpInject_InjectBlock
161 |
162 |
163 | class HttpInject_Header(DataStructure):
164 | _pack_ = 1
165 | _fields_ = [('flags',c_word),('size',c_word),('urlMask',c_word),('fakeUrl',c_word),
166 | ('postDataBlackMask',c_word),('postDataWhiteMask',c_word),
167 | ('blockOnUrl',c_word),('contextMask',c_word)
168 | ]
169 | _flags = _http_inj_Flags
170 |
171 | def is_inject(self):
172 | return self.flags & self._flags['FLAG_IS_INJECT']
173 |
174 | def is_capture(self):
175 | return self.flags & self._flags['FLAG_IS_CAPTURE']
176 |
177 | class HttpInject_HList(StructList):
178 | struct = HttpInject_Header
179 |
180 |
181 | class WebFilter(object):
182 | _wf = {
183 | '@' : 'SCREENSHOT',
184 | '!' : 'DONT-REPORT',
185 | '-' : 'SAVE-COOCKIE',
186 | '^' : 'BLOCK-ACCESS'
187 | }
188 | def __init__(self,d):
189 | self.act = d[0]
190 | self.trg = d[1:]
191 | if 0x61 < ord(self.act) < 0x7a:
192 | ## some strange shit...
193 | self.trg = self.act + self.trg
194 | self.act = ""
195 |
196 |
197 | def __getitem__(self,x):
198 | if x in self._wf:
199 | return self._wf[x]
200 | return x
201 |
202 | def json(self):
203 | return {'action':self[self.act],'target':self.trg}
204 |
--------------------------------------------------------------------------------
/libzpy/libs/rtb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | # -*- coding: utf-8 -*-
3 | import re,fnmatch
4 |
5 | data = {
6 | 'KB24 - KredytBank': [
7 | 'https://www.kb24.pl/MonitySterujacy',
8 | 'https://www.kb24.pl/Login',
9 | 'https://www.kb24.pl/ikd/DETAL/PL/_SCR/Logowanie.js'
10 | ],
11 | 'Bank Zagrzebski - grupa unicredit': [
12 | 'https://www.zaba.hr/ebank/gradjani/Gradjani',
13 | 'https://www.zaba.hr/ezaba/MainServlet',
14 | 'https://www.zaba.hr/ezaba/PlatniPromet',
15 | 'https://www.zaba.hr/ezaba/VA/StanjeIPrometiPregledPrometa',
16 | 'https://www.zaba.hr/ebank/gradjani/JavaScript/gLogin.js'
17 | ],
18 | 'mBank - company': [
19 | 'https://companynet.mbank.pl/mt/fragments/cua/login.jsp'
20 | ],
21 | 'Alpha Bank Romania': [
22 | 'https://secure2.alphabank.ro/corporate/CorpOTPLoginLangRom.jsp'
23 | ],
24 | 'Alior' : [
25 | 'https://aliorbank.pl/hades/do/Login'
26 | ],
27 | 'PBZCOM@NET' : [
28 | 'https://comnet.pbz.hr/PbzComnetWeb/stateAndTransactions/userAccountState.html',
29 | 'https://comnet.pbz.hr/PbzComnetWeb/kunaBusiness/ordersForSending.html'
30 | ],
31 | 'Pekao S.A. - Biznes ' : [
32 | 'https://ww.pekaobiznes24.pl/webcorpo/do/desktop',
33 | 'https://ww.pekaobiznes24.pl/webcorpo/do/operationHistory',
34 | 'https://www.pekaofirma24.pl/webcorpo/do/confidentialPhone?open=true',
35 | 'https://www.pekaofirma24.pl/sme/do/confidentialPhone?open=true',
36 | 'https://www.pekaofirma24.pl/sme/do/aggregation',
37 | 'https://www.pekaobiznes24.pl/sme/do/domesticTransfer?open=true'
38 | ],
39 | 'HYPO ALPE-ADRIA-BANK' : [
40 | 'https://www.hypo.hr/hyponet/Payments/PaymentSubmit?menu=loadPartial',
41 | 'https://www.hypo.hr/hyponet/Payments/PaymentViewSubmit?menu=loadPartial',
42 | 'https://www.hypo.hr/hyponet/Order10/IndexGridPartial'
43 | ],
44 | 'Citibank BG': [
45 | 'https://online.cibank.bg/EBankCI/',
46 | 'https://online.cibank.bg/EBankCI/Login',
47 | 'https://online.cibank.bg/EBankCI/Home',
48 | 'https://online.cibank.bg/EBankCI/StmtInFilesServlet'
49 | ],
50 |
51 | 'Pekao S.A.' : [
52 | 'https://www.pekao24.pl',
53 | 'https://www.prepaid.pekao24.pl',
54 | 'https://www.cdm24.pl',
55 | 'https://www.pekaofirma24.pl/do/login;jsessionid=',
56 | 'https://www.pekaobiznes24.pl/do/login'
57 | ],
58 | 'BRD@ffice':[
59 | 'https://www.brdoffice.ro/smartoffice/index.html'
60 | ],
61 | 'Raiffeisen Bank, Zagreb' : [
62 | 'https://direkt.rba.hr/cgi-bin/ppz2/app/app_main.jsp',
63 | 'https://direkt.rba.hr/cgi-bin/ppz2/start/rbat.jsp'
64 | ],
65 | 'Erste&Steiermärkische Bank' : [
66 | 'https://netbanking.erstebank.hr',
67 | 'https://netbanking.erstebank.hr/Prijava/Prijava.aspx',
68 | 'https://netbanking.erstebank.rs/Prijava/Prijava.aspx',
69 | 'https://www.erstebank.rs/en/NetBanking/E-banking/Reta'
70 | ],
71 | 'BGŻ - corpo' : [
72 | 'https://www.pf.bgz.pl/bgzweb/auth/login/submit',
73 | 'https://www.pf.bgz.pl/bgzweb/auth/login/submit',
74 | 'https://www.ebgzfirma.pl'
75 | ],
76 | 'BGK' : [
77 | 'https://www.zleceniaplatnosci.bgk.pl/BGKSSO/Login.aspx?redirect',
78 | 'https://www.bgk24biznes.pl/',
79 | 'https://repozytorium.bgk.com.pl/'
80 | ],
81 | 'BOŚ' : [
82 | 'https://bosbank24.pl/twojekonto',
83 | 'https://bosbank24.pl/iboss',
84 | 'https://bosbank24.pl/bosfaktor/login.jsf'
85 | ],
86 | 'Bank Pocztowy' : [
87 | 'https://www.pocztowy24.pl/',
88 | 'https://www.pocztowy24biznes.pl/web/guest/home',
89 | 'https://e-wniosek.pocztowy.pl/lokaty-online/index.php'
90 | ],
91 | 'BNP Paribas Bank Polska S.A.' : [
92 | 'https://planet.bnpparibas.pl/hades/do/Login',
93 | 'https://biznesplanet.bnpparibas.pl/hades/do/Login',
94 | 'https://planet.bnpparibas.pl/hades/do/Login'
95 | ],
96 | 'Credit Agricole Bank Polska S.A.' : [
97 | 'https://e-bank.credit-agricole.pl/',
98 | 'https://firmabank.credit-agricole.pl/mt-front/'
99 | ],
100 | 'Deutsche Bank' : [
101 | 'https://ebank.db-pbc.pl/auth/login.jsp',
102 | 'https://ebusinessbank.db-pbc.pl/auth/login.jsp',
103 | 'https://makler.dbmakler.pl/',
104 | 'https://webfaktor.db-pbc.pl/login.jsf',
105 | 'https://autobahn.db.com/',
106 | 'https://db-direct.db.com/u/eb/Login_Main.serv',
107 | 'https://dbdi-mobile.db.com/dbdm/public/crud/core/login/Login/input.xhtml'
108 | ],
109 | 'Euro Euro Bank S.A.' : [
110 | 'https://online.eurobank.pl/bi/bezpieczenstwo_logowanie.ebk'
111 | ],
112 | 'Polski Bank Przedsiębiorczości S.A' : [
113 | 'https://bank.fmbank24.pl/'
114 | ],
115 | 'Getin Bank' : [
116 | 'https://secure.getinbank.pl/'
117 | 'https://korporacja.gb24.pl/ceb-web/pages/login.jsp'
118 | ],
119 | 'Noble Bank' : [
120 | 'https://secure.noblebank.pl/'
121 | 'https://online.noblesecurities.pl/SidomaLight/pl.pbpolsoft.sidomalight.Start/Start.html?module=login'
122 | ],
123 | 'HSBC Bank Polska S.A.' : [
124 | 'https://www2.secure.hsbcnet.com/uims/portal/IDV_CAM10_AUTHENTICATION?__cancelLogonUrl=http://www.hsbcnet.com',
125 | 'http://www.hsbcnet.com/displayArticle?cd_doc_path=/gbm/about-us/news/2013/euromoney-awards.html',
126 | 'http://www.hsbcnet.com/gbm/fxcalc-disp',
127 | 'https://www.iif.hsbc.pl/Logon?locale=pl_PL'
128 | ],
129 | 'Idea Bank S.A.' : [
130 | 'https://secure.ideabank.pl/'
131 | ],
132 | 'ING Bank Śląski S.A.' : [
133 | 'https://online.ingbank.pl/bskonl/login.html',
134 | 'https://www.ingonline.com/pl/!UPR.Dispatcher?ps_redir_proc=homepage',
135 | 'https://start.ingbusinessonline.pl/ing/do/sms',
136 | 'www.ingbank.pl/ing-businessonline',
137 | 'www.ingbank.pl/en-ing-businessonline'
138 | ],
139 | 'PLUS BANK S.A.' : [
140 | 'https://plusbank24.pl/web-client/login!input.action'
141 | ],
142 | 'BZ WBK' : [
143 | 'https://www.centrum24.pl/centrum24-web/?x=',
144 | 'https://www.centrum24.pl/centrum24-web/login',
145 | 'https://www.centrum24.pl/bzwbkonline/eSmart.html?typ=13&',
146 | 'https://www.centrum24.pl/centrum24-web/login',
147 | 'https://ibiznes24.pl/bzwbk24biznes-client/login.html',
148 | 'https://www.inwestoronline.pl/cbm/',
149 | 'https://www.centrum24.pl/prepaid/index?index=1491',
150 | 'https://www.kb24.pl/',
151 | 'https://www.kbnet.pl/web/guest/login'
152 | ],
153 | 'Raiffeisen Polbank S.A.' : [
154 | 'https://www.r-bank.pl/newsbi/index.jsp?'
155 | 'https://moj.raiffeisenpolbank.com/',
156 | 'https://moj.raiffeisenpolbank.com/polbank',
157 | 'https://www.polbank24.pl/netbanking/',
158 | 'https://wyciagi.polbank24.pl/Login.aspx?ReturnUrl='
159 | ],
160 | 'Sygma Banque Societe Anonyme S.A.' : [
161 | 'https://online.sygmabank.pl/SygmaOnLine/'
162 | ],
163 | 'Volkswagen Bank Polska S.A.' : [
164 | 'https://login.vwbankdirect.pl/',
165 | 'https://biznesbanking.vwbankdirect.pl/'
166 | ],
167 | 'Podkarpacki Bank Spółdzielczy' : [
168 | 'https://sbe.pbsbank.pl/'
169 | ],
170 | 'Bank BPH S.A.' : [
171 | 'https://www.bph.pl/pi/do/Login',
172 | 'https://www.bph.pl/mobile/do/login',
173 | 'https://www.bph.pl/bnlite/spring/authenticate'
174 | ],
175 | 'Bank Millennium S.A.' : [
176 | 'https://www.bankmillennium.pl/osobiste/Default.qz',
177 | 'https://www.bankmillennium.pl/firmy/Default.qz?'
178 | ],
179 | 'Meritum Bank ICB S.A.' : [
180 | 'https://www.meritumbank.pl/'
181 | ],
182 | 'NORDEA Bank Polska S.A.' : [
183 | 'https://netbank.nordea.pl/pnb/login.do',
184 | 'https://atlanticfundservices.eu/int2nordea/tfi/nordea/Login.app?'
185 | ],
186 | 'Bank Polskiej Spółdzielczości S.A.' : [
187 |
188 | 'https://bps25.pl/',
189 | 'https://ebank.bankbps.pl/bpswarszawa_k',
190 | 'https://ebank.bankbps.pl/bpswroclaw_k',
191 | 'https://ebank.bankbps.pl/bpsolsztyn_k',
192 | 'https://ebank.bankbps.pl/bpskatowice_k',
193 | 'https://ebank.bankbps.pl/bpslublin_k',
194 | 'https://ebank.bankbps.pl/bpskrakow_k',
195 | 'https://ebank.bankbps.pl/bpsrzeszow_k'
196 | ],
197 | 'Giełda Papierów Wartościowych': [
198 | 'https://4brokernet.gpw.pl/dana-na/auth/url_default/welcome.cgi'
199 | ],
200 | 'Krajowa Izba Rozliczeniowa S.A.' : [
201 | 'https://pbn.paybynet.com.pl/PayByNet/login.do',
202 | 'http://www.kir.com.pl/main.php?do=login&noreferer'
203 | ],
204 | 'Związek Banków Polskich' : [
205 | 'https://zbp.pl/logowanie'
206 | ]
207 | }
208 |
209 |
210 | def check_url(rgx) :
211 | def fire(u):
212 | try:
213 | return bool(rgx.search(u))
214 | except AttributeError:
215 | return bool(re.search(fnmatch.translate(rgx),u))
216 |
217 | r = []
218 | for bank in data:
219 | c = 0
220 |
221 | for u in data[bank]:
222 | if fire(u):
223 | c +=1
224 | if c >0: r.append(bank + ' (%d/%d)' % (c,len(data[bank])))
225 | return ' | '.join(r)
226 |
--------------------------------------------------------------------------------
/libzpy/libs/binPCRE.py:
--------------------------------------------------------------------------------
1 | from libzpy.libs.xstream import xstream
2 |
3 |
4 | OPCODES=dict(OP_END = 0,OP_SOD = 1,OP_SOM = 2,OP_SET_SOM = 3,OP_NOT_WORD_BOUNDARY = 4,OP_WORD_BOUNDARY = 5,OP_NOT_DIGIT = 6,OP_DIGIT = 7,OP_NOT_WHITESPACE = 8,OP_WHITESPACE = 9,OP_NOT_WORDCHAR = 10,OP_WORDCHAR = 11,OP_ANY = 12,OP_ALLANY = 13,OP_ANYBYTE = 14,OP_NOTPROP = 15,OP_PROP = 16,OP_ANYNL = 17,OP_NOT_HSPACE = 18,OP_HSPACE = 19,OP_NOT_VSPACE = 20,OP_VSPACE = 21,OP_EXTUNI = 22,OP_EODN = 23,OP_EOD = 24,OP_OPT = 25,OP_CIRC = 26,OP_DOLL = 27,OP_CHAR = 28,OP_CHARNC = 29,OP_NOT = 30,OP_STAR = 31,OP_MINSTAR = 32,OP_PLUS = 33,OP_MINPLUS = 34,OP_QUERY = 35,OP_MINQUERY = 36,OP_UPTO = 37,OP_MINUPTO = 38,OP_EXACT = 39,OP_POSSTAR = 40,OP_POSPLUS = 41,OP_POSQUERY = 42,OP_POSUPTO = 43,OP_NOTSTAR = 44,OP_NOTMINSTAR = 45,OP_NOTPLUS = 46,OP_NOTMINPLUS = 47,OP_NOTQUERY = 48,OP_NOTMINQUERY = 49,OP_NOTUPTO = 50,OP_NOTMINUPTO = 51,OP_NOTEXACT = 52,OP_NOTPOSSTAR = 53,OP_NOTPOSPLUS = 54,OP_NOTPOSQUERY = 55,OP_NOTPOSUPTO = 56,OP_TYPESTAR = 57,OP_TYPEMINSTAR = 58,OP_TYPEPLUS = 59,OP_TYPEMINPLUS = 60,OP_TYPEQUERY = 61,OP_TYPEMINQUERY = 62,OP_TYPEUPTO = 63,OP_TYPEMINUPTO = 64,OP_TYPEEXACT = 65,OP_TYPEPOSSTAR = 66,OP_TYPEPOSPLUS = 67,OP_TYPEPOSQUERY = 68,OP_TYPEPOSUPTO = 69,OP_CRSTAR = 70,OP_CRMINSTAR = 71,OP_CRPLUS = 72,OP_CRMINPLUS = 73,OP_CRQUERY = 74,OP_CRMINQUERY = 75,OP_CRRANGE = 76,OP_CRMINRANGE = 77,OP_CLASS = 78,OP_NCLASS = 79,OP_XCLASS = 80,OP_REF = 81,OP_RECURSE = 82,OP_CALLOUT = 83,OP_ALT = 84,OP_KET = 85,OP_KETRMAX = 86,OP_KETRMIN = 87,OP_ASSERT = 88,OP_ASSERT_NOT = 89,OP_ASSERTBACK = 90,OP_ASSERTBACK_NOT = 91,OP_REVERSE = 92,OP_ONCE = 93,OP_BRA = 94,OP_CBRA = 95,OP_COND = 96,OP_SBRA = 97,OP_SCBRA = 98,OP_SCOND = 99,OP_CREF = 100,OP_NCREF = 101,OP_RREF = 102,OP_NRREF = 103,OP_DEF = 104,OP_BRAZERO = 105,OP_BRAMINZERO = 106,OP_MARK = 107,OP_PRUNE = 108,OP_PRUNE_ARG = 109,OP_SKIP = 110,OP_SKIP_ARG = 111,OP_THEN = 112,OP_THEN_ARG = 113,OP_COMMIT = 114,OP_FAIL = 115,OP_ACCEPT = 116,OP_CLOSE = 117,OP_SKIPZERO = 118,OP_TABLE_LENGTH = 119 )
5 | REV_COEDS = dict((v,k) for k, v in OPCODES.iteritems())
6 |
7 |
8 | #OPCODES=dict(
9 | OP_END = 0
10 | OP_SOD = 1
11 | OP_SOM = 2
12 | OP_SET_SOM = 3
13 | OP_NOT_WORD_BOUNDARY = 4
14 | OP_WORD_BOUNDARY = 5
15 | OP_NOT_DIGIT = 6
16 | OP_DIGIT = 7
17 | OP_NOT_WHITESPACE = 8
18 | OP_WHITESPACE = 9
19 | OP_NOT_WORDCHAR = 10
20 | OP_WORDCHAR = 11
21 | OP_ANY = 12
22 | OP_ALLANY = 13
23 | OP_ANYBYTE = 14
24 | OP_NOTPROP = 15
25 | OP_PROP = 16
26 | OP_ANYNL = 17
27 | OP_NOT_HSPACE = 18
28 | OP_HSPACE = 19
29 | OP_NOT_VSPACE = 20
30 | OP_VSPACE = 21
31 | OP_EXTUNI = 22
32 | OP_EODN = 23
33 | OP_EOD = 24
34 | OP_OPT = 25
35 | OP_CIRC = 26
36 | OP_DOLL = 27
37 | OP_CHAR = 28
38 | OP_CHARNC = 29
39 | OP_NOT = 30
40 | OP_STAR = 31
41 | OP_MINSTAR = 32
42 | OP_PLUS = 33
43 | OP_MINPLUS = 34
44 | OP_QUERY = 35
45 | OP_MINQUERY = 36
46 | OP_UPTO = 37
47 | OP_MINUPTO = 38
48 | OP_EXACT = 39
49 | OP_POSSTAR = 40
50 | OP_POSPLUS = 41
51 | OP_POSQUERY = 42
52 | OP_POSUPTO = 43
53 | OP_NOTSTAR = 44
54 | OP_NOTMINSTAR = 45
55 | OP_NOTPLUS = 46
56 | OP_NOTMINPLUS = 47
57 | OP_NOTQUERY = 48
58 | OP_NOTMINQUERY = 49
59 | OP_NOTUPTO = 50
60 | OP_NOTMINUPTO = 51
61 | OP_NOTEXACT = 52
62 | OP_NOTPOSSTAR = 53
63 | OP_NOTPOSPLUS = 54
64 | OP_NOTPOSQUERY = 55
65 | OP_NOTPOSUPTO = 56
66 | OP_TYPESTAR = 57
67 | OP_TYPEMINSTAR = 58
68 | OP_TYPEPLUS = 59
69 | OP_TYPEMINPLUS = 60
70 | OP_TYPEQUERY = 61
71 | OP_TYPEMINQUERY = 62
72 | OP_TYPEUPTO = 63
73 | OP_TYPEMINUPTO = 64
74 | OP_TYPEEXACT = 65
75 | OP_TYPEPOSSTAR = 66
76 | OP_TYPEPOSPLUS = 67
77 | OP_TYPEPOSQUERY = 68
78 | OP_TYPEPOSUPTO = 69
79 | OP_CRSTAR = 70
80 | OP_CRMINSTAR = 71
81 | OP_CRPLUS = 72
82 | OP_CRMINPLUS = 73
83 | OP_CRQUERY = 74
84 | OP_CRMINQUERY = 75
85 | OP_CRRANGE = 76
86 | OP_CRMINRANGE = 77
87 | OP_CLASS = 78
88 | OP_NCLASS = 79
89 | OP_XCLASS = 80
90 | OP_REF = 81
91 | OP_RECURSE = 82
92 | OP_CALLOUT = 83
93 | OP_ALT = 84
94 | OP_KET = 85
95 | OP_KETRMAX = 86
96 | OP_KETRMIN = 87
97 | OP_ASSERT = 88
98 | OP_ASSERT_NOT = 89
99 | OP_ASSERTBACK = 90
100 | OP_ASSERTBACK_NOT = 91
101 | OP_REVERSE = 92
102 | OP_ONCE = 93
103 | OP_BRA = 94
104 | OP_CBRA = 95
105 | OP_COND = 96
106 | OP_SBRA = 97
107 | OP_SCBRA = 98
108 | OP_SCOND = 99
109 | OP_CREF = 100
110 | OP_NCREF = 101
111 | OP_RREF = 102
112 | OP_NRREF = 103
113 | OP_DEF = 104
114 | OP_BRAZERO = 105
115 | OP_BRAMINZERO = 106
116 | OP_MARK = 107
117 | OP_PRUNE = 108
118 | OP_PRUNE_ARG = 109
119 | OP_SKIP = 110
120 | OP_SKIP_ARG = 111
121 | OP_THEN = 112
122 | OP_THEN_ARG = 113
123 | OP_COMMIT = 114
124 | OP_FAIL = 115
125 | OP_ACCEPT = 116
126 | OP_CLOSE = 117
127 | OP_SKIPZERO = 118
128 | OP_TABLE_LENGTH = 119
129 | #)
130 | #REV_COEDS = dict((v,k) for k, v in OPCODES.iteritems())
131 |
132 | def hexx(s):
133 | r = ''
134 | for c in s: r+="%02X " % ord(c)
135 | return r
136 |
137 | def singleByte(b):
138 | if b == OP_ANY or b == OP_ALLANY or b == OP_ANYBYTE: return "."
139 | elif b == OP_ANYNL : return "\\R"
140 | elif b == OP_CIRC : return "^"
141 | elif b == OP_DOLL : return "$"
142 | elif b == OP_DIGIT : return "\\d"
143 | elif b == OP_WHITESPACE : return "\\s"
144 | return None
145 |
146 | def reClass(data,positive):
147 | r = ''
148 | charIndex = 0
149 | for c in data:
150 | nc = ord(c)
151 | cb = 1
152 | for j in range(8):
153 | bit = 1 if nc & cb else 0
154 | cb *= 2
155 | if bit == positive: r+= chr(charIndex)
156 | charIndex += 1
157 | return r
158 |
159 | def readBinary(data):
160 | verbose = False
161 | RET=""
162 | size = len(data)
163 | xs = xstream(data)
164 | hdr_names = ('magic','size','opts','flags','dummy1','top_bracket','top_backref','first_byte','req_byte','name_tbl_off','name_entry_size','name_cnt','ref_cnt')
165 | hdr = xs.readFmt("IIIHHHHHHHHHH", into=hdr_names )
166 | name_tbl_size = hdr['name_tbl_off'] + hdr['name_entry_size'] * hdr['name_cnt']
167 |
168 | hdr['names']=dict()
169 | xs.seek(hdr['name_tbl_off'])
170 | for i in range(hdr['name_cnt']):
171 | idx = xs.readOne('>H')
172 | name = xs.readN(hdr['name_entry_size'])
173 | name = name[:name.find("\x00")]
174 | hdr['names'][idx]=name
175 | if verbose:
176 | print hexx(data)
177 | print hdr
178 | print "offset : %d " % name_tbl_size
179 |
180 | xs.seek(name_tbl_size);
181 | pos = name_tbl_size
182 |
183 | while pos < hdr['size']:
184 | opcode = xs.readOne("B")
185 | opsize = 1
186 |
187 | if verbose:
188 | print "%d) %d %x | %s \t| %s" % (xs.tell(),opcode,opcode,REV_COEDS[opcode],RET)
189 |
190 | b1 = singleByte(opcode)
191 | if b1:
192 | RET += b1
193 | elif opcode == OP_END:
194 | if verbose:
195 | print "end<"
196 | break
197 | elif opcode == OP_BRA or opcode == OP_SBRA:
198 | RET+="(?:"; xs.readN(2)
199 | elif opcode == OP_KET: RET+=")"; xs.readN(2)
200 | elif opcode == OP_CBRA or opcode == OP_SCBRA:
201 | v1,v2=xs.readFmt(">HH");
202 | if v2 in hdr['names']: RET+="(?P<%s>" % hdr['names'][v2]
203 | else: RET+="("
204 |
205 | elif opcode == OP_ALT: RET+="|"; xs.readN(2)
206 | elif opcode == OP_OPT: xs.readN(1)
207 | elif opcode == OP_CHAR or opcode == OP_CHARNC:
208 | RET+=`xs.readN(1)`.replace("'","")
209 |
210 |
211 | elif opcode == OP_CRSTAR : RET += "*"
212 | elif opcode == OP_CRPLUS : RET += "+"
213 | elif opcode == OP_CRMINPLUS : RET += "+?"
214 | elif opcode == OP_CRMINSTAR : RET += "*?"
215 | elif opcode == OP_CRRANGE : RET+= "{%d,%d}" % xs.readFmt(">HH")
216 |
217 | elif opcode == OP_QUERY : RET += "%s?" % xs.readN(1)
218 |
219 | elif opcode == OP_STAR : RET+= "%s*" % xs.readN(1)
220 | elif opcode == OP_POSSTAR : RET+= "%s*+" % xs.readN(1)
221 | elif opcode == OP_MINSTAR : RET+= "%s*?" % xs.readN(1)
222 |
223 | elif opcode == OP_PLUS : RET+= "%s+" % xs.readN(1)
224 | elif opcode == OP_POSPLUS : RET+= "%s++" % xs.readN(1)
225 | elif opcode == OP_MINPLUS : RET+= "%s+?" % xs.readN(1)
226 |
227 | elif opcode == OP_MINQUERY : RET+= "%s??" % xs.readN(1)
228 |
229 | elif opcode == OP_TYPESTAR : RET+= "%s*" % singleByte( xs.readOne("B") )
230 | elif opcode == OP_TYPEPOSSTAR : RET+= "%s*+" % singleByte( xs.readOne("B") )
231 | elif opcode == OP_TYPEMINSTAR : RET+= "%s*?" % singleByte( xs.readOne("B") )
232 |
233 | elif opcode == OP_TYPEPLUS : RET+= "%s+" % singleByte( xs.readOne("B") )
234 | elif opcode == OP_TYPEPOSPLUS : RET+= "%s++" % singleByte( xs.readOne("B") )
235 | elif opcode == OP_TYPEMINPLUS : RET+= "%s+?" % singleByte( xs.readOne("B") )
236 |
237 | elif opcode == OP_TYPEMINQUERY : RET+= "%s??" % singleByte( xs.readOne("B") )
238 |
239 | elif opcode == OP_TYPEMINUPTO : RET+= "%(char)s{,%(cnt)d}?" % dict( cnt=xs.readOne(">H"), char=singleByte( xs.readOne("B") ) )
240 |
241 | elif opcode == OP_CLASS : junk=xs.readN(32); RET+="[%s]" % reClass(junk,1)
242 | elif opcode in [OP_PRUNE]:
243 | pass
244 | else:
245 | if verbose:
246 | print "CODE :%d " % opcode
247 | else:
248 | pass
249 |
250 |
251 | if verbose:
252 | print "\n\nDONE: [%s]\n\n" % RET
253 | return RET
254 |
255 |
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/libzpy/modules/p2p.py:
--------------------------------------------------------------------------------
1 | """Zeus-P2P binstorage parser """
2 | """
3 | import os
4 | import sys
5 | import struct
6 | import md5
7 | import zlib
8 |
9 | import json
10 |
11 | from libzpy.libs.storage import storageException
12 |
13 | from libzpy.libs.xstream import xstream
14 | from libzpy.libs import fmt
15 | from libzpy.libs import cr_tools
16 | from libzpy.libs import binPCRE
17 |
18 | #from _local.tmp import zBinStorage
19 | class zBinStorage(object):
20 | pass
21 |
22 |
23 | #from parsers import *
24 | #from libs.cr_tools import xorWithKey
25 | #import libs.binPCRE
26 | #from libs import fmt
27 |
28 | STORAGE_HEADER_SIZE = 48 # 20 + 3*4 + 16
29 | ITEM_HEADER_SIZE = 16 # 4*4
30 |
31 | FLG_ITEM_PACKED = 0x00000001
32 | FLG_ITEM_WEBINJECT = 0x40000000
33 | FLG_ITEM_CONFIG = 0x10000000
34 |
35 |
36 | def decode():
37 | pass
38 |
39 | def _p2p_inflate(data):
40 | dc = zlib.decompressobj(-15)
41 | d = dc.decompress(data)
42 | return d
43 |
44 |
45 |
46 |
47 | def unpack(data,verb,checkMD5=False,calcMD5=True,showInfo=False):
48 | size = len(data)
49 | if size < STORAGE_HEADER_SIZE + ITEM_HEADER_SIZE :
50 | raise storageException("Not enoungh data (<48) !")
51 |
52 | xs = xstream(data)
53 | RET = dict( head=dict() , items=[] )
54 | H = xs.readFmt("=20s I I I 16s ",into=('padding','size','unk1','version','md5') )
55 | H['padding'] = fmt.s2hex(H['padding'])
56 | H['md5'] = fmt.s2hex(H['md5'])
57 | dif = size-H['size']
58 | if dif < 0:
59 | raise storageException("Data size missmatch ! (%d<->%d) " % (H['size'],size) )
60 | if dif > 0:
61 | verb( "[Warning] too much data , will truncate (lost %d bytes)" % dif )
62 | xs.truncate(size - dif )
63 |
64 | RET['head'] = H
65 |
66 | if checkMD5 or calcMD5:
67 | tmp = xs.getPos()
68 | realMD5 = md5.new( xs.read() ).hexdigest()
69 | xs.seek(tmp)
70 | RET['head']['realMD5'] = realMD5
71 |
72 | if checkMD5:
73 | if RET['head']['md5'] != RET['head']['realMD5'] :
74 | raise storageException("Bad MD5 sum ! [ %s <-> %s ]" % (RET['head']['md5'] , RET['head']['realMD5']) )
75 | else:
76 | verb("MD5 is OK !")
77 |
78 | version = H['version']
79 |
80 | while xs.availableLen() > ITEM_HEADER_SIZE :
81 | ih = xs.readFmt("=IIII",into=("recId","recFlag","recSize","realSize"))
82 | verb(`ih`)
83 | key = 0xFFFFFFFF & ( ( 0x0000FFFF & ih['recId'] ) | ( ih['recSize'] << 0x10 ) | ( RET['head']['version'] << 8 ) )
84 | #print "KEY : %08X " % key
85 | binKey = struct.pack("=I",key)
86 | ic = xs.readN( ih['recSize'] )
87 | #print `ic`
88 | # decode item
89 | ic = cr_tools.xorWithKey(ic, binKey)
90 | #print `ic`
91 | # unpack
92 | if ih['recFlag'] & FLG_ITEM_PACKED :
93 | ic = _p2p_inflate(ic)
94 | #print `ic`
95 | ih['data'] = ic
96 | RET['items'].append(ih)
97 |
98 | if showInfo:
99 | print RET['head']
100 | print "Recods : %d " % len(RET['items'])
101 |
102 | return RET
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | class format:
114 | def __init__(self,data,verb,to='json'):
115 | self.verb = verb
116 | for item in data['items']:
117 | item['data'],item['desc'] = self.processItem(item)
118 | if to == 'json':
119 | print json.dumps(data)
120 |
121 |
122 | def processItem(self,i):
123 | F = i['recFlag']
124 | N = i['recId']
125 | if F & FLG_ITEM_WEBINJECT:
126 | return self.fmtWebinject(i)
127 | if F & FLG_ITEM_CONFIG:
128 | fn = "config_rec_%d" % N
129 | func = getattr(self,fn)
130 | return func(i)
131 | ## other
132 | return None
133 |
134 | def fmtWebinject(self,i):
135 | data = i['data']
136 | xs = xstream(data)
137 | PARTS = []
138 | while xs.availableLen() > 4:
139 | el = xs.readFmt("=IH",into=("size","flag"))
140 | tmp = xs.readN( el['size'] - 6 )
141 | if tmp[:4] == 'ERCP':
142 | tmp = `binPCRE.readBinary(tmp)`
143 | el['data'] = tmp
144 | PARTS.append(tmp)
145 | return PARTS,"webinject"
146 |
147 | def config_rec_22003(self,i):
148 | l = fmt.NullTermStringList(i['data'])
149 | return l,"Webfilters"
150 |
151 | def config_rec_22004(self,i):
152 | l = fmt.NullTermStringList(i['data'])
153 | return l,"list2"
154 |
155 | def config_rec_22002(self,i):
156 | t = self.rec_22002(i['data'])
157 | return t,'webinject-table'
158 |
159 |
160 | def rec_22002(self,data):
161 | r = []
162 | xs = xstream( data )
163 | i=1
164 | while xs.availableLen()>4:
165 | wi = xs.readFmt("=IHH",into=("len","flag","id"))
166 | wi['len'] -= 4 + 2 + 2
167 | entry = xstream( xs.readN(wi['len']) )
168 |
169 | params=''
170 | for k in wi: params += ' %s=%04X|%d ' % (k,wi[k],wi[k])
171 |
172 | cond=[]
173 | while entry.availableLen()>4:
174 | cond = entry.readFmt("=III",into=("len","flag1","flag2"))
175 | cond['len'] -= 4*3
176 | cont = entry.readN( cond['len'] )
177 | if cont[:4] == "ERCP":
178 | cont = `binPCRE.readBinary(cont)`
179 | params = ''
180 | for k in cond: params += ' %s=%04X|%d ' % (k,cond[k],cond[k])
181 | cond['text'] = cont
182 |
183 | wi['conditions'] = cond
184 | r.append(wi)
185 | i+=1
186 | return r
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | class storage(zBinStorage):
197 | def __init__(self):
198 | zBinStorage.__init__(self)
199 | self.outbuf = ''
200 |
201 |
202 | def parseNullTermStringList(self,data):
203 | r = data.split(chr(0))
204 | for i in range(len(r)):
205 | self.out( " [%d] %s \n" % (i,r[i]) )
206 | return r
207 |
208 | def readPCRE(self,data):
209 | txt = libs.binPCRE.readBinary(data)
210 | return txt
211 |
212 | def rec_webinject(self,data):
213 | size = len(data)
214 | xs = xstream(data)
215 | PARTS=[]
216 | while xs.availableLen() > 4:
217 |
218 | entrySize,entryFlag = xs.readFmt("=IH")
219 | entrySize -= 4 + 2
220 |
221 | entryData = xs.readN(entrySize)
222 | self.out( " <<--- DATA : %d | FLAG : %04X --->>\n" % ( entrySize , entryFlag ) )
223 |
224 | if entryData[:4]=='ERCP':
225 | entryData = self.readPCRE(entryData)
226 |
227 | self.out( `entryData`+"\n" )
228 |
229 | self.out( " <<--- /DATA --->>\n" )
230 | WI=dict(size=entrySize,flag=entryFlag,data=entryData)
231 | PARTS.append(WI)
232 | return PARTS
233 |
234 | def rec_22003(self,data):
235 | self.out( " \n" )
236 | r = self.parseNullTermStringList(data)
237 | self.out( " \n" )
238 | return r
239 |
240 |
241 |
242 | def rec_22004(self,data):
243 | self.out( " \n" )
244 | r = self.parseNullTermStringList(data)
245 | self.out( " \n" )
246 | return r
247 |
248 | def rec_22001(self,data):
249 | self.out(" \n")
250 | xs = xstream(data)
251 | #self.out(xs.hexDump())
252 | r=[]
253 | of = 0
254 | while xs.availableLen()>12:
255 | e = xs.readFmt("=IIH",into=("len","nul1","flag1") ) ;of+=10
256 | e['sub']=[]
257 | self.out(" - \n" %(e['len'], e['nul1'], e['flag1']))
258 |
259 | toRead = e['len'] - 10;
260 | nRead = 0
261 | while nRead < toRead:
262 | sub = xs.readFmt("=IBBBB",into=("size","f1","f2","f3","f4")) ;of+=8; nRead+=8;
263 | sub['content']=''
264 | if sub['size']>0:
265 | data = xs.readN(sub['size']-8) ; of+=sub['size']-8; nRead+=sub['size']-8;
266 | cont = self.readPCRE(data)
267 | sub['content'] = cont
268 | self.out(" %s\n" % (sub['size'],sub['f1'],sub['f2'],sub['f3'],sub['f4'],sub['content']))
269 | e['sub'].append(sub)
270 | r.append(e)
271 | self.out("
\n\n")
272 | self.out(" \n")
273 | return r
274 |
275 | def rec_22002(self,data):
276 | self.out( " \n" )
277 | r = []
278 | xs = xstream( data )
279 | i=1
280 | while xs.availableLen()>4:
281 | wi = xs.readFmt("=IHH",into=("len","flag","id"))
282 | wi['len'] -= 4 + 2 + 2
283 | entry = xstream( xs.readN(wi['len']) )
284 |
285 | params=''
286 | for k in wi: params += ' %s=%04X|%d ' % (k,wi[k],wi[k])
287 | self.out( " \n" % ( i,params) )
288 |
289 | cond=[]
290 | while entry.availableLen()>4:
291 | cond = entry.readFmt("=III",into=("len","flag1","flag2"))
292 | cond['len'] -= 4*3
293 | cont = entry.readN( cond['len'] )
294 | if cont[:4] == "ERCP":
295 | cont = self.readPCRE(cont)
296 | params = ''
297 | for k in cond: params += ' %s=%04X|%d ' % (k,cond[k],cond[k])
298 | self.out(" %s \n" % (params,cont) )
299 | cond['text'] = cont
300 |
301 | self.out( " \n")
302 | wi['conditions'] = cond
303 | r.append(wi)
304 | i+=1
305 | self.out( " \n" )
306 | return r
307 |
308 |
309 | def formatRecord(self,RH,data):
310 | rid = RH['recId']
311 | rflg = RH['recFlag']
312 |
313 | if rflg & 0x40000000:
314 | fname = "rec_webinject"
315 | else :
316 | fname = "rec_%d" % rid
317 |
318 | if hasattr(self,fname):
319 | func = getattr(self,fname)
320 | fmt=func(data)
321 | return fmt
322 | else :
323 | self.out("< -- NOT IMPLEMENTED ID %d -- >\n" % rid )
324 | txt = xstream(data).hexDump() ## make nice hexdump :)
325 | self.out(txt)
326 | return txt
327 |
328 |
329 |
330 |
331 | def inflate(self,data,dstSize=0):
332 | dc = zlib.decompressobj(-15)
333 | d = dc.decompress(data)
334 | return d
335 |
336 | def unpack_head(self,data):
337 |
338 | if len(data) < 48:
339 | raise storageException("Need more data (1)")
340 |
341 | xs = xstream(data)
342 | st = xs.readFmt("=20s I I I 16s ",into=('padding','size','cnt1','cnt2','md5') )
343 | st['padding'] = fmt.s2hex(st['padding'])
344 | st['md5'] = fmt.s2hex(st['md5'])
345 | # convert datetime !?
346 |
347 | self.out("\n junk\t: %s\n size\t: %d\n cnt1\t: %d\n cnt2\t: %d\n MD5\t: %s\n\n\n" % ( st['padding'] ,st['size'],st['cnt1'],st['cnt2'], st['md5'] ) )
348 |
349 | content = xs.read()
350 | dif = len(content) - ( st['size'] - 48 ) # size of binstorage head
351 | if dif <0 :
352 | raise storageException("Need more data (2)")
353 | if dif > 0:
354 | self.verb("Got spare bytes :%d , truncate !" % dif)
355 | content = content[:-dif]
356 |
357 | m5s = md5.new(content).hexdigest()
358 | st['real-md5'] = m5s
359 | self.out(" %s \n\n" % m5s )
360 |
361 | return st,content
362 |
363 |
364 | def unpack_recs(self,st,data):
365 | RECS = []
366 | version = st['cnt2'] # filed
367 |
368 | xs = xstream(data)
369 | while xs.availableLen()>16:
370 | RH = xs.readFmt("=IIII",into=("recId","recFlag","recSize","realSize"))
371 | try:
372 | RD = xs.readN( RH['recSize'] )
373 | except :
374 | raise storageException("Fail to read record ... corupted data ?")
375 |
376 | self.out( "\n" % ( RH['recId'],RH['recId'],RH['recFlag'],RH['recSize'],RH['realSize']) )
377 |
378 | rec_key = 0xFFFFFFFF & ( ( 0x0000FFFF & RH['recId']) | ( RH['recSize'] << 0x10 ) | ( version << 8 ) )
379 | rec_bin = struct.pack("I",rec_key)
380 | self.out( "%08X+%08X+%08X => %08X\n" % (RH['recId'],RH['recSize'],version,rec_key) )
381 | RD = cr_tools.xorWithKey(RD, rec_bin)
382 |
383 | if RH['recFlag'] & 0x01: ## handle zipped content
384 | RD = self.inflate(RD,RH['realSize'])
385 |
386 | #RH['rawData']=RD
387 | self.dumpRecord(RD) # dump support added :)
388 |
389 | RH['fmtData']=self.formatRecord(RH,RD)
390 | self.out( "\n\n" )
391 |
392 | RECS.append(RH)
393 | return RECS
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 | def pack_rec_default(self,content):
403 | print " >> %s <<" % content
404 | return content
405 |
406 | def pack_nullstr(self,c):
407 | return ''.join( '%s\x00' % str(u) for u in c )
408 |
409 | def pack_rec_20003(self,c): return self.pack_nullstr(c)
410 | def pack_rec_20005(self,c): return self.pack_nullstr(c)
411 | def pack_rec_20009(self,c): return self.pack_nullstr(c)
412 | def pack_rec_20011(self,c): return self.pack_nullstr(c)
413 |
414 | def pack_rec_20007(self,c): # webi tabe
415 | pass
416 |
417 | def pack_webinject(self,c):
418 | xs = xstream()
419 | for e in c:
420 | l = len(e)+4
421 | xs.writeFmt("I",l)
422 | xs.write(str(e))
423 | return xs.dump()
424 |
425 |
426 |
427 | def pack_record(self,record):
428 | fields = ("id","content")
429 | for f in fields:
430 | if f not in record:
431 | raise storageException("Missing requred field: [%s]"%f)
432 | return
433 |
434 | flag = 0x0
435 |
436 | opts = record.get("opt",{})
437 | if opts.get("webinject",None):
438 | fn = "pack_webinject"
439 | flag |= 0x40000000
440 | else:
441 | fn = "pack_rec_%d" % record['id']
442 | if not hasattr(self,fn):
443 | fn = "pack_rec_default"
444 |
445 | func = getattr(self,fn)
446 | bindata = func(record['content'])
447 | size = len(bindata)
448 | xs = xstream()
449 | xs.writeFmt("=IIII",record['id'],flag,size,size)
450 | xs.write(bindata)
451 | return xs.dump()
452 |
453 |
454 | def pack_recs(self,recList):
455 | recBin = ''
456 | recCnt = 0
457 | for rec in recList:
458 | recBin += self.pack_record(rec)
459 | recCnt += 1
460 | size = len(recBin)
461 | m5s = md5.new(recBin).digest()
462 |
463 | xs = xstream()
464 | xs.write("xpad"*5)
465 | xs.writeFmt("=III",size,recCnt,0)
466 | xs.write(m5s)
467 | xs.write(recBin)
468 | xs.seek(0)
469 | return xs.read()
470 | """
471 |
--------------------------------------------------------------------------------
/libzpy/libs/vmzeus.py:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/python
3 | ########################################################################
4 | # Copyright (c) 2014
5 | # all other co-authors here :)
6 | # Daniel Plohmann gmailcom>
7 | # All rights reserved.
8 | ########################################################################
9 | #
10 | # This is free software: you can redistribute it and/or modify it
11 | # under the terms of the GNU General Public License as published by
12 | # the Free Software Foundation, either version 3 of the License, or
13 | # (at your option) any later version.
14 | #
15 | # This program is distributed in the hope that it will be useful, but
16 | # WITHOUT ANY WARRANTY; without even the implied warranty of
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 | # General Public License for more details.
19 | #
20 | # You should have received a copy of the GNU General Public License
21 | # along with this program. If not, see
22 | # .
23 | #
24 | ########################################################################
25 |
26 | import struct
27 | import Crypto.Cipher.ARC4
28 |
29 | # Hexdump
30 | # courtesy of http://code.activestate.com/recipes/142812/
31 | FILTER = "".join([(len(repr(chr(x))) == 3) and chr(x) or "." for x in range(256)])
32 |
33 |
34 | def hexdump(src, length=16):
35 | N = 0
36 | result = ""
37 | while src:
38 | s, src = src[:length], src[length:]
39 | hexa = " ".join(["%02X" % ord(ch) for ch in s])
40 | s = s.translate(FILTER)
41 | result += "%04X %-*s %s\r\n" % (N, length * 3, hexa, s)
42 | N += length
43 | return result
44 |
45 |
46 | class VmContext(object):
47 |
48 | def __init__(self, bytecode, config):
49 | self.bytecode = bytecode
50 | self.config = config
51 | self.eip = 0
52 | self.edi = 0
53 | self.ecx = 0
54 | self.r = [0 for i in xrange(16)]
55 | self.magics = {"nop": {1: 0x32, 2: 0x26, 4: 0xF3},
56 | "xor": {1: 0xF1, 2: 0xE9, 4: 0x6A},
57 | "add": {1: 0x73, 2: 0xD9},
58 | "sub": {1: 0xEB},
59 | "rol": {1: 0x85},
60 | "ror": {1: 0xF3, 2: 0xA6},
61 | "not": {1: 0xE7, 2: 0x8B, 4: 0x24},
62 | "reorder": 0xBA,
63 | "rc4": 0xE9,
64 | "setecx": {2: 0xDA, 4: 0x70},
65 | "setedi": 0xC8,
66 | "loop": {1: 0xD0, 2: 0xEC},
67 | "mov_r_const": {1: 0x0B, 2: 0x0F, 4: 0x70},
68 | "mov_r_r": {1: 0x46, 2: 0x39, 4: 0x9E},
69 | "add_r_r": {1: 0x72, 2: 0x5F, 4: 0xF9},
70 | "sub_r_r": {1: 0x1E, 2: 0xD1, 4: 0xA6},
71 | "xor_r_r": {1: 0xDB, 2: 0xAC, 4: 0xB7},
72 | "add_r_const": {1: 0x9D, 2: 0x8f, 4: 0x28},
73 | "sub_r_const": {1: 0x52, 2: 0x85, 4: 0xD8},
74 | "xor_r_const": {1: 0xD5, 2: 0x24, 4: 0x2E},
75 | "stos_add": {1: 0x65, 2: 0x89, 4: 0xDC},
76 | "stos_sub": {1: 0x1D, 4: 0xA0},
77 | "stos_xor": {1: 0x41, 2: 0x46, 4: 0x29},
78 | "lods": {1: 0xB8, 2: 0x68, 4: 0xFD},
79 | "stos": {1: 0x16, 2: 0xBB, 4: 0xF0}
80 | }
81 | self.instr_table = [self.instr_nop_byte, self.instr_nop_word, self.instr_nop_dword,
82 | self.instr_xor_byte, self.instr_xor_word, self.instr_xor_dword,
83 | self.instr_add_byte, self.instr_add_word, self.instr_add_dword,
84 | self.instr_sub_byte, self.instr_sub_word, self.instr_sub_dword,
85 | self.instr_rol_byte, self.instr_rol_word, self.instr_rol_dword,
86 | self.instr_ror_byte, self.instr_ror_word, self.instr_ror_dword,
87 | self.instr_not_byte, self.instr_not_word, self.instr_not_dword,
88 | self.instr_reorder,
89 | self.instr_rc4,
90 | self.instr_setecx_byte, self.instr_setecx_word, self.instr_setecx_dword,
91 | self.instr_setedi,
92 | self.instr_loop_byte, self.instr_loop_word,
93 | self.instr_mov_r_const_byte, self.instr_mov_r_const_word, self.instr_mov_r_const_dword,
94 | self.instr_mov_r_r_byte, self.instr_mov_r_r_word, self.instr_mov_r_r_dword,
95 | self.instr_add_r_r_byte, self.instr_add_r_r_word, self.instr_add_r_r_dword,
96 | self.instr_sub_r_r_byte, self.instr_sub_r_r_word, self.instr_sub_r_r_dword,
97 | self.instr_xor_r_r_byte, self.instr_xor_r_r_word, self.instr_xor_r_r_dword,
98 | self.instr_add_r_const_byte, self.instr_add_r_const_word, self.instr_add_r_const_dword,
99 | self.instr_sub_r_const_byte, self.instr_sub_r_const_word, self.instr_sub_r_const_dword,
100 | self.instr_xor_r_const_byte, self.instr_xor_r_const_word, self.instr_xor_r_const_dword,
101 | self.instr_stos_add_byte, self.instr_stos_add_word, self.instr_stos_add_dword,
102 | self.instr_stos_sub_byte, self.instr_stos_sub_word, self.instr_stos_sub_dword,
103 | self.instr_stos_xor_byte, self.instr_stos_xor_word, self.instr_stos_xor_dword,
104 | self.instr_lods_byte, self.instr_lods_word, self.instr_lods_dword,
105 | self.instr_stos_byte, self.instr_stos_word, self.instr_stos_dword,
106 | self.instr_leave
107 | ]
108 | self.pack_sizes = {1: "B", 2: "H", 4: "I"}
109 | self.modulus = {1: 0xFF, 2: 0xFFFF, 4: 0xFFFFFFFF}
110 |
111 | def __str__(self):
112 | return "EIP: 0x%08x -> 0x%x | EDI: 0x%08x | ECX: 0x%08x" % (self.eip, ord(self.bytecode[self.eip]), self.edi, self.ecx)
113 |
114 | def _fix_xors(self,xors):
115 | suf = {'byte':1,'word':2,'dword':4}
116 | print 'Instrs: %d' % len(self.instr_table)
117 | print 'Magics %d' % len(xors)
118 |
119 | for idx in xrange(0,len(self.instr_table)-1):
120 | name = self.instr_table[idx].im_func.func_name.split('_')
121 | print 'Updating %s with %x' % (`name`,xors[idx])
122 | try:
123 | self.magics['_'.join(name[1:-1])][suf[name[-1]]] = xors[idx]
124 | except IndexError:
125 | self.magics[name[1]] = xors[idx]
126 |
127 | except KeyError:
128 | self.magics[name[1]] = xors[idx]
129 |
130 |
131 | def dump_r(self):
132 | output = " Custom Registers: \n"
133 | for i in xrange(4):
134 | line = " "
135 | for j in xrange(4):
136 | line += "%s " % struct.pack("I", self.r[4 * i + j]).encode("hex")
137 | output += line + "\n"
138 | return output
139 |
140 | def run(self):
141 | self.instr_count = 0
142 | print "Decoding BaseConfig. Initial VM state:"
143 | print str(self) + "\n"
144 | stop_exec = False
145 | while not stop_exec and self.eip < len(self.bytecode):
146 | self.instr_count += 1
147 | print "+ fetching opcode [%d]: 0x%02x (%d)" % (self.instr_count, ord(self.bytecode[self.eip]), ord(self.bytecode[self.eip]))
148 | stop_exec = self.instr_table[ord(self.bytecode[self.eip])]()
149 | print " ", str(self)
150 |
151 | ################################
152 | # opcode handlers
153 | ################################
154 | def instr_nop_byte(self):
155 | # operand: 0x00
156 | self.instr_nop(1)
157 |
158 | def instr_nop_word(self):
159 | # operand: 0x01
160 | self.instr_nop(2)
161 |
162 | def instr_nop_dword(self):
163 | # operand: 0x02
164 | self.instr_nop(4)
165 |
166 | def instr_nop(self, size):
167 | eip_offset = {1: 0, 2: 1, 4: 1}[size]
168 | bXorKey = self.deref_bytecode(self.eip + eip_offset, 1) ^ self.magics["nop"][size]
169 | self.eip += size
170 | if self.deref_bytecode(self.eip, 1) & 0x80:
171 | self.decode_next_opcode_byte(bXorKey)
172 | print " -> nop_%d" % (size)
173 |
174 | def instr_xor_byte(self):
175 | # operand: 0x03
176 | self.instr_xor(1)
177 |
178 | def instr_xor_word(self):
179 | # operand: 0x04
180 | self.instr_xor(2)
181 |
182 | def instr_xor_dword(self):
183 | # operand: 0x05
184 | self.instr_xor(4)
185 |
186 | def instr_xor(self, size):
187 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["xor"][size]
188 | self.eip += 1
189 | # there is some EDI fuckup here not properly dereferenced?
190 | # also EIP offset has to be adjusted
191 | value = self.deref_bytecode(self.eip, size) ^ self.deref_config(self.edi, size)
192 | replacement = struct.pack(self.pack_sizes[size], value)
193 | self.config = self.replace_in_buffer(self.config, self.edi, replacement)
194 | self.eip += size
195 | self.edi += size
196 | if self.deref_bytecode(self.eip, 1) & 0x80:
197 | self.decode_next_opcode_byte(bXorKey)
198 | print " -> xor_%d 0x%08x" % (size, self.edi - size)
199 |
200 | def instr_add_byte(self):
201 | # operand: 0x09
202 | self.instr_add(1)
203 |
204 | def instr_add_word(self):
205 | # operand: 0x0a
206 | self.instr_add(2)
207 |
208 | def instr_add_dword(self):
209 | # operand: 0x0b
210 | self.instr_add(4)
211 |
212 | def instr_add(self, size):
213 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["add"][size]
214 | self.eip += 1
215 | value = self.deref_config(self.edi, size) + self.deref_bytecode(self.eip, size)
216 | replacement = struct.pack(self.pack_sizes[size], value & self.modulus[size])
217 | self.config = self.replace_in_buffer(self.config, self.edi, replacement)
218 | self.eip += size
219 | self.edi += size
220 | if self.deref_bytecode(self.eip, 1) & 0x80:
221 | self.decode_next_opcode_byte(bXorKey)
222 | print " -> sub_%d 0x%08x" % (size, self.edi - size)
223 |
224 | def instr_sub_byte(self):
225 | # operand: 0x09
226 | self.instr_sub(1)
227 |
228 | def instr_sub_word(self):
229 | # operand: 0x0a
230 | self.instr_sub(2)
231 |
232 | def instr_sub_dword(self):
233 | # operand: 0x0b
234 | self.instr_sub(4)
235 |
236 | def instr_sub(self, size):
237 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["sub"][size]
238 | self.eip += 1
239 | value = self.deref_config(self.edi, size) - self.deref_bytecode(self.eip, size)
240 | replacement = struct.pack(self.pack_sizes[size], value & self.modulus[size])
241 | self.config = self.replace_in_buffer(self.config, self.edi, replacement)
242 | self.eip += size
243 | self.edi += size
244 | if self.deref_bytecode(self.eip, 1) & 0x80:
245 | self.decode_next_opcode_byte(bXorKey)
246 | print " -> sub_%d 0x%08x" % (size, self.edi - size)
247 |
248 | def rol(self, buf, size, count):
249 | while count > 0:
250 | buf = (buf << 1 | buf >> (size * 8 - 1)) & self.modulus[size]
251 | count -= 1
252 | return buf
253 |
254 | def instr_rol_byte(self):
255 | # operand: 0x0c
256 | self.instr_rol(1)
257 |
258 | def instr_rol_word(self):
259 | # operand: 0x0d
260 | self.instr_rol(2)
261 |
262 | def instr_rol_dword(self):
263 | # operand: 0x0e
264 | self.instr_rol(4)
265 |
266 | def instr_rol(self, size):
267 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["rol"][size]
268 | count = self.deref_bytecode(self.eip + 1, size) & (size * 8 - 1)
269 | self.eip += 2
270 | dataOffset = self.edi
271 | replacement = struct.pack(self.pack_sizes[size], (self.rol(self.deref_config(dataOffset, size), size, count)) & self.modulus[size])
272 | self.config = self.replace_in_buffer(self.config, dataOffset, replacement)
273 | self.edi += size
274 | if self.deref_bytecode(self.eip, 1) & 0x80:
275 | self.decode_next_opcode_byte(bXorKey)
276 | print " -> rol_%d 0x%08x" % (size, dataOffset)
277 |
278 | def ror(self, buf, size, count):
279 | while count > 0:
280 | buf = (buf >> 1 | buf << (size * 8 - 1)) & self.modulus[size]
281 | count -= 1
282 | return buf
283 |
284 | def instr_ror_byte(self):
285 | # operand: 0x0f
286 | self.instr_ror(1)
287 |
288 | def instr_ror_word(self):
289 | # operand: 0x10
290 | self.instr_ror(2)
291 |
292 | def instr_ror_dword(self):
293 | # operand: 0x11
294 | self.instr_ror(4)
295 |
296 | def instr_ror(self, size):
297 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["ror"][size]
298 | count = self.deref_bytecode(self.eip + 1, size) & (size * 8 - 1)
299 | self.eip += 2
300 | dataOffset = self.edi
301 | ### print "before: ", struct.pack(self.pack_sizes[size], self.deref_config(dataOffset, size)).encode("hex")
302 | replacement = struct.pack(self.pack_sizes[size], (self.ror(self.deref_config(dataOffset, size), size, count)) & self.modulus[size])
303 | ### print "after: ", replacement.encode("hex")
304 | self.config = self.replace_in_buffer(self.config, dataOffset, replacement)
305 | self.edi += size
306 | if self.deref_bytecode(self.eip, 1) & 0x80:
307 | self.decode_next_opcode_byte(bXorKey)
308 | print " -> ror_%d 0x%08x" % (size, dataOffset)
309 |
310 | def instr_not_byte(self):
311 | # operand: 0x12
312 | self.instr_not(1)
313 |
314 | def instr_not_word(self):
315 | # operand: 0x13
316 | self.instr_not(2)
317 |
318 | def instr_not_dword(self):
319 | # operand: 0x14
320 | self.instr_not(4)
321 |
322 | def instr_not(self, size):
323 | bXorKey = self.deref_bytecode(self.eip, 1) ^ self.magics["not"][size]
324 | self.eip += 1
325 | valueOffset = self.edi
326 | replacement = struct.pack(self.pack_sizes[size], (~self.deref_config(valueOffset, size)) & self.modulus[size])
327 | self.config = self.replace_in_buffer(self.config, valueOffset, replacement)
328 | self.edi += size
329 | if self.deref_bytecode(self.eip, 1) & 0x80:
330 | self.decode_next_opcode_byte(bXorKey)
331 | print " -> not_%d 0x%08x" % (size, valueOffset)
332 |
333 | def instr_reorder(self):
334 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["reorder"]
335 | operand = self.deref_bytecode(self.eip + 1, 1)
336 | value = struct.pack(self.pack_sizes[4], self.deref_config(self.edi, 4))
337 | replacement = [0, 0, 0, 0]
338 | for i in xrange(4):
339 | index = operand & 0x3
340 | replacement[index] = value[i]
341 | operand = operand >> 2
342 | replacement = "".join(replacement)
343 | # after shuffling
344 | self.config = self.replace_in_buffer(self.config, self.edi, replacement)
345 | self.edi += 4
346 | self.eip += 2
347 | if self.deref_bytecode(self.eip, 1) & 0x80:
348 | self.decode_next_opcode_byte(bXorKey)
349 | print " -> reorder 0x%08x" % (self.deref_config(self.edi - 4, 4))
350 |
351 | def instr_rc4(self):
352 | # operand: 0x16
353 | bXorKey = self.deref_bytecode(self.eip + 3, 1) ^ self.magics["rc4"]
354 | keySize = struct.unpack("B", self.bytecode[self.eip + 1])[0]
355 | dataSize = struct.unpack("B", self.bytecode[self.eip + 2])[0]
356 | # build rc4 key with password given in bytecode
357 | keyOffset = self.eip + 3
358 | rc4Key = self.bytecode[keyOffset:keyOffset + keySize]
359 | dataOffset = self.edi
360 | data = self.config[dataOffset:dataOffset + dataSize]
361 | rc4 = Crypto.Cipher.ARC4.new(rc4Key)
362 | cryptedBin = b"".join(data)
363 | plaintext = rc4.decrypt(cryptedBin)
364 | # insert decrypted part in config
365 | self.config = self.replace_in_buffer(self.config, self.edi, plaintext)
366 | self.edi += dataSize
367 | self.eip += 3 + keySize
368 | if self.deref_bytecode(self.eip, 1) & 0x80:
369 | self.decode_next_opcode_byte(bXorKey)
370 | print " -> rc4 -> offset: 0x%08x (%d bytes), key_offset: 0x%08x (%d bytes)" % (dataOffset, dataSize, keyOffset, keySize)
371 |
372 | def instr_setecx_byte(self):
373 | # operand: 0x17
374 | self.instr_setecx(1)
375 |
376 | def instr_setecx_word(self):
377 | # operand: 0x18
378 | self.instr_setecx(2)
379 |
380 | def instr_setecx_dword(self):
381 | # operand: 0x19
382 | self.instr_setecx(4)
383 |
384 | def instr_setecx(self, size):
385 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["setecx"][size]
386 | self.eip += 1
387 | value = self.deref_bytecode(self.eip, size)
388 | self.ecx += value
389 | self.eip += size
390 | if self.deref_bytecode(self.eip, 1) & 0x80:
391 | self.decode_next_opcode_byte(bXorKey)
392 | print " -> set_%d ecx, 0x%08x" % (size, value)
393 |
394 | def instr_setedi(self):
395 | # operand: 0x1A
396 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["setedi"]
397 | self.eip += 1
398 | self.edi += self.deref_bytecode(self.eip, 2)
399 | self.edi = self.edi & 0xFFFF
400 | self.eip += 2
401 | if self.deref_bytecode(self.eip, 1) & 0x80:
402 | self.decode_next_opcode_byte(bXorKey)
403 | print " -> set edi, 0x%08x" % self.edi
404 |
405 | def instr_loop_byte(self):
406 | # operand: 0x1B
407 | self.instr_loop(1)
408 |
409 | def instr_loop_word(self):
410 | # operand: 0x1C
411 | self.instr_loop(2)
412 |
413 | def instr_loop(self, size):
414 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["loop"][size]
415 | if self.deref_bytecode(self.eip + 1 + size, 1) & 0x80:
416 | self.decode_next_opcode_byte(bXorKey, 1 + size)
417 | self.eip += 1
418 | if self.ecx != 0:
419 | self.ecx -= 1
420 | self.eip = self.eip + size - self.deref_bytecode(self.eip, size)
421 | else:
422 | self.eip += size
423 | print " -> loop_%d 0x%08x" % (size, self.ecx)
424 |
425 | def instr_mov_r_const_byte(self):
426 | # operand: 0x1D
427 | self.instr_mov_r_const(1)
428 |
429 | def instr_mov_r_const_word(self):
430 | # operand: 0x1E
431 | self.instr_mov_r_const(2)
432 |
433 | def instr_mov_r_const_dword(self):
434 | # operand: 0x1F
435 | self.instr_mov_r_const(4)
436 |
437 | def instr_mov_r_const(self, size):
438 | bXorKey = self.deref_bytecode(self.eip + 2, 1) ^ self.magics["mov_r_const"][size]
439 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
440 | value = self.deref_bytecode(self.eip + 2, 4) & self.modulus[size]
441 | self.r[dst_r_index] = value
442 | self.eip += 2 + size
443 | if self.deref_bytecode(self.eip, 1) & 0x80:
444 | self.decode_next_opcode_byte(bXorKey)
445 | print " -> mov_%d r[%d], 0x%08x" % (size, dst_r_index, value)
446 | print self.dump_r()
447 |
448 | def instr_mov_r_r_byte(self):
449 | # operand: 0x20
450 | self.instr_mov_r_r(1)
451 |
452 | def instr_mov_r_r_word(self):
453 | # operand: 0x21
454 | self.instr_mov_r_r(2)
455 |
456 | def instr_mov_r_r_dword(self):
457 | # operand: 0x22
458 | self.instr_mov_r_r(4)
459 |
460 | def instr_mov_r_r(self, size):
461 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["mov_r_r"][size]
462 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
463 | src_r_index = self.deref_bytecode(self.eip + 1, 1) >> 4
464 | # according to commentary: "lower than 32 bit size operations do not preserve destination's higher bits, they get set to 0"
465 | self.r[dst_r_index] = self.r[src_r_index] & self.modulus[size]
466 | self.eip += 2
467 | if self.deref_bytecode(self.eip, 1) & 0x80:
468 | self.decode_next_opcode_byte(bXorKey)
469 | print " -> mov_%d r[%d], r[%d]" % (size, dst_r_index, src_r_index)
470 | print self.dump_r()
471 |
472 | def instr_add_r_r_byte(self):
473 | # operand: 0x23
474 | self.instr_add_r_r(1)
475 |
476 | def instr_add_r_r_word(self):
477 | # operand: 0x24
478 | self.instr_add_r_r(2)
479 |
480 | def instr_add_r_r_dword(self):
481 | # operand: 0x25
482 | self.instr_add_r_r(4)
483 |
484 | def instr_add_r_r(self, size):
485 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["add_r_r"][size]
486 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
487 | src_r_index = self.deref_bytecode(self.eip + 1, 1) >> 4
488 | self.r[dst_r_index] += self.r[src_r_index] & self.modulus[size]
489 | self.r[dst_r_index] = self.r[dst_r_index] & self.modulus[4]
490 | self.eip += 2
491 | if self.deref_bytecode(self.eip, 1) & 0x80:
492 | self.decode_next_opcode_byte(bXorKey)
493 | print " -> add_%d r[%d], r[%d]" % (size, dst_r_index, src_r_index)
494 | print self.dump_r()
495 |
496 | def instr_sub_r_r_byte(self):
497 | # operand: 0x26
498 | self.instr_sub_r_r(1)
499 |
500 | def instr_sub_r_r_word(self):
501 | # operand: 0x27
502 | self.instr_sub_r_r(2)
503 |
504 | def instr_sub_r_r_dword(self):
505 | # operand: 0x28
506 | self.instr_sub_r_r(4)
507 |
508 | def instr_sub_r_r(self, size):
509 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["sub_r_r"][size]
510 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
511 | src_r_index = self.deref_bytecode(self.eip + 1, 1) >> 4
512 | self.r[dst_r_index] -= self.r[src_r_index] & self.modulus[size]
513 | self.r[dst_r_index] = self.r[dst_r_index] & self.modulus[4]
514 | self.eip += 2
515 | if self.deref_bytecode(self.eip, 1) & 0x80:
516 | self.decode_next_opcode_byte(bXorKey)
517 | print " -> sub_%d r[%d], r[%d]" % (size, dst_r_index, src_r_index)
518 | print self.dump_r()
519 |
520 | def instr_xor_r_r_byte(self):
521 | # operand: 0x29
522 | self.instr_xor_r_r(1)
523 |
524 | def instr_xor_r_r_word(self):
525 | # operand: 0x2A
526 | self.instr_xor_r_r(2)
527 |
528 | def instr_xor_r_r_dword(self):
529 | # operand: 0x2B
530 | self.instr_xor_r_r(4)
531 |
532 | def instr_xor_r_r(self, size):
533 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["xor_r_r"][size]
534 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
535 | src_r_index = self.deref_bytecode(self.eip + 1, 1) >> 4
536 | dst_value = self.r[dst_r_index] ^ (self.r[src_r_index] & self.modulus[size])
537 | self.r[dst_r_index] = dst_value
538 | self.eip += 2
539 | if self.deref_bytecode(self.eip, 1) & 0x80:
540 | self.decode_next_opcode_byte(bXorKey)
541 | print " -> xor_%d r[%d], r[%d]" % (size, dst_r_index, src_r_index)
542 | print self.dump_r()
543 |
544 | def instr_add_r_const_byte(self):
545 | # operand: 0x2C
546 | self.instr_add_r_const(1)
547 |
548 | def instr_add_r_const_word(self):
549 | # operand: 0x2D
550 | self.instr_add_r_const(2)
551 |
552 | def instr_add_r_const_dword(self):
553 | # operand: 0x2E
554 | self.instr_add_r_const(4)
555 |
556 | def instr_add_r_const(self, size):
557 | bXorKey = self.deref_bytecode(self.eip + 2, 1) ^ self.magics["add_r_const"][size]
558 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
559 | value = self.deref_bytecode(self.eip + 2, size)
560 | self.r[dst_r_index] += value
561 | self.r[dst_r_index] = self.r[dst_r_index] & self.modulus[4]
562 | self.eip += 2 + size
563 | if self.deref_bytecode(self.eip, 1) & 0x80:
564 | self.decode_next_opcode_byte(bXorKey)
565 | print " -> add_%d r[%d], 0x%x" % (size, dst_r_index, value)
566 | print self.dump_r()
567 |
568 | def instr_sub_r_const_byte(self):
569 | # operand: 0x2F
570 | self.instr_sub_r_const(1)
571 |
572 | def instr_sub_r_const_word(self):
573 | # operand: 0x30
574 | self.instr_sub_r_const(2)
575 |
576 | def instr_sub_r_const_dword(self):
577 | # operand: 0x31
578 | self.instr_sub_r_const(4)
579 |
580 | def instr_sub_r_const(self, size):
581 | bXorKey = self.deref_bytecode(self.eip + 2, 1) ^ self.magics["sub_r_const"][size]
582 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
583 | value = self.deref_bytecode(self.eip + 2, size)
584 | self.r[dst_r_index] -= value
585 | self.r[dst_r_index] = self.r[dst_r_index] & self.modulus[4]
586 | self.eip += 2 + size
587 | if self.deref_bytecode(self.eip, 1) & 0x80:
588 | self.decode_next_opcode_byte(bXorKey)
589 | print " -> sub_%d r[%d], 0x%x" % (size, dst_r_index, value)
590 | print self.dump_r()
591 |
592 | def instr_xor_r_const_byte(self):
593 | # operand: 0x32
594 | self.instr_xor_r_const(1)
595 |
596 | def instr_xor_r_const_word(self):
597 | # operand: 0x33
598 | self.instr_xor_r_const(2)
599 |
600 | def instr_xor_r_const_dword(self):
601 | # operand: 0x34
602 | self.instr_xor_r_const(4)
603 |
604 | def instr_xor_r_const(self, size):
605 | bXorKey = self.deref_bytecode(self.eip + 2, 1) ^ self.magics["xor_r_const"][size]
606 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
607 | value = self.deref_bytecode(self.eip + 2, size)
608 | self.eip += 2 + size
609 | self.r[dst_r_index] ^= value
610 | if self.deref_bytecode(self.eip, 1) & 0x80:
611 | self.decode_next_opcode_byte(bXorKey)
612 | print " -> xor_%d r[%d], 0x%x" % (size, dst_r_index, value)
613 | print self.dump_r()
614 |
615 | def instr_stos_add_byte(self):
616 | # operand: 0x35
617 | self.instr_stos_add(1)
618 |
619 | def instr_stos_add_word(self):
620 | # operand: 0x36
621 | self.instr_stos_add(2)
622 |
623 | def instr_stos_add_dword(self):
624 | # operand: 0x37
625 | self.instr_stos_add(4)
626 |
627 | def instr_stos_add(self, size):
628 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["stos_add"][size]
629 | src_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
630 | self.eip += 2
631 | valueOffset = self.edi
632 | replacement = struct.pack(self.pack_sizes[size], (self.deref_config(valueOffset, size) + self.r[src_r_index]) & self.modulus[size])
633 | # print self.config[valueOffset:valueOffset + 4].encode("hex")
634 | self.config = self.replace_in_buffer(self.config, valueOffset, replacement)
635 | # print self.config[valueOffset:valueOffset + 4].encode("hex")
636 | self.edi += size
637 | if self.deref_bytecode(self.eip, 1) & 0x80:
638 | self.decode_next_opcode_byte(bXorKey)
639 | print " -> add_%d stos edi, r[%d]" % (size, src_r_index)
640 | print self.dump_r()
641 |
642 | def instr_stos_sub_byte(self):
643 | # operand: 0x38
644 | self.instr_stos_sub(1)
645 |
646 | def instr_stos_sub_word(self):
647 | # operand: 0x39
648 | self.instr_stos_sub(2)
649 |
650 | def instr_stos_sub_dword(self):
651 | # operand: 0x3a
652 | self.instr_stos_sub(4)
653 |
654 | def instr_stos_sub(self, size):
655 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["stos_sub"][size]
656 | src_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
657 | valueOffset = self.edi
658 | replacement = struct.pack(self.pack_sizes[size], (self.deref_config(valueOffset, size) - self.r[src_r_index]) & self.modulus[size])
659 | self.config = self.replace_in_buffer(self.config, valueOffset, replacement)
660 | self.eip += 2
661 | self.edi += size
662 | if self.deref_bytecode(self.eip, 1) & 0x80:
663 | self.decode_next_opcode_byte(bXorKey)
664 | print " -> sub_%d stos edi, r[%d]" % (size, src_r_index)
665 | print self.dump_r()
666 |
667 | def instr_stos_xor_byte(self):
668 | # operand: 0x3b
669 | self.instr_stos_xor(1)
670 |
671 | def instr_stos_xor_word(self):
672 | # operand: 0x3c
673 | self.instr_stos_xor(2)
674 |
675 | def instr_stos_xor_dword(self):
676 | # operand: 0x3d
677 | self.instr_stos_xor(4)
678 |
679 | def instr_stos_xor(self, size):
680 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["stos_xor"][size]
681 | src_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
682 | self.eip += 2
683 | valueOffset = self.edi
684 | replacement = struct.pack(self.pack_sizes[size], (self.deref_config(valueOffset, size) ^ self.r[src_r_index]) & self.modulus[size])
685 | self.config = self.replace_in_buffer(self.config, valueOffset, replacement)
686 | self.edi += size
687 | if self.deref_bytecode(self.eip, 1) & 0x80:
688 | self.decode_next_opcode_byte(bXorKey)
689 | print " -> xor_%d stos edi, r[%d]" % (size, src_r_index)
690 | print self.dump_r()
691 |
692 | def instr_lods_byte(self):
693 | # operand: 0x3e
694 | self.instr_lods(1)
695 |
696 | def instr_lods_word(self):
697 | # operand: 0x3f
698 | self.instr_lods(2)
699 |
700 | def instr_lods_dword(self):
701 | # operand: 0x40
702 | self.instr_lods(4)
703 |
704 | def instr_lods(self, size):
705 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["lods"][size]
706 | dst_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
707 | dst_value = self.r[dst_r_index] & (0xFFFFFFFF - self.modulus[size])
708 | dst_value += self.deref_config(self.edi, size)
709 | self.r[dst_r_index] = dst_value
710 | self.eip += 2
711 | if self.deref_bytecode(self.eip, 1) & 0x80:
712 | self.decode_next_opcode_byte(bXorKey)
713 | print " -> lods_%d edi, r[%d]" % (size, dst_r_index)
714 | print self.dump_r()
715 |
716 | def instr_stos_byte(self):
717 | # operand: 0x41
718 | self.instr_stos(1)
719 |
720 | def instr_stos_word(self):
721 | # operand: 0x42
722 | self.instr_stos(2)
723 |
724 | def instr_stos_dword(self):
725 | # operand: 0x43
726 | self.instr_stos(4)
727 |
728 | def instr_stos(self, size):
729 | bXorKey = self.deref_bytecode(self.eip + 1, 1) ^ self.magics["stos"][size]
730 | src_r_index = self.deref_bytecode(self.eip + 1, 1) & 0xF
731 | replacement = struct.pack(self.pack_sizes[size], (self.r[src_r_index]) & self.modulus[size])
732 | self.config = self.replace_in_buffer(self.config, self.edi, replacement)
733 | self.eip += 2
734 | self.edi += size
735 | if self.deref_bytecode(self.eip, 1) & 0x80:
736 | self.decode_next_opcode_byte(bXorKey)
737 | print " -> stos_%d edi, r[%d]" % (size, src_r_index)
738 | print self.dump_r()
739 |
740 | def instr_leave(self):
741 | return True
742 |
743 | ################################
744 | # utility functions
745 | ################################
746 |
747 | def deref(self, buf, offset, size):
748 | return struct.unpack(self.pack_sizes[size], buf[offset:offset + size])[0]
749 |
750 | def deref_bytecode(self, offset, size):
751 | return self.deref(self.bytecode, offset, size)
752 |
753 | def deref_config(self, offset, size):
754 | return self.deref(self.config, offset, size)
755 |
756 | def decode_next_opcode_byte(self, key, offset=0):
757 | # decode the next opcode byte, depending on the XOR key of the function
758 | # in case of a loop function, the next opcode byte sits beyond an offset, thus the parameter
759 | self.bytecode = self.replace_in_buffer(self.bytecode,
760 | self.eip + offset,
761 | chr((self.deref_bytecode(self.eip + offset, 1) ^ key) & 0x7F)
762 | )
763 |
764 | def replace_in_buffer(self, buf, pos, bytes):
765 | if len(buf) <= pos:
766 | raise IndexError("buffer to short to replace at position")
767 | return buf[:pos] + \
768 | bytes + \
769 | buf[pos + len(bytes):]
770 |
771 |
772 | if __name__ == "__main__":
773 | vm_bytecode = "1ac802960208e2e1916affb18705b70550deea058c2aa150fa055dad0e3ac005cdaad205d901ddcb081d8b060abd01cb9d8caa5e018cbefdee0100ce4bf53676c0035cbb75c4b20d4fbdf40d4ab25875c80d7dc9d3a50d1c4cbe0374c4cf0d95a523e888033d11ac0dd60ca9094af30c30d50ca44d910cce82fa0c131ff218fa09a5d9ba70c90ce84109b5e0c9fd99f40ca40bad00d894e7007ae5d5b0b900d0b0db004895e00000ddce0bdd04e7012860970167bdd604392c4894d404e293dba345271c1013cb2a7352273be735b5ecc487c7178e8263324f7d7161b9d4a87df22e0c9c81651d3c39e398db4af41aa59e6cfb8a5bb149ec940b92e5407d00e741131856d68862343e844e3f9c73ef9cc5831c2f4fffbec2ecbeeff3b2728451b1daaceb937906b8ef92e45e7b0f9fb662fd7d45720f11cac48644206661559f6ca5bdcd45af4bff1892920b6f588ae09b887cd61b01e1f01a1814bb4a958981152db53327ef6f41a89b6be426152e0998d0d1e1faab495818ad83b00ba821993f17b3f98e8d17ad7f37de4c04f2ff1ed5f892d1004ebea08b5788abb1132c97ad1a6cbce006bf5f06b43785d53cbbadb6eceef7633049fcd06414c83cf2448051490f0071a5f1f0c003929efa3082c8f5b9e723f543b69865703e733fee6f4b27cd0c7a914b648682426d591f49fc1db3326ae5874ba14310ba9c1de56a240ee6bc8c6b74b100b16693027296c0597b9628d7dec458dd1627b09f60e235d1b4189d9d67b48b47c07b0a78691dc34c12ad2324a03b6ce06fb3d9fbe74b81d4a11f35a624d0df6411acce0ef80906ccace9a40ebf1be842a50eb2a29f33a80ebe4e1338be0e054453238499e1e9b099830e9bcdba0e6e44b888ef99dd03f18f5123a493a80ea30f048a9049cfda245ab9e9915351a4df1edc08fe078008900d5934bd2d8a87d2dda687b503a50c990851f3b708a59741893950ba4d5e8fa0fb74e9ebccdbe46c48f86123e70802b4a3fc5a2d7f3771b7f90919dd5324763460366a3846626e37f8818a131e456eaac0d9fdf0784d482758909c5ffdca677e743552ad2f6456f3ecbceb3a5bc8bf91543b080c4d2b5da0f2ee34e4a97cfccf2921991e5dbcb841e978e78df70e3deb176990d4f527456d79db177c1f696b739d29811f397ef06556a978c4c62728a00dee0c93f8bfcc94ccd10d1004fe9dedcc93cce00ddfbb0c8d9c4383e10cf9c95693f90d2fac3e6dc40de009f6c90929b279ce990ac4d6f109bfd70524b201687042572daef4ad7d9ff44c38be40e011fac61ef8866c44e26548389e8b79ce0009f32fc85e3c44f8581599cad35915c8cd12d94ddbe732334cb8313796e44bed30ad7438773ed996a3aa612570da48725125c3573f8abac9685f836c8f7820c2fc1d593c79a26324df382afda4ee019d601e02c109b8f8e57dca8ef5af3d59f84fc4018c8fa659494803751a77234e6d37a1023464e4df299c3d56cfffabaeb71cf6e713b74d74967eb11bf49ff5d19e4ccb3e34cc0fe3cb17a84c7e2f5c7fc01e4a08cd20626059167f9e3d5dc2ec36fed990d711fec405869201460a971e8605333b9a013f8a55c005b7f9a0012f85a60521329f0500f3a8a6ea01a1c60104ec05b303239a3b8ace02a88d032e38e015a90290f3034c6c01018a0bb47f8a0bffe55bdf8b0349e00353703280e30ec5cefb038e424bdae60ef78fc1034b30c6b3c602bff7dbb0a70264b2c72e820b27d5ee8b025fe9a98dc903de05e5096ace058ff699b30143e0999b11fc05b9c0054ef091d105f0960586e5bd0ec27cd52d9d0e108105f440e29fbac90bfe077ee80458f4778f47b6b7bcb7cc44d80bfc2bd50b1eb20b3aa9a49ac977de003eea96b0cd04c3ea0bffa2bfd5930b8f03f5086f00cb38a303219a88bf38c5388a032b9b03efdfc88885888e03bacbc0faa003a8eedb850311870184910abd8f9933b50ac6d6d350b7a1d603329c0a3c24bf13e7aafc01b0fd099241ff8cc719d20a23c503f610e00193ec9a9809b552f1ebbaa1c209d8bd03daefe70388f73126fd8d93efefc0e984049bae33b7b18e5580898a36302451a3ac13a0c1f8c7837da666958eed920f0c5b341a540f916dd8e1bd00ca5a359ce477036ab0673c9571555316e33855d2e7e237aec35a2227c225ad56e697966b4166e4eef16a279dfbe838a499ca2bea35d2512ae006333f392e861df9470f7bb5b490c473a43a12b6fe3f46fdedb4f485fd8642367f6280794677c9cf8e205aafc78855d47928c06560e990b43c2b1a9101ece0b023f3b7bf1449de7da80e11ca0a03e270ad83c4e76269e568ef586b624e0e4d41a6a1ced08b8ec0a0fd47a0cff77add896322392f7f10f5d5781a38a3f4aea31ecd4a0c0b3b9af55273e8c9e4880ad2cfcd8d8aaab90af00fb8ad8bc1e1ff880f74c50fc4fdff8e0f10d5bec98c0f872e2e3e82ffd60e6c50d30e3f458e0e3c505801a50fc532dab182a9c63529f17e7ba2f0edb3a4ecdb7b0d86e80096ac06e4f3d1656b47a579660f1f788b2ba860fac75a97b1925938f1b2c01000d70ba0b507fde6d5bbf70408ae04a8ca8174de0b5af7531cdc4bcdb0da0067d40781d30de69904c95ae504ef0461e4d70457d3c0076e1fe604e7cb044fee140da6043095438dc607a1613e97ba00493ac204ec9100fa9e0499ae0a5567c70fae8a0a38c40f58983678ed0501b80517ee0a81b30558bb0f8b21b263f4ff8c5be1a5c80f37de0fcb346994ce548003f408db39a08f9808336cbd388b0b241089d0ff38a10306b86c288ab8f8009f5da78bc00321dab8cd0305c223689f0384f20bd13bb60b8f08b00bba0b916368199c30ef08be30b803b41301f8a8031a3acc0b840372c3b503b9e2cb0be3ecfc01e20ae01cde0138527a38d0015550cf07a9ba9273fdaac401f4f97fcc800139970180828117c8a79017e10779c3b501e3ef97fcc70300cda6e50a27dd10e211418fe7504f1353fc5cfb498b5917da8a85739ae391c8bbcfc21e8640efa9165cda326eccd26a71fc6b56c1e9b75d106f251b661e4b893fc48e41731c92bd33d9b1b0275cb5c494c5b49f65606c1ec20b930f0fac0dbb6b1541438928ad14abdf4c527e8fd70b4f08f62b7d829859f977fad3c8d492f4a90c2babd9054f96dc8aadc01df1436f92fd0e0e5104a29b8b64dfc86e0a31c7579a595cdf177078dcf282308d2cda5341acced0741ef4e4458dec56520b892272d8ca6e59f077a36382d248ed9ce8ddc1b23545adee0d8941f755aa93fb4dcdc431e0d27d600f3dfa2cf10ff90cad818c0ccb947adecc0fa6dffc890fa90191840466a2c60414f401ddb9048b58336bcd052f978615a1158e04d426b1ea08d1eb1013bc0f74cb0fce2475b8c988faffba0afa0dd188e3080586cae0850acd8c831cca0f0deb0ff954f4f6ffffe80f12edaa17e40fe34094edfb0f62fcc0afc60f97cc252cfcb094af05923432d7eaa724dc8d293ba46e205d0c1758c46d7e2939db6e677d3cf857574ee3deec824c50a8bd9783559957277ded905f4de7efb3332cc105144b67612236d7a767c24867c7e0e51da6a1beaa7b23b7e52b00659d1b8337e1ac5af08c3305038ba32d3b011a88581be90a7bd15703acb32c8d40824d3ba36cc50b539203cef55992f0100aafb380b5be30a3b2f56857e6e8f0ff01d306e4089bae2f50c2689c0621c7085aa2acb1d268d806ef7afe84f406d732df068bb588de68f406c805a00cc7d10ec8e7ee810ed63dfe05d759f40523a00727548507e0d6ca7ca905ac95cca00506238e07f0dc056e6eb5578205c8b99b61ce5ed6055a4946fcb305d302e105c588e60263d0025f78e35cd80213ee02d0ad02f98702b685020e90dd798a0206ab057301b502ec0df7dacb0d051c80d6dd0dd0acddab066446da06a68033dfcf0db867908cdc0dcad9f60af7f00574520665d659dd4877ea89e008cc6b389756be182dd3ec18ecca383a86bd3d5c60d07d3d2012feb441b40f3506be26a02be6e3aa03ee3e009b0d0f3f02a91cdf540bf0631a217080372d57e874f31ff82dabdbdc8e403047a53302b71859a5da702681ecf8640d03d9423a88a1ed9d4a33ea9f15d0dd772442bf13f2c751969f37ec8e41bc1cb1067d052dc9c1af3914e661906cdbc15c754002d6bbb94c18a0c0de86d60a9e11bbdb9db2f6e71e83df4a42e9de4bbcaa1d7927a65a0453a6fd9a595845b4a5f2f2722e28c8e87add9d24913c70eaf32e7e80484f5e90e8cce40a4d841ca0caef9e87cc41b18de5b8c68753fe9bb04e14aeadfcd935dc0100cbabb303a50d33348f0322e8b70305c226169c038b02b67ea6079508384ed707f78f025ce8e207cee4d767b522cd0f12a907f25bd222ef0f2d295922a3fa9677ef0a4c619ea0d60258397922d07ac3f289f7e602a47e9b23ac1d60d43c5ef68080f02457cbc66037b299c018c31be4c3c401b37d6fa66093b231645fef7eb495fecbb95df0e9bb0f02251869ea7df0f6f89d9e2526ef1ee74dec60749d008e80ecba892197d16569e26b742f35a88f4e018f44553ef43dfc1b5f67439417a45a496d70f224c4991e4f0c6b3a2c0b9aeca31e214e11f4bb8f4caad90cffccbd35bb466aaf59eaa95606f555764b0c92b6091c3ef82a3a5ce4e7e6da7aaedaefeb63be0d0a15eb63a63bb84fb654907c7dd817ab62aefecc0337f0d3e6b785fae417b42a858e511e5c4c62f832e9700b9b858b48a56301a05d86ecde7914840ca8bd00f06dddc6f40098a906cde3007fdac502a0319b06d783892dc906200a8fccd200ed8a02d0a80cfc94dc0059a160fd00280c4e90c800dd0fef0d7dd80f8bae386684fd820fa178947bca0fe9a9ea5303710015070eee06b8e7135f668b2bc047f048b50ebeacf4191160ff761304c800fc988e22e0c3bc5d85edd450ddaebca114f3ae1ccb92cca1989178b33e7df815e6f1266ae899dd9e0041303f49b3f85bdac8713e7373c8672182ec503a99757ac962db0d9b10d26c5247c28efb6784067698a93cfbc1830837422c6639d750beccb1765b75f4dbaa0e8efa62a0c1dd23b2790723fae500c1deffbdd84f2fdf2e7aadebb7d29e6ea0eafcba0400d9e522b09e8d7315268106158ff1354db5916a524975ee1a2ebfb8729c2940b96fc6a8d7fbc1a3791c03c6acabab4ea13bdc8720a05a2d6a6df9a829079c3a7058746487e146ff789b0aa0945b8d877effe2785e6c246f7751ebae10854d67f5aced5b802ef47c0300751dab0de930dc72234c44b9f21420f7fef5d104ad958e040f8c08ca2ad80261d204870786aa960e92027411d00e68a20972d0078baf0e48cbe0e98c0e11b85aa18f0e039fb40784e1097668df07f2dc076f22ff075a492312c807dc0cd5f10cbcc00cb55039fe80079da50c4d00c607bddc077471eb0cdb9d9b221cb4ac7c7518c71e2a1ea1a0cade6bc6a6cd03bfa759545a82316666c03614748a2c47bfb2065d4b9c237e23c597ab4d2db7688c7b0b9d3f41fa552f83c15fabbf236326c55b43bd20f11e9b29028673f1b9cd3d1dcf682a1240b01ef60a36ba113f11960b37bdb5d99e443d7c12858cc8cbaddacacb409ff25619cf3874af1c35c98fcd1461f789d04acd6250cec13572011bb9465299ca0f44f9d2d78301f00fde587cbc8ffef30fd38b737fd20ee1ae01a888e1c808be30830e09f7e1f9080eee0e42b80fc0aa0ed308e80e318e0822b296adab8ef9eeb308bc0000".decode("hex")
774 | vm_cconfig = "b1a4d432c9e0d7a5a65376312a3aa31d5c0f3d12d85d908ceabaea8138bb66f3e52407d63fd7d46f4e963aaaf99f25c59eab5240802a3872831ff4e7d51b81e1cbf463821da018f084d4474a7bd1f84dcce99a19ecbf7db1815a8bb7a8463f9c404178cf5107951af6ac2af34babc325b9243602f5e6701fd6f3f3465943b69b63698c7c80a45a28d0e1e43a2f9d22fffbbaa8e7970b216b47684b596f748f4010b7406e9365593bd106526b856e4e36103dffee93c463955d9a1732d6b11f9a9bf3a6a8322add2c43c5b4877f991365ecb3a8b6030c4664df321141200ea86ac3caa7ea41359a7184593f9dc8ccc833a06e66099b4d2acd0667d67aee229689ef56382195287ef9ec2635db14b0a4f79daf8f9322885d9db02b81aa6cd8c87ed9f50a6dd2ae5f37e5770871c1f1100ab8604c3533be403594a7f2de364447740f04a4d0cae4ae448fd60bd3d70f5cffd894814f07b050784015f560c0ad26b518895cb5f5310cdb59698e091d98971d411c0c7c8a0002da388af2211b4c6e4e223dec842ab2589c1142d2fbe76fe1b26c25e1a82ccf9b57c96fe71bc772445376c7a774f4dcfcb33cef3272c19d5c2619633a8718c745e219d986ac5090b1d0af9a063f3e80de559938051f26c05d16ab68d5826bcf2149dcf48fcd800a8e4640b559bdda924a5ce620e22d2267183fcd8ceb12d8296ea8ee094e5dee20faa34bc230dbb0cda2860282e39b662f0e94c0a317f39f6a497d58e2f60c796951213512933db8fe31125f6b896c32acf2f514930a9f209ac562e2713abd5c20ec1b99b5963a1e76fcd0e3d4e35e3f895e50a41cda56ffcf349086d270bc0684733c34e1ad96edb1b76272105d083fd62383221bc496a4b410a104ee3e95d07fc85d78e2dcbb4b7cb71875bac53be4996168744bcec430ecd8b7eb9f359c233e836400711a4c0e8f0c818fde7fa2a9d75e40aa8e28199b419ccbdb29c31bc54a5557547667cea73b73ba4c799a791f9b80f59ac0109f6695360f7bf757c759d22035cb4ec11b5f262c71a029bd18d4e11f0e5c101f2b3afecf354eea7940931e13e9dbafbb4f4da37573456eec7115a8fe3887909987a05b6aa96de6b50ee0393d49e9ddae6f27f45e35a41a7b1d9214570532ab53688b672582ffe36c778bbd59bf9c83b22d32e5d198fac241ced87a8d6631a1a58a35c19b37d93e47fd9588e3e10bbccca06ffb6af744246a037f95b85a7371395f363074455ab362511136a1e5547cc84d782d24d9284f2befe59308008408e557fcf6034d72e6d430b4780ab7ac1e404d64c9de6f".decode("hex")
775 | vm_dconfig = "96c73597606994ee41517aa32abff61d376dadfad71f1f4c2e7b2b02b71bd5a42ee14844ad8a17b11586c8ed0a000a001359675049712e0a2fc852621a6a80e1c049ac3c56d85584f5d50a9d42662df14e68f765bb04bc8d214d6f7a696c6c612f352e322028636f6d70617469626c653b204d53494520372e303b2057696e646f7773204e5420362e313b20535631290092b671be8b7381f7e1b33d8ff5213429f110fe475cbc74b3ecd2211f9b33f308fcf536e0d0abc36bd5e7756adefddd7728093730ec339c97313179b9e40e3f8e2a2a5c21f5836bf0d632a750000a00a7f77b44dc700cdd70d8abbfc90c8dde5bc45dcaca2380df4e8c9dbb0e01000083056f0d9411d09e058849db973a39392d00190022812c884da02f9a04f8f134d1fbec799ff7687474703a2f2f6c696c6963383831326173732e696e2f736f6369756d2f0049364586a50e358d4b34be3ba533d4036fae1a4d81e95419e98c1fe63da3e0d230e8fa02624544447d95baf37dab721c4f95d2de9e210117eaa19b3ddaeca989d3a5d05bc9c0c8da554110da0847e004004a6030b8a117162447a626fedeb6b45bf42f588186aa95fcc20f407f1207f3fd1d80118dbb057e8901a86a5182ef9bef5e7fc3339fd3be9aa06e55d911cd63723f9a378695223aea6309d17ddf3c85b86a286286142a9c563082010a0282010100b472d4c02e470e8031b5c604d10baa4c514f35ecb0b2b52abe6a3f36d4330f00201afc78b0077b7cbd87d1764e1c037c12be03ef01c99eac7b076f5c12f630001a88164409e6b45bfe07e23405c352dd31c4456b7ce97f1802bd9833b60dca07842598fc6c9b2b03916bde63e66d8c0fcc8659278fbc8a0178500feba3abf5c76bdbd89b0706f6303490363516cf2ee186734f962ece36aac5f8e67b1cce634ef740a2a95c360ec3dd94b78076a3b9865520ee096b11a039cac7ee4a5efd7cf17034cfe64224c4ad0329294e77b8d66d4a4839e8f0031ffa2e5124751e14bfe75371befc20f2adc378e737702a0995f9977c12e4a86bd425abc4e672cec0b3290203010001f5758c31782de003d8cd04ca2a2262d6cf1cfabd53255f4f95b102cc2817b355fa9f65a133dc32f1603c9f46d1dd20d13fa2dfabb38747006f006c00640041000000b7e8a99a95eb0597b493457191f27eff80a431cca8bd70b24f0042aa585249e2096ea21012d90d07cb194e87be22d35a6511969c351c455bdbc9a160c55f244be49ae6e6b0a3c1b36d3f0000100085db1758aaa166cb6a54b5e84093f956806fcfd63cc3783269c4216f".decode("hex")
776 | print "target from 8fbba8c234bf9fa0c05d4fe2773086a8: "
777 | print hexdump(vm_dconfig)
778 | print "Baseconfig length: 0x%x (%d) bytes\n" % (len(vm_dconfig), len(vm_dconfig))
779 | ctx = VmContext(vm_bytecode, vm_cconfig)
780 | ctx.run()
781 | if ctx.config == vm_dconfig:
782 | print "Success!"
783 |
784 |
--------------------------------------------------------------------------------