📄 krnlapi.cxx
字号:
//+-------------------------------------------------------------------------
//
// Function: NtLmInitKernelContext
//
// Synopsis: Creates a kernel-mode context from a packed LSA mode context
//
// Arguments: LsaContextHandle - Lsa mode context handle for the context
// PackedContext - A marshalled buffer containing the LSA
// mode context.
//
// Requires:
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
NtLmInitKernelContext(
IN ULONG_PTR LsaContextHandle,
IN PSecBuffer PackedContext,
OUT PULONG_PTR NewContextHandle
)
{
NTSTATUS Status = STATUS_SUCCESS;
PNTLM_KERNEL_CONTEXT pContext = NULL;
unsigned int Length = 0;
PNTLM_KERNEL_CONTEXT pTmpContext = (PNTLM_KERNEL_CONTEXT) PackedContext->pvBuffer;
PAGED_CODE();
DebugLog(( DEB_TRACE, "Entering NtLmInitKernelContext\n" ));
*NewContextHandle = NULL;
if (PackedContext->cbBuffer < sizeof(NTLM_KERNEL_CONTEXT))
{
Status = STATUS_INVALID_PARAMETER;
DebugLog(( DEB_ERROR,
"Bad size of Packed context 0x%lx\n", PackedContext->cbBuffer));
goto Cleanup;
}
pContext = (PNTLM_KERNEL_CONTEXT) NtLmAllocate( sizeof(NTLM_KERNEL_CONTEXT) );
if (!pContext)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
DebugLog(( DEB_ERROR, "Allocation error for pContext\n"));
goto Cleanup;
}
RtlZeroMemory(
pContext,
sizeof(NTLM_KERNEL_CONTEXT)
);
KsecInitializeListEntry( &pContext->List, NTLM_CONTEXT_SIGNATURE );
// Copy contents of PackedContext->pvBuffer to pContext
pContext->ClientTokenHandle = pTmpContext->ClientTokenHandle;
pContext->LsaContext = LsaContextHandle;
pContext->NegotiateFlags = pTmpContext->NegotiateFlags;
//
// keep all 128 bits here, so signing can be strong even if encrypt can't be
//
RtlCopyMemory( pContext->SessionKey,
pTmpContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
//
// if doing full duplex as part of NTLM2, generate different sign
// and seal keys for each direction
// all we do is MD5 the base session key with a different magic constant
//
if ( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
MD5_CTX Md5Context;
ULONG KeyLen;
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_128 )
KeyLen = 16;
else if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_56 )
KeyLen = 7;
else
KeyLen = 5;
// DebugLog(( SSP_SESSION_KEYS, "NTLMv2 session key size: %lu\n", KeyLen));
//
// make client to server encryption key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
MD5Update(&Md5Context, (unsigned char*)CSSEALMAGIC, sizeof(CSSEALMAGIC));
MD5Final(&Md5Context);
//
// if TokenHandle == NULL, this is the client side
// put key in the right place: for client it's seal, for server it's unseal
//
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make server to client encryption key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
MD5Update(&Md5Context, (unsigned char*)SCSEALMAGIC, sizeof(SCSEALMAGIC));
MD5Final(&Md5Context);
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make client to server signing key -- always 128 bits!
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
MD5Update(&Md5Context, (unsigned char*)CSSIGNMAGIC, sizeof(CSSIGNMAGIC));
MD5Final(&Md5Context);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make server to client signing key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
MD5Update(&Md5Context, (unsigned char*)SCSIGNMAGIC, sizeof(SCSIGNMAGIC));
MD5Final(&Md5Context);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// set pointers to different key schedule and nonce for each direction
// key schedule will be filled in later...
//
pContext->pSealRc4Sched = &pContext->SealRc4Sched;
pContext->pUnsealRc4Sched = &pContext->UnsealRc4Sched;
pContext->pSendNonce = &pContext->SendNonce;
pContext->pRecvNonce = &pContext->RecvNonce;
} else {
//
// just copy session key to all four keys
// leave them 128 bits -- they get cut to 40 bits later
//
RtlCopyMemory( pContext->SealSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->UnsealSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->SignSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->VerifySessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
//
// set pointers to share a key schedule and nonce for each direction
// (OK because half duplex!)
//
pContext->pSealRc4Sched = &pContext->SealRc4Sched;
pContext->pUnsealRc4Sched = &pContext->SealRc4Sched;
pContext->pSendNonce = &pContext->SendNonce;
pContext->pRecvNonce = &pContext->SendNonce;
}
Length = (unsigned int) (PackedContext->cbBuffer -
sizeof(NTLM_KERNEL_CONTEXT));
if (Length == 0)
{
//There's no string after the NTLM_KERNEL_CONTEXT struct
pContext->ContextNames = NULL;
}
else
{
pContext->ContextNames = (LPWSTR) NtLmAllocate(Length + sizeof(WCHAR));
if (!pContext->ContextNames)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(pContext->ContextNames,
pTmpContext + 1,
Length );
// null terminate the string
*(pContext->ContextNames + (Length/sizeof(WCHAR))) = L'\0';
}
pContext->SendNonce = pTmpContext->SendNonce;
pContext->RecvNonce = pTmpContext->RecvNonce;
SspRc4Key(pContext->NegotiateFlags, &pContext->SealRc4Sched, pContext->SealSessionKey);
SspRc4Key(pContext->NegotiateFlags, &pContext->UnsealRc4Sched, pContext->UnsealSessionKey);
pContext->PasswordExpiry = pTmpContext->PasswordExpiry;
pContext->UserFlags = pTmpContext->UserFlags;
KSecInsertListEntry(
NtlmActiveList,
&pContext->List );
NtlmDerefContext( pContext );
*NewContextHandle = (ULONG_PTR) pContext;
Cleanup:
if (!NT_SUCCESS(Status))
{
if (pContext != NULL)
{
NtlmFreeKernelContext( pContext );
}
}
if (PackedContext->pvBuffer != NULL)
{
LsaKernelFunctions->FreeHeap(PackedContext->pvBuffer);
PackedContext->pvBuffer = NULL;
}
DebugLog(( DEB_TRACE, "Leaving NtLmInitKernelContext 0x%lx\n", Status ));
return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: NtLmMapKernelHandle
//
// Synopsis: Maps a kernel handle into an LSA handle
//
// Arguments: KernelContextHandle - Kernel context handle of the context to map
// LsaContextHandle - Receives LSA context handle of the context
// to map
//
// Returns: STATUS_SUCCESS on success
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
NtLmMapKernelHandle(
IN ULONG_PTR KernelContextHandle,
OUT PULONG_PTR LsaContextHandle
)
{
NTSTATUS Status = STATUS_SUCCESS;
PNTLM_KERNEL_CONTEXT Context = NULL;
PAGED_CODE();
DebugLog((DEB_TRACE,"Entering NtLmMapKernelhandle\n"));
Status = NtlmReferenceContext( KernelContextHandle, FALSE );
if ( NT_SUCCESS( Status ) )
{
Context = (PNTLM_KERNEL_CONTEXT) KernelContextHandle ;
*LsaContextHandle = Context->LsaContext ;
NtlmDerefContext( Context );
}
else
{
DebugLog(( DEB_WARN, "Invalid context handle - %x\n",
KernelContextHandle ));
*LsaContextHandle = KernelContextHandle ;
}
DebugLog((DEB_TRACE,"Leaving NtLmMapKernelhandle 0x%lx\n", Status));
return (Status);
}
//
// Bogus add-shift check sum
//
void
SspGenCheckSum(
IN PSecBuffer pMessage,
OUT PNTLMSSP_MESSAGE_SIGNATURE pSig
)
/*++
RoutineDescription:
Generate a crc-32 checksum for a buffer
Arguments:
Return Value:
Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
routine SspGenCheckSum. It's possible that
bugs got copied too
--*/
{
MAYBE_PAGED_CODE();
Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
}
VOID
SspEncryptBuffer(
IN PNTLM_KERNEL_CONTEXT pContext,
IN struct RC4_KEYSTRUCT * pRc4Key,
IN ULONG BufferSize,
IN OUT PVOID Buffer
)
/*++
RoutineDescription:
Encrypts a buffer with the RC4 key in the context. If the context
is for a datagram session, then the key is copied before being used
to encrypt the buffer.
Arguments:
pContext - Context containing the key to encrypt the data
BufferSize - Length of buffer in bytes
Buffer - Buffer to encrypt.
Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
routine SspEncryptBuffer. It's possible that
bugs got copied too
Return Value:
--*/
{
MAYBE_PAGED_CODE();
struct RC4_KEYSTRUCT TemporaryKey;
struct RC4_KEYSTRUCT * EncryptionKey = pRc4Key;
if (BufferSize == 0)
{
return;
}
//
// For datagram (application supplied sequence numbers) before NTLM2
// we used to copy the key before encrypting so we don't
// have a changing key; but that reused the key stream. Now we only
// do that when backwards compatibility is explicitly called for.
//
if (((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) &&
((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) == 0) ) {
RtlCopyMemory(
&TemporaryKey,
EncryptionKey,
sizeof(TemporaryKey)
);
EncryptionKey = &TemporaryKey;
}
rc4(
EncryptionKey,
BufferSize,
(PUCHAR) Buffer
);
}
VOID
SspRc4Key(
IN ULONG NegotiateFlags,
OUT struct RC4_KEYSTRUCT *pRc4Key,
IN PUCHAR pSessionKey
)
/*++
RoutineDescription:
Create an RC4 key schedule, making sure key length is OK for export
Arguments:
NegotiateFlags negotiate feature flags; NTLM2 bit is only one looked at
pRc4Key pointer to RC4 key schedule structure; filled in by this routine
pSessionKey pointer to session key -- must be full 16 bytes
Return Value:
--*/
{
PAGED_CODE();
//
// For NTLM2, effective length was already cut down
//
if ((NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
} else if( NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
UCHAR Key[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
ULONG KeyLen;
ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH == 8);
// prior to Win2k, negotiated key strength had no bearing on
// key size. So, to allow proper interop to NT4, we don't
// worry about 128bit. 56bit and 40bit are the only supported options.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -