Skip to content

Instantly share code, notes, and snippets.

@ngbrown
Created April 23, 2012 01:06
Show Gist options
  • Save ngbrown/2467960 to your computer and use it in GitHub Desktop.
Save ngbrown/2467960 to your computer and use it in GitHub Desktop.
Demonstrates Windows reading past the source string when using WideCharToMultiByte.
// WideCharToMultiByteTest.c : Demonstrates Windows reading past the source string
// when using WideCharToMultiByte.
// The source problem uses UNICODE_STRING, so it may not be null terminated.
//
#define _WIN32_WINNT 0x400
#include <WinSDKVer.h>
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
void print_last_error_msg()
{
DWORD lasterror;
LPWSTR errormessage = NULL;
lasterror = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, lasterror, 0, (LPWSTR)&errormessage, 0x1024, 0);
wprintf(L"lasterror=%i: %s\r\n", lasterror, errormessage);
LocalFree(errormessage);
}
int _tmain(int argc, _TCHAR* argv[])
{
int len, newlen;
char *name = NULL;
WCHAR* tempBuffer;
SYSTEM_INFO systeminfo;
HANDLE memoryHndl;
LPVOID memoryPtr;
DWORD allocation_size;
LPVOID guardPtr;
const WCHAR* sourceBuffer = L"\\??\\C:\\Windows\\system32\\tzres.dll";
int sourceLen = lstrlenW(sourceBuffer); /* characters */
/* bytes, as passed by UNICODE_STRING.Length */
int sourceBytes = sourceLen * 2;
printf("sourceBytes=%i\r\n", sourceBytes);
GetSystemInfo(&systeminfo);
allocation_size = systeminfo.dwAllocationGranularity;
printf("dwAllocationGranularity: %u\r\n", allocation_size);
memoryHndl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
0, allocation_size, L"Local\\Memblock");
memoryPtr = MapViewOfFile(
memoryHndl, FILE_MAP_ALL_ACCESS, 0, 0, allocation_size);
if(memoryPtr == NULL) {
print_last_error_msg();
}
/* Create a guard page next */
guardPtr = VirtualAlloc((byte*)memoryPtr + allocation_size,
allocation_size, MEM_RESERVE, PAGE_NOACCESS);
if(guardPtr == NULL) {
print_last_error_msg();
}
/* put our source string at the end of the memory page, before the guard page */
tempBuffer = (WCHAR*)((byte*)memoryPtr + allocation_size - sourceBytes);
memcpy(tempBuffer, sourceBuffer, sourceBytes);
/* check the size */
len = WideCharToMultiByte(
CP_ACP, 0, tempBuffer, sourceBytes, 0, 0, NULL, NULL);
printf("reported len=%i\r\n", len);
if(len > 0) {
/* Alter the way WideCharToMultiByte takes the cbMultiByte parameter,
* not per doc. WideCharToMultiByte reports an error.
*/
name = (char*)malloc(len + 1);
newlen = WideCharToMultiByte(
CP_ACP, 0, tempBuffer, sourceBytes, name, len/2, NULL, NULL);
if (newlen <=0) {
print_last_error_msg();
}
name[len/2] = 0;
printf("reported newlen=%i\r\n", newlen);
printf("converted string=%s\r\n", name);
free(name);
name = NULL;
}
if(len > 0) {
/* The normal way WideCharToMultiByte takes the cbMultiByte parameter,
* as returned from the size check. WideCharToMultiByte crashes into
* the next page when reading. This means that it is reading past the
* sourceBytes count.
*/
name = (char*)malloc(len + 1);
newlen = WideCharToMultiByte(
CP_ACP, 0, tempBuffer, sourceBytes, name, len, NULL, NULL);
if (newlen <=0) {
print_last_error_msg();
}
name[len] = 0;
printf("reported newlen=%i\r\n", newlen);
printf("converted string=%s\r\n", name);
free(name);
name = NULL;
}
CloseHandle(memoryHndl);
return 0;
}
static char *unicode_to_ansi(PUNICODE_STRING uni)
{
int len;
char *name = NULL;
USHORT *uniBufferTerminated;
if (uni->Buffer == NULL || uni->Length == 0)
return NULL;
uniBufferTerminated = malloc(uni->Length + 2);
memcpy(uniBufferTerminated, uni->Buffer, uni->Length);
*(WCHAR*)((char*)uniBufferTerminated + uni->Length) = 0x0000L;
len = WideCharToMultiByte(CP_ACP, 0, uniBufferTerminated, -1, 0, 0, NULL, NULL);
if(len > 0) {
name = malloc(len + 1);
WideCharToMultiByte(CP_ACP, 0, uniBufferTerminated, -1, name, len, NULL, NULL);
name[len] = 0;
}
free(uniBufferTerminated);
return name;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment