S. |
Crash occurs if there is an unreadable yet traversable
directory on your %APPDATA% path. I.e. such directory
where you can not run 'dir' in, but can
'chdir' to a subdirectory. In our particular case
%APPDATA% is redirected through a DFS root, where we
forbid users to list referrals for security and primarily
performance reasons. Crash takes places in MSVCRT and is worked
around [naturally with
DLL_PRELOAD's help] by pulling
directory status information for
'...\unreadable\subdir\.' instead of
'...\unreadable\subdir'.
 |
statpatch.c
|
/*
* Copyright (c) 2010 Andy Polyakov
*
* Build with:
*
* cl -Ox -GD -GF -GS- -Zl -MD -LD statpatch.c kernel32.lib ntdll.lib
*
* See http://fy.chalmers.se/~appro/nt/DLL_PRELOAD/ for further details.
*
*/
#ifndef _DLL
#error "_DLL is not defined."
#endif
#ifdef _WIN64
#pragma comment(linker,"/entry:DllMain")
#pragma comment(linker,"/merge:.rdata=.text")
#else
#pragma comment(linker,"/entry:DllMain@12")
#pragma comment(linker,"/section:.text,erw")
#pragma comment(linker,"/merge:.rdata=.text")
#pragma comment(linker,"/merge:.data=.text")
#endif
#define UNICODE
#define _UNICODE
#if defined(WIN32) && !defined(_WIN32)
#define _WIN32
#endif
#define _WIN32_WINNT 0x0500
#include
#include
#include
#ifdef _WIN64
/* October 2002 Platform SDK is screwed up */
#define _RUNTIME_FUNCTION _RUNTIME_FUNCTION_
#define RUNTIME_FUNCTION RUNTIME_FUNCTION_
#define PRUNTIME_FUNCTION PRUNTIME_FUNCTION_
#endif
#include
#include
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS (0x0)
#define STATUS_ACCESS_DENIED (0xc0000022L)
#endif
#ifndef FILE_DIRECTORY_FILE
/* Excerpt from /inc/wdm.h */
#define FILE_DIRECTORY_FILE 0x00000001
#define FILE_WRITE_THROUGH 0x00000002
#define FILE_SEQUENTIAL_ONLY 0x00000004
#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
#define FILE_NON_DIRECTORY_FILE 0x00000040
#define FILE_CREATE_TREE_CONNECTION 0x00000080
#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
#define FILE_NO_EA_KNOWLEDGE 0x00000200
#define FILE_OPEN_FOR_RECOVERY 0x00000400
#define FILE_RANDOM_ACCESS 0x00000800
#define FILE_DELETE_ON_CLOSE 0x00001000
#define FILE_OPEN_BY_FILE_ID 0x00002000
#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
#define FILE_NO_COMPRESSION 0x00008000
#endif
/* from /inc/ntdef.h */
#ifndef OBJ_CASE_INSENSITIVE
#define OBJ_CASE_INSENSITIVE (0x00000040L)
#endif
#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
#endif
/* from "Windows NT Native API" */
typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
#ifdef _DEBUG
static VOID DebugOutputA (const char *fmt,...)
{ va_list argv;
char buf[256];
va_start(argv,fmt);
_vsnprintf (buf,sizeof(buf)/sizeof(buf[0])-1,fmt,argv);
buf[sizeof(buf)/sizeof(buf[0])-1]='\0';
OutputDebugStringA (buf);
va_end(argv);
}
#endif
NTSYSAPI NTSTATUS NTAPI ZwClose(
IN HANDLE FileHandle
);
static IMAGE_THUNK_DATA *__NtCreateFile=NULL,*__NtCreateFile7=NULL;
NTSYSAPI NTSTATUS NTAPI ZwCreateFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
);
#ifdef _DEBUG
static NTSTATUS WINAPI NtCreateFile_ (
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG CreateDisposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength
)
{ NTSTATUS ret;
ret = ZwCreateFile(
FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatusBlock,
AllocationSize,
FileAttributes,
ShareAccess,
CreateDisposition,
CreateOptions,
EaBuffer,
EaLength);
DebugOutputA("create(\"%.*S\",%x,%x,%x)=%x",
ObjectAttributes->ObjectName->Length/2,
ObjectAttributes->ObjectName->Buffer,
DesiredAccess,ShareAccess,CreateOptions,ret);
return ret;
}
#endif
static IMAGE_THUNK_DATA *__NtOpenFile=NULL,*__NtOpenFile7=NULL;
NTSYSAPI NTSTATUS NTAPI ZwOpenFile(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
#ifdef _DEBUG
static NTSTATUS WINAPI NtOpenFile_ (
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
)
{ NTSTATUS ret;
ret = ZwOpenFile(
FileHandle,
DesiredAccess,
ObjectAttributes,
IoStatusBlock,
ShareAccess,
OpenOptions);
DebugOutputA("open(\"%.*S\",%x,%x,%x)=%x",
ObjectAttributes->ObjectName->Length/2,
ObjectAttributes->ObjectName->Buffer,
DesiredAccess,ShareAccess,OpenOptions,ret);
return ret;
}
#endif
static IMAGE_THUNK_DATA *__NtQueryDirectoryFile=NULL,*__NtQueryDirectoryFile7=NULL;
NTSYSAPI NTSTATUS NTAPI ZwQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
);
static NTSTATUS WINAPI NtQueryDirectoryFile_ (
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
)
{ NTSTATUS ret;
ret = ZwQueryDirectoryFile(
FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
FileInformation,
FileInformationLength,
FileInformationClass,
ReturnSingleEntry,
FileName,
RestartScan);
if (ret==STATUS_ACCESS_DENIED && ReturnSingleEntry && FileInformationClass==3)
{ HANDLE h;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK io;
#ifdef _DEBUG
DebugOutputA(">re-open \"%.*S\"",FileName->Length/2,FileName->Buffer);
#endif
InitializeObjectAttributes(&oa,FileName,OBJ_CASE_INSENSITIVE,FileHandle,NULL);
if (ZwOpenFile(&h,SYNCHRONIZE|FILE_READ_ATTRIBUTES|FILE_LIST_DIRECTORY,
&oa,&io,
FILE_SHARE_DELETE|FILE_SHARE_WRITE|FILE_SHARE_READ,
FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE)
== STATUS_SUCCESS)
{ /* Query . instead */
ret = ZwQueryDirectoryFile(
h,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
FileInformation,
FileInformationLength,
FileInformationClass,
ReturnSingleEntry,
NULL,
RestartScan);
if (ret==STATUS_SUCCESS)
{ FILE_BOTH_DIR_INFORMATION *inf=(FILE_BOTH_DIR_INFORMATION *)FileInformation;
ULONG len = FileName->Length;
#ifdef _DEBUG
DebugOutputA(">fixing FileInformation->FileName");
#endif
if (len > (FileInformationLength-sizeof(*inf)))
len=FileInformationLength-sizeof(*inf);
inf->FileNameLength = len;
memcpy(inf->FileName,FileName->Buffer,len);
inf->ShortNameLength=0;
}
ZwClose(h);
}
}
#ifdef _DEBUG
DebugOutputA("query(\"%*S\",%d,%d)=%x",
FileName ? FileName->Length/2 : 6,
FileName ? FileName->Buffer : L"(null)",
FileInformationLength,FileInformationClass,ret);
#endif
return ret;
}
static int _lstricmp(const char *s1, const char *s2)
{ char c1,c2;
int ret;
while (c1=*s1, c2=*s2, c1&&c2)
{ c1|=0x20, c2|=0x20; /* lower the case */
if (ret=c1-c2) return ret;
s1++, s2++;
}
return c1-c2;
}
BOOL WINAPI DllMain (HINSTANCE h, DWORD reason, LPVOID junk)
{ DWORD acc;
HMODULE hmod;
IMAGE_DOS_HEADER *dos_header;
IMAGE_NT_HEADERS *nt_headers;
IMAGE_DATA_DIRECTORY *dir;
IMAGE_IMPORT_DESCRIPTOR *idesc;
IMAGE_THUNK_DATA *thunk;
static void *page=NULL,*page7=NULL;
static size_t plen=0,plen7=0;
switch (reason)
{ case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(h);
if (!(hmod=GetModuleHandle(_T("NTDLL.DLL"))))
{ OutputDebugString(_T("NTDLL.DLL not found?"));
return FALSE;
}
if (!(hmod=GetModuleHandle(_T("KERNEL32.DLL"))))
{ OutputDebugString(_T("KERNEL32.DLL not found?"));
return FALSE;
}
dos_header = (IMAGE_DOS_HEADER *)hmod;
nt_headers = (IMAGE_NT_HEADERS *)((char *)hmod + dos_header->e_lfanew);
dir=&nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
idesc=(IMAGE_IMPORT_DESCRIPTOR *)((char *)hmod + dir->VirtualAddress);
while (idesc->Name)
{ if (!_lstricmp((char *)hmod+idesc->Name,"NTDLL.DLL")) break;
idesc++;
}
if (!idesc->Name)
{ OutputDebugString(_T("Can't locate NTDLL.DLL import descriptor in KERNEL32"));
return FALSE;
}
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwCreateFile;
thunk++) ;
__NtCreateFile=thunk;
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwOpenFile;
thunk++) ;
__NtOpenFile=thunk;
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwQueryDirectoryFile;
thunk++) ;
__NtQueryDirectoryFile=thunk;
if ((void *)__NtOpenFile > (void *)__NtCreateFile)
page=__NtCreateFile,
plen=(size_t)__NtOpenFile-(size_t)page+sizeof(void(*)());
else
page=__NtOpenFile,
plen=(size_t)__NtCreateFile-(size_t)page+sizeof(void(*)());
if ((void *)__NtQueryDirectoryFile > (void *)((BYTE*)page+plen))
plen=(size_t)__NtQueryDirectoryFile-(size_t)page+sizeof(void(*)());
else if ((void *)__NtQueryDirectoryFile < page)
page=__NtQueryDirectoryFile,
plen+=(size_t)page-(size_t)__NtQueryDirectoryFile;
if (!VirtualProtect (page,plen,PAGE_EXECUTE_READWRITE,&acc))
{ OutputDebugString(_T("Unable to unlock KERNEL32 Thunk Table"));
return FALSE;
}
#ifdef _DEBUG
__NtOpenFile->u1.Function=(size_t)NtOpenFile_;
__NtCreateFile->u1.Function=(size_t)NtCreateFile_;
#endif
__NtQueryDirectoryFile->u1.Function=(size_t)NtQueryDirectoryFile_;
VirtualProtect (page,plen,acc,&acc);
/*
* On Windows 7 most native calls go through KernelBase.dll
*/
if (!(hmod=GetModuleHandle(_T("KernelBase.dll"))))
{ OutputDebugString(_T("KernelBase.dll not found..."));
return TRUE;
}
dos_header = (IMAGE_DOS_HEADER *)hmod;
nt_headers = (IMAGE_NT_HEADERS *)((char *)hmod + dos_header->e_lfanew);
dir=&nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
idesc=(IMAGE_IMPORT_DESCRIPTOR *)((char *)hmod + dir->VirtualAddress);
while (idesc->Name)
{ if (!_lstricmp((char *)hmod+idesc->Name,"NTDLL.DLL")) break;
idesc++;
}
if (!idesc->Name)
{ OutputDebugString(_T("Can't locate NTDLL.DLL import descriptor in KernelBase"));
return TRUE;
}
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwCreateFile;
thunk++) ;
__NtCreateFile7=thunk;
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwOpenFile;
thunk++) ;
__NtOpenFile7=thunk;
for (thunk=(IMAGE_THUNK_DATA *)((char *)hmod+idesc->FirstThunk);
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwQueryDirectoryFile;
thunk++) ;
__NtQueryDirectoryFile7=thunk;
if ((void *)__NtOpenFile7 > (void *)__NtCreateFile7)
page7=__NtCreateFile7,
plen7=(size_t)__NtOpenFile7-(size_t)page7+sizeof(void(*)());
else
page7=__NtOpenFile7,
plen7=(size_t)__NtCreateFile7-(size_t)page7+sizeof(void(*)());
if ((void *)__NtQueryDirectoryFile7 > (void *)((BYTE*)page7+plen7))
plen7=(size_t)__NtQueryDirectoryFile7-(size_t)page7+sizeof(void(*)());
else if ((void *)__NtQueryDirectoryFile7 < page7)
page7=__NtQueryDirectoryFile7,
plen7+=(size_t)page7-(size_t)__NtQueryDirectoryFile7;
if (!VirtualProtect (page7,plen7,PAGE_EXECUTE_READWRITE,&acc))
{ OutputDebugString(_T("Unable to unlock KernelBase Thunk Table"));
return FALSE;
}
#ifdef _DEBUG
__NtOpenFile7->u1.Function=(size_t)NtOpenFile_;
__NtCreateFile7->u1.Function=(size_t)NtCreateFile_;
#endif
__NtQueryDirectoryFile7->u1.Function=(size_t)NtQueryDirectoryFile_;
VirtualProtect (page7,plen7,acc,&acc);
break;
case DLL_PROCESS_DETACH:
VirtualProtect (page,plen,PAGE_EXECUTE_READWRITE,&acc);
#ifdef _DEBUG
__NtOpenFile->u1.Function=(size_t)ZwOpenFile;
__NtCreateFile->u1.Function=(size_t)ZwCreateFile;
#endif
__NtQueryDirectoryFile->u1.Function=(size_t)ZwQueryDirectoryFile;
VirtualProtect (page,plen,acc,&acc);
if (page7==NULL) return TRUE;
VirtualProtect (page7,plen7,PAGE_EXECUTE_READWRITE,&acc);
#ifdef _DEBUG
__NtOpenFile7->u1.Function=(size_t)ZwOpenFile;
__NtCreateFile7->u1.Function=(size_t)ZwCreateFile;
#endif
__NtQueryDirectoryFile7->u1.Function=(size_t)ZwQueryDirectoryFile;
VirtualProtect (page7,plen7,acc,&acc);
break;
}
return TRUE;
}
|
|
|