S. |
Yes, Windows again.
Gr-r-r-r... This module is designed to modify behaviour of
ActiveSync components, wcescomm.exe, wcesmg.exe and rapimgr.exe, in
following manner. First of all the module places itself between
KERNEL32.DLL and NTDLL.DLL and strips Global\ prefix from mutex and
semaphore objects created/opened by either component. This makes
ActiveSync adhere to session-specific object name space. Secondly
it places itself between WS2_32.DLL and currently registered WSP,
Windows Socket Provider, and re-bias references to
127.0.0.1 to a session-specific address from 127.
subnet. This effectively isolates concurrently executing instances
of the application suite in question in every given session, which
is the key to successful application deployment in Terminal Server
environment. It should be noted that Citrix already arranges for
the latter, per-session loopback communication interface, so one
can wonder why did I do it? Well, because we've found that it's
actually possible to make ActiveSync work [at least] with rdesktop COM-port redirection
even without Citrix! Reliable and seamless deployment, in
particular of USB-connected PDAs, requires some Linux kernel as
well as rdesktop patching. We plan to publish these patches as we
make progress.
[an error occurred while processing this directive]
 |
vsync.c
|
[an error occurred while processing this directive]
/*
* Copyright (c) 2006 Andy Polyakov
*
* Build with:
*
* cl -Ox -GD -GF -Zl -MD -LD vsync.c ws2_32.lib kernel32.lib ntdll.lib
*
* Pre-load as:
*
* [HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\DLL_PRELOAD]
* "wcescomm.exe"="vsync.dll"
* "wcesmgr.exe"="vsync.dll"
* "rapimgr.exe"="vsync.dll"
* [HKLM\SOFTWARE\Microsoft\Windows CE Services\Http server]
* "HttpSysOverride"=dword:1
* [-HKLM\SOFTWARE\Citrix\CtxHook\AppInit_Dlls\VIPHook\wcescomm.exe]
* [-HKLM\SOFTWARE\Citrix\CtxHook\AppInit_Dlls\VIPHook\wcesmgr.exe]
*
* See http://fy.chalmers.se/~appro/nt/DLL_PRELOAD/ for further details.
*
*/
#ifndef _DLL
#error "_DLL is not defined."
#endif
#pragma comment(linker,"/entry:DllMain@12")
#pragma comment(linker,"/section:.text,erw")
#pragma comment(linker,"/merge:.rdata=.text")
#pragma comment(linker,"/merge:.data=.text")
#define UNICODE
#define _UNICODE
#if defined(WIN32) && !defined(_WIN32)
#define _WIN32
#endif
#define _WIN32_WINNT 0x0500
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
/* Native API wrappers */
__declspec(dllimport) NTSTATUS WINAPI ZwCreateMutant (
OUT PHANDLE MutantHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN BOOLEAN InitialOwner
);
static NTSTATUS WINAPI NtCreateMutant_ (
OUT PHANDLE MutantHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN BOOLEAN InitialOwner
)
{ OBJECT_ATTRIBUTES *p = ObjectAttributes,ob;
UNICODE_STRING us;
if (p && p->ObjectName &&
p->ObjectName->Length>14 &&
!_wcsnicmp(L"global\\",p->ObjectName->Buffer,7))
{ us = *p->ObjectName;
us.Buffer += 7, us.Length -= 14, us.MaximumLength =- 14;
ob = *p;
ob.ObjectName = &us;
p = &ob;
}
return ZwCreateMutant(
MutantHandle,
DesiredAccess,
p,
InitialOwner);
}
__declspec(dllimport) NTSTATUS WINAPI ZwOpenMutant (
OUT PHANDLE MutantHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
static NTSTATUS WINAPI NtOpenMutant_ (
OUT PHANDLE MutantHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
)
{ OBJECT_ATTRIBUTES *p = ObjectAttributes,ob;
UNICODE_STRING us;
if (p && p->ObjectName &&
p->ObjectName->Length>14 &&
!_wcsnicmp(L"global\\",p->ObjectName->Buffer,7))
{ us = *p->ObjectName;
us.Buffer += 7, us.Length -= 14, us.MaximumLength =- 14;
ob = *p;
ob.ObjectName = &us;
p = &ob;
}
return ZwOpenMutant(
MutantHandle,
DesiredAccess,
p);
}
__declspec(dllimport) NTSTATUS WINAPI ZwCreateSemaphore (
OUT PHANDLE SemaphoreHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN LONG InitialCount,
IN LONG MaxCount
);
static NTSTATUS WINAPI NtCreateSemaphore_ (
OUT PHANDLE SemaphoreHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN LONG InitialCount,
IN LONG MaxCount
)
{ OBJECT_ATTRIBUTES *p = ObjectAttributes,ob;
UNICODE_STRING us;
if (p && p->ObjectName &&
p->ObjectName->Length>14 &&
!_wcsnicmp(L"global\\",p->ObjectName->Buffer,7))
{ us = *p->ObjectName;
us.Buffer += 7, us.Length -= 14, us.MaximumLength =- 14;
ob = *p;
ob.ObjectName = &us;
p = &ob;
}
return ZwCreateSemaphore(
SemaphoreHandle,
DesiredAccess,
p,
InitialCount,
MaxCount);
}
__declspec(dllimport) NTSTATUS WINAPI ZwOpenSemaphore (
OUT PHANDLE SemaphoreHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
static NTSTATUS WINAPI NtOpenSemaphore_ (
OUT PHANDLE SemaphoreHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
)
{ OBJECT_ATTRIBUTES *p = ObjectAttributes,ob;
UNICODE_STRING us;
if (p && p->ObjectName &&
p->ObjectName->Length>14 &&
!_wcsnicmp(L"global\\",p->ObjectName->Buffer,7))
{ us = *p->ObjectName;
us.Buffer += 7, us.Length -= 14, us.MaximumLength =- 14;
ob = *p;
ob.ObjectName = &us;
p = &ob;
}
return ZwOpenSemaphore(
SemaphoreHandle,
DesiredAccess,
p);
}
/* WSP wrappers */
static LPWSPSTARTUP _WSPStartup;
static WSPPROC_TABLE WSPDispatch_;
static struct in_addr vloopback;
static SOCKET WSPAPI WSPAccept_(
SOCKET s,
struct sockaddr FAR * addr,
LPINT addrlen,
LPCONDITIONPROC lpfnCondition,
DWORD_PTR dwCallbackData,
LPINT lpErrno
)
{ SOCKET ret=WSPDispatch_.lpWSPAccept (s,addr,addrlen,NULL,(DWORD_PTR)NULL,lpErrno);
struct sockaddr_in *sin=(void *)addr;
#ifdef _DEBUG
DebugOutputA("accept %p %p %s",ret,addr,addr?inet_ntoa(sin->sin_addr):"(null)");
#endif
if (ret!=INVALID_SOCKET && addr!=NULL && addr->sa_family==AF_INET)
{ if (sin->sin_addr.s_addr == vloopback.s_addr ||
sin->sin_addr.s_addr == (vloopback.s_addr|0x0000807F))
sin->sin_addr.s_addr = 0x0100007F;
}
return ret;
}
static int WSPAPI WSPBind_(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPINT lpErrno
)
{ struct sockaddr_in *sin=(void *)name;
if (name->sa_family == AF_INET)
{ if (sin->sin_addr.s_addr == 0x0100007F)
{ sin = _alloca(namelen);
memcpy (sin,name,namelen);
sin->sin_addr = vloopback;
}
else if (sin->sin_addr.s_addr == 0 && sin->sin_port!=0)
{ sin = _alloca(namelen);
memcpy (sin,name,namelen);
sin->sin_addr.s_addr = vloopback.s_addr|0x0000807F;
}
#ifdef _DEBUG
DebugOutputA("bind %s:%d",inet_ntoa(sin->sin_addr),ntohs(sin->sin_port));
#endif
}
return WSPDispatch_.lpWSPBind (s,(void *)sin,namelen,lpErrno);
}
static int WSPAPI WSPConnect_(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPINT lpErrno
)
{ struct sockaddr_in *sin=(void *)name;
int ret;
if (name->sa_family == AF_INET)
{ if (sin->sin_addr.s_addr == 0x0100007F)
{ sin = _alloca(namelen);
memcpy (sin,name,namelen);
sin->sin_addr = vloopback;
}
#ifdef _DEBUG
DebugOutputA("connect %s:%d",inet_ntoa(sin->sin_addr),ntohs(sin->sin_port));
#endif
}
ret = WSPDispatch_.lpWSPConnect (s,(void *)sin,namelen,
lpCallerData,lpCalleeData,lpSQOS,lpGQOS,lpErrno);
if (ret!=0 && (void*)sin!=(void*)name && *lpErrno==WSAECONNREFUSED)
{ sin->sin_addr.s_addr |= 0x0000807F;
#ifdef _DEBUG
DebugOutputA("retry connect %s:%d",inet_ntoa(sin->sin_addr),ntohs(sin->sin_port));
#endif
ret = WSPDispatch_.lpWSPConnect (s,(void *)sin,namelen,
lpCallerData,lpCalleeData,lpSQOS,lpGQOS,lpErrno);
}
return ret;
}
static int WSPAPI WSPGetPeerName_(
SOCKET s,
struct sockaddr FAR * name,
LPINT namelen,
LPINT lpErrno
)
{ int ret=WSPDispatch_.lpWSPGetPeerName(s,name,namelen,lpErrno);
struct sockaddr_in *sin=(void *)name;
if (ret==0 && name->sa_family==AF_INET)
{ if (sin->sin_addr.s_addr == vloopback.s_addr ||
sin->sin_addr.s_addr == (vloopback.s_addr|0x0000807F))
sin->sin_addr.s_addr = 0x0100007F;
}
return ret;
}
static int WSPAPI WSPGetSockName_(
SOCKET s,
struct sockaddr FAR * name,
LPINT namelen,
LPINT lpErrno
)
{ int ret=WSPDispatch_.lpWSPGetSockName(s,name,namelen,lpErrno);
struct sockaddr_in *sin=(void *)name;
if (ret==0 && name->sa_family==AF_INET)
{ if (sin->sin_addr.s_addr == vloopback.s_addr ||
sin->sin_addr.s_addr == (vloopback.s_addr|0x0000807F))
sin->sin_addr.s_addr = 0x0100007F;
}
return ret;
}
static int WSPAPI WSPStartup_(
IN WORD wVersionRequested,
OUT LPWSPDATA lpWSPData,
IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
IN WSPUPCALLTABLE UpcallTable,
OUT LPWSPPROC_TABLE lpProcTable
)
{ int ret = (*_WSPStartup)(
wVersionRequested,
lpWSPData,
lpProtocolInfo,
UpcallTable,
&WSPDispatch_);
/* Copy whole table... */
*lpProcTable = WSPDispatch_;
/* ... and subclass selected functions */
lpProcTable->lpWSPAccept = WSPAccept_;
lpProcTable->lpWSPBind = WSPBind_;
lpProcTable->lpWSPConnect = WSPConnect_;
lpProcTable->lpWSPGetPeerName = WSPGetPeerName_;
lpProcTable->lpWSPGetSockName = WSPGetSockName_;
return ret;
}
static PVOID WINAPI GetProcAddress_ (
HMODULE hModule,
LPCSTR lpProcName
)
{ PVOID ret = GetProcAddress(hModule,lpProcName);
if (ret && !strcmp(lpProcName,"WSPStartup"))
{ /* Place myself between WS2_32 and WSP */
_WSPStartup = ret;
ret = WSPStartup_;
}
return ret;
}
PVOID *__NtCreateMutant =NULL,
*__NtOpenMutant =NULL,
*__NtCreateSemaphore =NULL,
*__NtOpenSemaphore =NULL,
*__GetProcAddress =NULL;
BOOL WINAPI DllMain (HINSTANCE h, DWORD reason, LPVOID junk)
{ DWORD acc0,acc1,sess;
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 *page0,*page1;
static size_t plen0,plen1;
switch (reason)
{ case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(h);
if (!ProcessIdToSessionId(GetCurrentProcessId(),&sess) || sess==0)
return FALSE;
/* 0x7F524450 is 127.'R'.'D'.'P' */
vloopback.s_addr = htonl(0x7F524450+sess);
if (!(hmod=GetModuleHandle(_T("KERNEL32.DLL"))))
{ OutputDebugStringA("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 (!_stricmp((char *)hmod+idesc->Name,"NTDLL.DLL")) break;
idesc++;
}
if (!idesc->Name)
{ OutputDebugStringA("Can't locate NTDLL.DLL import descriptor");
return FALSE;
}
page0 = (char *)hmod+idesc->FirstThunk;
for (thunk=(IMAGE_THUNK_DATA *)page0;
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwCreateMutant;
thunk++) ;
if (thunk->u1.Function) __NtCreateMutant=(PVOID *)thunk;
for (thunk=(IMAGE_THUNK_DATA *)page0;
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwOpenMutant;
thunk++) ;
if (thunk->u1.Function) __NtOpenMutant=(PVOID *)thunk;
for (thunk=(IMAGE_THUNK_DATA *)page0;
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwCreateSemaphore;
thunk++) ;
if (thunk->u1.Function) __NtCreateSemaphore=(PVOID *)thunk;
for (thunk=(IMAGE_THUNK_DATA *)page0;
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)ZwOpenSemaphore;
thunk++) ;
if (thunk->u1.Function) __NtOpenSemaphore=(PVOID *)thunk;
for (thunk=(IMAGE_THUNK_DATA *)page0;thunk->u1.Function;thunk++) ;
plen0 = (size_t)thunk-(size_t)page0;
if (!(hmod=GetModuleHandle(_T("WS2_32.DLL"))))
{ OutputDebugStringA("WS2_32.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 (!_stricmp((char *)hmod+idesc->Name,"KERNEL32.DLL")) break;
idesc++;
}
if (!idesc->Name)
{ OutputDebugStringA("Can't locate KERNEL32.DLL import descriptor");
return FALSE;
}
page1 = (char *)hmod+idesc->FirstThunk;
for (thunk=(IMAGE_THUNK_DATA *)page1;
thunk->u1.Function && thunk->u1.Function!=(ULONG_PTR)GetProcAddress;
thunk++) ;
if (thunk->u1.Function) __GetProcAddress=(PVOID *)thunk;
for (thunk=(IMAGE_THUNK_DATA *)page1;thunk->u1.Function;thunk++) ;
plen1 = (size_t)thunk-(size_t)page1;
if (!VirtualProtect (page0,plen0,PAGE_EXECUTE_READWRITE,&acc0))
{ OutputDebugStringA("Unable to unlock KERNEL32.DLL Thunk Table");
return FALSE;
}
if (!VirtualProtect (page1,plen1,PAGE_EXECUTE_READWRITE,&acc1))
{ OutputDebugStringA("Unable to unlock WS2_32.DLL Thunk Table");
return FALSE;
}
if (__NtCreateMutant) *__NtCreateMutant =NtCreateMutant_;
if (__NtOpenMutant) *__NtOpenMutant =NtOpenMutant_;
if (__NtCreateSemaphore) *__NtCreateSemaphore=NtCreateSemaphore_;
if (__NtOpenSemaphore) *__NtOpenSemaphore =NtOpenSemaphore_;
if (__GetProcAddress) *__GetProcAddress =GetProcAddress_;
VirtualProtect (page0,plen0,acc0,&acc0);
VirtualProtect (page1,plen1,acc1,&acc1);
break;
case DLL_PROCESS_DETACH:
VirtualProtect (page0,plen0,PAGE_EXECUTE_READWRITE,&acc0);
VirtualProtect (page1,plen1,PAGE_EXECUTE_READWRITE,&acc1);
if (__NtCreateMutant) *__NtCreateMutant =ZwCreateMutant;
if (__NtOpenMutant) *__NtOpenMutant =ZwOpenMutant;
if (__NtCreateSemaphore) *__NtCreateSemaphore=ZwCreateSemaphore;
if (__NtOpenSemaphore) *__NtOpenSemaphore =ZwOpenSemaphore;
if (__GetProcAddress) *__GetProcAddress =GetProcAddress;
VirtualProtect (page0,plen0,acc0,&acc0);
VirtualProtect (page1,plen1,acc1,&acc1);
break;
}
return TRUE;
}
|
|
|