HTTPS TLS with AFD.sys, WinSocks not necessary
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
typedef LONG NTSTATUS;
#define AF_INET 2
#define AUTHTYPE_SERVER 1
#define DEFAULT_BUFFER_ALLOCATION_SIZE 16384
#define DEFAULT_HTTPHEADER_GET_SIZE 68
#define DEFAULT_HTTPHEADER_POST_OCTETSTREAM_SIZE 104
#define InlineGetMinimum(a,b) (((a) < (b)) ? (a) : (b))
#define HTTP_CR '\r'
#define HTTP_LF '\n'
#define HTTP_SP ' '
#define HTTP_TB '\t'
#define HTTP_CO ':'
#define HTTP_DELIMITED_LENGTH 3
#define HTTP_DELIMITER "\r\n"
#define SECURITY_NATIVE_DREP 0x00000010
#define SECPKG_ATTR_STREAM_SIZES 4
#define SECBUFFER_VERSION 0
#define SECBUFFER_EMPTY 0
#define SECBUFFER_DATA 1
#define SECBUFFER_TOKEN 2
#define SECBUFFER_EXTRA 5
#define SECBUFFER_STREAM_TRAILER 6
#define SECBUFFER_STREAM_HEADER 7
#define ISC_REQ_REPLAY_DETECT 0x00000004
#define ISC_REQ_SEQUENCE_DETECT 0x00000008
#define ISC_REQ_CONFIDENTIALITY 0x00000010
#define ISC_REQ_ALLOCATE_MEMORY 0x00000100
#define ISC_REQ_EXTENDED_ERROR 0x00004000
#define ISC_REQ_STREAM 0x00008000
#define SCHANNEL_CRED_VERSION 0x00000004
#define SCHANNEL_SHUTDOWN 0x00000001
#define SCH_CRED_NO_DEFAULT_CREDS 0x00000010
#define SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT 0x00000400
#define SECPKG_ATTR_REMOTE_CERT_CONTEXT 0x53
#define SOCK_STREAM 1
#define IPPROTO_TCP 6
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL)
#define OBJ_CASE_INSENSITIVE 0x00000040
#define FILE_OPEN_IF 0x00000003
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
typedef struct _LSA_UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef enum _EVENT_TYPE {
NotificationEvent = 0,
SynchronizationEvent = 1
} EVENT_TYPE;
typedef PVOID HCERTSTORE;
typedef PVOID HCRYPTMSG;
typedef PVOID HCERTCHAINENGINE;
typedef struct _CERT_CONTEXT CERT_CONTEXT;
typedef struct _CERT_CHAIN_CONTEXT CERT_CHAIN_CONTEXT;
typedef struct _CTL_CONTEXT CTL_CONTEXT;
typedef const CERT_CONTEXT* PCCERT_CONTEXT;
typedef const CERT_CHAIN_CONTEXT* PCCERT_CHAIN_CONTEXT;
typedef const CTL_CONTEXT* PCCTL_CONTEXT;
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData;
BYTE* pbData;
} CRYPT_DATA_BLOB, *PCRYPT_DATA_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_INTEGER_BLOB, *PCRYPT_INTEGER_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_UINT_BLOB, *PCRYPT_UINT_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_OBJID_BLOB, *PCRYPT_OBJID_BLOB;
typedef CRYPT_DATA_BLOB CERT_NAME_BLOB, *PCERT_NAME_BLOB;
typedef CRYPT_DATA_BLOB CERT_RDN_VALUE_BLOB, *PCERT_RDN_VALUE_BLOB;
typedef CRYPT_DATA_BLOB CERT_BLOB, *PCERT_BLOB;
typedef CRYPT_DATA_BLOB CRL_BLOB, *PCRL_BLOB;
typedef CRYPT_DATA_BLOB DATA_BLOB, *PDATA_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_HASH_BLOB, *PCRYPT_HASH_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_DIGEST_BLOB, *PCRYPT_DIGEST_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_DER_BLOB, *PCRYPT_DER_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_ATTR_BLOB, *PCRYPT_ATTR_BLOB;
typedef CRYPT_DATA_BLOB CRYPT_DATA_BLOB_ALIAS, *PCRYPT_DATA_BLOB_ALIAS;
typedef struct _CERT_TRUST_STATUS {
DWORD dwErrorStatus;
DWORD dwInfoStatus;
} CERT_TRUST_STATUS, *PCERT_TRUST_STATUS;
typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
LPSTR pszObjId;
CRYPT_OBJID_BLOB Parameters;
} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER;
typedef struct _CRYPT_BIT_BLOB {
DWORD cbData;
BYTE* pbData;
DWORD cUnusedBits;
} CRYPT_BIT_BLOB, *PCRYPT_BIT_BLOB;
typedef struct _CERT_PUBLIC_KEY_INFO {
CRYPT_ALGORITHM_IDENTIFIER Algorithm;
CRYPT_BIT_BLOB PublicKey;
} CERT_PUBLIC_KEY_INFO, *PCERT_PUBLIC_KEY_INFO;
typedef struct _CERT_EXTENSION {
LPSTR pszObjId;
BOOL fCritical;
CRYPT_OBJID_BLOB Value;
} CERT_EXTENSION, *PCERT_EXTENSION;
typedef struct _CERT_EXTENSIONS {
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CERT_EXTENSIONS, *PCERT_EXTENSIONS;
typedef struct _CERT_INFO {
DWORD dwVersion;
CRYPT_INTEGER_BLOB SerialNumber;
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
CERT_NAME_BLOB Issuer;
FILETIME NotBefore;
FILETIME NotAfter;
CERT_NAME_BLOB Subject;
CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
CRYPT_BIT_BLOB IssuerUniqueId;
CRYPT_BIT_BLOB SubjectUniqueId;
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CERT_INFO, *PCERT_INFO;
typedef struct _CERT_CONTEXT {
DWORD dwCertEncodingType;
BYTE* pbCertEncoded;
DWORD cbCertEncoded;
PCERT_INFO pCertInfo;
HCERTSTORE hCertStore;
}CERT_CONTEXT, *PCERT_CONTEXT;
typedef struct _CRL_CONTEXT {
DWORD dwCertEncodingType;
BYTE* pbCrlEncoded;
DWORD cbCrlEncoded;
PCERT_INFO pCrlInfo;
HCERTSTORE hCertStore;
} CRL_CONTEXT, *PCRL_CONTEXT;
typedef const CRL_CONTEXT* PCCRL_CONTEXT;
typedef struct _CRL_ENTRY {
CRYPT_INTEGER_BLOB SerialNumber;
FILETIME RevocationDate;
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CRL_ENTRY, *PCRL_ENTRY;
typedef struct _CERT_REVOCATION_CRL_INFO {
DWORD cbSize;
PCCRL_CONTEXT pBaseCrlContext;
PCCRL_CONTEXT pDeltaCrlContext;
PCRL_ENTRY pCrlEntry;
BOOL fDeltaCrlEntry;
} CERT_REVOCATION_CRL_INFO, *PCERT_REVOCATION_CRL_INFO;
typedef struct _CERT_REVOCATION_INFO {
DWORD cbSize;
DWORD dwRevocationResult;
LPCSTR pszRevocationOid;
LPVOID pvOidSpecificInfo;
BOOL fHasFreshnessTime;
DWORD dwFreshnessTime;
PCERT_REVOCATION_CRL_INFO pCrlInfo;
} CERT_REVOCATION_INFO, *PCERT_REVOCATION_INFO;
typedef struct _CRYPT_ATTRIBUTE {
LPSTR pszObjId;
DWORD cValue;
PCRYPT_ATTR_BLOB rgValue;
} CRYPT_ATTRIBUTE, *PCRYPT_ATTRIBUTE;
typedef struct _CTL_ENTRY {
CRYPT_DATA_BLOB SubjectIdentifier;
DWORD cAttribute;
PCRYPT_ATTRIBUTE rgAttribute;
} CTL_ENTRY, *PCTL_ENTRY;
typedef struct _CTL_USAGE {
DWORD cUsageIdentifier;
LPSTR* rgpszUsageIdentifier;
} CTL_USAGE, *PCTL_USAGE, CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;
typedef struct _CTL_INFO {
DWORD dwVersion;
CTL_USAGE SubjectUsage;
CRYPT_DATA_BLOB ListIdentifier;
CRYPT_INTEGER_BLOB SequenceNumber;
FILETIME ThisUpdate;
FILETIME NextUpdate;
CRYPT_ALGORITHM_IDENTIFIER SubjectAlgorithm;
DWORD cCTLEntry;
PCTL_ENTRY rgCTLEntry;
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CTL_INFO, *PCTL_INFO;
typedef struct _CTL_CONTEXT {
DWORD dwMsgAndCertEncodingType;
BYTE* pbCtlEncoded;
DWORD cbCtlEncoded;
PCTL_INFO pCtlInfo;
HCERTSTORE hCertStore;
HCRYPTMSG hCryptMsg;
BYTE* pbCtlContent;
DWORD cbCtlContent;
}CTL_CONTEXT, *PCTL_CONTEXT;
typedef struct _CERT_TRUST_LIST_INFO {
DWORD cbSize;
PCTL_ENTRY pCtlEntry;
PCCTL_CONTEXT pCtlContext;
} CERT_TRUST_LIST_INFO, *PCERT_TRUST_LIST_INFO;
typedef struct _CERT_CHAIN_ELEMENT {
DWORD cbSize;
PCCERT_CONTEXT pCertContext;
CERT_TRUST_STATUS TrustStatus;
PCERT_REVOCATION_INFO pRevocationInfo;
PCERT_ENHKEY_USAGE pIssuanceUsage;
PCERT_ENHKEY_USAGE pApplicationUsage;
LPCWSTR pwszExtendedErrorInfo;
} CERT_CHAIN_ELEMENT, *PCERT_CHAIN_ELEMENT;
typedef struct _CERT_SIMPLE_CHAIN {
DWORD cbSize;
CERT_TRUST_STATUS TrustStatus;
DWORD cElement;
PCERT_CHAIN_ELEMENT* rgpElement;
PCERT_TRUST_LIST_INFO pTrustListInfo;
BOOL fHasRevocationFreshnessTime;
DWORD dwRevocationFreshnessTime;
} CERT_SIMPLE_CHAIN, *PCERT_SIMPLE_CHAIN;
typedef struct _SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
DWORD cbSize;
DWORD dwAuthType;
DWORD fdwChecks;
WCHAR* pwszServerName;
} SSL_EXTRA_CERT_CHAIN_POLICY_PARA, *PSSL_EXTRA_CERT_CHAIN_POLICY_PARA;
typedef struct _CERT_CHAIN_CONTEXT {
DWORD cbSize;
CERT_TRUST_STATUS TrustStatus;
DWORD cChain;
PCERT_SIMPLE_CHAIN* rgpChain;
DWORD cLowerQualityChainContext;
PCCERT_CHAIN_CONTEXT* rgpLowerQualityChainContext;
BOOL fHasRevocationFreshnessTime;
DWORD dwRevocationFreshnessTime;
DWORD dwCreateFlags;
GUID ChainId;
}CERT_CHAIN_CONTEXT, *PCERT_CHAIN_CONTEXT;
typedef struct _CERT_USAGE_MATCH {
DWORD dwType;
CERT_ENHKEY_USAGE Usage;
} CERT_USAGE_MATCH, *PCERT_USAGE_MATCH;
typedef struct _CERT_STRONG_SIGN_SERIALIZED_INFO {
DWORD dwFlags;
LPWSTR pwszCNGSignHashAlgids;
LPWSTR pwszCNGPubKeyMinBitLengths;
} CERT_STRONG_SIGN_SERIALIZED_INFO, *PCERT_STRONG_SIGN_SERIALIZED_INFO;
typedef struct _CERT_STRONG_SIGN_PARA {
DWORD cbSize;
DWORD dwInfoChoice;
union {
PVOID pvInfo;
PCERT_STRONG_SIGN_SERIALIZED_INFO pSerializedInfo;
LPSTR pszOID;
} DUMMYUNIONNAME;
} CERT_STRONG_SIGN_PARA, *PCERT_STRONG_SIGN_PARA;
typedef const CERT_STRONG_SIGN_PARA* PCCERT_STRONG_SIGN_PARA;
typedef struct _CERT_CHAIN_PARA {
DWORD cbSize;
CERT_USAGE_MATCH RequestedUsage;
CERT_USAGE_MATCH RequestedIssuancePolicy;
DWORD dwUrlRetrievalTimeout;
BOOL fCheckRevocationFreshnessTime;
DWORD dwRevocationFreshnessTime;
LPFILETIME pftCacheResync;
PCCERT_STRONG_SIGN_PARA pStrongSignPara;
DWORD dwStrongSignFlags;
} CERT_CHAIN_PARA, *PCERT_CHAIN_PARA;
typedef struct _CERT_CHAIN_POLICY_STATUS {
DWORD cbSize;
DWORD dwError;
LONG lChainIndex;
LONG lElementIndex;
PVOID pvExtraPolicyStatus;
} CERT_CHAIN_POLICY_STATUS, *PCERT_CHAIN_POLICY_STATUS;
#define CERT_CHAIN_POLICY_SSL ((LPCSTR)4)
typedef struct _CERT_CHAIN_POLICY_PARA {
DWORD cbSize;
DWORD dwFlags;
PVOID pvExtraPolicyPara;
} CERT_CHAIN_POLICY_PARA, *PCERT_CHAIN_POLICY_PARA;
typedef struct _SCHANNEL_CRED {
DWORD dwVersion;
DWORD cCreds;
PCCERT_CONTEXT* paCred;
HCERTSTORE hRootStore;
DWORD cMappers;
struct _HMAPPER** aphMappers;
DWORD cSupportedAlgs;
PUINT palgSupportedAlgs;
DWORD grbitEnabledProtocols;
DWORD dwMinimumCipherStrength;
DWORD dwMaximumCipherStrength;
DWORD dwSessionLifespan;
DWORD dwFlags;
DWORD dwCredFormat;
} SCHANNEL_CRED, *PSCHANNEL_CRED;
typedef struct _SECURITY_INTEGER {
ULONG LowPart;
ULONG HighPart;
} SECURITY_INTEGER, *PSECURITY_INTEGER;
typedef SECURITY_INTEGER TimeStamp;
typedef SECURITY_INTEGER* PTimeStamp;
typedef struct _SecBuffer {
ULONG cbBuffer;
ULONG BufferType;
PVOID pvBuffer;
} SecBuffer, *PSecBuffer;
typedef struct _SecBufferDesc {
ULONG ulVersion;
ULONG cBuffers;
PSecBuffer pBuffers;
} SecBufferDesc, *PSecBufferDesc;
typedef struct _SecPkgContext_StreamSizes {
ULONG cbHeader;
ULONG cbTrailer;
ULONG cbMaximumMessage;
ULONG cBuffers;
ULONG cbBlockSize;
} SecPkgContext_StreamSizes, *PSecPkgContext_StreamSizes;
typedef struct _SecHandle {
ULONG_PTR dwLower;
ULONG_PTR dwUpper;
} SecHandle, *PSecHandle;
typedef SecHandle CredHandle;
typedef PSecHandle PCredHandle;
typedef SecHandle CtxtHandle;
typedef PSecHandle PCtxtHandle;
typedef LONG SECURITY_STATUS;
typedef VOID(NTAPI* GETKEY)(PVOID, PVOID, ULONG, PVOID*, SECURITY_STATUS*);
typedef SECURITY_STATUS(NTAPI* ACQUIRECREDENTIALSHANDLEW)(PWCHAR, PWCHAR, ULONG, PVOID, PVOID, GETKEY, PVOID, PCredHandle, PTimeStamp);
typedef SECURITY_STATUS(NTAPI* ENCRYPTMESSAGE)(PCtxtHandle, ULONG, PSecBufferDesc, ULONG);
typedef SECURITY_STATUS(NTAPI* DECRYPTMESSAGE)(PCtxtHandle, PSecBufferDesc, ULONG, PULONG);
typedef SECURITY_STATUS(NTAPI* QUERYCONTEXTATTRIBUTESW)(PCtxtHandle, ULONG, PVOID);
typedef SECURITY_STATUS(NTAPI* INITIALIZESECURITYCONTEXTW)(PCredHandle, PCtxtHandle, PWCHAR, ULONG, ULONG, ULONG, PSecBufferDesc, ULONG, PCtxtHandle, PSecBufferDesc, PULONG, PTimeStamp);
typedef SECURITY_STATUS(NTAPI* DELETESECURITYCONTEXT)(PCtxtHandle);
typedef SECURITY_STATUS(NTAPI* FREECONTEXTBUFFER)(PVOID);
typedef SECURITY_STATUS(NTAPI* FREECREDENTIALSHANDLE)(PCredHandle);
typedef SECURITY_STATUS(NTAPI* APPLYCONTROLTOKEN)(PCtxtHandle, PSecBufferDesc);
typedef struct _SECURITY_FUNCTION_TABLE_W {
ULONG dwVersion;
PVOID EnumerateSecurityPackagesW;
PVOID QueryCredentialsAttributesW;
ACQUIRECREDENTIALSHANDLEW AcquireCredentialsHandleW;
FREECREDENTIALSHANDLE FreeCredentialsHandle;
PVOID Reserved2;
INITIALIZESECURITYCONTEXTW InitializeSecurityContextW;
PVOID AcceptSecurityContext;
PVOID CompleteAuthToken;
DELETESECURITYCONTEXT DeleteSecurityContext;
APPLYCONTROLTOKEN ApplyControlToken;
QUERYCONTEXTATTRIBUTESW QueryContextAttributesW;
PVOID ImpersonateSecurityContext;
PVOID RevertSecurityContext;
PVOID MakeSignature;
PVOID VerifySignature;
FREECONTEXTBUFFER FreeContextBuffer;
PVOID QuerySecurityPackageInfoW;
PVOID Reserved3;
PVOID Reserved4;
PVOID ExportSecurityContext;
PVOID ImportSecurityContextW;
PVOID AddCredentialsW;
PVOID Reserved8;
PVOID QuerySecurityContextToken;
ENCRYPTMESSAGE EncryptMessage;
DECRYPTMESSAGE DecryptMessage;
PVOID SetContextAttributesW;
PVOID SetCredentialsAttributesW;
PVOID Reserved9;
} SecurityFunctionTableW, *PSecurityFunctionTableW;
// nt
typedef NTSTATUS(NTAPI* NTDEVICEIOCONTROLFILE)(HANDLE, HANDLE, PVOID, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG);
typedef NTSTATUS(NTAPI* NTCREATEFILE)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG);
typedef NTSTATUS(NTAPI* NTCREATEEVENT)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, EVENT_TYPE, BOOLEAN);
typedef NTSTATUS(NTAPI* NTWAITFORSINGLEOBJECT)(HANDLE, BOOLEAN, PLARGE_INTEGER);
// rtl
typedef PVOID(NTAPI* RTLALLOCATEHEAP)(PVOID, ULONG, SIZE_T);
typedef BOOL(NTAPI* RTLFREEHEAP)(PVOID, ULONG, PVOID);
typedef PVOID(NTAPI* RTLREALLOCATEHEAP)(PVOID, ULONG, PVOID, SIZE_T);
// sspi
typedef PSecurityFunctionTableW(NTAPI* INITSECURITYINTERFACEW)(VOID);
// crypt32
typedef VOID(WINAPI* CERTFREECERTIFICATECHAIN)(PCCERT_CHAIN_CONTEXT);
typedef BOOL(WINAPI* CERTFREECERTIFICATECONTEXT)(PCCERT_CONTEXT);
typedef BOOL(WINAPI* CERTVERIFYCERTIFICATECHAINPOLICY)(LPCSTR, PCCERT_CHAIN_CONTEXT, PCERT_CHAIN_POLICY_PARA, PCERT_CHAIN_POLICY_STATUS);
typedef BOOL(WINAPI* CERTGETCERTIFICATECHAIN)(HCERTCHAINENGINE, PCCERT_CONTEXT, LPFILETIME, HCERTSTORE, PCERT_CHAIN_PARA, DWORD, LPVOID, PCCERT_CHAIN_CONTEXT*);
CERTFREECERTIFICATECHAIN CertFreeCertificateChain = NULL;
CERTFREECERTIFICATECONTEXT CertFreeCertificateContext = NULL;
CERTVERIFYCERTIFICATECHAINPOLICY CertVerifyCertificateChainPolicy = NULL;
CERTGETCERTIFICATECHAIN CertGetCertificateChain = NULL;
NTDEVICEIOCONTROLFILE NtDeviceIoControlFile = NULL;
NTCREATEFILE NtCreateFile = NULL;
NTCREATEEVENT NtCreateEvent = NULL;
NTWAITFORSINGLEOBJECT NtWaitForSingleObject = NULL;
RTLALLOCATEHEAP RtlAllocateHeap = NULL;
RTLFREEHEAP RtlFreeHeap = NULL;
RTLREALLOCATEHEAP RtlReAllocateHeap = NULL;
INITSECURITYINTERFACEW InitSecurityInterfaceW = NULL;
PSecurityFunctionTableW SspiVirtualFunctionTable = NULL;
__forceinline UINT HostToNetworkLong(UINT Host)
{
return ((Host & 0x000000FF) << 24) | ((Host & 0x0000FF00) << 8) | ((Host & 0x00FF0000) >> 8) | ((Host & 0xFF000000) >> 24);
}
__forceinline UINT16 HostToNetworkShort(UINT16 Host)
{
return (UINT16)((Host << 8) | (Host >> 8));
}
#define InitializeObjectAttributesLocal(p, n, a, r, s) do { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = (r); \
(p)->Attributes = (a); \
(p)->ObjectName = (n); \
(p)->SecurityDescriptor = (s); \
(p)->SecurityQualityOfService = NULL; \
} while(0)
#define IOCTL_AFD_BIND 0x00012003
#define IOCTL_AFD_CONNECT 0x00012007
#define IOCTL_AFD_SEND 0x0001201F
#define IOCTL_AFD_RECV 0x00012017
typedef struct IN_ADDR {
union {
struct {
UCHAR s_b1;
UCHAR s_b2;
UCHAR s_b3;
UCHAR s_b4;
} S_un_b;
struct {
USHORT s_w1;
USHORT s_w2;
} S_un_w;
ULONG S_addr;
} S_un;
} IN_ADDR, *PIN_ADDR;
typedef struct SOCKADDR_IN {
SHORT sin_family; // Address family (AF_INET = 2)
USHORT sin_port; // Port number (network byte order)
IN_ADDR sin_addr; // IPv4 address
CHAR sin_zero[8]; // Padding (unused)
} SOCKADDR_IN, * PSOCKADDR_IN;
#ifndef s_addr
#define s_addr S_un.S_addr
#endif
typedef struct AFD_CONNECT_REQUEST_IPV4 {
ULONGLONG SharedAccessNamespaceActive;
ULONGLONG RootEndpoint;
ULONGLONG ConnectEndpoint;
SOCKADDR_IN Address;
}AFD_CONNECT_REQUEST_IPV4, *PAFD_CONNECT_REQUEST_IPV4;
typedef struct _AFD_OPEN_PACKET_EXTENDED_ATTRIBUTES {
UINT NextEntryOffset;
BYTE Flags;
BYTE ExtendedAttributeNameLength;
USHORT ExtendedAttributeValueLength;
CHAR ExtendedAttributeName[16];
UINT EndpointFlags;
UINT GroupID;
UINT AddressFamily;
UINT SocketType;
UINT Protocol;
UINT SizeOfTransportName;
BYTE Unknown1[9];
}AFD_OPEN_PACKET_EXTENDED_ATTRIBUTES, *PAFD_OPEN_PACKET_EXTENDED_ATTRIBUTES;
typedef struct _AFD_BIND_SOCKET {
UINT32 Flags;
SOCKADDR_IN Address;
}AFD_BIND_SOCKET, *PAFD_BIND_SOCKET;
typedef struct _AFD_IO_BUFFER {
UINT Length;
PVOID Buffer;
}AFD_IO_BUFFER, *PAFD_IO_BUFFER;
typedef struct AFD_TRANSFER_REQUEST {
PAFD_IO_BUFFER Buffer;
UINT BufferCount;
UINT AfdFlags;
UINT TdiFlags;
}AFD_TRANSFER_REQUEST, *PAFD_TRANSFER_REQUEST;
typedef struct _NTSOCKET {
HANDLE Socket;
} NTSOCKET, *PNTSOCKET;
typedef struct _DNS_HEADER {
UINT16 Id;
UINT16 Flags;
UINT16 QdCount;
UINT16 AnCount;
UINT16 NsCount;
UINT16 ArCount;
}DNS_HEADER, *PDNS_HEADER;
typedef struct _TLSCLIENT {
CredHandle CredentialHandle;
CtxtHandle ContextHandle;
BOOL CredentialInitializedFlag;
BOOL ContextInitializedFlag;
SecPkgContext_StreamSizes Sizes;
}TLSCLIENT, *PTLSCLIENT;
typedef struct _HTTP_HEADER {
PCHAR Name;
PCHAR Value;
} HTTP_HEADER, *PHTTP_HEADER;
typedef struct _HTTP_RESPONSE {
INT StatusCode;
PCHAR Reason;
SIZE_T ReasonLength;
HTTP_HEADER Headers[64];
SIZE_T HeaderCount;
PBYTE Body;
SIZE_T BodyLength;
} HTTP_RESPONSE, *PHTTP_RESPONSE;
SIZE_T WCharStringToCharString2(PCHAR Destination, PWCHAR Source, SIZE_T MaximumAllowed)
{
SIZE_T Index = 0;
for (; Index < MaximumAllowed - 1 && Source[Index]; ++Index)
{
WCHAR IndividualCharacter = Source[Index];
if (IndividualCharacter > 0x7f)
Destination[Index] = '?';
else
Destination[Index] = (CHAR)IndividualCharacter;
}
Destination[Index] = '\0';
return Index;
}
SIZE_T StringLengthA(LPCSTR String)
{
LPCSTR String2;
for (String2 = String; *String2; ++String2);
return (String2 - String);
}
PCHAR StringCopyA(PCHAR String1, PCHAR String2)
{
PCHAR p = String1;
while ((*p++ = *String2++) != 0);
return String1;
}
PCHAR StringConcatA(PCHAR String, PCHAR String2)
{
StringCopyA(&String[StringLengthA(String)], String2);
return String;
}
PCHAR HttpUSizeToDecimalA(SIZE_T Value, PCHAR Out, SIZE_T OutSize)
{
SIZE_T i = 0;
if (Value == 0)
{
Out[0] = '0';
Out[1] = '\0';
return Out;
}
while (Value != 0)
{
if (i + 1 >= OutSize)
return NULL;
Out[i++] = (CHAR)('0' + (Value % 10));
Value /= 10;
}
for (SIZE_T FrontIndex = 0, BackIndex = i - 1; FrontIndex < BackIndex; FrontIndex++, BackIndex--)
{
CHAR Object = Out[FrontIndex];
Out[FrontIndex] = Out[BackIndex];
Out[BackIndex] = Object;
}
Out[i] = '\0';
return Out;
}
SIZE_T StringLengthW(LPCWSTR String)
{
LPCWSTR String2;
for (String2 = String; *String2; ++String2);
return (String2 - String);
}
VOID RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
{
SIZE_T DestSize;
if (SourceString)
{
DestSize = StringLengthW(SourceString) * sizeof(WCHAR);
DestinationString->Length = (USHORT)DestSize;
DestinationString->MaximumLength = (USHORT)DestSize + sizeof(WCHAR);
}
else
{
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
}
DestinationString->Buffer = (PWCHAR)SourceString;
}
VOID RtlInitializeSecurityBuffer(SecBuffer* SecurityBuffer, ULONG BufferType, ULONG cbBuffer, PVOID pvBuffer)
{
SecurityBuffer->BufferType = BufferType;
SecurityBuffer->cbBuffer = cbBuffer;
SecurityBuffer->pvBuffer = pvBuffer;
}
VOID RtlInitializeSecurityDescription(SecBufferDesc* SecurityDescription, ULONG ulVersion, ULONG cBuffers, PSecBuffer pBuffers)
{
SecurityDescription->ulVersion = ulVersion;
SecurityDescription->cBuffers = cBuffers;
SecurityDescription->pBuffers = pBuffers;
}
INT LowercaseCharacter(INT Character)
{
if (Character >= 'A' && Character <= 'Z')
return (Character - 'A' + 'a');
return Character;
}
INT StringCompareByLengthLowerA(PCHAR String1, PCHAR String2, SIZE_T Length)
{
INT Lower1 = 0;
INT Lower2 = 0;
for (SIZE_T i = 0; i < Length; i++)
{
Lower1 = LowercaseCharacter((BYTE)String1[i]);
Lower2 = LowercaseCharacter((BYTE)String2[i]);
if (Lower1 != Lower2)
return (Lower1 - Lower2);
if ((BYTE)String1[i] == 0)
return 0;
}
return 0;
}
PVOID SetMemory(PVOID Destination, INT Value, SIZE_T Size)
{
PBYTE Pointer = (PBYTE)Destination;
while (Size--)
*Pointer++ = (BYTE)Value;
return Destination;
}
INT CompareMemory(PVOID MemoryA, PVOID MemoryB, SIZE_T Length)
{
PBYTE Pointer1 = (PBYTE)MemoryA;
PBYTE Pointer2 = (PBYTE)MemoryB;
while (Length--)
{
if (*Pointer1 != *Pointer2)
return (INT)(*Pointer1 - *Pointer2);
Pointer1++;
Pointer2++;
}
return 0;
}
PCHAR FindStringInMemoryRegion(PCHAR Buffer, SIZE_T BufferLength, PCHAR String, SIZE_T StringLength)
{
for (SIZE_T i = 0; i + StringLength <= BufferLength; i++)
{
if (CompareMemory(Buffer + i, String, StringLength) == 0)
return Buffer + i;
}
return NULL;
}
BOOL HttpGetContentLength(PCHAR Header, SIZE_T HeaderLength, PSIZE_T outLen)
{
PCHAR Pointer = Header;
PCHAR BufferEnd = Header + HeaderLength;
PCHAR HttpClrf = NULL;
CHAR ContentLengthHeader[] = "content-length:";
SIZE_T ContentLengthLength = sizeof(ContentLengthHeader) - 1;
PCHAR ContentLengthValue = NULL;
SIZE_T ContentLengthValueLength = 0;
BOOL bFlag = FALSE;
while (Pointer < BufferEnd)
{
HttpClrf = FindStringInMemoryRegion(Pointer, (SIZE_T)(BufferEnd - Pointer), (PCHAR)"\r\n", 2);
if (HttpClrf == NULL)
HttpClrf = BufferEnd;
if ((SIZE_T)(HttpClrf - Pointer) >= (sizeof(ContentLengthHeader) - 1) && StringCompareByLengthLowerA(Pointer, ContentLengthHeader, ContentLengthLength) == 0)
{
ContentLengthValue = Pointer + (sizeof(ContentLengthHeader) - 1);
while (ContentLengthValue < HttpClrf && (*ContentLengthValue == ' ' || *ContentLengthValue == '\t'))
ContentLengthValue++;
while (ContentLengthValue < HttpClrf && *ContentLengthValue >= '0' && *ContentLengthValue <= '9')
{
bFlag = TRUE;
ContentLengthValueLength = (ContentLengthValueLength * 10) + (SIZE_T)(*ContentLengthValue - '0');
ContentLengthValue++;
}
if (bFlag)
*outLen = ContentLengthValueLength;
return bFlag;
}
Pointer = (HttpClrf + 2);
}
return FALSE;
}
VOID AfdClose(PNTSOCKET Socket)
{
if (Socket && Socket->Socket)
CloseHandle(Socket->Socket);
}
NTSTATUS AfdSendRequest(HANDLE Socket, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG_PTR InformationOutBuffer)
{
NTSTATUS Status = STATUS_SUCCESS;
IO_STATUS_BLOCK Io = { 0 };
HANDLE AfdEventHandleObject = NULL;
Status = NtCreateEvent(&AfdEventHandleObject, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE);
if (!NT_SUCCESS(Status))
return Status;
Status = NtDeviceIoControlFile(Socket, AfdEventHandleObject, NULL, NULL, &Io, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength);
if (Status == STATUS_PENDING)
{
NtWaitForSingleObject(AfdEventHandleObject, FALSE, NULL);
Status = Io.Status;
}
if (InformationOutBuffer)
*InformationOutBuffer = Io.Information;
CloseHandle(AfdEventHandleObject);
return Status;
}
NTSTATUS AdfCreateSocket(PNTSOCKET Socket, UINT AddressFamily, UINT SocketType, UINT Protocol)
{
NTSTATUS Status = STATUS_SUCCESS;
ACCESS_MASK AccessMask = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
UNICODE_STRING AfdEndpoint = { 0 };
OBJECT_ATTRIBUTES Attributes = { 0 };
IO_STATUS_BLOCK Io = { 0 };
PCHAR AfdExtendedAttributeName = (PCHAR)"AfdOpenPacketXX";
AFD_OPEN_PACKET_EXTENDED_ATTRIBUTES AfdOpenPacketAttributes = { 0 };
AfdOpenPacketAttributes.ExtendedAttributeNameLength = 15;
AfdOpenPacketAttributes.ExtendedAttributeValueLength = 30;
AfdOpenPacketAttributes.AddressFamily = AddressFamily;
AfdOpenPacketAttributes.SocketType = SocketType;
AfdOpenPacketAttributes.Protocol = Protocol;
CopyMemory(AfdOpenPacketAttributes.ExtendedAttributeName, AfdExtendedAttributeName, 15);
SetMemory(AfdOpenPacketAttributes.Unknown1, 0xff, sizeof(AfdOpenPacketAttributes.Unknown1));
RtlInitUnicodeString(&AfdEndpoint, L"\\Device\\Afd\\Endpoint");
InitializeObjectAttributesLocal(&Attributes, &AfdEndpoint, OBJ_CASE_INSENSITIVE, NULL, NULL);
return NtCreateFile(
&Socket->Socket,
AccessMask,
&Attributes,
&Io,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
&AfdOpenPacketAttributes,
(ULONG)sizeof(AfdOpenPacketAttributes));
}
NTSTATUS AfdCreateTcpSocket(PNTSOCKET Socket)
{
return AdfCreateSocket(Socket, AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
NTSTATUS AfdBindSocketToTransportProvider(PNTSOCKET Socket)
{
BYTE OutputBlob[16] = { 0 };
AFD_BIND_SOCKET BindSocketObject = { 0 };
BindSocketObject.Address.sin_family = AF_INET;
return AfdSendRequest(Socket->Socket, IOCTL_AFD_BIND, &BindSocketObject, sizeof(BindSocketObject), OutputBlob, sizeof(OutputBlob), NULL);
}
NTSTATUS AfdSendConnectRequestIpv4(PNTSOCKET Socket, UINT IpAddress, UINT16 Port)
{
AFD_CONNECT_REQUEST_IPV4 ConnectionRequest = { 0 };
ConnectionRequest.Address.sin_family = AF_INET;
ConnectionRequest.Address.sin_addr.s_addr = IpAddress;
ConnectionRequest.Address.sin_port = HostToNetworkShort(Port);
return AfdSendRequest(Socket->Socket, IOCTL_AFD_CONNECT, &ConnectionRequest, sizeof(ConnectionRequest), NULL, 0, NULL);
}
BOOL AfdSendData(PNTSOCKET Socket, PVOID Buffer, UINT Length)
{
NTSTATUS Status = STATUS_SUCCESS;
PBYTE BufferOffsetPointer = (PBYTE)Buffer;
UINT Remaining = Length;
UINT Sent = 0;
while (Remaining)
{
AFD_IO_BUFFER IoBuffer = { 0 };
AFD_TRANSFER_REQUEST Request = { 0 };
BYTE EmptyOutputBuffer[16] = { 0 };
ULONG_PTR ReceiveInformation = 0;
IoBuffer.Buffer = BufferOffsetPointer;
IoBuffer.Length = Remaining;
Request.Buffer = &IoBuffer;
Request.BufferCount = 1;
Status = AfdSendRequest(Socket->Socket, IOCTL_AFD_SEND, &Request, sizeof(Request), EmptyOutputBuffer, sizeof(EmptyOutputBuffer), &ReceiveInformation);
if (!NT_SUCCESS(Status))
return FALSE;
Sent = (UINT)ReceiveInformation;
if (Sent == 0)
return FALSE;
BufferOffsetPointer += Sent;
Remaining -= Sent;
}
return TRUE;
}
BOOL AfdReceiveData(PNTSOCKET Socket, PVOID Buffer, UINT MaximumLength, PUINT ReturnLength)
{
NTSTATUS Status = STATUS_SUCCESS;
AFD_IO_BUFFER IoBuffer = { 0 };
AFD_TRANSFER_REQUEST Request = { 0 };
BYTE EmptyOutputBuffer[16] = { 0 };
ULONG_PTR ReceiveInformation = 0;
IoBuffer.Buffer = Buffer;
IoBuffer.Length = MaximumLength;
Request.Buffer = &IoBuffer;
Request.BufferCount = 1;
Request.TdiFlags = 32;
*ReturnLength = 0;
Status = AfdSendRequest(Socket->Socket, IOCTL_AFD_RECV, &Request, sizeof(Request), EmptyOutputBuffer, sizeof(EmptyOutputBuffer), &ReceiveInformation);
if (!NT_SUCCESS(Status))
return FALSE;
*ReturnLength = (UINT)ReceiveInformation;
return TRUE;
}
VOID TlsFreeClientCredentialHandle(PTLSCLIENT TlsClient)
{
if (TlsClient->ContextInitializedFlag)
{
SspiVirtualFunctionTable->DeleteSecurityContext(&TlsClient->ContextHandle);
TlsClient->ContextInitializedFlag = FALSE;
}
if (TlsClient->CredentialInitializedFlag)
{
SspiVirtualFunctionTable->FreeCredentialsHandle(&TlsClient->CredentialHandle);
TlsClient->CredentialInitializedFlag = FALSE;
}
}
BOOL TlsAcquireClientCredentialHandle(TLSCLIENT* TlsClient)
{
SECURITY_STATUS SecurityStatus = STATUS_SUCCESS;
TimeStamp Expiration = { 0 };
SCHANNEL_CRED ChannelCredential = { 0 };
ChannelCredential.dwVersion = SCHANNEL_CRED_VERSION;
SecurityStatus = SspiVirtualFunctionTable->AcquireCredentialsHandleW(
NULL,
(LPWSTR)L"Microsoft Unified Security Protocol Provider",
0x00000002,
NULL,
&ChannelCredential,
NULL,
NULL,
&TlsClient->CredentialHandle,
&Expiration);
if (SecurityStatus != SEC_E_OK)
return FALSE;
TlsClient->CredentialInitializedFlag = TRUE;
return TRUE;
}
BOOL TlsHandshake(TLSCLIENT* TlsClient, PNTSOCKET Socket, PWCHAR Host)
{
SECURITY_STATUS SecurityStatus = 0;
TimeStamp Expiration = { 0 };
PBYTE Data = NULL;
DWORD Length = 0;
BOOL bFlag = FALSE;
SCHANNEL_CRED ChannelCredential = { 0 };
DWORD ContextRequirement =
ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_REQ_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
SecBufferDesc OutputSecurityDescription = { 0 };
SecBuffer OutputSecurityBuffer = { 0 };
SecBufferDesc InputSecurityDescription = { 0 };
SecBuffer InputSecurityBuffer[2] = { 0 };
PCCERT_CONTEXT ServerCertificate = NULL;
CERT_CHAIN_PARA CertChainParameters = { 0 };
CertChainParameters.cbSize = sizeof(CertChainParameters);
PCCERT_CHAIN_CONTEXT ChainContext = NULL;
SSL_EXTRA_CERT_CHAIN_POLICY_PARA Extra = { 0 };
Extra.cbSize = sizeof(Extra);
Extra.dwAuthType = AUTHTYPE_SERVER;
Extra.pwszServerName = Host;
CERT_CHAIN_POLICY_PARA Policy = { 0 };
Policy.cbSize = sizeof(Policy);
Policy.pvExtraPolicyPara = &Extra;
CERT_CHAIN_POLICY_STATUS PolicyStatus;
PolicyStatus.cbSize = sizeof(PolicyStatus);
Data = (PBYTE)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, DEFAULT_BUFFER_ALLOCATION_SIZE);
if (Data == NULL)
return FALSE;
while (TRUE)
{
RtlInitializeSecurityBuffer(&InputSecurityBuffer[0], SECBUFFER_TOKEN, Length, ((Length > 0) ? Data : NULL));
RtlInitializeSecurityBuffer(&InputSecurityBuffer[1], SECBUFFER_EMPTY, 0, NULL);
RtlInitializeSecurityDescription(&InputSecurityDescription, SECBUFFER_VERSION, 2, InputSecurityBuffer);
RtlInitializeSecurityBuffer(&OutputSecurityBuffer, SECBUFFER_TOKEN, 0, NULL);
RtlInitializeSecurityDescription(&OutputSecurityDescription, SECBUFFER_VERSION, 1, &OutputSecurityBuffer);
DWORD ContextAttributes = ERROR_SUCCESS;
INT Sent = 0;
UINT Received = 0;
ZeroMemory(&Expiration, sizeof(Expiration));
SecurityStatus = 0;
if (!TlsClient->ContextInitializedFlag)
{
SecurityStatus = SspiVirtualFunctionTable->InitializeSecurityContextW(
&TlsClient->CredentialHandle,
NULL,
Host,
ContextRequirement,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
&TlsClient->ContextHandle,
&OutputSecurityDescription,
&ContextAttributes,
&Expiration);
TlsClient->ContextInitializedFlag = TRUE;
}
else {
SecurityStatus = SspiVirtualFunctionTable->InitializeSecurityContextW(
&TlsClient->CredentialHandle,
&TlsClient->ContextHandle,
Host,
ContextRequirement,
0,
SECURITY_NATIVE_DREP,
&InputSecurityDescription,
0,
NULL,
&OutputSecurityDescription,
&ContextAttributes,
&Expiration);
}
if (OutputSecurityBuffer.pvBuffer && OutputSecurityBuffer.cbBuffer)
{
Sent = AfdSendData(Socket, OutputSecurityBuffer.pvBuffer, (INT)OutputSecurityBuffer.cbBuffer);
if (Sent <= 0)
goto EXIT_ROUTINE;
else
SspiVirtualFunctionTable->FreeContextBuffer(OutputSecurityBuffer.pvBuffer);
}
if (SecurityStatus == SEC_E_OK)
break;
if (SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus == SEC_E_INCOMPLETE_MESSAGE)
{
if (InputSecurityBuffer[1].BufferType == SECBUFFER_EXTRA)
{
MoveMemory(Data, (Data + (Length - InputSecurityBuffer[1].cbBuffer)), InputSecurityBuffer[1].cbBuffer);
Length = InputSecurityBuffer[1].cbBuffer;
}
else
Length = 0;
if (Length >= DEFAULT_BUFFER_ALLOCATION_SIZE)
goto EXIT_ROUTINE;
if (!AfdReceiveData(Socket, (PCHAR)Data + Length, (INT)(DEFAULT_BUFFER_ALLOCATION_SIZE - Length), &Received))
goto EXIT_ROUTINE;
if (Received <= 0)
goto EXIT_ROUTINE;
Length += (DWORD)Received;
}
else
goto EXIT_ROUTINE;
}
SecurityStatus = 0;
SecurityStatus = SspiVirtualFunctionTable->QueryContextAttributesW(&TlsClient->ContextHandle, SECPKG_ATTR_STREAM_SIZES, &TlsClient->Sizes);
if (SecurityStatus != SEC_E_OK)
goto EXIT_ROUTINE;
SecurityStatus = 0;
SecurityStatus = SspiVirtualFunctionTable->QueryContextAttributesW(&TlsClient->ContextHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&ServerCertificate);
if (SecurityStatus != SEC_E_OK || ServerCertificate == NULL)
goto EXIT_ROUTINE;
if (!CertGetCertificateChain(NULL, ServerCertificate, NULL, ServerCertificate->hCertStore, &CertChainParameters, 0, NULL, &ChainContext))
goto EXIT_ROUTINE;
if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, ChainContext, &Policy, &PolicyStatus))
goto EXIT_ROUTINE;
if (PolicyStatus.dwError != ERROR_SUCCESS)
goto EXIT_ROUTINE;
bFlag = TRUE;
EXIT_ROUTINE:
if (ChainContext)
CertFreeCertificateChain(ChainContext);
if (ServerCertificate)
CertFreeCertificateContext(ServerCertificate);
if (OutputSecurityBuffer.pvBuffer)
SspiVirtualFunctionTable->FreeContextBuffer(OutputSecurityBuffer.pvBuffer);
if (Data)
RtlFreeHeap(GetProcessHeap(), 0, Data);
return bFlag;
}
BOOL TlsSendCloseNotification(PTLSCLIENT TlsClient, PNTSOCKET Socket)
{
SECURITY_STATUS Status = STATUS_SUCCESS;
SecBuffer InputBuffer = { 0 };
SecBufferDesc InputDescriptionBuffer = { 0 };
DWORD ShutdownNotification = SCHANNEL_SHUTDOWN;
SecBuffer OutputBuffer = { 0 };
SecBufferDesc OutputDescriptionBuffer = { 0 };
ULONG Attributes = 0;
TimeStamp Expiration = { 0 };
RtlInitializeSecurityBuffer(&InputBuffer, SECBUFFER_TOKEN, sizeof(ShutdownNotification), &ShutdownNotification);
RtlInitializeSecurityDescription(&InputDescriptionBuffer, SECBUFFER_VERSION, 1, &InputBuffer);
RtlInitializeSecurityBuffer(&OutputBuffer, SECBUFFER_TOKEN, 0, NULL);
RtlInitializeSecurityDescription(&OutputDescriptionBuffer, SECBUFFER_VERSION, 1, &OutputBuffer);
Status = SspiVirtualFunctionTable->ApplyControlToken(&TlsClient->ContextHandle, &InputDescriptionBuffer);
if (Status != SEC_E_OK)
return FALSE;
Status = SspiVirtualFunctionTable->InitializeSecurityContextW(
&TlsClient->CredentialHandle,
&TlsClient->ContextHandle,
NULL,
ISC_REQ_ALLOCATE_MEMORY,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
&TlsClient->ContextHandle,
&OutputDescriptionBuffer,
&Attributes,
&Expiration);
if (Status != SEC_E_OK && Status != SEC_I_CONTEXT_EXPIRED)
return FALSE;
if (!OutputBuffer.pvBuffer || OutputBuffer.cbBuffer == 0)
return FALSE;
if (!AfdSendData(Socket, OutputBuffer.pvBuffer, (INT)OutputBuffer.cbBuffer))
return FALSE;
return TRUE;
}
BOOL TlsSendData(PTLSCLIENT TlsClient, PNTSOCKET Socket, PBYTE Data, DWORD Length)
{
SECURITY_STATUS SecurityStatus = 0;
SIZE_T Offset = 0;
PBYTE Buffer = NULL;
BOOL bFlag = FALSE;
INT BytesReceived = 0;
for (DWORD Fragment = 0, BufferSize = 0; Offset < Length;)
{
SecBuffer SecurityBufferObjectArray[4] = { 0 };
SecBufferDesc SecurityDescription = { 0 };
Fragment = (DWORD)InlineGetMinimum((SIZE_T)TlsClient->Sizes.cbMaximumMessage, Length - Offset);
BufferSize = TlsClient->Sizes.cbHeader + Fragment + TlsClient->Sizes.cbTrailer;
Buffer = (PBYTE)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
if (Buffer == NULL)
goto EXIT_ROUTINE;
CopyMemory(Buffer + TlsClient->Sizes.cbHeader, ((PCHAR)Data + Offset), Fragment);
RtlInitializeSecurityBuffer(
&SecurityBufferObjectArray[0],
SECBUFFER_STREAM_HEADER,
TlsClient->Sizes.cbHeader,
Buffer);
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[1],
SECBUFFER_DATA,
Fragment,
((PCHAR)Buffer + TlsClient->Sizes.cbHeader));
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[2],
SECBUFFER_STREAM_TRAILER,
TlsClient->Sizes.cbTrailer,
((PCHAR)Buffer + TlsClient->Sizes.cbHeader + Fragment));
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[3], SECBUFFER_EMPTY, 0, NULL);
RtlInitializeSecurityDescription(&SecurityDescription, SECBUFFER_VERSION, 4, SecurityBufferObjectArray);
SecurityStatus = SspiVirtualFunctionTable->EncryptMessage(&TlsClient->ContextHandle, 0, &SecurityDescription, 0);
if (SecurityStatus != SEC_E_OK)
goto EXIT_ROUTINE;
if (AfdSendData(Socket, Buffer, (INT)(SecurityBufferObjectArray[0].cbBuffer + SecurityBufferObjectArray[1].cbBuffer + SecurityBufferObjectArray[2].cbBuffer)) <= 0)
goto EXIT_ROUTINE;
if (Buffer)
RtlFreeHeap(GetProcessHeap(), 0, Buffer);
Buffer = NULL;
Offset += Fragment;
}
bFlag = TRUE;
EXIT_ROUTINE:
if (Buffer)
RtlFreeHeap(GetProcessHeap(), 0, Buffer);
return bFlag;
}
BOOL WsaProcessIncomingResponseBuffer(PBYTE* Buffer, PSIZE_T Length, PBYTE Response, SIZE_T ResponseLength)
{
SIZE_T AllocationBlock = *Length + ResponseLength;
PBYTE Object = NULL;
if (*Buffer == NULL)
Object = (PBYTE)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, AllocationBlock + 1);
else
Object = (PBYTE)RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, *Buffer, *Length + ResponseLength + 1);
if (Object == NULL)
return FALSE;
CopyMemory(Object + *Length, Response, ResponseLength);
Object[*Length + ResponseLength] = 0;
*Buffer = Object;
*Length += ResponseLength;
return TRUE;
}
PBYTE TlsReceiveData(PTLSCLIENT TlsClient, PNTSOCKET Socket, PSIZE_T Length)
{
SECURITY_STATUS SecurityStatus = 0;
SecBuffer SecurityBufferObjectArray[4] = { 0 };
SecBufferDesc SecurityDescription = { 0 };
PBYTE NetworkBuffer = NULL;
SIZE_T NetworkBufferLength = 0;
PBYTE Response = NULL;
SIZE_T ResponseLength = 0;
BYTE ResponseDigestObject[8192] = { 0 };
PBYTE SecBufferChannelExtraHandler = NULL;
ULONG SecBufferChannelExtraLength = 0;
BOOL HttpKeepAliveAreHeadersPresentFlag = FALSE;
BOOL HttpIsContentLengthPresentFlag = FALSE;
SIZE_T HttpResponseBodyLength = 0;
SIZE_T HttpResponseTotal = 0;
for (INT BytesReceived = 0; TRUE;)
{
if (HttpKeepAliveAreHeadersPresentFlag)
{
if (HttpIsContentLengthPresentFlag && ResponseLength >= HttpResponseTotal)
{
*Length = HttpResponseTotal;
break;
}
}
if (!AfdReceiveData(Socket, (PCHAR)ResponseDigestObject, sizeof(ResponseDigestObject), (PUINT)&BytesReceived))
goto EXIT_ROUTINE;
if (BytesReceived == 0)
break;
if (BytesReceived < 0)
goto EXIT_ROUTINE;
if (!WsaProcessIncomingResponseBuffer(&NetworkBuffer, &NetworkBufferLength, ResponseDigestObject, (SIZE_T)BytesReceived))
goto EXIT_ROUTINE;
while (TRUE)
{
if (NetworkBufferLength == ERROR_SUCCESS)
break;
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[0], SECBUFFER_DATA, (ULONG)NetworkBufferLength, NetworkBuffer);
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[1], SECBUFFER_EMPTY, 0, NULL);
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[2], SECBUFFER_EMPTY, 0, NULL);
RtlInitializeSecurityBuffer(&SecurityBufferObjectArray[3], SECBUFFER_EMPTY, 0, NULL);
RtlInitializeSecurityDescription(&SecurityDescription, SECBUFFER_VERSION, 4, SecurityBufferObjectArray);
SecurityStatus = SspiVirtualFunctionTable->DecryptMessage(&TlsClient->ContextHandle, &SecurityDescription, 0, NULL);
if (SecurityStatus == SEC_E_INCOMPLETE_MESSAGE)
break;
if (SecurityStatus == SEC_I_CONTEXT_EXPIRED)
{
RtlFreeHeap(GetProcessHeap(), 0, NetworkBuffer);
*Length = ResponseLength;
return Response;
}
if (SecurityStatus != SEC_E_OK && SecurityStatus != SEC_I_RENEGOTIATE)
goto EXIT_ROUTINE;
for (INT Ordinal = 0; Ordinal < 4; Ordinal++)
{
if (SecurityBufferObjectArray[Ordinal].BufferType == SECBUFFER_DATA && SecurityBufferObjectArray[Ordinal].cbBuffer)
{
if (!WsaProcessIncomingResponseBuffer(&Response, &ResponseLength, (PBYTE)SecurityBufferObjectArray[Ordinal].pvBuffer, SecurityBufferObjectArray[Ordinal].cbBuffer))
goto EXIT_ROUTINE;
}
}
if (!HttpKeepAliveAreHeadersPresentFlag)
{
PCHAR HeaderEndOffset = NULL;
HeaderEndOffset = FindStringInMemoryRegion((PCHAR)Response, ResponseLength, (PCHAR)"\r\n\r\n", 4);
if (HeaderEndOffset)
{
HttpKeepAliveAreHeadersPresentFlag = TRUE;
HttpIsContentLengthPresentFlag = HttpGetContentLength((PCHAR)Response, ((SIZE_T)(HeaderEndOffset - (PCHAR)Response)), &HttpResponseBodyLength);
if (HttpIsContentLengthPresentFlag)
HttpResponseTotal = (((SIZE_T)(HeaderEndOffset - (PCHAR)Response)) + 4) + HttpResponseBodyLength;
}
}
if (SecurityStatus == SEC_I_RENEGOTIATE)
goto EXIT_ROUTINE;
SecBufferChannelExtraHandler = NULL;
SecBufferChannelExtraLength = 0;
for (INT i = 0; i < 4; i++)
{
if (SecurityBufferObjectArray[i].BufferType == SECBUFFER_EXTRA && SecurityBufferObjectArray[i].cbBuffer > 0)
{
SecBufferChannelExtraHandler = (PBYTE)SecurityBufferObjectArray[i].pvBuffer;
SecBufferChannelExtraLength = SecurityBufferObjectArray[i].cbBuffer;
break;
}
}
if (SecBufferChannelExtraLength)
{
MoveMemory(NetworkBuffer, SecBufferChannelExtraHandler, SecBufferChannelExtraLength);
NetworkBufferLength = SecBufferChannelExtraLength;
}
else
NetworkBufferLength = 0;
}
}
EXIT_ROUTINE:
if (NetworkBuffer)
RtlFreeHeap(GetProcessHeap(), 0, NetworkBuffer);
*Length = ResponseLength;
return Response;
}
BOOL DnsEncodeHostNameToQNameWire(PCHAR Host, PBYTE OutputBuffer, SIZE_T OutputBufferMaxLength, PSIZE_T OutputLength)
{
SIZE_T WriteIndex = 0;
for (PCHAR Pointer = Host; *Pointer;)
{
PCHAR Delimiter = Pointer;
SIZE_T LabelLength = 0;
while (*Delimiter && *Delimiter != '.')
Delimiter++;
LabelLength = (SIZE_T)(Delimiter - Pointer);
if (LabelLength == 0 || LabelLength > 63)
return FALSE;
if (WriteIndex + 1 + LabelLength >= OutputBufferMaxLength)
return FALSE;
OutputBuffer[WriteIndex++] = (BYTE)LabelLength;
for (SIZE_T i = 0; i < LabelLength; i++)
OutputBuffer[WriteIndex++] = (BYTE)Pointer[i];
Pointer = (*Delimiter == '.') ? Delimiter + 1 : Delimiter;
}
if (WriteIndex + 1 > OutputBufferMaxLength)
return FALSE;
OutputBuffer[WriteIndex++] = 0;
*OutputLength = WriteIndex;
return TRUE;
}
SIZE_T DnsSkipOverDnsNameWire(PBYTE Buffer, SIZE_T Length, SIZE_T Offset)
{
while (Offset < Length)
{
BYTE Ordinal = Buffer[Offset];
if (Ordinal == 0)
return Offset + 1;
if ((Ordinal & 0xC0) == 0xC0)
return (Offset + 2 <= Length) ? Offset + 2 : Length;
Offset++;
if (Offset + Ordinal > Length)
return Length;
Offset += Ordinal;
}
return Length;
}
BOOL DnsExtractFirstARecordIp(PBYTE Buffer, SIZE_T Length, UINT16 Id, PUINT32 IpAddress)
{
UINT16 DnsId = 0;
UINT16 Flags = 0;
UINT16 QdCount = 0;
UINT16 AnCount = 0;
UINT16 Type = 0;
UINT16 ClassField = 0;
UINT16 RdataLength = 0;
SIZE_T Offset = 0;
DnsId = (Buffer[0] << 8) | Buffer[1];
if (DnsId != Id)
return FALSE;
Flags = (Buffer[2] << 8) | Buffer[3];
if ((Flags & 0x8000) == 0)
return FALSE;
if ((Flags & 0x000F) != 0)
return FALSE;
QdCount = (Buffer[4] << 8) | Buffer[5];
AnCount = (Buffer[6] << 8) | Buffer[7];
Offset = 12;
for (UINT16 i = 0; i < QdCount; i++)
{
Offset = DnsSkipOverDnsNameWire(Buffer, Length, Offset);
if (Offset + 4 > Length)
return FALSE;
Offset += 4;
}
for (UINT16 i = 0; i < AnCount; i++)
{
Offset = DnsSkipOverDnsNameWire(Buffer, Length, Offset);
if (Offset + 10 > Length)
return FALSE;
Type = (Buffer[Offset] << 8) | Buffer[Offset + 1];
Offset += 2;
ClassField = (Buffer[Offset] << 8) | Buffer[Offset + 1];
Offset += 2;
Offset += 4;
RdataLength = (Buffer[Offset] << 8) | Buffer[Offset + 1];
Offset += 2;
if (Offset + RdataLength > Length)
return FALSE;
if (Type == 1 && ClassField == 1 && RdataLength == 4)
{
CopyMemory(IpAddress, Buffer + Offset, sizeof(UINT));
return TRUE;
}
Offset += RdataLength;
}
return FALSE;
}
BOOL AfdGetAddressFromHostname(PWCHAR Host, PUINT32 Address)
{
NTSTATUS Status = STATUS_SUCCESS;
NTSOCKET Socket = { 0 };
CHAR DnsHostName[256] = { 0 };
UINT DnsServer = HostToNetworkLong(0x01010101); //1.1.1.1
BOOL bFlag = FALSE;
WCharStringToCharString2(DnsHostName, Host, sizeof(DnsHostName));
BYTE DnsMessage[512] = { 0 };
SIZE_T DnsMessageLength = 0;
UINT16 BigEndianLength = 0;
UINT16 DnsTransactionId = (UINT16)GetTickCount64();
BYTE DnsResponseBuffer[4096] = { 0 };
UINT TotalBytesReceived = 0;
SIZE_T QnameLength = 0;
UINT16 ResponseBufferBigEndianLength = 0;
UINT Received = 0;
UINT16 ResponseLength = 0;
if (sizeof(DNS_HEADER) + 5 > sizeof(DnsMessage))
return FALSE;
PDNS_HEADER Header = (PDNS_HEADER)DnsMessage;
Header->Id = HostToNetworkShort(DnsTransactionId);
Header->Flags = HostToNetworkShort(0x0100); //256
Header->QdCount = HostToNetworkShort(1);
Header->AnCount = 0;
Header->NsCount = 0;
Header->ArCount = 0;
DnsMessageLength = sizeof(DNS_HEADER);
if (!DnsEncodeHostNameToQNameWire(DnsHostName, DnsMessage + DnsMessageLength, sizeof(DnsMessage) - DnsMessageLength, &QnameLength))
return FALSE;
DnsMessageLength += QnameLength;
if (DnsMessageLength + 4 > sizeof(DnsMessage))
return FALSE;
DnsMessage[DnsMessageLength++] = 0x00;
DnsMessage[DnsMessageLength++] = 0x01;
DnsMessage[DnsMessageLength++] = 0x00;
DnsMessage[DnsMessageLength++] = 0x01;
Status = AfdCreateTcpSocket(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
Status = AfdBindSocketToTransportProvider(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
Status = AfdSendConnectRequestIpv4(&Socket, DnsServer, 53);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
BigEndianLength = HostToNetworkShort((UINT16)DnsMessageLength);
if (!AfdSendData(&Socket, &BigEndianLength, sizeof(BigEndianLength)))
goto EXIT_ROUTINE;
if (!AfdSendData(&Socket, DnsMessage, (UINT)DnsMessageLength))
goto EXIT_ROUTINE;
if (!AfdReceiveData(&Socket, &ResponseBufferBigEndianLength, sizeof(ResponseBufferBigEndianLength), &Received) || Received != sizeof(ResponseBufferBigEndianLength))
goto EXIT_ROUTINE;
ResponseLength = HostToNetworkShort(ResponseBufferBigEndianLength);
if (ResponseLength < sizeof(DNS_HEADER) || ResponseLength > 4096)
goto EXIT_ROUTINE;
for (UINT Fragment = 0; TotalBytesReceived < ResponseLength; TotalBytesReceived += Fragment)
{
if (!AfdReceiveData(&Socket, DnsResponseBuffer + TotalBytesReceived, ResponseLength - TotalBytesReceived, &Fragment))
goto EXIT_ROUTINE;
if (Fragment == 0)
goto EXIT_ROUTINE;
}
if (!DnsExtractFirstARecordIp(DnsResponseBuffer, ResponseLength, DnsTransactionId, Address))
goto EXIT_ROUTINE;
bFlag = TRUE;
EXIT_ROUTINE:
AfdClose(&Socket);
return bFlag;
}
PCHAR HttpGetCrlf(PCHAR Start, PCHAR End)
{
for (PCHAR p = Start; p + 1 < End; p++)
{
if (p[0] == HTTP_CR && p[1] == HTTP_LF)
return p;
}
return NULL;
}
PBYTE RtlProcessInitialHttpHeaderClrf(PBYTE Data, SIZE_T Length)
{
PCHAR HttpBufferStart = (PCHAR)Data;
PCHAR HttpBufferEnd = HttpBufferStart + Length;
PCHAR InitialCrlfObject = HttpGetCrlf(HttpBufferStart, HttpBufferEnd);
for (PCHAR CrlfObjectNext = NULL; InitialCrlfObject;)
{
CrlfObjectNext = InitialCrlfObject + 2;
if (CrlfObjectNext + 1 < HttpBufferEnd && CrlfObjectNext[0] == HTTP_CR && CrlfObjectNext[1] == HTTP_LF)
return (PBYTE)InitialCrlfObject;
InitialCrlfObject = HttpGetCrlf(InitialCrlfObject + 2, HttpBufferEnd);
}
return NULL;
}
PVOID HttpFindByte(PVOID Buffer, INT Target, SIZE_T Length)
{
PBYTE Pointer = (PBYTE)Buffer;
PBYTE End = (PBYTE)Buffer + Length;
BYTE TargetByte = Target;
for (; Pointer < End; Pointer++)
{
if (*Pointer == TargetByte)
return (PVOID)Pointer;
}
return NULL;
}
INT GetHttpStatusCode(PCHAR Buffer, SIZE_T Length)
{
INT Status = 0;
for (SIZE_T i = 0; i < Length; i++)
{
if (Buffer[i] < '0' || Buffer[i] > '9')
return -1;
Status = (Status * 10) + (Buffer[i] - '0');
}
if (Status < 100 || Status > 599)
return -1;
return Status;
}
PCHAR ParseHttpHeaderValue(PCHAR String, SIZE_T Count)
{
PCHAR Out = (PCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, Count + 1);
if (Out == NULL)
return NULL;
CopyMemory(Out, String, Count);
Out[Count] = '\0';
return Out;
}
BOOL ProcessHttpResponseData(PBYTE Data, SIZE_T DataLength, PHTTP_RESPONSE Response)
{
PBYTE HeaderDelimitedObject = NULL;
PCHAR HttpHeaderStart = NULL;
PCHAR HttpHeaderEnd = NULL;
PCHAR LineTerminationPointer = NULL;
PCHAR VersionEnd = NULL;
PCHAR StatusCodeEnd = NULL;
HeaderDelimitedObject = RtlProcessInitialHttpHeaderClrf(Data, DataLength);
if (!HeaderDelimitedObject)
return FALSE;
HttpHeaderStart = (PCHAR)Data;
HttpHeaderEnd = (PCHAR)Data + (SIZE_T)(HeaderDelimitedObject - Data);
LineTerminationPointer = HttpGetCrlf(HttpHeaderStart, HttpHeaderEnd);
if (!LineTerminationPointer)
return FALSE;
VersionEnd = (PCHAR)HttpFindByte((PVOID)HttpHeaderStart, HTTP_SP, (SIZE_T)(LineTerminationPointer - HttpHeaderStart));
StatusCodeEnd = (PCHAR)HttpFindByte((PVOID)(VersionEnd + 1), HTTP_SP, (SIZE_T)(LineTerminationPointer - (VersionEnd + 1)));
if (!VersionEnd || !StatusCodeEnd)
return FALSE;
Response->StatusCode = GetHttpStatusCode(VersionEnd + 1, (SIZE_T)(StatusCodeEnd - (VersionEnd + 1)));
if (Response->StatusCode < 0)
return FALSE;
Response->Reason = ParseHttpHeaderValue((PCHAR)(StatusCodeEnd + 1), (SIZE_T)(LineTerminationPointer - ((StatusCodeEnd + 1))));
if (Response->Reason == NULL)
return FALSE;
HttpHeaderStart = ((PCHAR)LineTerminationPointer + 2);
for (PCHAR HttpLineEndObject = NULL, HttpParseDelimiterPointer = NULL, HttpParseValuePointer = NULL; HttpHeaderStart < HttpHeaderEnd;)
{
HttpLineEndObject = NULL;
HttpParseDelimiterPointer = NULL;
HttpParseValuePointer = NULL;
if ((SIZE_T)(HttpHeaderEnd - HttpHeaderStart) < 2)
break;
HttpLineEndObject = HttpGetCrlf(HttpHeaderStart, HttpHeaderEnd);
if (!HttpLineEndObject)
break;
HttpParseDelimiterPointer = (PCHAR)HttpFindByte((PVOID)HttpHeaderStart, HTTP_CO, (SIZE_T)(HttpLineEndObject - HttpHeaderStart));
if (HttpParseDelimiterPointer && Response->HeaderCount < 64)
{
HttpParseValuePointer = (HttpParseDelimiterPointer + 1);
while (HttpParseValuePointer < HttpLineEndObject && (*HttpParseValuePointer == HTTP_SP || *HttpParseValuePointer == HTTP_TB))
HttpParseValuePointer++;
Response->Headers[Response->HeaderCount].Name = ParseHttpHeaderValue(HttpHeaderStart, (SIZE_T)(HttpParseDelimiterPointer - HttpHeaderStart));
Response->Headers[Response->HeaderCount].Value = ParseHttpHeaderValue(HttpParseValuePointer, (SIZE_T)(HttpLineEndObject - HttpParseValuePointer));
if (!Response->Headers[Response->HeaderCount].Value || !Response->Headers[Response->HeaderCount].Name)
return FALSE;
Response->HeaderCount++;
}
HttpHeaderStart = HttpLineEndObject + 2;
}
Response->Body = (PBYTE)HeaderDelimitedObject + 4;
Response->BodyLength = DataLength - (SIZE_T)(Response->Body - Data);
return TRUE;
}
VOID FreeHttpResponse(PHTTP_RESPONSE Response)
{
if (Response->Reason)
{
RtlFreeHeap(GetProcessHeap(), 0, (PVOID)Response->Reason);
Response->Reason = NULL;
Response->ReasonLength = 0;
}
for (SIZE_T i = 0; i < Response->HeaderCount; i++)
{
if (Response->Headers[i].Name)
{
RtlFreeHeap(GetProcessHeap(), 0, (PVOID)Response->Headers[i].Name);
Response->Headers[i].Name = NULL;
}
if (Response->Headers[i].Value)
{
RtlFreeHeap(GetProcessHeap(), 0, (PVOID)Response->Headers[i].Value);
Response->Headers[i].Value = NULL;
}
}
Response->HeaderCount = 0;
}
PCHAR HttpCreateSection(PCHAR Header, PCHAR Attribute)
{
PCHAR Out = NULL;
SIZE_T BufferSize = HTTP_DELIMITED_LENGTH;
BufferSize += StringLengthA(Header); BufferSize += StringLengthA(Attribute);
Out = (PCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferSize);
if (Out == NULL)
return NULL;
StringCopyA(Out, Header);
StringConcatA(Out, Attribute);
StringConcatA(Out, (PCHAR)HTTP_DELIMITER);
return Out;
}
PCHAR RtlBuildHttpRequest(INT Method, PCHAR Host, PCHAR UserAgent, PCHAR AcceptHeaderAttributes, PCHAR ConnectionHeaderAttributes, PCHAR ContentType, ULONG ContentLength)
{
PCHAR HttpBufferRequestObject = NULL;
PCHAR HttpBufferSectionHandler = NULL;
SIZE_T HttpBufferSize = DEFAULT_BUFFER_ALLOCATION_SIZE;
BOOL bFlag = FALSE;
CHAR ContentLengthObject[32] = { 0 };
HttpBufferRequestObject = (PCHAR)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, HttpBufferSize);
if (HttpBufferRequestObject == NULL)
goto EXIT_ROUTINE;
switch (Method)
{
case 0:
{
StringCopyA(HttpBufferRequestObject, (PCHAR)"GET /get HTTP/1.1\r\n");
break;
}
case 1:
{
StringCopyA(HttpBufferRequestObject, (PCHAR)"POST /post HTTP/1.1\r\n");
break;
}
default:
goto EXIT_ROUTINE;
}
if (Host)
{
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"Host: ", Host);
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
}
if (UserAgent)
{
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"User-Agent: ", UserAgent);
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
}
if (AcceptHeaderAttributes)
{
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"Accept: ", AcceptHeaderAttributes);
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
}
if (ContentType && ContentLength)
{
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"Content-Type: ", ContentType);
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"Content-Length: ", HttpUSizeToDecimalA((SIZE_T)ContentLength, ContentLengthObject, sizeof(ContentLengthObject)));
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
}
if (ConnectionHeaderAttributes)
{
HttpBufferSectionHandler = HttpCreateSection((PCHAR)"Connection: ", ConnectionHeaderAttributes);
if (HttpBufferSectionHandler == NULL)
goto EXIT_ROUTINE;
else {
StringConcatA(HttpBufferRequestObject, HttpBufferSectionHandler);
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferSectionHandler);
}
}
StringConcatA(HttpBufferRequestObject, (PCHAR)HTTP_DELIMITER);
bFlag = TRUE;
EXIT_ROUTINE:
if (!bFlag)
RtlFreeHeap(GetProcessHeap(), 0, HttpBufferRequestObject);
return (bFlag ? HttpBufferRequestObject : NULL);
}
BOOL ResolveNtdllImports(VOID)
{
HMODULE hModule = NULL;
hModule = GetModuleHandleA("ntdll.dll");
if (hModule == NULL)
return FALSE;
NtCreateFile = (NTCREATEFILE)GetProcAddress(hModule, "NtCreateFile");
NtDeviceIoControlFile = (NTDEVICEIOCONTROLFILE)GetProcAddress(hModule, "NtDeviceIoControlFile");
NtCreateEvent = (NTCREATEEVENT)GetProcAddress(hModule, "NtCreateEvent");
NtWaitForSingleObject = (NTWAITFORSINGLEOBJECT)GetProcAddress(hModule, "NtWaitForSingleObject");
RtlAllocateHeap = (RTLALLOCATEHEAP)GetProcAddress(hModule, "RtlAllocateHeap");
RtlFreeHeap = (RTLFREEHEAP)GetProcAddress(hModule, "RtlFreeHeap");
RtlReAllocateHeap = (RTLREALLOCATEHEAP)GetProcAddress(hModule, "RtlReAllocateHeap");
if (!NtCreateFile || !NtDeviceIoControlFile || !NtCreateEvent || !RtlAllocateHeap || !RtlFreeHeap || !RtlReAllocateHeap || !NtWaitForSingleObject)
return FALSE;
return TRUE;
}
BOOL InitSspiTable(VOID)
{
HMODULE hModule = NULL;
hModule = LoadLibraryA("sspicli.dll");
if (hModule == NULL)
return FALSE;
InitSecurityInterfaceW = (INITSECURITYINTERFACEW)GetProcAddress(hModule, "InitSecurityInterfaceW");
if (!InitSecurityInterfaceW)
return FALSE;
SspiVirtualFunctionTable = InitSecurityInterfaceW();
if (!SspiVirtualFunctionTable)
return FALSE;
return TRUE;
}
BOOL LoadCrypt32CertFunctions(VOID)
{
HMODULE hModule = NULL;
hModule = LoadLibraryA("Crypt32.dll");
if (hModule == NULL)
return FALSE;
CertFreeCertificateChain = (CERTFREECERTIFICATECHAIN)GetProcAddress(hModule, "CertFreeCertificateChain");
CertFreeCertificateContext = (CERTFREECERTIFICATECONTEXT)GetProcAddress(hModule, "CertFreeCertificateContext");
CertVerifyCertificateChainPolicy = (CERTVERIFYCERTIFICATECHAINPOLICY)GetProcAddress(hModule, "CertVerifyCertificateChainPolicy");
CertGetCertificateChain = (CERTGETCERTIFICATECHAIN)GetProcAddress(hModule, "CertGetCertificateChain");
if (!CertFreeCertificateChain || !CertFreeCertificateContext || !CertVerifyCertificateChainPolicy || !CertGetCertificateChain)
return FALSE;
return TRUE;
}
BOOL RtlInitializeProcessApis(VOID)
{
if (!ResolveNtdllImports() || !InitSspiTable() || !LoadCrypt32CertFunctions())
return FALSE;
return TRUE;
}
VOID PrintHttpResponse(PHTTP_RESPONSE Response)
{
printf("HTTP Response\r\n");
printf("==============\r\n");
printf("Status : %d\r\n", Response->StatusCode);
if (Response->Reason && Response->ReasonLength)
printf("Reason : %.*s\r\n", (int)Response->ReasonLength, Response->Reason);
else
printf("Reason : <none>\r\n");
printf("\nHeaders (%zu):\n", Response->HeaderCount);
printf("------------------------------\r\n");
for (SIZE_T i = 0; i < Response->HeaderCount; i++)
{
PHTTP_HEADER p = &Response->Headers[i];
if (!p->Name)
continue;
printf(" %s: %s\r\n", p->Name, p->Value ? p->Value : "");
}
printf("\nBody:\r\n");
printf("------------------------------\r\n");
printf("Length : %zu bytes\r\n", Response->BodyLength);
if (Response->Body && Response->BodyLength)
{
printf("Content:\r\n");
for (SIZE_T i = 0; i < Response->BodyLength; i++)
{
BYTE c = Response->Body[i];
putchar((c >= 32 && c <= 126) ? c : '.');
}
printf("\r\n");
}
else
printf("**NO BODY RECEIVED**\n");
printf("\r\n");
}
INT EXAMPLE_HttpsSimpleGetRequestClose(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
TLSCLIENT TlsClient = { 0 };
NTSOCKET Socket = { 0 };
PBYTE TlsResponse = NULL;
SIZE_T TlsResponseLength = 0;
HTTP_RESPONSE HttpResponse = { 0 };
PCHAR HttpRequestObject = NULL;
WCHAR Host[] = L"httpbin.org";
CHAR AnsiHost[256] = { 0 };
UINT32 IpAddress = 0;
Status = AfdCreateTcpSocket(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
Status = AfdBindSocketToTransportProvider(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!AfdGetAddressFromHostname(Host, &IpAddress))
goto EXIT_ROUTINE;
Status = AfdSendConnectRequestIpv4(&Socket, IpAddress, 443);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!TlsAcquireClientCredentialHandle(&TlsClient))
goto EXIT_ROUTINE;
if (!TlsHandshake(&TlsClient, &Socket, Host))
goto EXIT_ROUTINE;
WCharStringToCharString2(AnsiHost, Host, sizeof(AnsiHost));
HttpRequestObject = RtlBuildHttpRequest(0, AnsiHost, (PCHAR)"i like kitty cats/1.0", (PCHAR)"*/*", (PCHAR)"close", NULL, 0);
if (HttpRequestObject == NULL)
goto EXIT_ROUTINE;
if (!TlsSendData(&TlsClient, &Socket, (PBYTE)HttpRequestObject, (DWORD)StringLengthA(HttpRequestObject)))
goto EXIT_ROUTINE;
TlsResponse = TlsReceiveData(&TlsClient, &Socket, &TlsResponseLength);
if (TlsResponse == NULL)
goto EXIT_ROUTINE;
if (!ProcessHttpResponseData(TlsResponse, TlsResponseLength, &HttpResponse))
goto EXIT_ROUTINE;
PrintHttpResponse(&HttpResponse);
EXIT_ROUTINE:
if (HttpRequestObject)
RtlFreeHeap(GetProcessHeap(), 0, HttpRequestObject);
FreeHttpResponse(&HttpResponse);
if (TlsResponse)
RtlFreeHeap(GetProcessHeap(), 0, TlsResponse);
TlsFreeClientCredentialHandle(&TlsClient);
AfdClose(&Socket);
return 0;
}
INT EXAMPLE_HttpsSimpleGetRequestKeepAlive(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
TLSCLIENT TlsClient = { 0 };
NTSOCKET Socket = { 0 };
PBYTE TlsResponse = NULL;
SIZE_T TlsResponseLength = 0;
HTTP_RESPONSE HttpResponse = { 0 };
PCHAR HttpRequestObject = NULL;
WCHAR Host[] = L"httpbin.org";
CHAR AnsiHost[256] = { 0 };
UINT32 IpAddress = 0;
Status = AfdCreateTcpSocket(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
Status = AfdBindSocketToTransportProvider(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!AfdGetAddressFromHostname(Host, &IpAddress))
goto EXIT_ROUTINE;
Status = AfdSendConnectRequestIpv4(&Socket, IpAddress, 443);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!TlsAcquireClientCredentialHandle(&TlsClient))
goto EXIT_ROUTINE;
if (!TlsHandshake(&TlsClient, &Socket, Host))
goto EXIT_ROUTINE;
WCharStringToCharString2(AnsiHost, Host, sizeof(AnsiHost));
HttpRequestObject = RtlBuildHttpRequest(0, AnsiHost, (PCHAR)"i like kitty cats/1.0", (PCHAR)"*/*", (PCHAR)"keep-alive", NULL, 0);
if (HttpRequestObject == NULL)
goto EXIT_ROUTINE;
if (!TlsSendData(&TlsClient, &Socket, (PBYTE)HttpRequestObject, (DWORD)StringLengthA(HttpRequestObject)))
goto EXIT_ROUTINE;
TlsResponse = TlsReceiveData(&TlsClient, &Socket, &TlsResponseLength);
if (TlsResponse == NULL)
goto EXIT_ROUTINE;
if (!ProcessHttpResponseData(TlsResponse, TlsResponseLength, &HttpResponse))
goto EXIT_ROUTINE;
PrintHttpResponse(&HttpResponse);
EXIT_ROUTINE:
TlsSendCloseNotification(&TlsClient, &Socket);
if (HttpRequestObject)
RtlFreeHeap(GetProcessHeap(), 0, HttpRequestObject);
FreeHttpResponse(&HttpResponse);
if (TlsResponse)
RtlFreeHeap(GetProcessHeap(), 0, TlsResponse);
TlsFreeClientCredentialHandle(&TlsClient);
AfdClose(&Socket);
return 0;
}
INT EXAMPLE_HttpsPostUploadFile(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
TLSCLIENT TlsClient = { 0 };
NTSOCKET Socket = { 0 };
PBYTE TlsResponse = NULL;
SIZE_T TlsResponseLength = 0;
HTTP_RESPONSE HttpResponse = { 0 };
PCHAR HttpRequestObject = NULL;
WCHAR Host[] = L"httpbin.org";
CHAR AnsiHost[256] = { 0 };
UINT32 IpAddress = 0;
//*****************************************************
// Variables for generic file reading operations
// required for file upload
//*****************************************************
PBYTE FileBuffer = NULL;
HANDLE hHandle = INVALID_HANDLE_VALUE;
DWORD BytesRead = 0;
LARGE_INTEGER FileSize = { 0 };
//*****************************************************
//*****************************************************
Status = AfdCreateTcpSocket(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
Status = AfdBindSocketToTransportProvider(&Socket);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!AfdGetAddressFromHostname(Host, &IpAddress))
goto EXIT_ROUTINE;
Status = AfdSendConnectRequestIpv4(&Socket, IpAddress, 443);
if (!NT_SUCCESS(Status))
goto EXIT_ROUTINE;
if (!TlsAcquireClientCredentialHandle(&TlsClient))
goto EXIT_ROUTINE;
if (!TlsHandshake(&TlsClient, &Socket, Host))
goto EXIT_ROUTINE;
//*****************************************************
//
// This code is extremely generic. The next code is
// simply reading a file into memory, getting it's
// file size, and then sending it to the remote host
//
//*****************************************************
hHandle = CreateFileW(L"C:\\Users\\maldev\\Desktop\\TestUpload.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hHandle == INVALID_HANDLE_VALUE)
goto EXIT_ROUTINE;
if (!GetFileSizeEx(hHandle, &FileSize))
goto EXIT_ROUTINE;
FileBuffer = (PBYTE)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)FileSize.QuadPart);
if (FileBuffer == NULL)
goto EXIT_ROUTINE;
if (!ReadFile(hHandle, FileBuffer, (DWORD)FileSize.QuadPart, &BytesRead, NULL))
goto EXIT_ROUTINE;
//*****************************************************
//*****************************************************
WCharStringToCharString2(AnsiHost, Host, sizeof(AnsiHost));
HttpRequestObject = RtlBuildHttpRequest(1, AnsiHost, (PCHAR)"i like kitty cats/1.0", (PCHAR)"*/*", (PCHAR)"keep-alive", (PCHAR)"application/octet-stream", (ULONG)FileSize.QuadPart);
if (HttpRequestObject == NULL)
goto EXIT_ROUTINE;
if (!TlsSendData(&TlsClient, &Socket, (PBYTE)HttpRequestObject, (DWORD)StringLengthA(HttpRequestObject)))
goto EXIT_ROUTINE;
if (!TlsSendData(&TlsClient, &Socket, (PBYTE)FileBuffer, (SIZE_T)FileSize.QuadPart))
goto EXIT_ROUTINE;
TlsResponse = TlsReceiveData(&TlsClient, &Socket, &TlsResponseLength);
if (TlsResponse == NULL)
goto EXIT_ROUTINE;
if (!ProcessHttpResponseData(TlsResponse, TlsResponseLength, &HttpResponse))
goto EXIT_ROUTINE;
PrintHttpResponse(&HttpResponse);
EXIT_ROUTINE:
//*****************************************************
// Variables for generic file reading operations
// required for file upload
//*****************************************************
if (FileBuffer)
RtlFreeHeap(GetProcessHeap(), 0, FileBuffer);
if (hHandle)
CloseHandle(hHandle);
//*****************************************************
//*****************************************************
TlsSendCloseNotification(&TlsClient, &Socket);
if (HttpRequestObject)
RtlFreeHeap(GetProcessHeap(), 0, HttpRequestObject);
FreeHttpResponse(&HttpResponse);
if (TlsResponse)
RtlFreeHeap(GetProcessHeap(), 0, TlsResponse);
TlsFreeClientCredentialHandle(&TlsClient);
AfdClose(&Socket);
return 0;
}
INT EXAMPLE_ResolveDnsW(VOID)
{
UINT32 IpAddress = 0;
AfdGetAddressFromHostname((PWCHAR)L"httpbin.org", &IpAddress);
if (IpAddress != 0)
{
PBYTE p = (PBYTE)&IpAddress;
printf("%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
}
return 0;
}
INT main(VOID)
{
NTSTATUS Status = STATUS_SUCCESS;
NTSOCKET Socket = { 0 };
WCHAR Host[] = L"httpbin.org";
TLSCLIENT TlsClient = { 0 };
UINT32 IpAddress = 0;
BOOL bFlag = FALSE;
PBYTE TlsResponse = NULL;
SIZE_T TlsResponseLength = 0;
HTTP_RESPONSE HttpResponse = { 0 };
PCHAR HttpRequestObject = NULL;
if (!RtlInitializeProcessApis())
return GetLastError();
//EXAMPLE_HttpsSimpleGetRequestClose();
//EXAMPLE_HttpsSimpleGetRequestKeepAlive();
//EXAMPLE_HttpsPostUploadFile();
//EXAMPLE_ResolveDnsW();
return ERROR_SUCCESS;
}
Last updated