Пример #1
0
static int RpcRequest(const RPC_REQUEST *const Request, RPC_RESPONSE *const Response, const DWORD RpcAssocGroup, const SOCKET sock, const unsigned int len)
{
	uint_fast16_t  _v;
	_v = LE16(((WORD*)Request->Data)[1]) - 4;

	int ResponseSize = _Versions[_v].CreateResponse(Request->Data, Response->Data);

	if ( ResponseSize )
	{
		Response->Ndr.DataSizeIs1 = LE32(0x00020000);
		Response->Ndr.DataLength  =
		Response->Ndr.DataSizeIs2 = LE32(ResponseSize);

		int len = ResponseSize + sizeof(Response->Ndr);

		BYTE* pRpcReturnCode = ((BYTE*)&Response->Ndr) + len;
		UA32(pRpcReturnCode) = 0; //LE16 not needed for 0
		len += sizeof(DWORD);

		// Pad zeros to 32-bit align (seems not neccassary but Windows RPC does it this way)
		int pad = ((~len & 3) + 1) & 3;
		memset(pRpcReturnCode + sizeof(DWORD), 0, pad);
		len += pad;

		Response->AllocHint = LE32(len);

		Response->AllocHint +=
				Response->ContextId = Request->ContextId;

		*((WORD*)&Response->CancelCount) = 0; // CancelCount + Pad1
	}

	return ResponseSize;
}
Пример #2
0
/*
 * Sends a KMS request via RPC and receives a response.
 * Parameters are raw (encrypted) reqeuests / responses.
 * Returns 0 on success.
 */
RpcStatus rpcSendRequest(const RpcCtx sock, const BYTE *const kmsRequest, const size_t requestSize, BYTE **kmsResponse, size_t *const responseSize)
{
#define MAX_EXCESS_BYTES 16
	RPC_HEADER *RequestHeader, ResponseHeader;
	RPC_REQUEST64 *RpcRequest;
	RPC_RESPONSE64 _Response;
	int status;
	int_fast8_t useNdr64 = RpcFlags.HasNDR64 && UseClientRpcNDR64 && firstPacketSent;
	size_t size = sizeof(RPC_HEADER) + (useNdr64 ? sizeof(RPC_REQUEST64) : sizeof(RPC_REQUEST)) + requestSize;
	size_t responseSize2;

	*kmsResponse = NULL;

	BYTE *_Request = (BYTE*)vlmcsd_malloc(size);

	RequestHeader = (RPC_HEADER*)_Request;
	RpcRequest = (RPC_REQUEST64*)(_Request + sizeof(RPC_HEADER));

	createRpcHeader(RequestHeader, RPC_PT_REQUEST, (WORD)size);

	// Increment CallId for next Request
	CallId++;

	RpcRequest->Opnum = 0;

	if (useNdr64)
	{
		RpcRequest->ContextId = LE16(1); // We negotiate NDR64 always as context 1
		RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr64)));
		RpcRequest->Ndr64.DataLength = LE64((uint64_t)requestSize);
		RpcRequest->Ndr64.DataSizeIs = LE64((uint64_t)requestSize);
		memcpy(RpcRequest->Ndr64.Data, kmsRequest, requestSize);
	}
	else
	{
		RpcRequest->ContextId = 0; // We negotiate NDR32 always as context 0
		RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr)));
		RpcRequest->Ndr.DataLength = LE32((DWORD)requestSize);
		RpcRequest->Ndr.DataSizeIs = LE32((DWORD)requestSize);
		memcpy(RpcRequest->Ndr.Data, kmsRequest, requestSize);
	}

	for (;;)
	{
		int bytesread;

		if (!_send(sock, _Request, (int)size))
		{
			printerrorf("\nFatal: Could not send RPC request\n");
			status = RPC_S_COMM_FAILURE;
			break;
		}

		if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER)))
		{
			printerrorf("\nFatal: No RPC response received from server\n");
			status = RPC_S_COMM_FAILURE;
			break;
		}

		if ((status = checkRpcResponseHeader(&ResponseHeader, RequestHeader, RPC_PT_RESPONSE, &printerrorf))) break;

		size = useNdr64 ? sizeof(RPC_RESPONSE64) : sizeof(RPC_RESPONSE);

		if (size > LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader))
			size = LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader);

		if (!_recv(sock, &_Response, (int)size))
		{
			printerrorf("\nFatal: RPC response is incomplete\n");
			status = RPC_S_COMM_FAILURE;
			break;
		}

		if (_Response.CancelCount != 0)
		{
			printerrorf("\nFatal: RPC response cancel count is not 0\n");
			status = RPC_S_CALL_CANCELLED;
			break;
		}

		if (_Response.ContextId != (useNdr64 ? LE16(1) : 0))
		{
			printerrorf("\nFatal: RPC response context id %u is not bound\n", (unsigned int)LE16(_Response.ContextId));
			status = RPC_X_SS_CONTEXT_DAMAGED;
			break;
		}

		int_fast8_t sizesMatch;

		if (useNdr64)
		{
			*responseSize = (size_t)LE64(_Response.Ndr64.DataLength);
			responseSize2 = (size_t)LE64(_Response.Ndr64.DataSizeIs);

			if (/*!*responseSize ||*/ !_Response.Ndr64.DataSizeMax)
			{
				status = (int)LE32(_Response.Ndr64.status);
				break;
			}

			sizesMatch = (size_t)LE64(_Response.Ndr64.DataLength) == responseSize2;
		}
		else
		{
			*responseSize = (size_t)LE32(_Response.Ndr.DataLength);
			responseSize2 = (size_t)LE32(_Response.Ndr.DataSizeIs);

			if (/*!*responseSize ||*/ !_Response.Ndr.DataSizeMax)
			{
				status = (int)LE32(_Response.Ndr.status);
				break;
			}

			sizesMatch = (size_t)LE32(_Response.Ndr.DataLength) == responseSize2;
		}

		if (!sizesMatch)
		{
			printerrorf("\nFatal: NDR data length (%u) does not match NDR data size (%u)\n",
				(uint32_t)*responseSize,
				(uint32_t)LE32(_Response.Ndr.DataSizeIs)
			);

			status = RPC_S_PROTOCOL_ERROR;
			break;
		}

		*kmsResponse = (BYTE*)vlmcsd_malloc(*responseSize + MAX_EXCESS_BYTES);

		// If RPC stub is too short, assume missing bytes are zero (same ill behavior as MS RPC)
		memset(*kmsResponse, 0, *responseSize + MAX_EXCESS_BYTES);

		// Read up to 16 bytes more than bytes expected to detect faulty KMS emulators
		if ((bytesread = recv(sock, (char*)*kmsResponse, (int)(*responseSize) + MAX_EXCESS_BYTES, 0)) < (int)*responseSize)
		{
			printerrorf("\nFatal: No or incomplete KMS response received. Required %u bytes but only got %i\n",
				(uint32_t)*responseSize,
				(int32_t)(bytesread < 0 ? 0 : bytesread)
			);

			status = RPC_S_PROTOCOL_ERROR;
			break;
		}

		DWORD *pReturnCode;

		size_t len = *responseSize + (useNdr64 ? sizeof(_Response.Ndr64) : sizeof(_Response.Ndr)) + sizeof(*pReturnCode);
		size_t pad = ((~len & 3) + 1) & 3;

		if (len + pad != LE32(_Response.AllocHint))
		{
			printerrorf("\nWarning: RPC stub size is %u, should be %u (probably incorrect padding)\n", (uint32_t)LE32(_Response.AllocHint), (uint32_t)(len + pad));
		}
		else
		{
			size_t i;
			for (i = 0; i < pad; i++)
			{
				if (*(*kmsResponse + *responseSize + sizeof(*pReturnCode) + i))
				{
					printerrorf("\nWarning: RPC stub data not padded to zeros according to Microsoft standard\n");
					break;
				}
			}
		}

		pReturnCode = (DWORD*)(*kmsResponse + *responseSize + pad);
		status = LE32(UA32(pReturnCode));

		break;
	}

	free(_Request);
	firstPacketSent = TRUE;
	return status;
#undef MAX_EXCESS_BYTES
}
Пример #3
0
/*
 * Handles the actual KMS request from the client.
 * Calls KMS functions (CreateResponseV4 or CreateResponseV6) in kms.c
 * Returns size of the KMS response packet or 0 on failure.
 *
 * The RPC packet size (excluding header) is actually in Response->AllocHint
 */
static int rpcRequest(const RPC_REQUEST64 *const Request, RPC_RESPONSE64 *const Response, const DWORD RpcAssocGroup_unused, const SOCKET sock_unused, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE isValid, const char* const ipstr)
{
	int ResponseSize; // <0 = Errorcode (HRESULT)
	BYTE* requestData;
	BYTE* responseData;
	BYTE* pRpcReturnCode;
	int len;

#	ifndef SIMPLE_RPC

	WORD Ctx = LE16(Request->ContextId);

	if (Ctx == *NdrCtx)
	{
		requestData = (BYTE*)&Request->Ndr.Data;
		responseData = (BYTE*)&Response->Ndr.Data;
	}
	else if (Ctx == *Ndr64Ctx)
	{
		requestData = (BYTE*)&Request->Ndr64.Data;
		responseData = (BYTE*)&Response->Ndr64.Data;
	}
	else
	{
		return SendError(Response, RPC_NCA_UNK_IF);
	}

#	else // SIMPLE_RPC

	requestData = (BYTE*)&Request->Ndr.Data;
	responseData = (BYTE*)&Response->Ndr.Data;

#	endif // SIMPLE_RPC

	ResponseSize = 0x8007000D; // Invalid Data

	if (isValid)
	{
		uint16_t majorIndex = LE16(((WORD*)requestData)[1]) - 4;
		if (!((ResponseSize = _Versions[majorIndex].CreateResponse(requestData, responseData, ipstr)))) ResponseSize = 0x8007000D;
	}

#	ifndef SIMPLE_RPC

	if (Ctx != *Ndr64Ctx)
	{

#	endif // !SIMPLE_RPC
		if (ResponseSize < 0)
		{
			Response->Ndr.DataSizeMax = Response->Ndr.DataLength = 0;
			len = sizeof(Response->Ndr) - sizeof(Response->Ndr.DataSizeIs);
		}
		else
		{
			Response->Ndr.DataSizeMax = LE32(0x00020000);
			Response->Ndr.DataLength = Response->Ndr.DataSizeIs = LE32(ResponseSize);
			len = ResponseSize + sizeof(Response->Ndr);
		}

#	ifndef SIMPLE_RPC

	}
	else
	{
		if (ResponseSize < 0)
		{
			Response->Ndr64.DataSizeMax = Response->Ndr64.DataLength = 0;
			len = sizeof(Response->Ndr64) - sizeof(Response->Ndr64.DataSizeIs);
		}
		else
		{
			Response->Ndr64.DataSizeMax = LE64(0x00020000ULL);
			Response->Ndr64.DataLength = Response->Ndr64.DataSizeIs = LE64((uint64_t)ResponseSize);
			len = ResponseSize + sizeof(Response->Ndr64);
		}
	}

#	endif // !SIMPLE_RPC

	pRpcReturnCode = ((BYTE*)&Response->Ndr) + len;
	UA32(pRpcReturnCode) = ResponseSize < 0 ? LE32(ResponseSize) : 0;
	len += sizeof(DWORD);

	// Pad zeros to 32-bit align (seems not neccassary but Windows RPC does it this way)
	int pad = ((~len & 3) + 1) & 3;
	memset(pRpcReturnCode + sizeof(DWORD), 0, pad);
	len += pad;

	Response->AllocHint = LE32(len);
	Response->ContextId = Request->ContextId;

	*((WORD*)&Response->CancelCount) = 0; // CancelCount + Pad1

	return len + 8;
}
Пример #4
0
int RpcSendRequest(const SOCKET sock, const BYTE *const KmsRequest, const size_t requestSize, BYTE **KmsResponse, size_t *const responseSize)
{
	#define MAX_EXCESS_BYTES 16
	RPC_HEADER *RequestHeader, ResponseHeader;
	RPC_REQUEST *RpcRequest;
	RPC_RESPONSE _Response;
	int status = 0;
	size_t size = sizeof(RPC_HEADER) + sizeof(RPC_REQUEST) + requestSize;

	*KmsResponse = NULL;

	BYTE *_Request = (BYTE*)malloc(size);
	if (!_Request) return !0;

	RequestHeader = (RPC_HEADER*)_Request;
	RpcRequest = (RPC_REQUEST*)(_Request + sizeof(RPC_HEADER));

	CreateRpcRequestHeader(RequestHeader, RPC_PT_REQUEST, size);

	// Increment CallId for next Request
	CallId++;

	RpcRequest->ContextId = 0;
	RpcRequest->Opnum = 0;
	RpcRequest->AllocHint = requestSize + sizeof(RpcRequest->Ndr);
	RpcRequest->Ndr.DataLength = LE32(requestSize);
	RpcRequest->Ndr.DataSizeIs = LE32(requestSize);

	memcpy(RpcRequest->Data, KmsRequest, requestSize);

	for(;;)
	{
		int bytesread;

		if (!_send(sock, _Request, size))
		{
			errorout("\nFatal: Could not send RPC request\n");
			status = !0;
			break;
		}

		if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER)))
		{
			errorout("\nFatal: No RPC response received from server\n");
			status = !0;
			break;
		}

		if ((status = CheckRpcHeaders(&ResponseHeader, RequestHeader, RPC_PT_RESPONSE, &errorout))) break;

		if (!_recv(sock, &_Response, sizeof(_Response)))
		{
			errorout("\nFatal: RPC response is incomplete\n");
			status = !0;
			break;
		}

		if (_Response.CancelCount != 0)
		{
			errorout("\nFatal: RPC response cancel count is not 0\n");
			status = !0;
		}

		if (_Response.ContextId != 0)
		{
			errorout("\nFatal: RPC response context id is not 0\n");
			status = !0;
		}

		*responseSize = LE32(_Response.Ndr.DataLength);

		if (!*responseSize || !_Response.Ndr.DataSizeIs1)
		{
			status = LE32(_Response.Ndr.DataSizeIs2);
			break;
		}

		if (_Response.Ndr.DataLength != _Response.Ndr.DataSizeIs2)
		{
			errorout("\nFatal: NDR data length (%u) does not match NDR data size (%u)\n",
					(uint32_t)*responseSize,
					(uint32_t)LE32(_Response.Ndr.DataSizeIs2)
			);

			status = !0;
		}

		*KmsResponse = (BYTE*)malloc(*responseSize + MAX_EXCESS_BYTES);

		if (!*KmsResponse)
		{
			errorout("\nFatal: Could not allocate memory for KMS response\n");
			status = !0;
			break;
		}

		// If RPC stub is too short, assume missing bytes are zero (same ill behavior as MS RPC)
		memset(*KmsResponse, 0, *responseSize + MAX_EXCESS_BYTES);

		// Read up to 16 bytes more than bytes expected to detect faulty KMS emulators
		if ((bytesread = recv(sock, (char*)*KmsResponse, *responseSize + MAX_EXCESS_BYTES, 0)) < (int)*responseSize)
		{
			errorout("\nFatal: No or incomplete KMS response received. Required %u bytes but only got %i\n",
					(uint32_t)*responseSize,
					(int32_t)(bytesread < 0 ? 0 : bytesread)
			);

			status = !0;
			break;
		}

		DWORD *pReturnCode;

		size_t len = *responseSize + sizeof(_Response.Ndr) + sizeof(*pReturnCode);
		size_t pad = ((~len & 3) + 1) & 3;

		if (len + pad != LE32(_Response.AllocHint))
		{
			errorout("\nWarning: RPC stub size is %u, should be %u (probably incorrect padding)\n", (uint32_t)LE32(_Response.AllocHint), (uint32_t)(len + pad));
		}
		else
		{
			size_t i;
			for (i = 0; i < pad; i++)
			{
				if (*(*KmsResponse + *responseSize + sizeof(*pReturnCode) + i))
				{
					errorout("\nWarning: RPC stub data not padded to zeros according to Microsoft standard\n");
					break;
				}
			}
		}

		pReturnCode = (DWORD*)(*KmsResponse + *responseSize);
		status = LE32(UA32(pReturnCode));

		if (status) errorout("\nWarning: RPC stub data reported Error %u\n", (uint32_t)status);

		break;
	}

	free(_Request);
	return status;
	#undef MAX_EXCESS_BYTES
}