/* * kexbases\ntdll\RtlString.c * * Copyright (C) 2013, Ley0k * Copyright (C) 2015-19 jumper * * This file is part of KernelEx source code. * * KernelEx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; version 2 of the License. * * KernelEx is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* TODO: RtlUnicodeStringInit, RtlUnicodeStringInitEx, RtlpFreeMemory_new Ansi is single-byte Unicode is double-byte Oem currently assumes single-byte, but could be either depending upon default Windows language. Notes: ------ *_STRING buffer lengths are always in bytes. *_STRING buffer text is not zero terminated. MultiByteToWideChar and WideCharToMultiByte lengths are in characters (not bytes) and only include the NULL terminator if -1 is given as input length. */ #include "ntstatus.h" #include "common.h" #include "_ntdll_apilist.h" #include "..\advapi32\_advapi32_apilist.h" //#include typedef LONG NTSTATUS; #undef _WIN32_WINNT #define _WIN32_WINDOWS 0x0410 /********** Byte-count wrappers for MultiByteToWideChar and WideCharToMultiByte *********/ int mb2wc (UINT cp, PCSTR pChar, ULONG cbChar, PWCH pWide, ULONG cbWide) { return 2 * MultiByteToWideChar (cp, 0, pChar, cbChar, pWide, cbWide/2); } int s2us_size (UINT cp, PSTRING ps) { return 2 * MultiByteToWideChar (cp, 0, ps->Buffer, ps->Length, NULL, 0); } // Convert STRING to UNICODE_STRING, returning bytes (not characters) written int s2us (UINT cp, PSTRING psIn, PUNICODE_STRING pusOut) { return 2 * MultiByteToWideChar (cp, 0, psIn->Buffer, psIn->Length, pusOut->Buffer, pusOut->MaximumLength/2); } // Convert UNICODE_STRING to STRING, returning bytes written (or needed if int wc2mb (UINT cp, PWCH pWide, ULONG cbWide, PCHAR pChar, ULONG cbChar) { return WideCharToMultiByte (cp, 0, pWide, cbWide/2, pChar, cbChar, 0, 0); } // int wc2mb() // For UNICODE_STRING to STRING conversion, return bytes needed int us2s_size (UINT cp, PUNICODE_STRING pusIn) { return WideCharToMultiByte (cp, 0, pusIn->Buffer, pusIn->Length/2, NULL, 0, 0, 0); } // int us2s_size() // Convert UNICODE_STRING to STRING, returning bytes written int us2s (UINT cp, PUNICODE_STRING pusIn, PSTRING psOut) { return WideCharToMultiByte (cp, 0, pusIn->Buffer, pusIn->Length/2, psOut->Buffer, psOut->Length, 0, 0 ); } // int us2s() /********** Rtl*ToUnicodeSize ********* RtlAnsiStringToUnicodeSize RtlxAnsiStringToUnicodeSize RtlOemStringToUnicodeSize RtlxOemStringToUnicodeSize RtlMultiByteToUnicodeSize ***********/ /* MAKE_EXPORT RtlMultiByteToUnicodeSize_new=RtlMultiByteToUnicodeSize */ NTSTATUS RtlMultiByteToUnicodeSize_new (PULONG puSize, PCSTR pMbStr, ULONG cbMbSize) { *puSize = mb2wc (CP_ACP, pMbStr, cbMbSize, NULL, 0); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlAnsiStringToUnicodeSize_new=RtlAnsiStringToUnicodeSize */ /* MAKE_EXPORT RtlAnsiStringToUnicodeSize_new=RtlxAnsiStringToUnicodeSize */ DWORD RtlAnsiStringToUnicodeSize_new (PSTRING psIn) { /* Return the size plus the null-char */ return s2us_size (CP_ACP, psIn) + sizeof(WCHAR); } /* MAKE_EXPORT RtlOemStringToUnicodeSize_new=RtlOemStringToUnicodeSize */ /* MAKE_EXPORT RtlOemStringToUnicodeSize_new=RtlxOemStringToUnicodeSize */ DWORD RtlOemStringToUnicodeSize_new (PSTRING psIn) { /* Return the size plus the null-char */ return s2us_size (CP_OEMCP, psIn) + sizeof(WCHAR); } /********** RtlUnicode*To*Size ********* RtlUnicodeStringToAnsiSize RtlxUnicodeStringToAnsiSize RtlUnicodeStringToOemSize RtlxUnicodeStringToOemSize RtlUnicodeToMultiByteSize ***********/ /* MAKE_EXPORT RtlUnicodeToMultiByteSize_new=RtlUnicodeToMultiByteSize */ NTSTATUS RtlUnicodeToMultiByteSize_new (PULONG pMbSize, PWCH pWcStr, ULONG WcSize) { /* *pMbSize = WideCharToMultiByte (CP_ACP, 0, pWcStr, WcSize/2, NULL, 0, NULL, NULL); */ *pMbSize = wc2mb (CP_ACP, pWcStr, WcSize/2, NULL, 0); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlUnicodeStringToAnsiSize */ /* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlxUnicodeStringToAnsiSize */ /* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlUnicodeStringToOemSize */ /* MAKE_EXPORT RtlUnicodeStringToASize_new=RtlxUnicodeStringToOemSize */ ULONG RtlUnicodeStringToASize_new (PUNICODE_STRING pusIn ) { ULONG uSize; RtlUnicodeToMultiByteSize_new (&uSize, pusIn->Buffer, pusIn->Length); return (uSize + sizeof(CHAR)); } /********** Rtl*To*N *********/ /* MAKE_EXPORT RtlMultiByteToUnicodeN_new=RtlMultiByteToUnicodeN */ NTSTATUS RtlMultiByteToUnicodeN_new ( PWCHAR pWide, ULONG cbWideMax, PULONG pcbWide, PCSTR pMbStr, ULONG MbSize ) { *pcbWide = mb2wc (CP_ACP, pMbStr, MbSize, pWide, cbWideMax); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlOemToUnicodeN_new=RtlOemToUnicodeN */ NTSTATUS RtlOemToUnicodeN_new( PWCHAR pWide, ULONG cbWideMax, PULONG pcbWide, PCCH pOem, ULONG cbOem ) { ULONG uSize; uSize = mb2wc (CP_OEMCP, pOem, cbOem, pWide, cbWideMax); if(uSize == 0) return STATUS_INVALID_PARAMETER; if(!IsBadWritePtr (pcbWide, sizeof(ULONG))) *pcbWide = uSize; return STATUS_SUCCESS; } /* MAKE_EXPORT RtlUnicodeToMultiByteN_new=RtlUnicodeToMultiByteN */ NTSTATUS RtlUnicodeToMultiByteN_new( PSTR pMbStr, ULONG MbMaxSize, PULONG pMbSize, PWCH pUnicodeStr, ULONG UnicodeSize ) { *pMbSize = WideCharToMultiByte (CP_ACP, 0, pUnicodeStr, UnicodeSize/2, pMbStr, MbMaxSize, NULL, NULL); return STATUS_SUCCESS; } /* ***FIX_EXPORT RtlUnicodeToOemN_new=RtlUnicodeToOemN */ NTSTATUS RtlUnicodeToOemN_new ( PWCHAR UnicodeString, ULONG UnicodeSize, PULONG ResultSize, PCCH OemString, ULONG OemSize ) { ULONG uSize; uSize = WideCharToMultiByte (CP_OEMCP, 0, UnicodeString, UnicodeSize/2, (LPSTR)OemString, OemSize, NULL, NULL); if (uSize == 0) return STATUS_INVALID_PARAMETER; if (!IsBadWritePtr(ResultSize, sizeof(ULONG))) *ResultSize = uSize; return STATUS_SUCCESS; } /********* Heap Allocation *********/ /* MAKE_EXPORT RtlpAllocateMemory_new=RtlpAllocateMemory */ PWCHAR RtlpAllocateMemory_new (UINT cbLen, UINT tag) #define TAG_ASTR 1 #define TAG_OSTR 1 #define TAG_USTR 2 { return (PWCHAR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cbLen+2); //zt } #define RtlpAllocateStringMemory RtlpAllocateMemory_new #define RtlpFreeStringMemory RtlpFreeMemory_new #define SetMaxLenW(ps) SetMaxLen((PSTRING)ps) void SetMaxLen (PSTRING ps) { int cbSize = HeapSize (GetProcessHeap(), 0, ps->Buffer); ps->MaximumLength = min (cbSize, 65535); } NTSTATUS DestStringPrep (PSTRING ps, int cbLen, BOOL bAllocate) { if (IsBadWritePtr (ps, sizeof(STRING))) return STATUS_INVALID_PARAMETER_1; if (cbLen > 65535) return STATUS_INVALID_PARAMETER_2; //STATUS_NAME_TOO_LONG; if (bAllocate) { ps->Buffer = (PSTR)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cbLen+2); //zt if (!ps->Buffer) return ps->Length= 0, ps->MaximumLength= 0, STATUS_NO_MEMORY; int cbSize = HeapSize (GetProcessHeap(), 0, ps->Buffer); ps->MaximumLength = cbSize<=65535? cbSize: 65535; } ps->Length = cbLen; return (ps->Length > ps->MaximumLength)? STATUS_BUFFER_TOO_SMALL: STATUS_SUCCESS; //return STATUS_SUCCESS; // sbo is warning. should truncate conversion! check this in caller function //return (ps->Length > ps->MaximumLength)? STATUS_BUFFER_OVERFLOW: STATUS_SUCCESS; } /* MAKE_EXPORT RtlAnsiStringToUnicodeString_fix=RtlAnsiStringToUnicodeString */ NTSTATUS RtlAnsiStringToUnicodeString_fix( PUNICODE_STRING pusOut, PSTRING pasIn, BOOLEAN bAllocate ) { int cbOut = s2us_size (CP_ACP, pasIn); NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, cbOut, bAllocate); if (Status<0) return Status; cbOut = s2us (CP_ACP, pasIn, pusOut); return cbOut? STATUS_SUCCESS: STATUS_UNSUCCESSFUL; } /* MAKE_EXPORT RtlOemStringToUnicodeString_new=RtlOemStringToUnicodeString */ NTSTATUS RtlOemStringToUnicodeString_new( PUNICODE_STRING pusOut, POEM_STRING posIn, BOOLEAN bAllocate ) { int cbOut = s2us_size (CP_OEMCP, posIn); NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, cbOut, bAllocate); if (Status<0) return Status; cbOut = s2us (CP_OEMCP, posIn, pusOut); return cbOut? STATUS_SUCCESS: STATUS_UNSUCCESSFUL; } /* MAKE_EXPORT RtlUnicodeStringToAnsiString_fix=RtlUnicodeStringToAnsiString */ NTSTATUS RtlUnicodeStringToAnsiString_fix ( PANSI_STRING pasOut, PUNICODE_STRING pusIn, BOOLEAN bAllocate ) { int cbOut = us2s_size (CP_ACP, pusIn); NTSTATUS Status = DestStringPrep ((PSTRING)pasOut, cbOut, bAllocate); if (Status<0) return Status; cbOut = us2s (CP_ACP, pusIn, pasOut); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlUnicodeStringToOemString_new=RtlUnicodeStringToOemString */ NTSTATUS RtlUnicodeStringToOemString_new ( POEM_STRING posOut, PUNICODE_STRING pusIn, BOOLEAN bAllocate ) { int cbOut = us2s_size (CP_OEMCP, pusIn); NTSTATUS Status = DestStringPrep ((PSTRING)posOut, cbOut, bAllocate); if (Status<0) return Status; cbOut = us2s (CP_OEMCP, pusIn, posOut); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlUpcaseUnicodeString_new=RtlUpcaseUnicodeString */ NTSTATUS RtlUpcaseUnicodeString_new( PUNICODE_STRING pusOut, PUNICODE_STRING pusIn, BOOLEAN bAllocate ) { NTSTATUS Status = DestStringPrep ((PSTRING)pusOut, pusIn->Length, bAllocate); ULONG i, j; j = pusIn->Length / sizeof(WCHAR); for (i = 0; i < j; i++) pusOut->Buffer[i] = RtlUpcaseUnicodeChar_new(pusIn->Buffer[i]); return STATUS_SUCCESS; } /********** RtlCreate*String ********* /* MAKE_EXPORT RtlCreateUnicodeString_new=RtlCreateUnicodeString */ BOOLEAN RtlCreateUnicodeString_new ( PUNICODE_STRING pusOut, PCWSTR wszIn) { if (DestStringPrep ((PSTRING)pusOut, sizeof(WCHAR)*lstrlenW (wszIn), TRUE)) return FALSE; RtlCopyMemory (pusOut->Buffer, wszIn, pusOut->Length); return TRUE; } /* MAKE_EXPORT RtlCreateUnicodeStringFromAsciiz_new=RtlCreateUnicodeStringFromAsciiz */ BOOLEAN RtlCreateUnicodeStringFromAsciiz_new( PUNICODE_STRING pusOut, PCSZ szIn ) { ANSI_STRING asIn; RtlInitString_new (&asIn, szIn); return RtlAnsiStringToUnicodeString_fix (pusOut, &asIn, TRUE)? FALSE: TRUE; } /* MAKE_EXPORT RtlCompareUnicodeString_new=RtlCompareUnicodeString */ LONG RtlCompareUnicodeString_new( IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInsensitive ) { UINT uLength; LONG result = 0; LPCWSTR p1, p2; uLength = min(String1->Length, String2->Length) / sizeof(WCHAR); p1 = String1->Buffer; p2 = String2->Buffer; if(CaseInsensitive) { while (!result && uLength--) result = towupper(*p1++) - towupper(*p2++); } else { while(!result && uLength--) result = *p1++ - *p2++; } if (!result) result = String1->Length - String2->Length; return result; } /* MAKE_EXPORT RtlEqualUnicodeString_new=RtlEqualUnicodeString */ BOOLEAN RtlEqualUnicodeString_new( IN CONST PUNICODE_STRING String1, IN CONST PUNICODE_STRING String2, IN BOOLEAN CaseInsensitive ) { if (String1->Length != String2->Length) return FALSE; return !RtlCompareUnicodeString_new(String1, String2, CaseInsensitive); } /* MAKE_EXPORT RtlExpandEnvironmentStrings_U_new=RtlExpandEnvironmentStrings_U */ NTSTATUS RtlExpandEnvironmentStrings_U_new( IN PWSTR Environment, IN PUNICODE_STRING pusSource, OUT PUNICODE_STRING pusDestination, OUT PULONG Length ) { STRING asSource, asDest; RtlUnicodeStringToAnsiString_fix (&asSource, pusSource, TRUE); UINT uLen = ExpandEnvironmentStringsA (asSource.Buffer, NULL, 0); NTSTATUS Status = DestStringPrep (&asDest, uLen, TRUE); uLen = ExpandEnvironmentStringsA (asSource.Buffer, asDest.Buffer, asDest.MaximumLength); DWORD dwLength; dwLength = 0; /* FIXME: Kernel32.ExpandEnvironmentStringsW is a stub, should be: ExpandEnvironmentStringsW_new(Source->Buffer, Destination->Buffer, Destination->Length); */ if(dwLength == 0) return STATUS_INVALID_PARAMETER; *Length = dwLength; return STATUS_SUCCESS; } /* MAKE_EXPORT RtlFreeString_new=RtlFreeAnsiString */ /* MAKE_EXPORT RtlFreeString_new=RtlFreeOemString */ /* MAKE_EXPORT RtlFreeString_new=RtlFreeUnicodeString */ VOID RtlFreeString_new (PSTRING pString) { if (!IsBadWritePtr (pString, sizeof(STRING))) { pString->Length = 0; pString->MaximumLength = 0; if (pString->Buffer) { HeapFree (GetProcessHeap(), 0, pString->Buffer); pString->Buffer = NULL; } // if Buffer } // if pString } // RtlFreeString /* MAKE_EXPORT RtlInitString_new=RtlInitAnsiString */ /* MAKE_EXPORT RtlInitString_new=RtlInitOemString */ /* MAKE_EXPORT RtlInitString_new=RtlInitString */ VOID RtlInitString_new( IN OUT PSTRING pString, IN PCSZ szSource ) { pString->Length = 0; pString->MaximumLength = 0; pString->Buffer = (PCHAR)szSource; if (szSource) { UINT uLength = lstrlenA (szSource); pString->Length = (uLength> 0xFFFF) ? 0xFFFF : (WORD)uLength; pString->MaximumLength = (uLength>=0xFFFF) ? 0xFFFF : (WORD)uLength + 1; } } /* MAKE_EXPORT RtlInitStringEx_new=RtlInitAnsiStringEx */ /* MAKE_EXPORT RtlInitStringEx_new=RtlInitOemStringEx */ /* MAKE~EXPORT RtlInitStringEx_new=RtlInitStringEx */ // Win10 drivers only NTSTATUS RtlInitStringEx_new( IN OUT PSTRING pString, IN PCSZ szSource ) { if (szSource && (lstrlenA (szSource) > 0xFFFF)) return STATUS_NAME_TOO_LONG; RtlInitString_new (pString, szSource); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlInitUnicodeString_new=RtlInitUnicodeString */ VOID RtlInitUnicodeString_new( IN OUT PUNICODE_STRING pString, IN PWSTR wszSource ) { pString->Length = 0; pString->MaximumLength = 0; pString->Buffer = wszSource; if (wszSource) { UINT uLength = lstrlenW (wszSource) * 2; pString->Length = (uLength> 0xFFFE) ? 0xFFFE : (WORD)uLength; pString->MaximumLength = (uLength>=0xFFFE) ? 0xFFFE : (WORD)uLength + 2; } } /* MAKE_EXPORT RtlInitUnicodeStringEx_new=RtlInitUnicodeStringEx */ NTSTATUS RtlInitUnicodeStringEx_new( IN OUT PUNICODE_STRING pString, IN PWSTR wszSource ) { if (wszSource && (lstrlenW (wszSource) > 0x7FFF)) return STATUS_NAME_TOO_LONG; RtlInitUnicodeString_new (pString, wszSource); return STATUS_SUCCESS; } /* MAKE_EXPORT RtlPrefixUnicodeString_new=RtlPrefixUnicodeString */ BOOLEAN RtlPrefixUnicodeString_new( PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInsensitive) { PWCHAR pc1; PWCHAR pc2; ULONG Length; if(String2->Length < String1->Length) return FALSE; Length = String1->Length / 2; pc1 = String1->Buffer; pc2 = String2->Buffer; if(pc1 && pc2) { if(CaseInsensitive) { while(Length--) { if (towupper(*pc1++) != towupper(*pc2++)) return FALSE; } } else { while(Length--) { if(*pc1++ != *pc2++) return FALSE; } } return TRUE; } return FALSE; } /* MAKE_EXPORT RtlUpcaseUnicodeChar_new=RtlUpcaseUnicodeChar */ WCHAR RtlUpcaseUnicodeChar_new (IN WCHAR Source) { return towupper(Source); } /* MAKE_EXPORT RtlCopyUnicodeString_new=RtlCopyUnicodeString */ VOID RtlCopyUnicodeString_new (PUNICODE_STRING pusDest, PUNICODE_STRING pusSrc) { pusDest->Length = !pusSrc? 0: min (pusDest->MaximumLength, pusSrc->Length); if (pusDest->Length > 0) RtlCopyMemory (pusDest->Buffer, pusSrc->Buffer, pusDest->Length); if (pusDest->Length + sizeof(UNICODE_NULL) <= pusDest->MaximumLength) pusDest->Buffer[pusDest->Length / sizeof(WCHAR)] = UNICODE_NULL; } /* MAKE_EXPORT RtlDuplicateUnicodeString_new=RtlDuplicateUnicodeString */ NTSTATUS RtlDuplicateUnicodeString_new (UINT Flags, PUNICODE_STRING pusSrc, PUNICODE_STRING pusDest) { if ((Flags^1 > 2) || !pusDest || !pusSrc || (!pusSrc->Buffer && pusSrc->MaximumLength) || ( pusSrc->Length > pusSrc->MaximumLength) ) return STATUS_INVALID_PARAMETER; if ((pusSrc->Length == 0) && (Flags != 3)) { pusDest->Length = 0; pusDest->MaximumLength = 0; pusDest->Buffer = NULL; } else { pusDest->Buffer = RtlpAllocateStringMemory (pusSrc->Length, TAG_USTR); if (!pusDest->Buffer) return STATUS_NO_MEMORY; SetMaxLenW (pusDest); RtlCopyMemory (pusDest->Buffer, pusSrc->Buffer, pusSrc->Length); pusDest->Length = pusSrc->Length; } return STATUS_SUCCESS; } /* MAKE~EXPORT RtlDuplicateUnicodeString_new=RtlDuplicateUnicodeString * NTSTATUS RtlUpcaseUnicodeToMultiByteN (PSTR AnsiDest->Buffer, AnsiDest->Length, &Index, UniSource->Buffer, UniSource->Length); */ // FILE: lib/rtl/encode.c /* MAKE_EXPORT RtlRunDecodeUnicodeString_new=RtlRunDecodeUnicodeString */ VOID RtlRunDecodeUnicodeString_new (UCHAR hash, PUNICODE_STRING pus) { } /* MAKE_EXPORT RtlRunEncodeUnicodeString_new=RtlRunEncodeUnicodeString */ VOID RtlRunEncodeUnicodeString_new (PUCHAR phash, PUNICODE_STRING pus) { }