├── .gitignore ├── MANIFEST ├── README.rst ├── requirements.txt ├── setup.py └── src ├── __init__.py ├── bits.py ├── compression ├── __init__.py ├── aplib.py ├── lznt1.py └── sfx.py ├── crypto ├── __init__.py ├── rabbit.py ├── rc2.py ├── rc6.py └── spritz.py ├── disasm ├── __init__.py ├── eng.py ├── hash.py └── vmext.py ├── hash.py ├── log.py ├── malware ├── __init__.py ├── isfb.py ├── pushdo.py └── trickbot.py ├── memory.py ├── misc.py ├── parse.py ├── rnd.py ├── so ├── _aplib.so ├── _lzmat.so └── _serpent.so ├── struct ├── __init__.py └── cparse.py └── winapi ├── __init__.py ├── crypto.py └── hashdb.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | *.*~ 4 | #.*# 5 | #.* 6 | 7 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | # file GENERATED by distutils, do NOT edit 2 | setup.py 3 | mlib/__init__.py 4 | mlib/bits.py 5 | mlib/log.py 6 | mlib/memory.py 7 | mlib/misc.py 8 | mlib/parse.py 9 | mlib/rnd.py 10 | mlib/compression/__init__.py 11 | mlib/compression/aplib.py 12 | mlib/compression/lznt1.py 13 | mlib/crypto/__init__.py 14 | mlib/crypto/rc2.py 15 | mlib/crypto/rc6.py 16 | mlib/so/_aplib.so 17 | mlib/so/_serpent.so 18 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==== 2 | mLib 3 | ==== 4 | 5 | Your bag of handy codez for malware researchers 6 | 7 | ------- 8 | Content 9 | ------- 10 | 11 | - crypto - couple of wrappers around `pycrypto `_ and other (stolen/borrowed) crypto things, so far: 12 | 13 | - rc2 14 | - rc4 + key derivation from m$ 15 | - rc6 16 | - spritz 17 | - rsa + pkcs 18 | - rolling xor 19 | - xor 20 | - xtea 21 | - serpent 22 | 23 | 24 | - compression - same thing for compression algos so far: 25 | 26 | - lznt1 27 | - lzmat 28 | - gzip 29 | - aplib 30 | 31 | - disasm - wrapper around `capstone `_ and some additions ;] 32 | - malware - codez from malware so far, 33 | 34 | - isfb 35 | 36 | - winapi - various things related to windows api, 37 | 38 | - resolve api name from hash 39 | - port of `CryptExportKey`/`CryptImportKey` returning object from `mlib.crypto` 40 | 41 | - bits - various things that operates on bits 42 | - hash - some old school hashes used in api resolving 43 | - rnd - random wrappers 44 | - memory - useful class for operation on blobs of data, reading bytes,dwords etc 45 | - parse - parse all the things! especially m$ crypto keys 46 | 47 | ------- 48 | License 49 | ------- 50 | 51 | Do whatever you want with this, 52 | Just remember to credit the authors and buy them beers when you meet them;] 53 | 54 | ------------- 55 | Documentation 56 | ------------- 57 | 58 | I wish... 59 | 60 | --------- 61 | Contact 62 | --------- 63 | 64 | If you have any questions, hit me up - mak@malwarelab.pl 65 | 66 | -- 67 | 68 | Enjoy and Happy hacking! 69 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyasn1 2 | pycrypto 3 | bitarray 4 | capstone 5 | pefile 6 | enum34 7 | pycparser[cstruct] 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | try: 4 | from setuptools import setup 5 | except ImportError: 6 | from distutils.core import setup 7 | 8 | def long_description(): 9 | with open('README.rst') as f: 10 | d=f.read() 11 | return d 12 | 13 | setup(name='mLib', 14 | version='1.2.5', 15 | description='Library contains functions commonly used in malware research', 16 | long_description=long_description(), 17 | author='Maciej Kotowicz', 18 | author_email='mak@lokalhost.pl', 19 | url='https://github.com/mak/mlib', 20 | package_dir={'mlib': 'src'}, 21 | packages=['mlib', 'mlib.compression', 'mlib.crypto', 22 | 'mlib.disasm', 'mlib.winapi', 'mlib.malware', 23 | 'mlib.struct'], 24 | package_data={'mlib': ['so/*so']}, 25 | classifiers=[ 26 | 'Development Status :: 5 - Production/Stable', 27 | 'License :: Public Domain', 28 | 'Operating System :: POSIX :: Linux', 29 | 'Programming Language :: Python :: 2 :: Only', 30 | 'Programming Language :: Assembly', 31 | 'Programming Language :: C', 32 | 'Topic :: Utilities' 33 | ]) 34 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mak/mlib/b6114487b8dc5a8a819c207d3f28a41ddd20c09f/src/__init__.py -------------------------------------------------------------------------------- /src/bits.py: -------------------------------------------------------------------------------- 1 | 2 | MASK_16 = 2 ** 16 - 1 3 | MASK_32 = 2 ** 32 - 1 4 | MASK_64 = 2 ** 64 - 1 5 | 6 | 7 | def uint(n, bits): 8 | mask = globals().get('MASK_%d' % bits, None) 9 | if not mask: 10 | mask = 2 ** bits - 1 11 | return n & mask 12 | 13 | 14 | def uint32(num): 15 | return uint(num, 32) 16 | 17 | 18 | def bswap32(n): 19 | return (((n & 0x000000FF) << 24) | 20 | ((n & 0x0000FF00) << 8) | 21 | ((n & 0x00FF0000) >> 8) | 22 | ((n & 0xFF000000) >> 24)) 23 | 24 | 25 | def bswap16(n): 26 | return (((n & 0x000000FF) << 8) | 27 | ((n & 0x0000FF00) >> 8)) 28 | 29 | 30 | def bswap64(n): 31 | return (((n & 0x00000000000000FF) << 56) | 32 | ((n & 0x000000000000FF00) << 40) | 33 | ((n & 0x0000000000FF0000) << 24) | 34 | ((n & 0x00000000FF000000) << 8) | 35 | ((n & 0x000000FF00000000) >> 8) | 36 | ((n & 0x0000FF0000000000) >> 24) | 37 | ((n & 0x00FF000000000000) >> 40) | 38 | ((n & 0xFF00000000000000) >> 56)) 39 | 40 | 41 | def bswap(n, bits): 42 | if bits not in (16, 32, 64): 43 | raise Exception("i can't swap those bits") 44 | return globals().get('bswap%d' % bits)(n) 45 | 46 | 47 | def rol(x, n, b=32): 48 | n = (b - 1) & n 49 | return x << n | 2 ** n - 1 & x >> b - n 50 | 51 | def ror(n, bits, b=32): 52 | return rol(n, b - bits, b) 53 | 54 | def byte0(x): return x & 0xff 55 | def byte1(x): return (x>>8) & 0xff 56 | def byte2(x): return (x>>16) & 0xff 57 | def byte3(x): return (x>>24) & 0xff 58 | 59 | -------------------------------------------------------------------------------- /src/compression/__init__.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import struct 3 | 4 | from . import lznt1 as _lznt1 5 | from . import aplib as _aplib 6 | from . import sfx as _sfx 7 | from mlib.misc import load_dll 8 | 9 | 10 | class lznt1: 11 | @classmethod 12 | def decompress(cls, data): 13 | return _lznt1.decompress_data(data) 14 | 15 | 16 | class lzmat: 17 | LIB = load_dll("so/_lzmat.so") 18 | 19 | @classmethod 20 | def _hash(d): 21 | return cls.LIB.hash(ctypes.c_buffer(d), ctypes.c_uint(len(d))) 22 | 23 | @classmethod 24 | def decompress(cls, d): 25 | dec_size = ctypes.c_uint(struct.unpack("I", d[:4])[0]) 26 | out = ctypes.c_buffer(dec_size.value) 27 | cls.LIB.lzmat_decode(out, ctypes.byref(dec_size), d[4:], len(d[4:])) 28 | return out.raw 29 | 30 | 31 | class gzip: 32 | 33 | @classmethod 34 | def decompress(cls, d): 35 | if not d.startswith("\x1f\x8b\x08\x00"): 36 | return d 37 | 38 | import subprocess 39 | p = subprocess.Popen(['gunzip', '-', '-c', '-n'], stdin=subprocess.PIPE, 40 | stdout=subprocess.PIPE, 41 | stderr=subprocess.PIPE) 42 | r, _ = p.communicate(d) 43 | return r 44 | 45 | def compress(cls, d): 46 | import subprocess 47 | p = subprocess.Popen(['gzip', '-', '-c', '-n'], 48 | stdin=subprocess.PIPE, stdout=subprocess.PIPE) 49 | r, _ = p.communicate(d) 50 | return r 51 | 52 | 53 | class aplib: 54 | 55 | @classmethod 56 | def decompress(cls, data, s=0): 57 | return _aplib.decompress(data, s) 58 | 59 | class sfx: 60 | 61 | @classmethod 62 | def decompress(cls,data, unpack = False): 63 | return _sfx.decompress(data, unpack) 64 | -------------------------------------------------------------------------------- /src/compression/aplib.py: -------------------------------------------------------------------------------- 1 | __all__ = ['unpack', 'decompress'] 2 | 3 | # this is a standalone single-file merge of aplib compression and decompression 4 | # taken from my own library Kabopan http://code.google.com/p/kabopan/ 5 | # (no other clean-up or improvement) 6 | 7 | # Ange Albertini, BSD Licence, 2007-2011 8 | 9 | # from kbp\comp\_lz77.py ################################################## 10 | 11 | 12 | def find_longest_match(s, sub): 13 | """returns the number of byte to look backward and the length of byte to copy)""" 14 | if sub == "": 15 | return 0, 0 16 | limit = len(s) 17 | dic = s[:] 18 | l = 0 19 | offset = 0 20 | length = 0 21 | first = 0 22 | word = "" 23 | 24 | word += sub[l] 25 | pos = dic.rfind(word, 0, limit + 1) 26 | if pos == -1: 27 | return offset, length 28 | 29 | offset = limit - pos 30 | length = len(word) 31 | dic += sub[l] 32 | 33 | while l < len(sub) - 1: 34 | l += 1 35 | word += sub[l] 36 | 37 | pos = dic.rfind(word, 0, limit + 1) 38 | if pos == -1: 39 | return offset, length 40 | offset = limit - pos 41 | length = len(word) 42 | dic += sub[l] 43 | return offset, length 44 | 45 | # from _misc.py ############################### 46 | 47 | 48 | def int2lebin(value, size): 49 | """ouputs value in binary, as little-endian""" 50 | result = "" 51 | for i in xrange(size): 52 | result = result + chr((value >> (8 * i)) & 0xFF) 53 | return result 54 | 55 | 56 | def modifystring(s, sub, offset): 57 | """overwrites 'sub' at 'offset' of 's'""" 58 | return s[:offset] + sub + s[offset + len(sub):] 59 | 60 | 61 | def getbinlen(value): 62 | """return the bit length of an integer""" 63 | result = 0 64 | if value == 0: 65 | return 1 66 | while value != 0: 67 | value >>= 1 68 | result += 1 69 | return result 70 | 71 | 72 | class _bits_decompress(): 73 | """bit machine for variable-sized auto-reloading tag decompression""" 74 | 75 | def __init__(self, data, tagsize): 76 | self.__curbit = 0 77 | self.__offset = 0 78 | self.__tag = None 79 | self.__tagsize = tagsize 80 | self.__in = data 81 | self.out = "" 82 | 83 | def getoffset(self): 84 | """return the current byte offset""" 85 | return self.__offset 86 | 87 | # def getdata(self): 88 | # return self.__lzdata 89 | 90 | def read_bit(self): 91 | """read next bit from the stream, reloads the tag if necessary""" 92 | if self.__curbit != 0: 93 | self.__curbit -= 1 94 | else: 95 | self.__curbit = (self.__tagsize * 8) - 1 96 | self.__tag = ord(self.read_byte()) 97 | for i in xrange(self.__tagsize - 1): 98 | self.__tag += ord(self.read_byte()) << (8 * (i + 1)) 99 | 100 | bit = (self.__tag >> ((self.__tagsize * 8) - 1)) & 0x01 101 | self.__tag <<= 1 102 | return bit 103 | 104 | def is_end(self): 105 | return self.__offset == len(self.__in) and self.__curbit == 1 106 | 107 | def read_byte(self): 108 | """read next byte from the stream""" 109 | if type(self.__in) == str: 110 | result = self.__in[self.__offset] 111 | elif hasattr(self.__in, 'read'): 112 | result = self.__in.read(1) 113 | self.__offset += 1 114 | return result 115 | 116 | def read_fixednumber(self, nbbit, init=0): 117 | """reads a fixed bit-length number""" 118 | result = init 119 | for i in xrange(nbbit): 120 | result = (result << 1) + self.read_bit() 121 | return result 122 | 123 | def read_variablenumber(self): 124 | """return a variable bit-length number x, x >= 2 125 | 126 | reads a bit until the next bit in the pair is not set""" 127 | result = 1 128 | result = (result << 1) + self.read_bit() 129 | while self.read_bit(): 130 | result = (result << 1) + self.read_bit() 131 | return result 132 | 133 | def read_setbits(self, max_, set_=1): 134 | """read bits as long as their set or a maximum is reached""" 135 | result = 0 136 | while result < max_ and self.read_bit() == set_: 137 | result += 1 138 | return result 139 | 140 | def back_copy(self, offset, length=1): 141 | for i in xrange(length): 142 | self.out += self.out[-offset] 143 | return 144 | 145 | def read_literal(self, value=None): 146 | if value is None: 147 | self.out += self.read_byte() 148 | else: 149 | self.out += value 150 | return False 151 | 152 | 153 | # from kbp\comp\aplib.py ################################################### 154 | """ 155 | aPLib, LZSS based lossless compression algorithm 156 | 157 | Jorgen Ibsen U{http://www.ibsensoftware.com} 158 | """ 159 | 160 | 161 | def lengthdelta(offset): 162 | if offset < 0x80 or 0x7D00 <= offset: 163 | return 2 164 | elif 0x500 <= offset: 165 | return 1 166 | return 0 167 | 168 | 169 | class a_decompress(_bits_decompress): 170 | def __init__(self, data): 171 | _bits_decompress.__init__(self, data, tagsize=1) 172 | self.__pair = True # paired sequence 173 | self.__lastoffset = 0 174 | self.__functions = [ 175 | self.__literal, 176 | self.__block, 177 | self.__shortblock, 178 | self.__singlebyte] 179 | return 180 | 181 | def __literal(self): 182 | self.read_literal() 183 | self.__pair = True 184 | return False 185 | 186 | def __block(self): 187 | b = self.read_variablenumber() # 2- 188 | if b == 2 and self.__pair: # reuse the same offset 189 | offset = self.__lastoffset 190 | length = self.read_variablenumber() # 2- 191 | else: 192 | high = b - 2 # 0- 193 | if self.__pair: 194 | high -= 1 195 | offset = (high << 8) + ord(self.read_byte()) 196 | length = self.read_variablenumber() # 2- 197 | length += lengthdelta(offset) 198 | self.__lastoffset = offset 199 | self.back_copy(offset, length) 200 | self.__pair = False 201 | return False 202 | 203 | def __shortblock(self): 204 | b = ord(self.read_byte()) 205 | if b <= 1: # likely 0 206 | return True 207 | length = 2 + (b & 0x01) # 2-3 208 | offset = b >> 1 # 1-127 209 | self.back_copy(offset, length) 210 | self.__lastoffset = offset 211 | self.__pair = False 212 | return False 213 | 214 | def __singlebyte(self): 215 | offset = self.read_fixednumber(4) # 0-15 216 | if offset: 217 | self.back_copy(offset) 218 | else: 219 | self.read_literal('\x00') 220 | self.__pair = True 221 | return False 222 | 223 | def do(self): 224 | """returns decompressed buffer and consumed bytes counter""" 225 | self.read_literal() 226 | while True: 227 | if self.__functions[self.read_setbits(3)](): 228 | break 229 | return self.out, self.getoffset() 230 | 231 | 232 | # end of Kabopan 233 | import StringIO 234 | import ctypes 235 | 236 | from mlib.misc import load_dll 237 | aPLIB = load_dll('so/_aplib.so') 238 | 239 | 240 | def unpack(data, s=0): 241 | cin = ctypes.c_buffer(data) 242 | cout = ctypes.c_buffer(s if s else len(data) * 20) 243 | n = aPLIB.aP_depack(cin, cout) 244 | return cout.raw[:n] 245 | 246 | 247 | def decompress(d, s): 248 | try: 249 | r = a_decompress(StringIO.StringIO(d)).do()[0] 250 | except IndexError: 251 | r = unpack(d, s) 252 | return r 253 | -------------------------------------------------------------------------------- /src/compression/lznt1.py: -------------------------------------------------------------------------------- 1 | # Rekall Memory Forensics 2 | # Copyright 2014 Google Inc. All Rights Reserved. 3 | # 4 | # Author: Michael Cohen scudette@google.com. 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or (at 9 | # your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | # General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, write to the Free Software 18 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | # 20 | 21 | """Decompression support for the LZNT1 compression algorithm. 22 | 23 | Reference: 24 | http://msdn.microsoft.com/en-us/library/jj665697.aspx 25 | (2.5 LZNT1 Algorithm Details) 26 | 27 | https://github.com/libyal/reviveit/ 28 | https://github.com/sleuthkit/sleuthkit/blob/develop/tsk/fs/ntfs.c 29 | """ 30 | import array 31 | import cStringIO 32 | 33 | import struct 34 | 35 | __all__ = ['decompress_data'] 36 | 37 | 38 | def get_displacement(offset): 39 | """Calculate the displacement.""" 40 | result = 0 41 | while offset >= 0x10: 42 | offset >>= 1 43 | result += 1 44 | 45 | return result 46 | 47 | 48 | DISPLACEMENT_TABLE = array.array( 49 | 'B', [get_displacement(x) for x in xrange(8192)]) 50 | 51 | COMPRESSED_MASK = 1 << 15 52 | SIGNATURE_MASK = 3 << 12 53 | SIZE_MASK = (1 << 12) - 1 54 | TAG_MASKS = [(1 << i) for i in range(0, 8)] 55 | 56 | 57 | def decompress_data(cdata): 58 | """Decompresses the data.""" 59 | 60 | in_fd = cStringIO.StringIO(cdata) 61 | output_fd = cStringIO.StringIO() 62 | block_end = 0 63 | 64 | while in_fd.tell() < len(cdata): 65 | block_offset = in_fd.tell() 66 | uncompressed_chunk_offset = output_fd.tell() 67 | 68 | block_header = struct.unpack("= block_end: 83 | break 84 | 85 | if header & mask: 86 | pointer = struct.unpack("> (12 - displacement)) + 1 91 | symbol_length = (pointer & (0xFFF >> displacement)) + 3 92 | 93 | output_fd.seek(-symbol_offset, 2) 94 | data = output_fd.read(symbol_length) 95 | 96 | # Pad the data to make it fit. 97 | if 0 < len(data) < symbol_length: 98 | data = data * (symbol_length / len(data) + 1) 99 | data = data[:symbol_length] 100 | 101 | output_fd.seek(0, 2) 102 | 103 | output_fd.write(data) 104 | 105 | else: 106 | data = in_fd.read(1) 107 | 108 | output_fd.write(data) 109 | 110 | else: 111 | # Block is not compressed 112 | data = in_fd.read(size + 1) 113 | output_fd.write(data) 114 | 115 | result = output_fd.getvalue() 116 | 117 | return result 118 | -------------------------------------------------------------------------------- /src/compression/sfx.py: -------------------------------------------------------------------------------- 1 | import libarchive 2 | import locale 3 | from mlib.log import get_logger 4 | 5 | log = get_logger(__file__) 6 | locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') 7 | 8 | 9 | class sfx_ent: 10 | 11 | def __init__(self,ent): 12 | self.ent = ent 13 | self._data = self._get_data() 14 | for x in dir(ent): 15 | if x.startswith('__'): 16 | continue 17 | setattr(self,x, getattr(ent,x)) 18 | 19 | def _get_data(self): 20 | r = [] 21 | for b in self.ent.get_blocks(): 22 | r.append(b) 23 | return ''.join(r) 24 | 25 | @property 26 | def data(self): 27 | if not self._data: 28 | self._data = self._get_data() 29 | return self._data 30 | 31 | 32 | class sfx_archive: 33 | 34 | def __init__(self, data, unpack = True): 35 | self._data = data 36 | self._ents = {} 37 | self._unpacked = unpack 38 | 39 | def _unpack(self): 40 | with libarchive.memory_reader(self._data) as archve: 41 | for ent in archve: 42 | e = sfx_ent(ent) 43 | self._ents[unicode(e.pathname)] = e 44 | self._unpacked = True 45 | 46 | def get_file(self, pathname): 47 | if not self._unpacked: 48 | self._unpack() 49 | 50 | return self._ents.get(unicode(pathname),None) 51 | 52 | def __iter__(self): 53 | if not self._unpacked: 54 | self._unpack() 55 | return iter(self._ents.values()) 56 | 57 | 58 | 59 | 60 | def decompress(data, unpack = True): 61 | 62 | if not data.startswith('MZ') or '!Require Windows' not in data: 63 | log.debug('[-] not an sfx archive (1)') 64 | raise StopIteration 65 | 66 | idx = data.find('!@InstallEnd@!\r\n') 67 | if idx == -1: 68 | log.debug('[-] not an sfx archive (2)') 69 | raise StopIteration 70 | 71 | data = data[idx+16:].lstrip() 72 | if data[0:2] != '7z': 73 | log.debug('[-] not an sfx archive (3)') 74 | raise StopIteration 75 | 76 | return sfx_archive(data, unpack) 77 | -------------------------------------------------------------------------------- /src/crypto/__init__.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import operator 3 | import itertools 4 | import sys 5 | import struct 6 | 7 | from Crypto.Cipher import AES 8 | from Crypto.Cipher import ARC4 as RC4 9 | from Crypto.Cipher import PKCS1_v1_5 10 | from Crypto.PublicKey import RSA 11 | 12 | from mlib.misc import load_dll, chunks 13 | from mlib.bits import rol 14 | 15 | from . import rc6 as _rc6 16 | from . import rc2 as _rc2 17 | from . import spritz as _spritz 18 | from . import rabbit as _rabbit 19 | try: 20 | from ctypes import c_buffer 21 | except ImportError: 22 | ## Jython does'nt have it... so lets copy def from cpython 23 | def create_string_buffer(init, size=None): 24 | if isinstance(init, bytes): 25 | if size is None: 26 | size = len(init)+1 27 | buftype = c_char * size 28 | buf = buftype() 29 | buf.value = init 30 | return buf 31 | elif isinstance(init, int): 32 | buftype = c_char * init 33 | buf = buftype() 34 | return buf 35 | raise TypeError(init) 36 | 37 | def c_buffer(init, size=None): 38 | return create_string_buffer(init, size) 39 | 40 | 41 | def rsa(k): 42 | return RSA.importKey(k) 43 | 44 | 45 | def rsa_pkcs(k): 46 | return PKCS1_v1_5.new(rsa(k)) 47 | 48 | 49 | def rsa_new_key(n=1024): 50 | return RSA.generate(n) 51 | 52 | 53 | def rsa_new_pkcs(n=1024): 54 | return PKCS1_v1_5.new(rsa_new_key(n)) 55 | 56 | 57 | class rc2: 58 | 59 | RC2_BLOCK_SIZE = 8 60 | MODE_ECB = 0 61 | MODE_CBC = 1 62 | PADDING_PKCS5 = 1 63 | 64 | @classmethod 65 | def decrypt(cls, d, key, mode, IV=None, padding=None): 66 | return _rc2(key).decrypt(d, mode, IV, padding) 67 | 68 | @classmethod 69 | def encrypt(cls, d, key, mode, IV=None, padding=None): 70 | return _rc2(key).decrypt(d, mode, IV, padding) 71 | 72 | 73 | class aes: 74 | 75 | @classmethod 76 | def decrypt(cls, d, k=None, mode='ecb', _xor = None, *rest): 77 | if not k: 78 | k = cls.key 79 | 80 | mode = getattr(AES, 'MODE_' + mode.upper()) 81 | clean = AES.new(k, mode, *rest).decrypt(d) 82 | if _xor: 83 | return xor(clean, _xor) 84 | return clean 85 | 86 | 87 | class rc4: 88 | 89 | @classmethod 90 | def decrypt(cls, data, key=None, derive_key=None, use_sbox=False, xor=None, mod1=0, mod2=0): 91 | 92 | if not key: 93 | key = cls.key 94 | 95 | if derive_key: 96 | key = derive_key(key) 97 | 98 | if not use_sbox: 99 | cip = RC4.new(key) 100 | return cip.decrypt(data) 101 | 102 | box = map(ord, key) 103 | x = 0 104 | y = 0 105 | out = [] 106 | idx = 0 107 | for byt in data: 108 | x = (x + 1 + mod1) % 256 109 | y = (y + box[x] + mod2) % 256 110 | box[x], box[y] = box[y], box[x] 111 | byt = ord(byt) ^ box[(box[x] + box[y]) % 256] 112 | if xor: 113 | byt ^= ord(xor[idx % len(xor)]) 114 | idx += 1 115 | out.append(chr(byt)) 116 | 117 | return ''.join(out) 118 | 119 | @classmethod 120 | def ms_derive_key(cls, key, hash): 121 | k = getattr(hashlib, hash)(key).digest()[:5] 122 | return k 123 | 124 | encrypt = decrypt 125 | 126 | def visEncry(datA): 127 | i = len(datA) - 1 128 | ret = map(ord, (datA)) 129 | for idx in range(1, len(datA)): 130 | ret[idx] ^= ret[idx - 1] 131 | return ''.join(map(chr, ret)) 132 | 133 | 134 | def visDecry(datA): 135 | i = len(datA) - 1 136 | ret = map(ord, (datA)) 137 | for idx in range(len(datA) - 1, 0, -1): 138 | ret[idx] ^= ret[idx - 1] 139 | return ''.join(map(chr, ret)) 140 | 141 | 142 | def rolling_xor(d, key, rl=8, off=0, add_index=False, xor_index=False): 143 | r = [] 144 | for i, c in enumerate(d): 145 | a = ord(c) ^ key ^ (i if xor_index else 0) 146 | r.append(chr(a & 0xff)) 147 | 148 | key = rol(key, rl) + off 149 | if add_index: 150 | key += i 151 | return ''.join(r) 152 | 153 | 154 | def xor(x, y, xor_index=False): 155 | return ''.join(map(lambda a: chr(ord(a[1][0]) ^ ord(a[1][1]) ^ (a[0] if xor_index else 0)), enumerate(zip(x, itertools.cycle(y))))) 156 | 157 | 158 | class xtea: 159 | 160 | @staticmethod 161 | def xtea_decrypt_block(key, block, n=32, endian="!"): 162 | v0, v1 = struct.unpack(endian + "2L", block) 163 | k = struct.unpack(endian + "4L", key) 164 | delta, mask = 0x9e3779b9L, 0xffffffffL 165 | sum = (delta * n) & mask 166 | for round in range(n): 167 | v1 = (v1 - (((v0 << 4 ^ v0 >> 5) + v0) ^ 168 | (sum + k[sum >> 11 & 3]))) & mask 169 | sum = (sum - delta) & mask 170 | v0 = (v0 - (((v1 << 4 ^ v1 >> 5) + v1) 171 | ^ (sum + k[sum & 3]))) & mask 172 | return struct.pack(endian + "2L", v0, v1) 173 | 174 | @staticmethod 175 | def xtea_encrypt_block(key, block, n=32, endian="!"): 176 | v0, v1 = struct.unpack(endian + "2L", block) 177 | k = struct.unpack(endian + "4L", key) 178 | sum, delta, mask = 0L, 0x9e3779b9L, 0xffffffffL 179 | for round in range(n): 180 | v0 = (v0 + (((v1 << 4 ^ v1 >> 5) + v1) 181 | ^ (sum + k[sum & 3]))) & mask 182 | sum = (sum + delta) & mask 183 | v1 = (v1 + (((v0 << 4 ^ v0 >> 5) + v0) ^ 184 | (sum + k[sum >> 11 & 3]))) & mask 185 | return struct.pack(endian + "2L", v0, v1) 186 | 187 | @staticmethod 188 | def xtea_worker(f, data): 189 | _len = len(data) 190 | assert len(data) % 8 == 0 191 | return ''.join(map(f, chunks(data, 8))) 192 | 193 | @classmethod 194 | def decrypt(cls, data, xkey): 195 | return cls.xtea_worker(lambda c: cls.xtea_decrypt_block(xkey, c), data) 196 | 197 | @classmethod 198 | def encrypt(cls, data, xkey): 199 | return cls.xtea_worker(lambda c: cls.xtea_encrypt_block(xkey, c), data) 200 | 201 | 202 | class rc6: 203 | 204 | @classmethod 205 | def decrypt(cls, d, k, typ='sbox',**kwargs): 206 | if typ == 'str': 207 | rc = _rc6.RC6(k,**kwargs) 208 | def ciph(d, k): return rc.decrypt(d) 209 | else: 210 | if type(k) == str: 211 | k = struct.unpack('I' * (len(k) / 4), k) 212 | 213 | def ciph(d, k): return _rc6.RC6('a' * 16).decrypt(d, k) 214 | 215 | r = [] 216 | for i in range(0, len(d) >> 4): 217 | r.append(ciph(d[i * 16:(i + 1) * 16], k)) 218 | return ''.join(r) 219 | 220 | @classmethod 221 | def encrypt(cls, d, k, typ='sbox',**kwargs): 222 | if typ == 'str': 223 | rc = _rc6.RC6(k,**kwargs) 224 | def ciph(d, k): return rc.encrypt(d) 225 | else: 226 | if type(k) == str: 227 | k = struct.unpack('I' * (len(k) / 4), k) 228 | 229 | def ciph(d, k): return _rc6.RC6('a' * 16).encrypt(d, k) 230 | 231 | r = [] 232 | for i in range(0, len(d) >> 4): 233 | r.append(ciph(d[i * 16:(i + 1) * 16], k)) 234 | return ''.join(r) 235 | 236 | 237 | class spritz: 238 | 239 | _class = _spritz.Spritz(op=operator.xor) 240 | 241 | @staticmethod 242 | def mk_args(data, key): 243 | xdata = data 244 | xkey = key 245 | if type(data) != bytearray: 246 | xdata = bytearray(xdata) 247 | 248 | if type(xkey) != bytearray: 249 | xkey = bytearray(xkey) 250 | return xdata, xkey 251 | 252 | @classmethod 253 | def decrypt(cls, data, key): 254 | data, key = cls.mk_args(data, key) 255 | return str(cls._class.decrypt(key, data)) 256 | 257 | encrypt = decrypt 258 | 259 | class serpent: 260 | LIB = load_dll('so/_serpent.so') 261 | BLOCK_SIZE = 16 262 | 263 | @staticmethod 264 | def align_size(n): 265 | return (n + (serpent.BLOCK_SIZE - 1)) & (~(serpent.BLOCK_SIZE - 1)) 266 | 267 | @classmethod 268 | def decrypt(cls, data, key): 269 | clen = cls.align_size(len(data)) 270 | ckey = c_buffer(key) 271 | cin = c_buffer(data) 272 | cout = c_buffer(clen) 273 | cls.LIB.decrypt(cin, clen, ckey, cout) 274 | return cout.raw 275 | 276 | @classmethod 277 | def encrypt(cls, data, key): 278 | clen = cls.align_size(len(data)) 279 | data = data.ljust(clen, "\x00") 280 | ckey = c_buffer(key) 281 | cin = c_buffer(data) 282 | cout = c_buffer(clen) 283 | cls.LIB.encrypt(cin, clen, ckey, cout) 284 | return cout.raw 285 | 286 | 287 | 288 | class rabbit: 289 | 290 | @classmethod 291 | def encrypt(cls,data,key,iv=None): 292 | return _rabbit.Rabbit(key,iv or '').crypt(data) 293 | 294 | decrypt = encrypt 295 | -------------------------------------------------------------------------------- /src/crypto/rabbit.py: -------------------------------------------------------------------------------- 1 | ## borrowed from https://github.com/TanXin96/Rabbit-Cipher 2 | 3 | from mlib.bits import rol 4 | 5 | def ROTL32(*args): 6 | return rol(*args) & 0xffffffff 7 | 8 | class Rabbit_state(object): 9 | def __init__(self): 10 | self.x=[0]*8 11 | self.c=[0]*8 12 | self.carry=0 13 | 14 | class Rabbit_ctx(object): 15 | def __init__(self): 16 | self.m=Rabbit_state() 17 | self.w=Rabbit_state() 18 | 19 | 20 | class Rabbit(object): 21 | def __init__(self,key,iv): 22 | self.ctx=Rabbit_ctx(); 23 | self.set_key(key); 24 | if(len(iv)): 25 | self.set_iv(iv); 26 | 27 | def g_func(self,x): 28 | x=x&0xffffffff 29 | x=(x*x)&0xffffffffffffffff 30 | result=(x>>32)^(x&0xffffffff) 31 | return result 32 | def set_key(self,key): 33 | #generate four subkeys 34 | key0=int(key[0:4][::-1].encode("hex"),16) 35 | key1=int(key[4:8][::-1].encode("hex"),16) 36 | key2=int(key[8:12][::-1].encode("hex"),16) 37 | key3=int(key[12:16][::-1].encode("hex"),16) 38 | s=self.ctx.m 39 | #generate initial state variables 40 | s.x[0]=key0 41 | s.x[2]=key1 42 | s.x[4]=key2 43 | s.x[6]=key3 44 | s.x[1]=((key3<<16)&0xffffffff)|((key2>>16)&0xffff) 45 | s.x[3]=((key0<<16)&0xffffffff)|((key3>>16)&0xffff) 46 | s.x[5]=((key1<<16)&0xffffffff)|((key0>>16)&0xffff) 47 | s.x[7]=((key2<<16)&0xffffffff)|((key1>>16)&0xffff) 48 | #generate initial counter values 49 | s.c[0]=ROTL32(key2,16) 50 | s.c[2]=ROTL32(key3,16) 51 | s.c[4]=ROTL32(key0,16) 52 | s.c[6]=ROTL32(key1,16) 53 | s.c[1]=(key0&0xffff0000) | (key1&0xffff) 54 | s.c[3]=(key1&0xffff0000) | (key2&0xffff) 55 | s.c[5]=(key2&0xffff0000) | (key3&0xffff) 56 | s.c[7]=(key3&0xffff0000) | (key0&0xffff) 57 | s.carry=0 58 | 59 | #Iterate system four times 60 | for i in range(4): 61 | self.next_state(self.ctx.m); 62 | 63 | for i in range(8): 64 | #modify the counters 65 | self.ctx.m.c[i]^=self.ctx.m.x[(i+4)&7] 66 | #Copy master instance to work instance 67 | self.ctx.w=self.copy_state(self.ctx.m) 68 | 69 | def copy_state(self,state): 70 | n=Rabbit_state() 71 | n.carry=state.carry 72 | 73 | for i,j in enumerate(state.x): 74 | n.x[i]=j 75 | for i,j in enumerate(state.c): 76 | n.c[i]=j 77 | return n 78 | def set_iv(self,iv): 79 | #generate four subvectors 80 | v=[0]*4 81 | v[0]=int(iv[0:4][::-1].encode("hex"),16) 82 | v[2]=int(iv[4:8][::-1].encode("hex"),16) 83 | v[1]=(v[0]>>16) |(v[2]&0xffff0000) 84 | v[3]=((v[2]<<16) |(v[0]&0x0000ffff))&0xffffffff 85 | #Modify work's counter values 86 | for i in range(8): 87 | self.ctx.w.c[i]=self.ctx.m.c[i]^v[i&3] 88 | #Copy state variables but not carry flag 89 | tmp=[] 90 | 91 | for cc in self.ctx.m.x: 92 | tmp+=[cc] 93 | self.ctx.w.x=tmp 94 | 95 | #Iterate system four times 96 | for i in range(4): 97 | self.next_state(self.ctx.w); 98 | 99 | 100 | 101 | def next_state(self,state): 102 | g=[0]*8 103 | x=[0x4D34D34D, 0xD34D34D3, 0x34D34D34] 104 | #calculate new counter values 105 | for i in range(8): 106 | tmp=state.c[i] 107 | state.c[i]=(state.c[i]+x[i%3]+state.carry)&0xffffffff 108 | state.carry=(state.c[i]>16)^(c.w.x[3]<<16) 136 | x[1]^=(c.w.x[7]>>16)^(c.w.x[5]<<16) 137 | x[2]^=(c.w.x[1]>>16)^(c.w.x[7]<<16) 138 | x[3]^=(c.w.x[3]>>16)^(c.w.x[1]<<16) 139 | b=[0]*16 140 | for i,j in enumerate(x): 141 | for z in range(4): 142 | b[z+4*i]=0xff&(j>>(8*z)) 143 | for i in range(16): 144 | plain+=chr(ord(msg[start])^b[i]) 145 | start+=1 146 | if(start==l): 147 | return plain 148 | -------------------------------------------------------------------------------- /src/crypto/rc2.py: -------------------------------------------------------------------------------- 1 | import array 2 | from mlib.bits import rol, ror 3 | 4 | 5 | def ROL16(x, n): 6 | return rol(x, n, 16) & 0xFFFF 7 | 8 | 9 | def ROR16(x, n): 10 | return ror(x, n, 16) & 0xFFFF 11 | 12 | 13 | class RC2(): 14 | 15 | RC2_BLOCK_SIZE = 8 16 | MODE_ECB = 0 17 | MODE_CBC = 1 18 | PADDING_PKCS5 = 1 19 | 20 | def __init__(self, key): 21 | 22 | sbox = array.array('B', [ 23 | 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, 24 | 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 25 | 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, 26 | 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, 27 | 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 28 | 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, 29 | 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, 30 | 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 31 | 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, 32 | 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, 33 | 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 34 | 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, 35 | 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, 36 | 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 37 | 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, 38 | 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD]) 39 | 40 | rc2_key = bytearray(128) 41 | 42 | for i in range(128): 43 | if len(key) > i: 44 | rc2_key[i] = key[i] 45 | else: 46 | rc2_key[i] = sbox[rc2_key[i - 1] + 47 | rc2_key[i - len(key)] & 0xFF] 48 | 49 | rc2_key[128 - len(key)] = sbox[rc2_key[128 - len(key)]] 50 | 51 | if len(key) < 128: 52 | for i in range(127 - len(key), -1, -1): 53 | xor = rc2_key[i + 1] ^ rc2_key[len(key) + i] 54 | rc2_key[i] = sbox[xor & 0xFF] 55 | 56 | self.K = array.array('H') 57 | try: 58 | self.K.fromstring(rc2_key) 59 | except: 60 | self.K.fromstring(''.join(map(chr, rc2_key))) 61 | 62 | def encrypt_mixup(self, K, x0, x1, x2, x3, round): 63 | 64 | j = round * 4 65 | x0 = (x0 + (x2 & x3) + (~x3 & x1) + K[j]) & 0xFFFF 66 | x0 = ROL16(x0, 1) 67 | j += 1 68 | 69 | x1 = (x1 + (x3 & x0) + (~x0 & x2) + K[j]) & 0xFFFF 70 | x1 = ROL16(x1, 2) 71 | j += 1 72 | 73 | x2 = (x2 + (x0 & x1) + (~x1 & x3) + K[j]) & 0xFFFF 74 | x2 = ROL16(x2, 3) 75 | j += 1 76 | 77 | x3 = (x3 + (x1 & x2) + (~x2 & x0) + K[j]) & 0xFFFF 78 | x3 = ROL16(x3, 5) 79 | 80 | return x0, x1, x2, x3 81 | 82 | def decrypt_mixup(self, K, x0, x1, x2, x3, round): 83 | 84 | j = round * 4 + 3 85 | x3 = ROR16(x3, 5) 86 | x3 = (x3 - (x1 & x2) - (~x2 & x0) - K[j]) & 0xFFFF 87 | j -= 1 88 | 89 | x2 = ROR16(x2, 3) 90 | x2 = (x2 - (x0 & x1) - (~x1 & x3) - K[j]) & 0xFFFF 91 | j -= 1 92 | 93 | x1 = ROR16(x1, 2) 94 | x1 = (x1 - (x3 & x0) - (~x0 & x2) - K[j]) & 0xFFFF 95 | j -= 1 96 | 97 | x0 = ROR16(x0, 1) 98 | x0 = (x0 - (x2 & x3) - (~x3 & x1) - K[j]) & 0xFFFF 99 | 100 | return x0, x1, x2, x3 101 | 102 | def encrypt_mash(self, K, x0, x1, x2, x3): 103 | 104 | x0 = (x0 + K[x3 & 63]) & 0xFFFF 105 | x1 = (x1 + K[x0 & 63]) & 0xFFFF 106 | x2 = (x2 + K[x1 & 63]) & 0xFFFF 107 | x3 = (x3 + K[x2 & 63]) & 0xFFFF 108 | 109 | return x0, x1, x2, x3 110 | 111 | def decrypt_mash(self, K, x0, x1, x2, x3): 112 | 113 | x3 = (x3 - K[x2 & 63]) & 0xFFFF 114 | x2 = (x2 - K[x1 & 63]) & 0xFFFF 115 | x1 = (x1 - K[x0 & 63]) & 0xFFFF 116 | x0 = (x0 - K[x3 & 63]) & 0xFFFF 117 | 118 | return x0, x1, x2, x3 119 | 120 | def block_encrypt(self, input_buffer): 121 | 122 | R = array.array('H') 123 | R.fromlist(list(input_buffer)) 124 | 125 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 126 | self.K, R[0], R[1], R[2], R[3], 0) 127 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 128 | self.K, R[0], R[1], R[2], R[3], 1) 129 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 130 | self.K, R[0], R[1], R[2], R[3], 2) 131 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 132 | self.K, R[0], R[1], R[2], R[3], 3) 133 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 134 | self.K, R[0], R[1], R[2], R[3], 4) 135 | 136 | R[0], R[1], R[2], R[3] = self.encrypt_mash( 137 | self.K, R[0], R[1], R[2], R[3]) 138 | 139 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 140 | self.K, R[0], R[1], R[2], R[3], 5) 141 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 142 | self.K, R[0], R[1], R[2], R[3], 6) 143 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 144 | self.K, R[0], R[1], R[2], R[3], 7) 145 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 146 | self.K, R[0], R[1], R[2], R[3], 8) 147 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 148 | self.K, R[0], R[1], R[2], R[3], 9) 149 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 150 | self.K, R[0], R[1], R[2], R[3], 10) 151 | 152 | R[0], R[1], R[2], R[3] = self.encrypt_mash( 153 | self.K, R[0], R[1], R[2], R[3]) 154 | 155 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 156 | self.K, R[0], R[1], R[2], R[3], 11) 157 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 158 | self.K, R[0], R[1], R[2], R[3], 12) 159 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 160 | self.K, R[0], R[1], R[2], R[3], 13) 161 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 162 | self.K, R[0], R[1], R[2], R[3], 14) 163 | R[0], R[1], R[2], R[3] = self.encrypt_mixup( 164 | self.K, R[0], R[1], R[2], R[3], 15) 165 | 166 | return bytearray(R.tostring()) 167 | 168 | def block_decrypt(self, input_buffer): 169 | 170 | R = array.array('H') 171 | try: 172 | R.fromstring(input_buffer) 173 | except: 174 | R.fromstring(''.join(map(chr, input_buffer))) 175 | 176 | # R.fromstring(input_buffer) 177 | 178 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 179 | self.K, R[0], R[1], R[2], R[3], 15) 180 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 181 | self.K, R[0], R[1], R[2], R[3], 14) 182 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 183 | self.K, R[0], R[1], R[2], R[3], 13) 184 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 185 | self.K, R[0], R[1], R[2], R[3], 12) 186 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 187 | self.K, R[0], R[1], R[2], R[3], 11) 188 | 189 | R[0], R[1], R[2], R[3] = self.decrypt_mash( 190 | self.K, R[0], R[1], R[2], R[3]) 191 | 192 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 193 | self.K, R[0], R[1], R[2], R[3], 10) 194 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 195 | self.K, R[0], R[1], R[2], R[3], 9) 196 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 197 | self.K, R[0], R[1], R[2], R[3], 8) 198 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 199 | self.K, R[0], R[1], R[2], R[3], 7) 200 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 201 | self.K, R[0], R[1], R[2], R[3], 6) 202 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 203 | self.K, R[0], R[1], R[2], R[3], 5) 204 | 205 | R[0], R[1], R[2], R[3] = self.decrypt_mash( 206 | self.K, R[0], R[1], R[2], R[3]) 207 | 208 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 209 | self.K, R[0], R[1], R[2], R[3], 4) 210 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 211 | self.K, R[0], R[1], R[2], R[3], 3) 212 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 213 | self.K, R[0], R[1], R[2], R[3], 2) 214 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 215 | self.K, R[0], R[1], R[2], R[3], 1) 216 | R[0], R[1], R[2], R[3] = self.decrypt_mixup( 217 | self.K, R[0], R[1], R[2], R[3], 0) 218 | 219 | return map(ord, R.tostring()) 220 | 221 | def encrypt(self, input_buffer, mode, IV=None, padding=None): 222 | 223 | if (len(input_buffer) % self.RC2_BLOCK_SIZE) == 0 and padding != PADDING_PKCS5: 224 | crypt_size = len(input_buffer) 225 | else: 226 | crypt_size = ( 227 | (len(input_buffer) // self.RC2_BLOCK_SIZE) + 1) * self.RC2_BLOCK_SIZE 228 | 229 | crypt_buffer = bytearray(crypt_size) 230 | 231 | for i in range(crypt_size): 232 | if len(input_buffer) > i: 233 | crypt_buffer[i] = input_buffer[i] 234 | elif padding == PADDING_PKCS5: 235 | crypt_buffer[i] = ( 236 | self.RC2_BLOCK_SIZE - (len(input_buffer) % self.RC2_BLOCK_SIZE)) & 0xFF 237 | 238 | result = bytearray() 239 | 240 | for block_counter in range(crypt_size // self.RC2_BLOCK_SIZE): 241 | 242 | block = crypt_buffer[block_counter * self.RC2_BLOCK_SIZE:block_counter * 243 | self.RC2_BLOCK_SIZE + self.RC2_BLOCK_SIZE] 244 | 245 | if block_counter == 0: 246 | if mode == self.MODE_CBC and IV is not None: 247 | for i in range(self.RC2_BLOCK_SIZE): 248 | block[i] = block[i] ^ IV[i] 249 | else: 250 | if mode == self.MODE_CBC: 251 | for i in range(self.RC2_BLOCK_SIZE): 252 | block[i] = block[i] ^ block_result[i] 253 | 254 | block_result = self.block_encrypt(block) 255 | 256 | result += block_result 257 | 258 | return result 259 | 260 | def decrypt(self, input_buffer, mode, IV=None, padding=None): 261 | 262 | crypt_size = len(input_buffer) 263 | crypt_buffer = bytearray(crypt_size) 264 | 265 | for i in range(crypt_size): 266 | crypt_buffer[i] = input_buffer[i] 267 | 268 | for block_counter in range(crypt_size // self.RC2_BLOCK_SIZE): 269 | 270 | block = crypt_buffer[block_counter * self.RC2_BLOCK_SIZE:block_counter * 271 | self.RC2_BLOCK_SIZE + self.RC2_BLOCK_SIZE] 272 | 273 | block_result = self.block_decrypt(block) 274 | 275 | if mode == self.MODE_CBC: 276 | if block_counter == 0: 277 | if IV is not None: 278 | for i in range(self.RC2_BLOCK_SIZE): 279 | crypt_buffer[block_counter * 280 | self.RC2_BLOCK_SIZE + i] = block_result[i] ^ IV[i] 281 | else: 282 | for i in range(self.RC2_BLOCK_SIZE): 283 | crypt_buffer[block_counter * self.RC2_BLOCK_SIZE + 284 | i] = block_result[i] ^ previous_block[i] 285 | else: 286 | for i in range(self.RC2_BLOCK_SIZE): 287 | crypt_buffer[block_counter * 288 | self.RC2_BLOCK_SIZE + i] = block_result[i] 289 | 290 | previous_block = block 291 | 292 | if padding == self.PADDING_PKCS5: 293 | crypt_buffer = crypt_buffer[:-crypt_buffer[crypt_size - 1]] 294 | return crypt_buffer 295 | -------------------------------------------------------------------------------- /src/crypto/rc6.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from mlib.bits import rol, ror 3 | 4 | 5 | def _add(*args): 6 | return sum(args) % 4294967296 7 | 8 | # def _rol(x, n): 9 | # n = 31 & n 10 | # return x << n | 2 ** n - 1 & x >> 32 - n 11 | 12 | # def _ror(x, y): # rorororor 13 | # return _rol(x, 32 - (31 & y)) 14 | 15 | 16 | def _mul(a, b): 17 | return (((a >> 16) * (b & 65535) + (b >> 16) * (a & 65535)) * 65536 + 18 | (a & 65535) * (b & 65535)) % 4294967296 19 | 20 | 21 | class RC6(object): 22 | def __init__(self, key, inverse=False, iv = None): 23 | self.state = S = [] 24 | key += "\0" * (4 - len(key) & 3) # pad key 25 | fmt = '> ' if inverse else '>' 26 | self.rol = ror if inverse else rol 27 | self.ror = rol if inverse else ror 28 | self.iv = iv 29 | 30 | L = list(struct.unpack(fmt+"%sL" % (len(key) / 4), key)) 31 | 32 | S.append(0xb7e15163) 33 | for i in range(43): 34 | S.append(_add(S[i], 0x9e3779b9)) 35 | 36 | v = max(132, len(L) * 3) 37 | 38 | A = B = i = j = 0 39 | 40 | for n in range(v): 41 | A = S[i] = self.rol(_add(S[i], A, B), 3) 42 | B = L[j] = self.rol(_add(L[j] + A + B), _add(A + B)) 43 | i = (i + 1) % len(S) 44 | j = (j + 1) % len(L) 45 | 46 | for e in iv: 47 | S.append(e) 48 | 49 | def encrypt(self, block, state=None): 50 | S = state if state else self.state 51 | A, B, C, D = struct.unpack("<4L", block.ljust(16, '\0')) 52 | 53 | B = _add(B, S[0]) 54 | D = _add(D, S[1]) 55 | 56 | for i in range(1, 21): # 1..20 57 | t = self.rol(_mul(B, add(B, B, 1)), 5) 58 | u = self.rol(_mul(D, add(D, D, 1)), 5) 59 | A = _add(self.rol(A ^ t, u), S[2 * i]) 60 | C = _add(self.rol(C ^ u, t), S[2 * i + 1]) 61 | 62 | A, B, C, D = B, C, D, A 63 | 64 | A = _add(A, S[42]) 65 | C = _add(C, S[43]) 66 | 67 | return struct.pack("<4L", A, B, C, D) 68 | 69 | def decrypt(self, block, state=None): 70 | S = state if state else self.state 71 | in_block = struct.unpack("<4L", block.ljust(16, "\0")) # * 16)a 72 | A, B, C, D = in_block 73 | 74 | C = _add(C, -S[43]) 75 | A = _add(A, -S[42]) 76 | 77 | for i in range(20, 0, -1): # 20..1 78 | A, B, C, D = D, A, B, C 79 | 80 | u = self.rol(_mul(D, _add(D, D, 1)), 5) 81 | t = self.rol(_mul(B, _add(B, B, 1)), 5) 82 | C = self.ror(_add(C, -S[2 * i + 1]), t) ^ u 83 | A = self.ror(_add(A, -S[2 * i]), u) ^ t 84 | 85 | D = _add(D, -S[1]) 86 | B = _add(B, -S[0]) 87 | 88 | # [A,B,C,D] 89 | if self.iv: 90 | A,B,C,D = [ x ^ y for x,y in zip([A,B,C,D],S[44:])] 91 | for i,e in enumerate(in_block): 92 | S[44+i] = e 93 | 94 | return struct.pack("<4L", A & 0xffffffff, B & 0xffffffff, C & 0xffffffff, D & 0xffffffff) 95 | -------------------------------------------------------------------------------- /src/crypto/spritz.py: -------------------------------------------------------------------------------- 1 | class Spritz: 2 | 3 | def __init__(self, op): 4 | self.initialise_state() 5 | self.op = op 6 | 7 | def encrypt(self, K, M): 8 | self.initialise_state() 9 | self.absorb(K) 10 | return bytearray(self.op(b1, b2) for b1, b2 in zip(M, self.squeeze(len(M)))) 11 | 12 | def decrypt(self, K, C): 13 | self.initialise_state() 14 | self.absorb(K) 15 | return bytearray(self.op(b1, b2) for b1, b2 in zip(C, self.squeeze(len(C)))) 16 | 17 | def hash(self, M, r): 18 | self.initialise_state() 19 | self.absorb(M) 20 | self.absorb_stop() 21 | self.absorb(bytearray(self.base_10_to_256(r))) 22 | return self.squeeze(r) 23 | 24 | def swap(self, i1, i2): 25 | self.S[i1], self.S[i2] = self.S[i2], self.S[i1] 26 | 27 | def initialise_state(self): 28 | self.i = self.j = self.k = self.z = self.a = 0 29 | self.w = 1 30 | self.S = bytearray(range(256)) 31 | 32 | def absorb(self, I): 33 | for b in I: 34 | self.absorb_byte(b) 35 | 36 | def absorb_byte(self, b): 37 | self.absorb_nibble(b & 0xf) 38 | self.absorb_nibble(b >> 4) 39 | 40 | def absorb_nibble(self, x): 41 | if self.a == 128: 42 | self.shuffle() 43 | self.swap(self.a, 128 + x) 44 | self.a = self.add(self.a, 1) 45 | 46 | def absorb_stop(self): 47 | if self.a == 128: 48 | self.shuffle() 49 | self.a = self.add(self.a, 1) 50 | 51 | def shuffle(self): 52 | self.whip(512) 53 | self.crush() 54 | self.whip(512) 55 | self.crush() 56 | self.whip(512) 57 | self.a = 0 58 | 59 | def whip(self, r): 60 | for _ in range(r): 61 | self.update() 62 | self.w = self.add(self.w, 2) 63 | 64 | def crush(self): 65 | for v in range(128): 66 | if self.S[v] > self.S[255 - v]: 67 | self.swap(v, 255 - v) 68 | 69 | def squeeze(self, r): 70 | if self.a > 0: 71 | self.shuffle() 72 | return bytearray([self.drip() for _ in range(r)]) 73 | 74 | def drip(self): 75 | if self.a > 0: 76 | self.shuffle() 77 | self.update() 78 | return self.output() 79 | 80 | def update(self): 81 | self.i = self.add(self.i, self.w) 82 | self.j = self.add(self.k, self.S[self.add(self.j, self.S[self.i])]) 83 | self.k = self.add(self.i, self.k, self.S[self.j]) 84 | self.swap(self.i, self.j) 85 | 86 | def output(self): 87 | self.z = self.S[self.add(self.j, self.S[self.add( 88 | self.i, self.S[self.add(self.z, self.k)])])] 89 | return self.z 90 | 91 | def add(self, *args): 92 | return sum(args) % 256 93 | 94 | # def xor(self, a,b): 95 | # return a ^ b 96 | 97 | def base_10_to_256(self, n): 98 | m = bytearray() 99 | while n: 100 | m.append(n % 256) 101 | n = n // 256 102 | return reversed(m) 103 | -------------------------------------------------------------------------------- /src/disasm/__init__.py: -------------------------------------------------------------------------------- 1 | import capstone as _c 2 | import capstone.x86 as cpu 3 | from .hash import x86_hash_table 4 | 5 | 6 | class Op(object): 7 | _regs = dict(map(lambda x: (x.split( 8 | '_')[-1].lower(), getattr(cpu, x)), filter(lambda x: x.startswith('X86_REG_'), dir(cpu)))) 9 | _xregs = dict(map(lambda x: (getattr(cpu, x), x.split( 10 | '_')[-1].lower()), filter(lambda x: x.startswith('X86_REG_'), dir(cpu)))) 11 | _xregs[0] = None 12 | _8bit_regs = [cpu.X86_REG_AH, cpu.X86_REG_AL, cpu.X86_REG_BH, cpu.X86_REG_BL, 13 | cpu.X86_REG_CH, cpu.X86_REG_CL, cpu.X86_REG_DH, cpu.X86_REG_DL] 14 | 15 | def __init__(self, op): 16 | self.op = op 17 | 18 | @property 19 | def type(self): 20 | return self.op.type 21 | 22 | @property 23 | def is_imm(self): 24 | return self.type == cpu.X86_OP_IMM 25 | 26 | @property 27 | def is_reg(self): 28 | return self.type == cpu.X86_OP_REG 29 | 30 | @property 31 | def is_mem(self): 32 | return self.type == cpu.X86_OP_MEM 33 | 34 | @property 35 | def val(self): 36 | if self.is_imm: 37 | return self.op.value.imm 38 | elif self.is_reg: 39 | return self._xregs[self.op.value.reg] 40 | elif self.is_mem: 41 | return self.op.value.mem.disp 42 | 43 | @property 44 | def reg(self): 45 | if self.is_reg: 46 | return self.val 47 | elif self.is_mem: 48 | x = self.op.value.mem.base 49 | return self._xregs[x or self.op.value.mem.index] 50 | return '' 51 | 52 | @property 53 | def is_8bit_reg(self): 54 | return self.is_reg and self.op.value.reg in self._8bit_regs 55 | 56 | def __eq__(self, op): 57 | r = False 58 | if self.is_mem and getattr(op, 'is_mem', False): 59 | r |= all(map(lambda a: getattr(self.op.mem, a) == getattr(op.op.mem, a), 60 | ['base', 'disp', 'index', 'scale'])) 61 | elif self.is_reg and (type(op) == str or getattr(op, 'is_reg', False)): 62 | r |= self.reg == (op if type(op) == str else op.reg) 63 | 64 | elif self.is_imm and (type(op) == int or getattr(op, 'is_imm', False)): 65 | r |= self.val == (op if type(op) == int else op.val) 66 | return r 67 | 68 | # class that abstract away disassembly access 69 | # base module is capston engine 70 | 71 | 72 | TBL_0F = 256 # /* table index: 0F-prefixed opcodes */ 73 | TBL_80_83 = 512 # /* table index: 80/81/82/83 /ttt */ 74 | TBL_F6 = 520 # /* table index: F6 /ttt */ 75 | TBL_F7 = 528 # /* table index: F7 /ttt */ 76 | TBL_FE = 536 # /* table index: FE /ttt */ 77 | TBL_FF = 544 # /* table index: FF /ttt */ 78 | 79 | 80 | class C(object): 81 | 82 | _groups = dict(map(lambda x: (x.split( 83 | '_')[-1].lower(), getattr(cpu, x)), filter(lambda x: x.startswith('X86_GRP_'), dir(cpu)))) 84 | 85 | def __init__(self, _ins, b): 86 | self.ins = _ins 87 | self.mnem = self.ins.mnemonic 88 | self.base = b 89 | self.operands = map(Op, self.ins.operands) 90 | self.size = self.ins.size 91 | self.address = self.ins.address 92 | 93 | def __str__(self): 94 | return "%s %s" % (self.mnem, self.ins.op_str) 95 | 96 | def __repr__(self): 97 | return "0%x: %s" % (self.ins.address, self.__str__()) 98 | 99 | @property 100 | def instr_hash(self): 101 | if not hasattr(self, '_instr_hash'): 102 | h = None 103 | if self.ins.opcode[0] == 0xf: 104 | h = x86_hash_table[TBL_0F + self.ins.opcode[1]] 105 | elif self.ins.modrm: 106 | modrm_reg = (self.ins.modrm & 0x38) >> 3 107 | if (self.ins.opcode[0] & 0xFC) == 0x80: 108 | h = x86_hash_table[TBL_80_83 + modrm_reg] 109 | elif self.ins.opcode[0] == 0xF6: 110 | h = x86_hash_table[TBL_F6 + modrm_reg] 111 | elif self.ins.opcode[0] == 0xF7: 112 | h = x86_hash_table[TBL_F7 + modrm_reg] 113 | elif self.ins.opcode[0] == 0xFE: 114 | h = x86_hash_table[TBL_FE + modrm_reg] 115 | elif self.ins.opcode[0] == 0xFF: 116 | h = x86_hash_table[TBL_FF + modrm_reg] 117 | if not h: 118 | h = x86_hash_table[self.ins.opcode[0]] 119 | 120 | self._instr_hash = h 121 | 122 | return self._instr_hash 123 | 124 | @property 125 | def regs_access(self): 126 | # lets cache this, it looks 127 | if not hasattr(self, '_regs_acc'): 128 | self._regs_acc = map(self.ins.reg_name, self.ins.regs_access()) 129 | return self._regs_acc 130 | 131 | @property 132 | def regs_write(self): 133 | return self.regs_access[1] 134 | 135 | @property 136 | def regs_read(self): 137 | return self.regs_access[0] 138 | 139 | def op(self, idx): 140 | return self.operands[idx] 141 | 142 | def group(self, grp): 143 | if type(grp) == str: 144 | grp = self._groups[grp] 145 | return self.ins.group(grp) 146 | 147 | def val(self, idx): 148 | return self.op(idx).val 149 | 150 | def reg(self, idx): 151 | return self.op(idx).reg 152 | 153 | def type(self, idx): 154 | return self.op(idx).type 155 | 156 | def is_imm(self, idx): 157 | return self.op(idx).is_imm 158 | 159 | def is_reg(self, idx): 160 | return self.op(idx).is_reg 161 | 162 | def is_mem(self, idx): 163 | return self.op(idx).is_mem 164 | 165 | 166 | def disasm(base=None, data=None, address=None): 167 | md = _c.Cs(_c.CS_ARCH_X86, _c.CS_MODE_32) 168 | md.detail = True 169 | for i in md.disasm(data, address): 170 | yield C(i, base) 171 | 172 | # compute SPP(small-prime-product) from diassembled code 173 | 174 | 175 | def spp_hash(base=None, data=None, address=None, code=None): 176 | if code: 177 | return reduce(lambda x, y: x * y.instr_hash, code, 1) 178 | else: 179 | return spp_hash(code=disasm(base, data, address)) 180 | -------------------------------------------------------------------------------- /src/disasm/eng.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | from Queue import Queue 4 | from collections import namedtuple 5 | from threading import current_thread, Lock, Thread, Event 6 | 7 | from . import vmext 8 | 9 | BB = namedtuple('BB', ['begin', 'end', 'size', 10 | 'code', 'ins_count', 11 | 'frm', 'to', 12 | 'funcs' 13 | ] 14 | ) 15 | F = namedtuple('F', ['bbs','addr']) 16 | 17 | def is_exit(impr): 18 | r = False 19 | if impr['dll'] == 'msvcrt.dll': 20 | r |= impr['name'] == '_exit' 21 | r |= impr['name'] == 'exit' 22 | if impr['dll'] == 'kernel32.dll': 23 | r |= impr['name'] == 'ExitProcess' 24 | return r 25 | 26 | 27 | class E(): 28 | 29 | def __init__(self, ldr): 30 | 31 | self._bb_lock = Lock() 32 | self._done = [] 33 | self.ldr = ldr 34 | 35 | # basic blocks... 36 | self._bb = {} 37 | self._bb_range = {} 38 | 39 | # functions 40 | self._funcs = set() 41 | self._funcs_obj = {} 42 | self._funcs_range = [] 43 | 44 | self.xrefs = {} 45 | self.drefs = {} 46 | 47 | self.switch_jmp = [] 48 | 49 | self._from_changes = {} 50 | 51 | def disasm_one(self,addr): 52 | try: 53 | i = self.ldr.disasm(addr, 15).next() 54 | return i 55 | except StopIteration: 56 | pass 57 | 58 | b = self.ldr.byte(addr) 59 | if b in (0x3e,0x2e): 60 | # just swallow branch predicitions 61 | waddr = addr+1 62 | while b in (0x3e,0x2e): 63 | b = self.ldr.byte(waddr) 64 | waddr += 1 65 | 66 | i = self.disasm_one(waddr-1) 67 | i.address = addr 68 | i.size += waddr-addr-1 69 | return i 70 | 71 | i = vmext.decode_vm(self.ldr,addr) 72 | if not i: 73 | raise Exception("Can't decode instruction at 0x%x"%addr) 74 | return i 75 | 76 | @property 77 | def funcs(self): 78 | return list(self._funcs) 79 | 80 | def function(self, addr): 81 | if addr in self._funcs_obj: 82 | return self._funcs_obj[addr] 83 | 84 | if addr not in self._funcs: 85 | ## this is kinda bad since bb can be part of many functions 86 | try: 87 | addr = iter(self.bb(addr).funcs).next() 88 | except StopIteration: 89 | self._funcs_obj[addr] = None 90 | return None 91 | 92 | bbs = self.get_reachable_blocks(addr) 93 | func = F._make([bbs,addr]) 94 | self._funcs_obj[addr] = func 95 | return func 96 | 97 | def bb(self, a, dont_cache=False): 98 | if a in self._bb: 99 | return self._bb[a] 100 | if a in self._bb_range: 101 | return self._bb_range[a] 102 | 103 | for bb in self._bb.values(): 104 | if bb.begin <= a < bb.end: 105 | if not dont_cache: 106 | self._bb_range[a] = bb 107 | return bb 108 | 109 | def get_reachable_blocks(self,addr): 110 | q = [addr] 111 | r = set() 112 | while q: 113 | a = q.pop() 114 | if a not in r: 115 | r.add(a) 116 | for a in self.bb(a).to: 117 | q.append(a) 118 | return map(lambda a: self.bb(a),r) 119 | # def track_val_in_bb(self,op,bb): 120 | 121 | def _add_ref(self, t, f, store): 122 | if f not in store: 123 | store[f] = [] 124 | if t not in store: 125 | store[t] = [] 126 | 127 | store[f].append(t) 128 | store[t].append(f) 129 | 130 | def add_xref(self, t, f): 131 | return self._add_ref(t, f, self.xrefs) 132 | 133 | def add_dref(self, t, f): 134 | return self._add_ref(t, f, self.drefs) 135 | 136 | def do_address(self, f, a, lf, x=None, func=False): 137 | #print '%x -> %x' % (x or -1,a) 138 | if x: 139 | self.add_xref(x, a) 140 | if func: 141 | self._funcs.add(a) 142 | 143 | self.q.append((f, a, a if func else lf )) 144 | # self.disas_block(None,a) 145 | 146 | def can_be_function(self, a): 147 | r = False 148 | if self.ldr.is_exec(a): 149 | r = self.ldr.read(a, 3) == '\x55\x8b\xec' 150 | r |= self.ldr.read(a, 2) == "\xff\x25" and\ 151 | self.ldr.is_addr(self.ldr.dword(a+2)) 152 | if r: 153 | return r 154 | 155 | try: 156 | ## can be setting up a SEH handler... 157 | i0 = self.disasm_one(a) 158 | i1 = self.disasm_one(a + i0.size) 159 | i2 = self.disasm_one(a + i1.size + i0.size) 160 | mnems = map(lambda i: i.mnem,[i0,i1,i2]) 161 | r = mnems == ['push','push','call'] 162 | r &= i0.is_imm(0) and i0.val(0) < 0x4000 163 | r &= i1.is_imm(0) and self.ldr.is_addr(i1.val(0)) 164 | except: 165 | pass 166 | 167 | return r 168 | 169 | 170 | 171 | def analyze_call(self, c): 172 | if c.is_mem(0) and not c.reg(0): 173 | # just simple call via memory 174 | # could be library call or some other 175 | 176 | if c.val(0) not in self.ldr.imports: 177 | try: 178 | addr = self.ldr.dword(c.val(0)) 179 | except: 180 | return 181 | 182 | if self.ldr.is_exec(addr): 183 | self.do_address(None, addr, -1, c.address, func=True) 184 | self.add_xref(c.val(0), c.address) 185 | 186 | elif c.val(0) in self.ldr.imports \ 187 | and is_exit(self.ldr.imports[c.val(0)]): 188 | self.add_xref(c.val(0), c.address) 189 | return -1 190 | elif c.val(0) in self.ldr.imports: 191 | self.add_xref(c.val(0), c.address) 192 | 193 | elif c.is_imm(0) and not c.reg(0): 194 | self.do_address(None, c.val(0), -1, c.address, func=True) 195 | # self.add_xref(c.val(0),c.address) 196 | # self.q.put(c.val(0)) 197 | def analyze_dref(self,c): 198 | dst = None 199 | for op in c.operands: 200 | if op.is_imm and self.ldr.is_data(op.val): 201 | dst = op.val 202 | break 203 | if op.is_mem and self.ldr.is_data(op.val): 204 | dst = op.val 205 | break 206 | if dst is not None: 207 | self.add_dref(dst,c.address) 208 | 209 | def _disas_block(self, addr, lf): 210 | 211 | cc = [] 212 | to = [] 213 | ends_with_ccjump = False 214 | waddr = addr 215 | 216 | while True: 217 | 218 | c = self.disasm_one(waddr) 219 | cc.append(c) 220 | 221 | self.analyze_dref(c) 222 | if c.group('ret'): 223 | if len(cc) >= 2 and cc[-2].mnem == 'push': 224 | print '%x hack!' % c.address 225 | break 226 | 227 | elif c.group('jump'): 228 | if c.is_imm(0): 229 | self.do_address(addr, c.val(0), lf, c.address) 230 | to.append(c.val(0)) 231 | 232 | elif c.mnem == 'jmp' and c.is_mem(0) and c.reg(0): 233 | # this can be switch jump 234 | self.switch_jmp.append(addr) 235 | 236 | elif c.mnem == 'jmp' and c.reg(0): 237 | # indirect jump, propably switch 238 | self.switch_jmp.append(addr) 239 | 240 | ends_with_ccjump = c.mnem != 'jmp' 241 | break 242 | 243 | elif c.group('call'): 244 | if self.analyze_call(c) == -1: 245 | break 246 | 247 | elif c.mnem == 'push' and c.is_imm(0) and self.can_be_function(c.val(0)): 248 | self.do_address(None, c.val(0), -1, c.address, func=True) 249 | 250 | elif c.mnem == 'mov' and c.is_imm(1) and self.can_be_function(c.val(1)): 251 | self.do_address(None, c.val(1), -1, c.address, func=True) 252 | 253 | waddr += c.size 254 | if waddr in self._done: 255 | #print 'donelbock',hex(addr),hex(waddr) 256 | to.append(waddr) 257 | break 258 | 259 | if len(cc) == 1 and cc[0].mnem == 'jmp': 260 | # TODO:this usless indirection that should be delt with 261 | if c.val(0) in self.ldr.imports: 262 | for a in self.xrefs[addr]: 263 | self.add_xref(a, c.val(0)) 264 | 265 | end = c.address + c.size 266 | if ends_with_ccjump: 267 | #print 'ccj',hex(waddr),hex(end),hex(lf) 268 | self.do_address(addr, end, lf) 269 | to.append(end) 270 | 271 | return BB._make([addr, end, end - addr, cc, len(cc), [], to,set() ]) 272 | 273 | def solve_switch_jump(self, a): 274 | print hex(a) 275 | 276 | # lets fire some heuristics, 277 | # we travel max 5 blocks back 278 | bb = self.bb(a) 279 | ins = bb.code[-1] 280 | op = ins.reg(0) 281 | cnt = 0 282 | addr = None 283 | jmps = [] 284 | for i in range(5): 285 | prev_ins = None 286 | for c in reversed(bb.code): 287 | print `c`, '|', op 288 | if c.mnem == 'cmp': 289 | if c.op(0) == op: 290 | cnt = c.val(1) 291 | break 292 | elif c.op(1) == op: 293 | cnt = c.val(0) 294 | break 295 | # else: 296 | 297 | elif c.mnem in ['lea', 'mov'] and c.op(0) == op: 298 | if not c.is_mem(1) or not c.reg(1): 299 | op = c.op(1) 300 | elif c.is_mem(1) and not c.val(1): 301 | op = c.reg(1) 302 | print 'hmm' 303 | elif c.is_mem(1) and c.val(1): 304 | pass 305 | 306 | elif c.reg(1) in ('esp','ebp'): 307 | op = c.op(1) 308 | 309 | elif c.mnem == 'add' and c.op(0) == op: # ,'sub','shl','shr']: 310 | if c.is_imm(1): 311 | # this is propably our address 312 | addr = c.val(1) 313 | 314 | prev_ins = c 315 | if cnt: 316 | break 317 | bb = self.bb(bb.frm[0]) 318 | 319 | if not addr: 320 | addr = ins.val(0) 321 | if cnt: 322 | # print addr, cnt 323 | jmps = [self.ldr.dword(addr + 4 * i)for i in range(cnt + 1)] 324 | return jmps 325 | 326 | def _split_bb(self,bb,new_begin): 327 | # print 'spliting bb' 328 | # print hex(int(bb.begin)),bb 329 | # print hex(int(new_begin)) 330 | 331 | if new_begin <= bb.begin: 332 | return bb 333 | 334 | for idx,c in enumerate(bb.code): 335 | if c.address == new_begin: 336 | break 337 | 338 | # print hex(idx) 339 | new_size = new_begin - bb.begin 340 | new_bb = BB._make([bb.begin,new_begin, new_size, bb.code[:idx], 341 | idx,bb.frm,[new_begin],bb.funcs]) 342 | self._bb[bb.begin] = new_bb 343 | new_bb = BB._make([new_begin,bb.end,bb.size - new_size, 344 | bb.code[idx:],bb.ins_count - idx,[],bb.to, 345 | bb.funcs]) 346 | 347 | new_bb.frm.append(bb.begin) 348 | 349 | ## update references in other bb's 350 | for baddr in bb.to: 351 | b = self.bb(baddr,dont_cache=True) 352 | if b: 353 | if bb.begin in b.frm: 354 | b.frm.remove(bb.begin) 355 | b.frm.append(new_begin) 356 | else: 357 | ## this block was anlyzed but reference is still 358 | ## in queue, make changing of from address 359 | self._from_changes[(bb.begin,baddr)] = new_begin 360 | else: 361 | ## this bblock is in queue, lets mark that 362 | ## from address must be changed 363 | self._from_changes[(bb.begin,baddr)] = new_begin 364 | 365 | del bb 366 | return new_bb 367 | 368 | 369 | 370 | # def _clean_bbs(self): 371 | # for bb_a in self._bb: 372 | # ns = 0 373 | # bb = self._bb[bb_a] 374 | # for i,c in enumerate(bb.code): 375 | # other_bb = self.bb(c.address,dont_cache=True) 376 | # if bb_a != other_bb.begin: 377 | # self._split_bb(bb,other_bb,ns,i) 378 | # break 379 | # ns += c.size 380 | 381 | 382 | def _run_in_loop(self): 383 | self._done = [] 384 | newf = False 385 | while self.q: 386 | newf = True 387 | from_addr, addr_to, lf = self.q.pop() 388 | if not addr_to in self._done: 389 | bb0 = self.bb(addr_to,dont_cache=True) 390 | if bb0: 391 | #print 'bb already exits',hex(addr_to) 392 | bb = self._split_bb(bb0,addr_to) 393 | else: 394 | self._done.append(addr_to) 395 | bb = self._disas_block(addr_to,lf) 396 | 397 | self._bb[addr_to] = bb 398 | 399 | self._bb[addr_to].funcs.add(lf) 400 | if from_addr: 401 | from_addr = self._from_changes.get((from_addr,addr_to),from_addr) 402 | #print 'frm',hex(addr_to),hex(from_addr) 403 | self._bb[addr_to].frm.append(from_addr) 404 | return newf 405 | 406 | def add_seh_records_v3(self): 407 | exp_hdlr = self.ldr.imports.get('_except_handler3') 408 | if not exp_hdlr or exp_hdlr['dll'] != 'msvcrt.dll': 409 | return 410 | 411 | exp_hdlr = exp_hdlr['addr'] 412 | sehp = self.xrefs[exp_hdlr][0] 413 | # TODO verify if this is __SEH_prolog indeed 414 | for xr in self.xrefs[sehp]: 415 | #print '----' 416 | b = self.bb(xr) 417 | if not b: continue 418 | 419 | for i,ins in enumerate(b.code): 420 | if ins.address == xr: 421 | break 422 | if ins.mnem != 'call': 423 | continue 424 | 425 | seh_rec = b.code[i-1].val(0) 426 | stack_size = b.code[i-2].val(0) 427 | # print hex(int(xr)),hex(seh_rec),stack_size 428 | # print `ins` 429 | try_start = [] 430 | for b in self.get_reachable_blocks(xr): 431 | ## we need to find out how many times 432 | ## registration records are setted up 433 | for c in b.code: 434 | if c.mnem in ('mov','and') and\ 435 | c.reg(0) == 'ebp' and c.is_mem(0) and\ 436 | c.val(0) == -4: 437 | # print `c` 438 | try_start.append(c.address) 439 | 440 | for a in sorted(try_start): 441 | bb_a = self.bb(a) 442 | 443 | ## maintain ida compability 444 | bb_a = self._split_bb(bb_a,a) 445 | self._bb[a] = bb_a 446 | 447 | b_filter = self.ldr.dword(seh_rec+4) 448 | b_handler = self.ldr.dword(seh_rec+8) 449 | if self.ldr.is_addr(b_filter) and\ 450 | self.ldr.is_exec(b_filter): 451 | 452 | b = self.bb(b_filter) 453 | if not b: 454 | bb_a.to.append(b_filter) 455 | for f in bb_a.funcs: 456 | yield bb_a.code[-1].address,b_filter,f 457 | else: 458 | print 'dupa',hex(a),hex(b_filter) 459 | 460 | 461 | if b_filter == b_handler: 462 | continue 463 | 464 | if self.ldr.is_addr(b_handler) and\ 465 | self.ldr.is_exec(b_handler): 466 | 467 | b = self.bb(b_handler) 468 | if not b: 469 | bb_a.to.append(b_handler) 470 | for f in bb_a.funcs: 471 | yield bb_a.code[-1].address,b_handler,f 472 | else: 473 | print 'dupa',hex(a),hex(b_filter) 474 | seh_rec += 0x0c 475 | 476 | def run(self): 477 | 478 | self.q = [] 479 | self.do_address(None, self.ldr.entry, -1, None, func=True) 480 | self._run_in_loop() 481 | 482 | idx = 0 483 | while True: 484 | print 'add seh3 round %d' % idx 485 | newblocks = self.add_seh_records_v3() 486 | for frm,addr,f in newblocks: 487 | print 'newblock',hex(frm),hex(addr) 488 | self.do_address(frm,addr,f) 489 | 490 | 491 | if not self._run_in_loop(): 492 | break 493 | idx +=1 494 | #self._run_in_loop() 495 | 496 | 497 | # print '[*] dicoverd bb: %d' % len(self._bb) 498 | # print '[*] problems with %d switch-case' % len(self.switch_jmp) 499 | # print map(hex, self.switch_jmp) 500 | # for a in self.switch_jmp: 501 | # 502 | # _pool.apply_async(self.disas_block,(addr,)) 503 | 504 | 505 | # with open(sys.argv[1]) as f: 506 | # d = f.read() 507 | # p = PE(_data=d) 508 | # engine = E(p) 509 | # print hex(p.entry) 510 | # engine.run() 511 | # print engine.bb(0x040158C) 512 | # print engine.bb(0x04015BD) 513 | # print engine.bb(0x040157D) 514 | # for a in engine.switch_jmp: 515 | # bb = engine.bb(a) 516 | # last_addr = bb.code[-1].address 517 | # for a0 in engine.solve_switch_jump(a): 518 | # bb.to.append(a0) 519 | # engine.do_address(a, a0, last_addr) 520 | # engine.run_in_loop() 521 | # xbb = engine.bb(0x0402814) 522 | # print xbb.code[0].group('jump') 523 | # print engine.xrefs[0x401584] 524 | 525 | # print hex(p.imports['printf']['addr']) 526 | # print engine.xrefs[p.imports['printf']['addr']] 527 | -------------------------------------------------------------------------------- /src/disasm/hash.py: -------------------------------------------------------------------------------- 1 | x86_hash_table = [ 2 | 3 | # add modrm 4 | 17, # 00 5 | 17, # 01 6 | 17, # 02 7 | 17, # 03 8 | # add al, c8 9 | 19, # 04 10 | # add ax/eax, c16/32 11 | 19, # 05 12 | # push es 13 | 137, # 06 14 | # pop es 15 | 137, # 07 16 | # or modrm 17 | 73, # 08 18 | 73, # 09 19 | 73, # 0A 20 | 73, # 0B 21 | # or al, c8 22 | 79, # 0C 23 | # or ax/eax, c16/32 24 | 79, # 0D 25 | # push cs 26 | 137, # 0E 27 | # 0F-prefix 28 | 137, # 0F 29 | # adc modrm 30 | 97, # 10 31 | 97, # 11 32 | 97, # 12 33 | 97, # 13 34 | # adc al, c8 35 | 101, # 14 36 | # adc ax/eax, c16/32 37 | 101, # 15 38 | # push ss 39 | 137, # 16 40 | # pop ss 41 | 137, # 17 42 | # sbb modrm 43 | 103, # 18 44 | 103, # 19 45 | 103, # 1A 46 | 103, # 1B 47 | # sbb al, c8 48 | 107, # 1C 49 | # sbb ax/eax, c16/32 50 | 107, # 1D 51 | # push ds 52 | 137, # 1E 53 | # pop ds 54 | 137, # 1F 55 | # and modrm 56 | 61, # 20 57 | 61, # 21 58 | 61, # 22 59 | 61, # 23 60 | # and al, c8 61 | 67, # 24 62 | # and ax/eax, c16/32 63 | 67, # 25 64 | # es: 65 | 137, # 26 66 | # daa 67 | 229, # 27 68 | # sub modrm 69 | 53, # 28 70 | 53, # 29 71 | 53, # 2A 72 | 53, # 2B 73 | # sub al, c8 74 | 59, # 2C 75 | # sub ax/eax, c16/32 76 | 59, # 2D 77 | # cs: 78 | 137, # 2E 79 | # das 80 | 229, # 2F 81 | # xor modrm 82 | 41, # 30 83 | 41, # 31 84 | 41, # 32 85 | 41, # 33 86 | # xor al, c8 87 | 43, # 34 88 | # xor ax/eax, c16/32 89 | 43, # 35 90 | # ss: 91 | 137, # 36 92 | # aaa 93 | 233, # 37 94 | # cmp modrm 95 | 11, # 38 96 | 11, # 39 97 | 11, # 3A 98 | 11, # 3B 99 | # cmp al, c8 100 | 13, # 3C 101 | # cmp ax, c16/32 102 | 13, # 3D 103 | # ds: 104 | 137, # 3E 105 | # aas 106 | 233, # 3F 107 | # inc ax/eax 108 | 47, # 40 109 | 47, # 41 110 | 47, # 42 111 | 47, # 43 112 | 47, # 44 113 | 47, # 45 114 | 47, # 46 115 | # inc di/edi 116 | 47, # 47 117 | # dec ax/eax 118 | 83, # 48 119 | 83, # 49 120 | 83, # 4A 121 | 83, # 4B 122 | 83, # 4C 123 | 83, # 4D 124 | 83, # 4E 125 | # dec di/edi 126 | 83, # 4F 127 | # push ax/eax 128 | 5, # 50 129 | 5, # 51 130 | 5, # 52 131 | 5, # 53 132 | 5, # 54 133 | 5, # 55 134 | 5, # 56 135 | # push di/edi 136 | 5, # 57 137 | # pop ax/eax 138 | 23, # 58 139 | 23, # 59 140 | 23, # 5A 141 | 23, # 5B 142 | 23, # 5C 143 | 23, # 5D 144 | 23, # 5E 145 | # pop di/edi 146 | 23, # 5F 147 | # pusha/pushad 148 | 109, # 60 149 | # popa/popad 150 | 113, # 61 151 | # bound 152 | 127, # 62 153 | # arpl 154 | 251, # 63 155 | # fs: 156 | 137, # 64 157 | # gs: 158 | 137, # 65 159 | # 66-prefix 160 | 137, # 66 161 | # 67-prefix 162 | 137, # 67 163 | # push c16/32 164 | 5, # 68 165 | # imul r,r,c16/32 166 | 131, # 69 167 | # push c8 168 | 5, # 6A 169 | # imul r,r,c8 170 | 131, # 6B 171 | # insb 172 | 167, # 6C 173 | # insd 174 | 167, # 6D 175 | # outsb 176 | 173, # 6E 177 | # outsd 178 | 173, # 6F 179 | # jxx short 180 | 311, # 70 181 | 311, # 71 182 | 311, # 72 183 | 311, # 73 184 | 311, # 74 185 | 311, # 75 186 | 311, # 76 187 | 311, # 77 188 | 311, # 78 189 | 311, # 79 190 | 311, # 7A 191 | 311, # 7B 192 | 311, # 7C 193 | 311, # 7D 194 | 311, # 7E 195 | 311, # 7F 196 | # ttt: 0=add 1=or 2=adc 3=sbb 4=and 5=sub 6=xor 7=cmp 197 | # ttt [r/m]:8, imm8 198 | 1, # ''' 80 ''' '''*C_SPECIAL*''' 199 | # ttt [r/m]:16/32, imm16/32 200 | 1, # ''' 81 ''' '''*C_SPECIAL*''' 201 | # ttt [r/m]:8, imm8 202 | 1, # ''' 82 ''' '''*C_SPECIAL*''' 203 | # ttt [r/m]:16/32, imm8 204 | 1, # ''' 83 ''' '''*C_SPECIAL*''' 205 | # test [r/m]:8, r8 206 | 31, # 84 207 | # test [r/m]:16/32, r16/32 208 | 31, # 85 209 | # xchg [r/m]:8, r8 210 | 89, # 86 211 | # xchg [r/m]:16/32, r16/32 212 | 89, # 87 213 | # mov [r/m]:8, r8 214 | 2, # 88 215 | # mov [r/m]:16/32, r16/32 216 | 2, # 89 217 | # mov r8, [r/m]:8 218 | 2, # 8A 219 | # mov r16/32, [r/m]:16/32 220 | 2, # 8B 221 | # mov [r/m]:16, sreg 222 | 137, # 8C 223 | # lea r16/32, [r/m] 224 | 29, # 8D 225 | # mov sreg, [r/m]:16 226 | 137, # 8E 227 | # pop [r/m]:16/32 228 | 23, # 8F 229 | # nop 230 | 1, # 90 231 | # xchg ecx, eax 232 | 89, # 91 233 | 89, # 92 234 | 89, # 93 235 | 89, # 94 236 | 89, # 95 237 | 89, # 96 238 | # xchg edi, eax 239 | 89, # 97 240 | # cwde 241 | 263, # 98 242 | # cdq 243 | 269, # 99 244 | # call far 245 | 271, # 9A 246 | # fwait 247 | 277, # 9B ''' fpu ''' 248 | # pushf 249 | 281, # 9C 250 | # popf 251 | 281, # 9D 252 | # sahf 253 | 283, # 9E 254 | # lahf 255 | 283, # 9F 256 | # mov al, [imm8] 257 | 2, # A0 258 | # mov ax/eax, [imm16/32] 259 | 2, # A1 260 | # mov [imm8], al 261 | 2, # A2 262 | # mov [imm16/32], ax/eax 263 | 2, # A3 264 | # movsb 265 | 179, # A4 266 | # movsd 267 | 179, # A5 268 | # cmpsb 269 | 181, # A6 270 | # cmpsd 271 | 181, # A7 272 | # test al, c8 273 | 37, # A8 274 | # test ax/eax, c16/32 275 | 37, # A9 276 | # stosb 277 | 191, # AA 278 | # stosd 279 | 191, # AB 280 | # lodsb 281 | 193, # AC 282 | # lodsd 283 | 193, # AD 284 | # scasb 285 | 197, # AE 286 | # scasd 287 | 197, # AF 288 | # mov al, c8 289 | 3, # B0 290 | 3, # B1 291 | 3, # B2 292 | 3, # B3 293 | 3, # B4 294 | 3, # B5 295 | 3, # B6 296 | # mov bh, c8 297 | 3, # B7 298 | # mov ax/eax, c16/32 299 | 3, # B8 300 | 3, # B9 301 | 3, # BA 302 | 3, # BB 303 | 3, # BC 304 | 3, # BD 305 | 3, # BE 306 | # mov di/edi, c16/32 307 | 3, # BF 308 | # ttt: 0=rol 1=ror 2=rcl 3=rcr 4=shl 5=shr 6=sal 7=sar 309 | # shift-ttt [r/m]:8, imm8 310 | 71, # C0 311 | # shift-ttt [r/m]:16/32, imm8 312 | 71, # C1 313 | # retn c16 314 | 239, # C2 315 | # retn 316 | 239, # C3 317 | # les 318 | 137, # C4 319 | # lds 320 | 137, # C5 321 | # ttt=000, other illegal 322 | # mov [r/m], imm8 323 | 3, # C6 324 | # mov [r/m], imm16/32 325 | 3, # C7 326 | # enter 327 | 139, # C8 328 | # leave 329 | 149, # C9 330 | # retf c16 331 | 239, # CA 332 | # retf 333 | 239, # CB 334 | # int3 335 | 199, # CC 336 | # int n 337 | 199, # CD 338 | # into 339 | 199, # CE 340 | # iret 341 | 239, # CF 342 | # ttt: 0=rol 1=ror 2=rcl 3=rcr 4=shl 5=shr 6=sal 7=sar 343 | # shift-ttt [r/m]:8, 1 344 | 71, # D0 345 | # shift-ttt [r/m]:16/32, 1 346 | 71, # D1 347 | # shift-ttt [r/m]:8, cl 348 | 71, # D2 349 | # shift-ttt [r/m]:16/32, cl 350 | 71, # D3 351 | # aam nn 352 | 233, # D4 353 | # aad nn 354 | 233, # D5 355 | # setalc 356 | 307, # D6 357 | # xlat 358 | 293, # D7 359 | 277, # D8 ''' fpu ''' 360 | 277, # D9 ''' fpu ''' 361 | 277, # DA ''' fpu ''' 362 | 277, # DB ''' fpu ''' 363 | 277, # DC ''' fpu ''' 364 | 277, # DD ''' fpu ''' 365 | 277, # DE ''' fpu ''' 366 | 277, # DF ''' fpu ''' 367 | # loopne 368 | 151, # E0 369 | # loope 370 | 151, # E1 371 | # loop 372 | 151, # E2 373 | # jecxz 374 | 311, # E3 375 | # in al, nn 376 | 167, # E4 377 | # in ax/eax, nn 378 | 167, # E5 379 | # out nn, al 380 | 173, # E6 381 | # out nn, ax/eax 382 | 173, # E7 383 | # call near 384 | 7, # E8 385 | # jmp near 386 | 311, # E9 387 | # jmp far 388 | 311, # EA 389 | # jmp short 390 | 311, # EB 391 | # in al, dx 392 | 167, # EC 393 | # in ax/eax, dx 394 | 167, # ED 395 | # out dx, al 396 | 173, # EE 397 | # out dx, ax/eax 398 | 173, # EF 399 | # lock prefix 400 | 173, # F0 401 | # int1 402 | 199, # F1 403 | # repne 404 | 157, # F2 405 | # repe 406 | 157, # F3 407 | # hlt 408 | 211, # F4 409 | # cmc 410 | 367, # F5 411 | # ttt: 0=test 1=??? 2=not 3=neg 4=mul 5=imul 6=div 7=idiv 412 | 1, # ''' F6 ''' '''*C_SPECIAL*''' 413 | 1, # ''' F7 ''' '''*C_SPECIAL*''' 414 | # clc 415 | 179, # F8 416 | # stc 417 | 163, # F9 418 | # cli 419 | 179, # FA 420 | # sti 421 | 163, # FB 422 | # cld 423 | 179, # FC 424 | # std 425 | 163, # FD 426 | # ttt: 0=inc 1=dec 2=??? 3=??? 4=??? 5=??? 6=??? 7=??? 427 | 1, # ''' FE ''' '''*SPECIAL*''' 428 | # ttt: 0=inc 1=dec 2=callnear 3=callfar 4=jmpnear 5=jmpfar 6=push 7=??? 429 | 1, # ''' FF ''' '''*SPECIAL*''' 430 | 431 | #''' 2nd half of the table, 0F-prefixed opcodes ''' 432 | 433 | # /0=SLDT /1=STR /2=LLDT /3=LTR /4=VERR /5=VERW /6=??? /7=??? 434 | 347, # 0F 00 435 | # /0=SGDT /1=SIDT /2=LGDT /3=LIDT /4=SMSW /5=??? /6=LMSW /7=INVPLG 436 | 347, # 0F 01 437 | # LAR r16/32, [r/m]:16/32 438 | 347, # 0F 02 439 | # LSL r16/32, [r/m]:16/32 440 | 347, # 0F 03 441 | 347, # 0F 04 442 | 347, # 0F 05 443 | # CLTS 444 | 353, # 0F 06 445 | 353, # 0F 07 446 | # INVD 447 | 359, # 0F 08 448 | # WBINVD 449 | 349, # 0F 09 450 | # ??? 451 | 347, # 0F 0A 452 | # UD2 453 | 347, # 0F 0B 454 | 331, # 0F 0C 455 | 331, # 0F 0D 456 | 331, # 0F 0E 457 | 331, # 0F 0F 458 | # 459 | 257, # 0F 10 460 | 257, # 0F 11 461 | 257, # 0F 12 462 | 257, # 0F 13 463 | 257, # 0F 14 464 | 257, # 0F 15 465 | 257, # 0F 16 466 | 257, # 0F 17 467 | 257, # 0F 18 468 | 257, # 0F 19 469 | 257, # 0F 1A 470 | 257, # 0F 1B 471 | 257, # 0F 1C 472 | 257, # 0F 1D 473 | 257, # 0F 1E 474 | 257, # 0F 1F 475 | 3, # 0F 20 476 | 3, # 0F 21 477 | 3, # 0F 22 478 | 3, # 0F 23 479 | 257, # 0F 24 480 | 257, # 0F 25 481 | 257, # 0F 26 482 | 257, # 0F 27 483 | 257, # 0F 28 484 | 257, # 0F 29 485 | 257, # 0F 2A 486 | 257, # 0F 2B 487 | 257, # 0F 2C 488 | 257, # 0F 2D 489 | 257, # 0F 2E 490 | 257, # 0F 2F 491 | # WRMSR 492 | 313, # 0F 30 493 | 313, # 0F 31 494 | 313, # 0F 32 495 | 313, # 0F 33 496 | 313, # 0F 34 497 | 313, # 0F 35 498 | 313, # 0F 36 499 | 313, # 0F 37 500 | 313, # 0F 38 501 | 313, # 0F 39 502 | 313, # 0F 3A 503 | 313, # 0F 3B 504 | 313, # 0F 3C 505 | 313, # 0F 3D 506 | 313, # 0F 3E 507 | 313, # 0F 3F 508 | 313, # 0F 40 509 | 313, # 0F 41 510 | 313, # 0F 42 511 | 313, # 0F 43 512 | 313, # 0F 44 513 | 313, # 0F 45 514 | 313, # 0F 46 515 | 313, # 0F 47 516 | 313, # 0F 48 517 | 313, # 0F 49 518 | 313, # 0F 4A 519 | 313, # 0F 4B 520 | 313, # 0F 4C 521 | 313, # 0F 4D 522 | 313, # 0F 4E 523 | 313, # 0F 4F 524 | 313, # 0F 50 525 | 313, # 0F 51 526 | 313, # 0F 52 527 | 313, # 0F 53 528 | 313, # 0F 54 529 | 313, # 0F 55 530 | 313, # 0F 56 531 | 313, # 0F 57 532 | 313, # 0F 58 533 | 313, # 0F 59 534 | 313, # 0F 5A 535 | 313, # 0F 5B 536 | 313, # 0F 5C 537 | 313, # 0F 5D 538 | 313, # 0F 5E 539 | 313, # 0F 5F 540 | 313, # 0F 60 541 | 313, # 0F 61 542 | 313, # 0F 62 543 | 313, # 0F 63 544 | 313, # 0F 64 545 | 313, # 0F 65 546 | 313, # 0F 66 547 | 313, # 0F 67 548 | 313, # 0F 68 549 | 313, # 0F 69 550 | 313, # 0F 6A 551 | 313, # 0F 6B 552 | 313, # 0F 6C 553 | 313, # 0F 6D 554 | 313, # 0F 6E 555 | 313, # 0F 6F 556 | 313, # 0F 70 557 | 313, # 0F 71 558 | 313, # 0F 72 559 | 313, # 0F 73 560 | 313, # 0F 74 561 | 313, # 0F 75 562 | 313, # 0F 76 563 | 313, # 0F 77 564 | 313, # 0F 78 565 | 313, # 0F 79 566 | 313, # 0F 7A 567 | 313, # 0F 7B 568 | 313, # 0F 7C 569 | 313, # 0F 7D 570 | 313, # 0F 7E 571 | 313, # 0F 7F 572 | # jxx near 573 | 311, # 0F 80 574 | 311, # 0F 81 575 | 311, # 0F 82 576 | 311, # 0F 83 577 | 311, # 0F 84 578 | 311, # 0F 85 579 | 311, # 0F 86 580 | 311, # 0F 87 581 | 311, # 0F 88 582 | 311, # 0F 89 583 | 311, # 0F 8A 584 | 311, # 0F 8B 585 | 311, # 0F 8C 586 | 311, # 0F 8D 587 | 311, # 0F 8E 588 | 311, # 0F 8F 589 | # ''' setxx ''' 590 | 181, # 0F 90 591 | 181, # 0F 91 592 | 181, # 0F 92 593 | 181, # 0F 93 594 | 181, # 0F 94 595 | 181, # 0F 95 596 | 181, # 0F 96 597 | 181, # 0F 97 598 | 181, # 0F 98 599 | 181, # 0F 99 600 | 181, # 0F 9A 601 | 181, # 0F 9B 602 | 181, # 0F 9C 603 | 181, # 0F 9D 604 | 181, # 0F 9E 605 | 181, # 0F 9F 606 | # push fs 607 | 137, # 0F A0 608 | # pop fs 609 | 137, # 0F A1 610 | # cpuid 611 | 337, # 0F A2 612 | # bt [r/m]:16/32, r16/32 613 | 317, # 0F A3 614 | # shld [r/m]:16/32, r16/32, imm8 615 | 241, # 0F A4 616 | # shld [r/m]:16/32, r16/32, CL 617 | 241, # 0F A5 618 | 317, # 0F A6 619 | 317, # 0F A7 620 | # push gs 621 | 137, # 0F A8 622 | # pop gs 623 | 137, # 0F A9 624 | # RSM 625 | 331, # 0F AA 626 | # bts [r/m]:16/32, r16/32 627 | 317, # 0F AB 628 | # shrd [r/m]:16/32, r16/32, imm8 629 | 241, # 0F AC 630 | # shrd [r/m]:16/32, r16/32, CL 631 | 241, # 0F AD 632 | 331, # 0F AE 633 | # imul r16/32, [r/m]:16/32 634 | 131, # 0F AF 635 | # cmpxchg [r/m]:8, r8 636 | 223, # 0F B0 637 | # cmpxchg [r/m]:16/32, r16/32 638 | 223, # 0F B1 639 | # lss reg, r/m 640 | 137, # 0F B2 641 | # btr [r/m]:16/32, r16/32 642 | 317, # 0F B3 643 | # lfs reg, r/m 644 | 137, # 0F B4 645 | # lgs reg, r/m 646 | 137, # 0F B5 647 | # movzx r16/32, [r/m]:8 648 | 367, # 0F B6 649 | # movzx 32, [r/m]:16 650 | 367, # 0F B7 651 | 331, # 0F B8 652 | 331, # 0F B9 653 | # ttt: 1=??? 2=??? 3=??? 4=bt 5=bts 6=btr 7=btc 654 | # ttt [r/m], imm8 655 | 317, # 0F BA 656 | # btc [r/m]:16/32, r16/32 657 | 317, # 0F BB 658 | # bsf r16/32, [r/m]:16/32 659 | 317, # 0F BC 660 | # bsr r16/32, [r/m]:16/32 661 | 317, # 0F BD 662 | # movsx r16/32, [r/m]:8 663 | 373, # 0F BE 664 | # movsx r32, [r/m]:16 665 | 373, # 0F BF 666 | # xadd [r/m]:8, r8 667 | 379, # 0F C0 668 | # xadd [r/m]:16/32, r16/32 669 | 379, # 0F C1 670 | 331, # 0F C2 671 | 331, # 0F C3 672 | 331, # 0F C4 673 | 331, # 0F C5 674 | 331, # 0F C6 675 | 331, # 0F C7 676 | # BSWAP r32 677 | 227, # 0F C8 678 | 227, # 0F C9 679 | 227, # 0F CA 680 | 227, # 0F CB 681 | 227, # 0F CC 682 | 227, # 0F CD 683 | 227, # 0F CE 684 | 227, # 0F CF 685 | 331, # 0F D0 686 | 331, # 0F D1 687 | 331, # 0F D2 688 | 331, # 0F D3 689 | 331, # 0F D4 690 | 331, # 0F D5 691 | 331, # 0F D6 692 | 331, # 0F D7 693 | 331, # 0F D8 694 | 331, # 0F D9 695 | 331, # 0F DA 696 | 331, # 0F DB 697 | 331, # 0F DC 698 | 331, # 0F DD 699 | 331, # 0F DE 700 | 331, # 0F DF 701 | 331, # 0F E0 702 | 331, # 0F E1 703 | 331, # 0F E2 704 | 331, # 0F E3 705 | 331, # 0F E4 706 | 331, # 0F E5 707 | 331, # 0F E6 708 | 331, # 0F E7 709 | 331, # 0F E8 710 | 331, # 0F E9 711 | 331, # 0F EA 712 | 331, # 0F EB 713 | 331, # 0F EC 714 | 331, # 0F ED 715 | 331, # 0F EE 716 | 331, # 0F EF 717 | 331, # 0F F0 718 | 331, # 0F F1 719 | 331, # 0F F2 720 | 331, # 0F F3 721 | 331, # 0F F4 722 | 331, # 0F F5 723 | 331, # 0F F6 724 | 331, # 0F F7 725 | 331, # 0F F8 726 | 331, # 0F F9 727 | 331, # 0F FA 728 | 331, # 0F FB 729 | 331, # 0F FC 730 | 331, # 0F FD 731 | 331, # 0F FE 732 | 331, # 0F FF 733 | 734 | #''' additional tables, added in XDE ''' 735 | 736 | # ''' ttt: 0=add 1=or 2=adc 3=sbb 4=and 5=sub 6=xor 7=cmp ''' 737 | # ''' x=0..3 ''' 738 | 19, # 8x /0 739 | 79, # 8x /1 740 | 101, # 8x /2 741 | 107, # 8x /3 742 | 67, # 8x /4 743 | 59, # 8x /5 744 | 43, # 8x /6 745 | 13, # 8x /7 746 | # ''' ttt: 0=test 1=??? 2=not 3=neg 4=mul 5=imul 6=div 7=idiv ''' 747 | 37, # F6 /0 748 | 131, # F6 /1 749 | 131, # F6 /2 750 | 131, # F6 /3 751 | 131, # F6 /4 752 | 131, # F6 /5 753 | 131, # F6 /6 754 | 131, # F6 /7 755 | # ''' ttt: 0=test 1=??? 2=not 3=neg 4=mul 5=imul 6=div 7=idiv ''' 756 | 37, # F7 /0 757 | 131, # F7 /1 758 | 131, # F7 /2 759 | 131, # F7 /3 760 | 131, # F7 /4 761 | 131, # F7 /5 762 | 131, # F7 /6 763 | 131, # F7 /7 764 | # ''' ttt: 0=inc 1=dec 2=??? 3=??? 4=??? 5=??? 6=??? 7=??? ''' 765 | 47, # FE /0 766 | 83, # FE /1 767 | 83, # FE /2 768 | 83, # FE /3 769 | 83, # FE /4 770 | 83, # FE /5 771 | 83, # FE /6 772 | 83, # FE /7 773 | # ''' ttt: 0=inc 1=dec 2=callnear 3=callfar 4=jmpnear 5=jmpfar 6=push 7=??? ''' 774 | 47, # FF /0 775 | 83, # FF /1 776 | 7, # FF /2 777 | 7, # FF /3 778 | 311, # FF /4 779 | 311, # FF /5 780 | 5, # FF /6 781 | 311, # FF /7 782 | ] 783 | -------------------------------------------------------------------------------- /src/disasm/vmext.py: -------------------------------------------------------------------------------- 1 | from . import C 2 | import capstone as cs 3 | 4 | class DummyIns(object): 5 | 6 | def group(self,grp): 7 | return '' 8 | 9 | 10 | class DummyOp(object): 11 | pass 12 | 13 | class DummyVal(object): 14 | pass 15 | 16 | 17 | def mk_inst(addr,base,mnem,bytes,ops=[],op_str=''): 18 | i = DummyIns() 19 | i.mnemonic = mnem 20 | i.address = addr 21 | i.opcode = bytes 22 | i.operands = ops 23 | i.op_str = op_str 24 | i.size = len(bytes) 25 | return C(i,base) 26 | 27 | vm_table = [ 28 | ['vmgetinfo','vmsetinfo','vmdxdsbl','vmdxenbl'], 29 | ['vmcpuid', 'vmhlt','vmsplaf'], 30 | ['vmpushfd','vmpopfd','vmcli','vmsti','vmiretd'], 31 | ['vmsgdt','vmsidt','vmsldt','vmstr'], 32 | ['vmsdte'], 33 | ] 34 | def decode_vm(ldr,addr): 35 | 36 | b0 = ldr.byte(addr) 37 | if b0 not in (0x0f,0xf0,0x66): 38 | # one of intels prefixes 39 | return None 40 | 41 | b1 = ldr.byte(addr+1) 42 | if b1 == 0x3f: 43 | b2 = ldr.byte(addr+2) 44 | b3 = ldr.byte(addr+3) 45 | if b2 in (0x01,0x05,0x07,0x0d,0x10) and b3: 46 | 47 | op1 = DummyOp() 48 | op1.type = cs.CS_OP_IMM 49 | op1.value = DummyVal() 50 | op1.value.imm = b2 51 | 52 | op2 = DummyOp() 53 | op2.type = cs.CS_OP_IMM 54 | op2.value = DummyVal() 55 | op2.value.imm = b3 56 | 57 | op_str = '%xh, %xh' % (b2,b3) 58 | ops =[op1,op2] 59 | b = [b0,b1,b2,b3] 60 | i = mk_inst(addr,ldr.base,'vpcext',b,ops,op_str) 61 | return i 62 | 63 | elif b1 in (0xc6,0xc7): 64 | b2 = ldr.byte(addr+2) 65 | if b2 in (0x28,0xc8): 66 | b3 = ldr.byte(addr+3) 67 | b4 = ldr.byte(addr+4) 68 | b = [b0,b1,b2,b3,b4] 69 | 70 | if b3 < len(vm_table) and b4 < len(vm_table[b3]): 71 | i = mk_inst(addr,ldr.base,vm_table[b3][b4],b) 72 | return i 73 | 74 | elif b1 == 0x01: 75 | b2 = ldr.byte(addr+2) 76 | idx = b2 - 0xc0 77 | tbl = [ "vmxoff","vmcall","vmlaunch","vmresume","vmxon"] 78 | if idx < 5: 79 | i = mk_inst(addr,ldr.base,tbl[idx],[b0,b1,b2]) 80 | return i 81 | return None 82 | -------------------------------------------------------------------------------- /src/hash.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | from mlib.bits import rol, ror 3 | 4 | 5 | def mlwr_hash(name): 6 | x = 0 7 | for c in name: 8 | x = rol(x, 7) 9 | x = (x ^ ord(c)) & 0xff | x & 0xffffff00 10 | return x 11 | 12 | 13 | def ror7_hash(name): 14 | x = 0 15 | for c in name: 16 | x = ror(x, 7) & 0xffffffff 17 | x += ord(c) 18 | x &= 0xffffffff 19 | return x 20 | 21 | 22 | def rol7_hash(name): 23 | x = 0 24 | for c in name: 25 | x = rol(x, 7) & 0xffffffff 26 | x += ord(c) 27 | x &= 0xffffffff 28 | return x 29 | 30 | 31 | def std_hash(name): 32 | x = 0 33 | for c in name: 34 | x = (rol(x, 19) + ord(c)) & 0xffffffff 35 | return x 36 | 37 | 38 | def crc32_hash(name): 39 | return binascii.crc32(name) & 0xffffffff 40 | 41 | 42 | def djb2_hash(name): 43 | x = 5381 44 | for c in name: 45 | x = ((x << 5) + x) + ord(c) 46 | x &= 0xffffffff 47 | return x 48 | 49 | 50 | def sdbm_hash(name): 51 | x = 0 52 | for c in name: 53 | x = ord(c) + (x << 6) + (x << 16) - x 54 | x &= 0xffffffff 55 | return x 56 | -------------------------------------------------------------------------------- /src/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import sys 3 | from logging import config, StreamHandler, Formatter, getLogger, INFO, DEBUG 4 | from logging.handlers import SysLogHandler 5 | 6 | 7 | logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] %(message)s') 8 | LOG_SUCCES = 1337 9 | 10 | LOG_TRANS = {} 11 | LOG_TRANS[logging.INFO] = {'old': '', 'new': '*'} 12 | LOG_TRANS[LOG_SUCCES] = {'old': 'SUCCSES', 'new': '+'} 13 | LOG_TRANS[logging.ERROR] = {'old': '', 'new': '-'} 14 | LOG_TRANS[logging.WARNING] = {'old': '', 'new': '!'} 15 | import StringIO 16 | 17 | LOGBUF = StringIO.StringIO() 18 | 19 | 20 | # logging.addLevelName(LOG_SUCCES,'+') 21 | 22 | def parse_fac(f): 23 | if isinstance(f, int): 24 | return f 25 | return getattr(SysLogHandler, 'LOG_LOCAL0') 26 | 27 | 28 | class F(Formatter): 29 | def format(self, rec): 30 | r = logging.Formatter.format(self, rec) 31 | if rec.levelno in LOG_TRANS: 32 | return '[%s]%s' % (LOG_TRANS[rec.levelno]['old'], rec) 33 | else: 34 | return '[%s]%s' % (logging.getLevelName(rec.levelno), rec) 35 | 36 | 37 | def get_logger(name, level=INFO, fac=SysLogHandler.LOG_LOCAL1): 38 | 39 | global LOG_TRANS 40 | 41 | for lt in LOG_TRANS: 42 | if not LOG_TRANS[lt]['old']: 43 | LOG_TRANS[lt]['old'] = logging.getLevelName(lt) 44 | logging.addLevelName(lt, LOG_TRANS[lt]['new']) 45 | 46 | fmt = F('[%(name)s.%(funcName)s]: %(message)s') 47 | log = logging.getLogger('%s' % name.split('.')[-1]) 48 | h = SysLogHandler(address='/dev/log', facility=parse_fac(fac)) 49 | h.setFormatter(fmt) 50 | log.addHandler(h) 51 | # h = StreamHandler(stream=LOGBUF) 52 | # h.setFormatter(fmt) 53 | # log.addHandler(h) 54 | log.setLevel(level) 55 | log.success = lambda msg: log.log(LOG_SUCCES, msg) 56 | return log 57 | 58 | 59 | def hide(n): 60 | logging.getLogger(n).setLevel(logging.CRITICAL) 61 | -------------------------------------------------------------------------------- /src/malware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mak/mlib/b6114487b8dc5a8a819c207d3f28a41ddd20c09f/src/malware/__init__.py -------------------------------------------------------------------------------- /src/malware/isfb.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from struct import unpack 3 | from mlib.crypto import serpent,rc6 4 | from mlib.compression import aplib 5 | 6 | 7 | CMDS = ['LOAD_UPDATE', 'LOAD_INI', 'GET_SYSINFO', 'LOAD_DLL', 'GROUP', 'SELF_DELETE', 'GET_CERTS', 8 | 'CLR_COOKIES', 'URL_BLOCK', 'KILL', 'GET_FILES', 'GET_COOKIES', 'LOAD_REG_DLL', 'LOAD_EXE'] 9 | 10 | 11 | def _decode_meta(pkey, enc_m, block): 12 | def cv(x): 13 | x = hex(x)[2:].strip('L') 14 | x = x.zfill(block * 2) 15 | return x.decode('hex') 16 | 17 | def strip_padd(x): 18 | if x[:2] == "\x00\x01": 19 | o = x[2:].find("\x00") + 1 + 2 20 | return x[o:] 21 | return x 22 | 23 | # we need to do rsa-pubkey decryption/unsing via hand... 24 | meta = pow(long(enc_m.encode('hex'), 16), pkey[1], pkey[0]) 25 | meta = cv(meta) 26 | 27 | meta = strip_padd(meta) 28 | md5 = meta[:0x10] 29 | xkey = meta[0x10:0x20] 30 | ss = unpack('I', meta[0x10 * 2:0x10 * 2 + 4])[0] 31 | return md5, xkey, ss 32 | 33 | 34 | def raw_decrypt_buffer(d, pkey, decrypt, xunpack=True): 35 | block = len(hex(pkey[0])[2:].strip('L')) / 2 36 | # decode last block as meta data 37 | md5, xkey, ss = _decode_meta(pkey, d[-block:], block) 38 | # with# open('/tmp/isfbx.xdec.bin','w') as f: f.write(d) 39 | 40 | d = decrypt(d[:-block], xkey)[:ss] 41 | 42 | if md5 == hashlib.md5(d).digest(): 43 | if not d: 44 | return 45 | if any(map(lambda x: d.startswith(x), CMDS)): 46 | return d 47 | s = unpack('I', d[:4])[0] 48 | return aplib.decompress(d[4:], s + 0x10) if xunpack else d 49 | else: 50 | raise Exception('Wrong checksum') 51 | 52 | 53 | def full_decrypt_buffer(data,pk,xunpack=False): 54 | 55 | 56 | def decryptor(d,k): 57 | return rc6.decrypt(d,k,typ='str',inverse=True,iv = [0,0,0,0]) 58 | 59 | algos = [('rc6big',decryptor), 60 | ('serpent',serpent.decrypt), 61 | ('rc6',rc6.decrypt) 62 | ] 63 | cfg = None 64 | for enc_typ, enc in algos: 65 | try: 66 | cfg = raw_decrypt_buffer(data,pk,enc,xunpack) 67 | break 68 | except: 69 | pass 70 | return cfg,enc_typ 71 | 72 | def decrypt_buffer(data,pk,xunpack=False): 73 | return full_decrypt_buffer(data,pk,xunpack)[0] 74 | -------------------------------------------------------------------------------- /src/malware/pushdo.py: -------------------------------------------------------------------------------- 1 | import ctypes as c 2 | import hashlib 3 | from mlib.crypto import rc4 4 | from mlib.compression import gzip 5 | from mlib.struct import Structure 6 | 7 | 8 | def find_buffer(d): 9 | r = -1, None 10 | for i in range(len(d) - 0x300): 11 | data = d[i:i + 0x300] 12 | key = hashlib.md5(data[:16]).digest() 13 | xdata = rc4.decrypt(data[16:], key) 14 | chk = hashlib.md5(data[:16] + xdata[:-16]).digest() 15 | 16 | if chk == xdata[752 - 16:]: 17 | r = i, data[:16] + xdata 18 | break 19 | return r 20 | 21 | 22 | class C(Structure): 23 | _pack_ = 1 24 | _fields_ = [ 25 | ('key', c.c_ubyte * 0x10), 26 | ('unk1', c.c_uint), 27 | ('unk2', c.c_uint), 28 | ('file_name', c.c_char * 20), 29 | ('_ds', c.c_ushort), 30 | ('_d', c.c_ubyte * (0x300 - 0x10 * 2 - 8 - 20 - 2)), 31 | ('checksum', c.c_ubyte * 0x10) 32 | ] 33 | _blacklist_ = ['key', 'checksum', '_ds', '_d'] 34 | 35 | @property 36 | def data(self): 37 | if not hasattr(self, '_data'): 38 | d = ''.join(map(chr, self._d[:self._ds])) 39 | self._data = gzip.decompress(d) 40 | return self._data 41 | 42 | def as_dict(self): 43 | r = super(C, self).as_dict() 44 | r['data'] = self.data 45 | return r 46 | 47 | 48 | def parse_cfg(data): 49 | return C.parse(data) 50 | -------------------------------------------------------------------------------- /src/malware/trickbot.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from mlib.crypto import aes 3 | from mlib.rnd import LCG 4 | 5 | BS = 16 6 | 7 | 8 | def pad(s): return s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 9 | 10 | 11 | def unpad(s): return s[:-ord(s[len(s) - 1:])] 12 | 13 | 14 | def hash_rounds(data_buf): 15 | while len(data_buf) <= 0x1000: 16 | buf_hash = hashlib.sha256(data_buf).digest() 17 | data_buf += buf_hash 18 | return buf_hash 19 | 20 | 21 | def decrypt(data): 22 | key = hash_rounds(data[:0x20])[:0x20] 23 | iv = hash_rounds(data[0x10:0x30])[:0x10] 24 | data = pad(data[0x30:]) 25 | return aes.decrypt(data, key, None, 'cbc', iv) 26 | 27 | 28 | class TrickLCG(LCG): 29 | mul = 0xAE529 30 | add = 0x24D69 31 | -------------------------------------------------------------------------------- /src/memory.py: -------------------------------------------------------------------------------- 1 | import types 2 | import sys 3 | import os 4 | import struct 5 | from StringIO import StringIO 6 | 7 | 8 | if 'struct' in sys.modules: 9 | del sys.modules['struct'] 10 | st = __import__('struct') 11 | 12 | 13 | def get_size(klass): 14 | import ctypes 15 | f = getattr(klass, 'sizeof', lambda: ctypes.sizeof(klass)) 16 | return f() 17 | 18 | 19 | # sys._getframe(1).f_code.co_name 20 | class M(object): 21 | 22 | TRANSL = {'byte': ('B', 1), 'word': ('H', 2), 23 | 'dword': ('I', 4), 'qword': ('Q', 8)} 24 | 25 | def __init__(self, d, end_fmt=''): 26 | self._len = len(d) 27 | self.b = StringIO(d) 28 | 29 | def _get_bytes(self, fmt, s, off): 30 | return st.unpack(fmt, self.read(off, s) if off else self.read(s))[0] 31 | 32 | def skip(self, n): 33 | self.b.seek(n, os.SEEK_CUR) 34 | 35 | def unskip(self, n): 36 | self.b.seek(-n, os.SEEK_CUR) 37 | 38 | def read(self, a0, a1= None): 39 | r = None 40 | if a1 is None: 41 | r = self.b.read(a0) 42 | else: 43 | r = self.read_at(a0,a1) 44 | return r 45 | 46 | def read_at(self, off, n): 47 | old_l = self.b.tell() 48 | self.b.seek(off, os.SEEK_SET) 49 | r = self.b.read(n) 50 | self.b.seek(old_l, os.SEEK_SET) 51 | return r 52 | 53 | 54 | def read_cstring_at(self, at, is_wide = False): 55 | csize = 1 + int(is_wide) 56 | delim = "\x00" * csize 57 | r = [] 58 | i = 0 59 | l = self.b.tell() 60 | self.b.seek(at, os.SEEK_SET) 61 | t = "" 62 | 63 | while t != delim: 64 | t = self.b.read(csize) 65 | r.append(t) 66 | 67 | r = ''.join(r) 68 | self.b.seek(l, os.SEEK_SET) 69 | return (r.decode('utf-16') if is_wide else r).strip("\x00") 70 | 71 | def read_cstring(self, is_wide = False): 72 | r = self.read_cstring_at(self.b.tell(), is_wide) 73 | self.b.seek((len(r)+1) * (1 + int(is_wide)), os.SEEK_CUR) 74 | return r 75 | 76 | def read_struct_at(self, klass, at): 77 | d = self.read_at(at, get_size(klass)) 78 | return klass.parse(d) 79 | 80 | def read_struct(self, klass): 81 | d = self.read(get_size(klass)) 82 | return klass.parse(d) 83 | 84 | # def bytes(self,t): 85 | # s= self.dword() 86 | # return self.read 87 | def __len__(self): 88 | return self._len 89 | 90 | def __getattr__(self, name): 91 | at = False 92 | if name.endswith('_at'): 93 | name = name[:-3] 94 | 95 | if name in M.TRANSL: 96 | f, s = M.TRANSL[name] 97 | return lambda off = None: self._get_bytes(f, s, off) 98 | 99 | 100 | 101 | if __name__ == '__main__': 102 | m = M(sys.stdin.read()) 103 | print dir(m) 104 | print m.word, m.byte 105 | # print m.byte() 106 | print m.dword() 107 | # print m.word_at(0) 108 | -------------------------------------------------------------------------------- /src/misc.py: -------------------------------------------------------------------------------- 1 | try: 2 | import re2 as re 3 | except ImportError: 4 | import re 5 | 6 | import enum 7 | from functools import wraps 8 | from copy import deepcopy 9 | import gzip as _gz 10 | import errno 11 | import signal 12 | import os 13 | import string 14 | import StringIO 15 | import random 16 | import hashlib 17 | import datetime 18 | #import log 19 | #log = log.get_logger(__name__) 20 | 21 | 22 | def chunks(l, n): return [l[x: x + n] for x in xrange(0, len(l), n)] 23 | 24 | def dostime_to_date(dosdate): 25 | date = dosdate >> 16; 26 | time = dosdate & 0xFFFF; 27 | y = ((date & 0xFE00) >> 9) + 1980; 28 | m = (date & 0x1E0) >> 5; 29 | d = date & 0x1F; 30 | h = (time & 0xF800) >> 11; 31 | mi = (time & 0x7E0) >> 5; 32 | s = (time & 0x1F) << 1; 33 | if s == 60: 34 | s = 59 35 | return datetime.datetime(year=y, month=m, day=d, hour=h, minute=mi, second=s) 36 | 37 | 38 | 39 | BASEPATH = '' 40 | 41 | 42 | def re_match(r, d, cstr): 43 | if cstr: 44 | r += '\x00' 45 | return map(lambda x: x.strip("\x00"), re.findall(r, d)) 46 | 47 | 48 | get_urls = lambda d, cstr=False: re_match("https?://[\x21-\x7e]{6,}", d, cstr) 49 | get_strings = lambda d, cstr=False: re_match('[ -~]{3,}', d, cstr) 50 | get_stringsW = lambda d, cstr=False: map(lambda x: x[0].decode('utf-16').strip("\x00"),re.findall(r'(([^\x00]\x00)+\x00\x00)', d + ("\x00\x00" if cstr else ''))) 51 | 52 | class E(enum.Enum): 53 | 54 | @classmethod 55 | def from_val(cls, val): 56 | for n, e in cls.__members__.items(): 57 | if e.value == val: 58 | return e 59 | return None 60 | 61 | # def generic_parse(_data): 62 | # try: 63 | # return _generic_parse(_data) 64 | # except: 65 | # print _data 66 | # raise Exception('asdf') 67 | 68 | def hexdump(src, length=16): 69 | FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) 70 | lines = [] 71 | for c in xrange(0, len(src), length): 72 | chars = src[c:c+length] 73 | hex = ' '.join(["%02x" % ord(x) for x in chars]) 74 | printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars]) 75 | lines.append("%04x %-*s %s\n" % (c, length*3, hex, printable)) 76 | return ''.join(lines) 77 | 78 | 79 | def generic_unparse(data, do_rest=False): 80 | cfg = deepcopy(data) 81 | r = ['INJECTS'] 82 | r.append('=' * 80) 83 | for inj in cfg['injects']: 84 | 85 | r.append('Target: ' + inj['target']) 86 | inj['injects'] 87 | for i in inj['injects']: 88 | if 'pre' in i: 89 | r.append('') 90 | r.append(i['pre']) 91 | r.append('') 92 | if 'post' in i: 93 | r.append('') 94 | r.append(i['post']) 95 | r.append('') 96 | if 'inj' in i: 97 | r.append('') 98 | r.append(i['inj']) 99 | r.append('') 100 | 101 | r.append('\n\nACTIONS') 102 | r.append('=' * 80) 103 | for a in cfg.get('actions', []): 104 | r.append('Target: %s | Action: %s | Type: %s' % 105 | (a['target'], a['action'], a['type'])) 106 | r.append("\n") 107 | if do_rest: 108 | for el in cfg: 109 | if el in ['injects', 'actions']: 110 | continue 111 | 112 | r.append(el.upper()) 113 | r.append('=' * 80) 114 | for e in cfg[el]: 115 | r.append(str(e)) 116 | r.append("\n") 117 | return "\n".join(r) 118 | 119 | 120 | def realpath(p): 121 | my_path = os.path.abspath(os.path.expanduser(p)) 122 | if os.path.islink(my_path): 123 | my_path = os.readlink(my_path) 124 | return my_path 125 | 126 | 127 | def realdir(p): 128 | my_path = realpath(p) 129 | return os.path.dirname(os.path.dirname(my_path)) 130 | 131 | 132 | def get_my_path(): 133 | global BASEPATH 134 | if not BASEPATH: 135 | BASEPATH = realdir(__file__) + os.sep + __name__.split('.')[0] 136 | return BASEPATH 137 | 138 | 139 | def ngrams(data, cnt=4): 140 | a = [data] 141 | for i in range(1, cnt): 142 | a.append(data[cnt:]) 143 | return zip(*a) 144 | 145 | 146 | def generic_parse(_data): 147 | 148 | if not _data: 149 | return None 150 | 151 | off = _data.find('set_url') 152 | off2 = 0 153 | ret = [] 154 | while off < len(_data): 155 | off2 = _data.find('set_url', off + 7) 156 | if off2 == -1: 157 | ret.append(_process_ent(_data[off:])) 158 | break 159 | else: 160 | ret.append(_process_ent(_data[off:off2])) 161 | off = off2 162 | # print off 163 | return ret 164 | 165 | 166 | def _process_ent(d): 167 | try: 168 | ret = {} 169 | __process_ent(d, ret) 170 | except Exception as e: 171 | import traceback 172 | print '-' * 20 173 | print d 174 | print '#' * 20 175 | print ret 176 | print '-' * 20 177 | traceback.print_exc() 178 | return ret 179 | 180 | 181 | def __process_ent(d, ret): 182 | TRNSL = {'data_before': 'pre', 'data_after': 'post', 183 | 'data_inject': 'inj', 'data_count': 'cnt'} 184 | d = d.strip() 185 | 186 | # try: 187 | trgt, rest = d.split("\n", 1) 188 | # except: 189 | # print '#'*20 190 | # print rest 191 | # raise Exception('e1') 192 | 193 | try: 194 | _, url, fl = trgt.strip().split(' ') 195 | except ValueError: 196 | if trgt.strip() == 'set_url': 197 | # huh target url in new line? 198 | url, rest = rest.split("\n", 1) 199 | else: 200 | _, url = trgt.strip().split(' ') 201 | 202 | fl = '' 203 | ret['flags'] = fl 204 | ret['target'] = url 205 | ret['injects'] = [] 206 | 207 | r = {} 208 | 209 | while rest: 210 | # skip comments? 211 | if rest.startswith(';') or rest.startswith('#'): 212 | o = rest.find("\n") 213 | if o == -1: 214 | return ret 215 | 216 | rest = rest[o + 1:] 217 | continue 218 | 219 | 220 | # try: 221 | tag, rest2 = rest.split("\n", 1) 222 | # except: 223 | # print '#'*20 224 | # print `rest` 225 | # raise Exception('e2') 226 | 227 | rest = rest2 228 | tag = tag.strip() 229 | if not tag: 230 | continue 231 | 232 | if tag == 'data_end': 233 | #log.error('fucked up config... skip it...') 234 | print '[-] fucked up config... skip it...' 235 | continue 236 | 237 | _end = rest.find('data_end') 238 | r[TRNSL[tag]] = rest[:_end].strip().decode('unicode-escape') 239 | 240 | if tag == 'data_after': 241 | ret['injects'].append(r) 242 | r = {} 243 | rest = rest[_end + 8:].strip() 244 | 245 | 246 | def load_dll(path): 247 | import ctypes 248 | p = get_my_path() 249 | return ctypes.cdll.LoadLibrary(os.path.join(p, path)) 250 | 251 | 252 | def get_thread_pool(c): 253 | from multiprocessing.pool import ThreadPool 254 | return ThreadPool(processes=c) 255 | -------------------------------------------------------------------------------- /src/parse.py: -------------------------------------------------------------------------------- 1 | import mlib 2 | from mlib.struct import udword 3 | from mlib.winapi.crypto import import_key 4 | 5 | 6 | def parse_pubkey_rsa(rsa_bin, ignore_len=False): 7 | r = import_key(rsa_bin, dump_key=True) 8 | if not r: 9 | return rsa_bin.encode('hex') 10 | r['n'] = str(r['n']) 11 | if 'd' in r: 12 | r['d'] = str(r['d']) 13 | return r 14 | 15 | 16 | def parse_key_ecc(ecc_bin): 17 | s = udword(ecc_bin) 18 | ecc_bin = ecc_bin[4:4 + s] 19 | keys = udword(ecc_bin, off=4) 20 | t = {'ECS3': 'ecdsa_pub_p384', 'ECS4': 'ecdsa_priv_p384'}[ecc_bin[0:4]] 21 | x = ecc_bin[8:8 + keys] 22 | y = ecc_bin[8 + keys:keys * 2 + 8] 23 | return {'t': t, 'x': str(int(x.encode('hex'), 16)), 'y': str(int(y.encode('hex'), 16))} 24 | 25 | 26 | def parse_asn1_pubkey(asn1): 27 | import bitarray 28 | from pyasn1.codec.der.decoder import decode 29 | bs = decode(asn1)[0][1] # frist is some oid 30 | try: 31 | b = bitarray.bitarray(str(bs).replace(',', '').replace(' ', '')[1:-1]) 32 | # backward compatibility? 33 | v = decode(b.tobytes())[0] 34 | except: 35 | b = bitarray.bitarray(str(bs)) 36 | v = decode(b.tobytes())[0] 37 | 38 | return {'n': str(v[0]), 'e': int(str(v[1]))} 39 | 40 | 41 | generic_parse = mlib.misc.generic_parse 42 | -------------------------------------------------------------------------------- /src/rnd.py: -------------------------------------------------------------------------------- 1 | import random as _rnd 2 | import string 3 | 4 | 5 | def rstring(n=0, rng=(4, 10)): 6 | n = n if n else _rnd.randint(*rng) 7 | return ''.join([_rnd.choice(string.ascii_letters) for _ in xrange(n)]) 8 | 9 | 10 | def rint32(): 11 | return _rnd.randint(0, 0xffffffff) 12 | 13 | 14 | def rint16(): 15 | return _rnd.randint(0, 0xffff) 16 | 17 | 18 | def rword(): 19 | return rint16() 20 | 21 | 22 | def rint8(): 23 | return _rnd.randint(0, 0xff) 24 | 25 | 26 | def rmax(n): 27 | return _rnd.randint(0, n) 28 | 29 | 30 | def rip(): 31 | return '%d.%d.%d.%d' % (rint8(), rint8(), rint8(), rint8()) 32 | 33 | 34 | class LCG(object): 35 | mul = 0 36 | add = 0 37 | 38 | def __init__(self): 39 | self.seed = 0 40 | 41 | @property 42 | def rnd(self): 43 | self.seed = (((self.mul * self.seed) & 0xFFFFFFFF) + 44 | self.add) & 0xFFFFFFFF 45 | return self.seed 46 | 47 | def choose(self, l): 48 | return l[self.rnd % len(l)] 49 | 50 | def xor(self, data): 51 | return ''.join([chr((self.rnd ^ ord(c)) & 0xff) for c in data]) 52 | 53 | 54 | def rbytes(n): 55 | with open('/dev/urandom') as f: 56 | r = f.read(n) 57 | return r 58 | 59 | 60 | class LsaRandom(LCG): 61 | mul = 0x19660D 62 | add = 0x3C6EF35F 63 | -------------------------------------------------------------------------------- /src/so/_aplib.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mak/mlib/b6114487b8dc5a8a819c207d3f28a41ddd20c09f/src/so/_aplib.so -------------------------------------------------------------------------------- /src/so/_lzmat.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mak/mlib/b6114487b8dc5a8a819c207d3f28a41ddd20c09f/src/so/_lzmat.so -------------------------------------------------------------------------------- /src/so/_serpent.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mak/mlib/b6114487b8dc5a8a819c207d3f28a41ddd20c09f/src/so/_serpent.so -------------------------------------------------------------------------------- /src/struct/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct as st 3 | import ctypes 4 | 5 | if st == sys.modules[__name__]: 6 | del sys.modules['struct'] 7 | st = __import__('struct') 8 | 9 | 10 | uqword = lambda d, off=0: st.unpack_from(' 128: 141 | m = 256 142 | r += data.ljust(m, "\x00")[::-1] 143 | return r 144 | 145 | 146 | class PLAINTEXTKEYBLOB(KRYPTO): 147 | 148 | def parse(self, m, **args): 149 | size = m.dword() 150 | return m.read(size) 151 | 152 | def export(self, data, **k): 153 | return struct.pack('I', len(data)) + data 154 | 155 | 156 | class PUBLICKEYBLOB(KRYPTO): 157 | 158 | magic = 'RSA1' 159 | 160 | def chk_magic(self, m): 161 | assert m.read(4) == self.magic 162 | 163 | def get_int(self, b): 164 | return long(self.mem.read(self.bits / b)[::-1].encode('hex'), 16) 165 | 166 | def pack_int(self, n, b): 167 | return hex(n)[2:].strip('L').decode('hex').ljust(self.bits / b, "\x00")[::-1] 168 | 169 | def check_key(self, data): 170 | if type(data) == dict and 'n' in data and 'e' in data: 171 | e = data['e'] 172 | n = data['n'] 173 | self.bits = len(hex(n)[2:].strip('L')) * 8 / 2 174 | else: 175 | raise WrongKeyType 176 | 177 | def parse(self, m, **args): 178 | self.chk_magic(m) 179 | self.mem = m 180 | self.bits = m.dword() 181 | pexp = m.dword() 182 | return {'e': pexp, 'n': self.get_int(8)} 183 | 184 | def export(self, data, **args): 185 | self.check_key(data) 186 | r = self.magic 187 | r += struct.pack('II', self.bits, e) 188 | r += self.pack_int(n, 8) 189 | return r 190 | 191 | def make_key(self, _, key): 192 | return RSA.construct((key['n'], long(key['e']))) 193 | 194 | 195 | class PRIVATEKEYBLOB(PUBLICKEYBLOB): 196 | 197 | magic = 'RSA2' 198 | 199 | def check_key(self, data): 200 | super(PRIVATEKEYBLOB, self).check_key(data) 201 | if 'd' not in data: 202 | raise WrongKeyType 203 | 204 | def parse(self, m, **args): 205 | 206 | key = super(PRIVATEKEYBLOB, self).parse(m, **args) 207 | key['p1'] = self.get_int(16) 208 | key['p2'] = self.get_int(16) 209 | key['exp1'] = self.get_int(16) 210 | key['exp2'] = self.get_int(16) 211 | key['coeff'] = self.get_int(16) 212 | key['d'] = self.get_int(8) 213 | return key 214 | 215 | def export(self, data, **args): 216 | self.check_key(data) 217 | key = super(PRIVATEKEYBLOB, self).export(data, **args) 218 | key += self.pack_int(data.get('p1', 0), 16) 219 | key += self.pack_int(data.get('p2', 0), 16) 220 | key += self.pack_int(data.get('exp1', 0), 16) 221 | key += self.pack_int(data.get('exp2', 0), 16) 222 | key += self.pack_int(data.get('coeff', 0), 16) 223 | key += self.pack_int(data.get('d', 0), 8) 224 | return key 225 | 226 | def make_key(self, _, key): 227 | return RSA.construct((key['n'], long(key['e']), key['d'])) 228 | 229 | 230 | def import_key(data, **kwargs): 231 | 232 | m = M(data) 233 | hdr = m.read_struct(BLOBHEADER) 234 | 235 | e = BTYPE.from_val(hdr.bType) 236 | if not e: 237 | raise WrongKeyType 238 | 239 | obj = getattr(sys.modules[__name__], e.name)() 240 | c = obj.get_cipher(hdr) 241 | if not c: 242 | raise UnsuportedKey 243 | 244 | key = obj.parse(m, **kwargs) 245 | if kwargs.get('dump_key', None) is True: 246 | return key 247 | elif hasattr(obj, 'make_key'): 248 | return obj.make_key(c, key, **kwargs) 249 | else: 250 | c.key = key 251 | return c 252 | 253 | 254 | def export_key(type, key, **kwargs): 255 | 256 | if '_' in type: 257 | alg, mod = type.split('_') 258 | else: 259 | alg = type 260 | mod = None 261 | 262 | if mod == 'enc' and alg in ('rc2', 'rc4', 'aes'): 263 | obj = SIMPLEBLOB() 264 | elif alg in ('rc2', 'rc4', 'aes'): 265 | obj = PLAINTEXTKEYBLOB() 266 | 267 | elif mod == 'priv' and alg == 'rsa': 268 | obj = PRIVATEKEYBLOB() 269 | elif alg == 'rsa': 270 | obj = PUBLICKEYBLOB() 271 | 272 | else: 273 | raise WrongKeyType 274 | 275 | if type == 'aes': 276 | type = 'aes%d' % (len(data) * 8) 277 | 278 | r = obj.mk_header(alg).pack() 279 | r += obj.export(key, **kwargs) 280 | return r 281 | 282 | 283 | if __name__ == '__main__': 284 | # some test and examples... 285 | pkey = '\x07\x02\x00\x00\x00\xa4\x00\x00RSA2\x00\x04\x00\x00\x01\x00\x01\x00\xb1O\x1f\xbe\xcaE\xadoe\x1a`V\x10.\xddr3\xcfwI_\xf0-\xe8T\xd8<3x\x03)\xc6\xaeL\xb0\xe1y]P\x1d\xd6\xa4\x84\x94\xc3|R\xac]\x9f\xb1W\xb9>\x17\x14\x98\xc7\xda\x8e\x8c\xb2y!z\x85\x8a>b\x02\xdf\x9e\xc8RO\xcd\xff\x8f]\xca;d\xd7\x82\'\xf8wqX\xa2\xa8\x82\xe5\xdd\x94\xe7\xc6\xa2\xb8\xb2\x89\xeay \xbd\xd76f\xf0\xe3\xd4\ng\xd0_\xc0\t:\xafk\xec\xb5\x01\xfe\xd4\xb9\x0c\xbb0\xb4\x96]\x0c9\xa9\x8e\x16\xc6\x7f\xf6C\x83\xe6!\x1cS\xd8\xbd\x19g\x18\xfe\x0f\x95pVA\xdb8\xe1\x99R$\x9e\xfc\xd3\xebC\xbb\x13\xf7f}M}\xc8x!\x98\xe4\x011\xb1\xed\x97}\xb7:\xfc\x88\xb0\xde\xd30\x06\xcc\x90\xdaW\xdd\xaa\x1d\x1e\xc7\x9f\x95yTa\xf5u\x996\x0c\xc8\x91\xd7\xcfw\xbc\x97\xee\x13\xd4p\x0e6\xba\x85L\x9c\\\xd8\xe3\xf5\x8d_\t\x81\x8a\xde\xbb\x15\x18\xee\xfe\x0e\x0fqi\xbd\xc7\x16\xab\x9e\xc9\xd9L\x82*\xfc0>#J\x1b\x1a^M\x8f\x8dF)\xd8\xa7I\xbb#z\x05\x93\xf5\xa2\x8a\xd4\x9e\xd8\t \x91\x9e\xa0\xae}\xc3\x95q\x9e.\xb8\xac\x9az(\xa8l*#\x963~\xdcX\x05X\x99\xdd\xddsC\xde\x17t}\xb3\xfdX\x9d3-^\x8a5\xaf\xbe\xc2\x8c\x1b\xf9\xab\xec\xef1,\xde\x15I~\x8e/[y&[\xce_k\x02\xf2N\x07\x0e/\xd4\x18\xfc\x133\xea\xe5\xa6/\x12\xce\xe1\xf4\xce\xba\x05\xb6c\xbb\'\x87\xce\x9d\xacD\x1b\xb1\x13\xa2\xb5\xde=@!Q\xc2+\xb8\x1bW\tbxu\x8a\xb8N]\xe3\x97\x9a\x974\xac\n\x1c(\xc4iIpyG\x04\x8e\xb6\xcd\n\xa8\xed!\xdbo`\'\xefb\x12^\xdc\x8ac_?\xdd\xb6\x15\xe2{\xfa\xc9\xd7\x82\xf78)VS_\x1b\x080?NQ\x92\x9e\xe5t\x9b\x02\xcf\xbb\x93\xe9\x10\x005_:$\x8a~\xeb\x94\x82*\xce r\x05\x96<\x86\xe7(\x9e,\xed\xfb?\xde\x8c\xbb\xb5D\x93v\xf8\x99J\x11\xa3\xd9\xc2F\x88B2" ' 286 | key = import_key(pkey) 287 | key = make_enc_key(pkey) 288 | 289 | smplk = "\x01\x02\x00\x00\x01h\x00\x00\x00\xa4\x00\x00\xb8\xa7\x92i5\xed+x\x080\x884x\xdf\xad\xa7\x03\xe6\xa2I\xefa\xe2\xf2\xa4\xe9Xu\xb6a\xd4s\x06J\x198\r<\xe0\x13\x04\x89\xfd\x1d\x96(\xad\xb9\xec\x9f\x82,\xc0\xb9\xaf4=\xdaR\xd7?\x9fFVF\xab\x9e\xc8\x0c\xc0\x81\xa2\xec\xc7\xee&\xa7qNH\x1e!\x1a\xc1\xaa\x81\xdcjQ\x88\xebv\xb7-\xeaQ<\xbe\xa1SR\xbd?ZG\xf1\x08\x8b\xf8\xd9\xe5\r$\x884&\xa0\xf7\xf3\xdd\xb5\x82;\x9b\xa5\xd5\xac\xa2" 290 | 291 | smplk2 = '\x01\x02\x00\x00\x01h\x00\x00\x00\xa4\x00\x00\x9b\xf3\xd5\x1f\xef\xb1\xcf\x97\x93\xb6=f\x8f~\xd6na\xf4j\x9c\xf6\xd9\x12-\x06yZ\xbb-Uk!\xe1XHd\x9b\xb9`\xba\xfcA\xcb\xddM&V<\xfcA\xfc\xfc\xe6A\x87\xef\xac\x96\x95c\xb4\xc6c\x0c\x8c\xdb\xaa\xa7\x7f\x89\xbd\x00_\xe3\x93>\xe5\xf4)(\xe4\xe3\x08Z\xa6\xce\xedW\x0c\x94(\xdc\xeb<\xa9\xa4]\x962\xbaX\x8c\x8b\x03\xbb\xccVtn\xcfZ\x8e\xd03\x97t\xe0\x99F\x8c\x89\xdf\x15=\x9b\xd8\x0cM' 292 | 293 | smplk3 = "\x01\x02\x00\x00\x01h\x00\x00\x00\xa4\x00\x00Q\xb1uo\xd8yn\x01\xd1\x1e\x88\xe3\xdaM\x00\xc2\xf6\x83i\xc39\x9a0\xbe\x1d\xff\xa4\xe5\xa5\x80\xdf\x8e\xf2\x99A:n\x1f\xd3\x89\xa9tv\x0fw%\x14G\xf8\x11\x1dj_\x1f\xff\xaa\xc8\xea\xdb`Q\xe5W@\xa9i\xca" 294 | 295 | pubkey = '0602000000a40000525341310004000001000100a111c7c06d5a0bfe352714cc48fb1b11d33654bcc67ef698242c6a5ac5388b44fe8f66ac7c943770a9d6fb802fa6e5a3b3f94c26b3a447ad8ff144c6045e8a63f3beea2da9dc32db22a9ca4048e6095b1592816fa040c24695dc27d87f7b01a1e8a8595b9fb356ea836da73e02ecda2d8a082d567a8b744f18c8d7ceebf804a5'.decode( 296 | 'hex') 297 | 298 | xkey = "A" * 0x10 299 | print len(smplk), len(smplk2), len(smplk3) 300 | 301 | c = import_key(smplk2, privkey=pkey) 302 | print c 303 | 304 | kk = export_key('rc4_enc', xkey, pubkey=key) 305 | print len(kk) 306 | print `kk` 307 | 308 | c = import_key(kk, privkey=key) 309 | print c 310 | print c.key 311 | 312 | print `export_key('rc4_enc', xkey)` 313 | --------------------------------------------------------------------------------