forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			332 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "FunctionHook.h"
 | 
						|
#include "FunctionBroker.h"
 | 
						|
#include "nsClassHashtable.h"
 | 
						|
#include "mozilla/ClearOnShutdown.h"
 | 
						|
 | 
						|
#if defined(XP_WIN)
 | 
						|
#include <shlobj.h>
 | 
						|
#endif
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
namespace plugins {
 | 
						|
 | 
						|
StaticAutoPtr<FunctionHookArray> FunctionHook::sFunctionHooks;
 | 
						|
 | 
						|
bool AlwaysHook(int) { return true; }
 | 
						|
 | 
						|
FunctionHookArray*
 | 
						|
FunctionHook::GetHooks()
 | 
						|
{
 | 
						|
  if (sFunctionHooks) {
 | 
						|
    return sFunctionHooks;
 | 
						|
  }
 | 
						|
 | 
						|
  // sFunctionHooks is the StaticAutoPtr to the singleton array of FunctionHook
 | 
						|
  // objects.  We free it by clearing the StaticAutoPtr on shutdown.
 | 
						|
  sFunctionHooks = new FunctionHookArray();
 | 
						|
  ClearOnShutdown(&sFunctionHooks);
 | 
						|
  sFunctionHooks->SetLength(ID_FunctionHookCount);
 | 
						|
 | 
						|
  AddFunctionHooks(*sFunctionHooks);
 | 
						|
  AddBrokeredFunctionHooks(*sFunctionHooks);
 | 
						|
  return sFunctionHooks;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
FunctionHook::HookFunctions(int aQuirks)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
 | 
						|
  FunctionHookArray* hooks = FunctionHook::GetHooks();
 | 
						|
  MOZ_ASSERT(hooks);
 | 
						|
  for(size_t i=0; i < hooks->Length(); ++i) {
 | 
						|
    FunctionHook* mhb = hooks->ElementAt(i);
 | 
						|
    // Check that the FunctionHook array is in the same order as the
 | 
						|
    // FunctionHookId enum.
 | 
						|
    MOZ_ASSERT((size_t)mhb->FunctionId() == i);
 | 
						|
    mhb->Register(aQuirks);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#if defined(XP_WIN)
 | 
						|
 | 
						|
// This cache is created when a DLL is registered with a FunctionHook.
 | 
						|
// It is cleared on a call to ClearDllInterceptorCache().  It
 | 
						|
// must be freed before exit to avoid leaks.
 | 
						|
typedef nsClassHashtable<nsStringHashKey, WindowsDllInterceptor> DllInterceptors;
 | 
						|
DllInterceptors* sDllInterceptorCache = nullptr;
 | 
						|
 | 
						|
WindowsDllInterceptor*
 | 
						|
FunctionHook::GetDllInterceptorFor(const char* aModuleName)
 | 
						|
{
 | 
						|
  if (!sDllInterceptorCache) {
 | 
						|
    sDllInterceptorCache = new DllInterceptors();
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(NS_IsAscii(aModuleName), "Non-ASCII module names are not supported");
 | 
						|
  NS_ConvertASCIItoUTF16 moduleName(aModuleName);
 | 
						|
 | 
						|
  WindowsDllInterceptor* ret =
 | 
						|
    sDllInterceptorCache->LookupOrAdd(moduleName);
 | 
						|
  MOZ_ASSERT(ret);
 | 
						|
  ret->Init(moduleName.get());
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
FunctionHook::ClearDllInterceptorCache()
 | 
						|
{
 | 
						|
  delete sDllInterceptorCache;
 | 
						|
  sDllInterceptorCache = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
/* GetWindowInfo */
 | 
						|
 | 
						|
typedef BasicFunctionHook<ID_GetWindowInfo, decltype(GetWindowInfo)> GetWindowInfoFH;
 | 
						|
 | 
						|
template<>
 | 
						|
ShouldHookFunc* const
 | 
						|
GetWindowInfoFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_GETWINDOWINFO>;
 | 
						|
 | 
						|
static const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
 | 
						|
static HWND sBrowserHwnd = nullptr;
 | 
						|
 | 
						|
 | 
						|
BOOL WINAPI
 | 
						|
GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi)
 | 
						|
{
 | 
						|
  if (!pwi) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  MOZ_ASSERT(ID_GetWindowInfo < FunctionHook::GetHooks()->Length());
 | 
						|
  GetWindowInfoFH* functionHook =
 | 
						|
    static_cast<GetWindowInfoFH*>(FunctionHook::GetHooks()->ElementAt(ID_GetWindowInfo));
 | 
						|
  if (!functionHook->OriginalFunction()) {
 | 
						|
    NS_ASSERTION(FALSE, "Something is horribly wrong in PHGetWindowInfoHook!");
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!sBrowserHwnd) {
 | 
						|
    wchar_t szClass[20];
 | 
						|
    // GetClassNameW returns the length it copied w/o null terminator.
 | 
						|
    // Therefore, if the name and null-terminator fit then it returns a
 | 
						|
    // value less than the buffer's length.
 | 
						|
    int nameLen = GetClassNameW(hWnd, szClass, ArrayLength(szClass));
 | 
						|
    if ((nameLen < (int)ArrayLength(szClass)) &&
 | 
						|
        !wcscmp(szClass, kMozillaWindowClass)) {
 | 
						|
      sBrowserHwnd = hWnd;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Oddity: flash does strange rect comparisons for mouse input destined for
 | 
						|
  // it's internal settings window. Post removing sub widgets for tabs, touch
 | 
						|
  // this up so they get the rect they expect.
 | 
						|
  // XXX potentially tie this to a specific major version?
 | 
						|
  typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi);
 | 
						|
  GetWindowInfoPtr gwiFunc =
 | 
						|
    static_cast<GetWindowInfoPtr>(functionHook->OriginalFunction());
 | 
						|
  BOOL result = gwiFunc(hWnd, pwi);
 | 
						|
  if (sBrowserHwnd && sBrowserHwnd == hWnd) {
 | 
						|
    pwi->rcWindow = pwi->rcClient;
 | 
						|
  }
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
/* PrintDlgW */
 | 
						|
 | 
						|
typedef BasicFunctionHook<ID_PrintDlgW, decltype(PrintDlgW)> PrintDlgWFH;
 | 
						|
 | 
						|
template<>
 | 
						|
ShouldHookFunc* const
 | 
						|
PrintDlgWFH::mShouldHook = &CheckQuirks<QUIRK_FLASH_HOOK_PRINTDLGW>;
 | 
						|
 | 
						|
BOOL WINAPI PrintDlgWHook(LPPRINTDLGW aDlg)
 | 
						|
{
 | 
						|
  // Zero out the HWND supplied by the plugin.  We are sacrificing window
 | 
						|
  // parentage for the ability to run in the NPAPI sandbox.
 | 
						|
  HWND hwnd = aDlg->hwndOwner;
 | 
						|
  aDlg->hwndOwner = 0;
 | 
						|
  MOZ_ASSERT(ID_PrintDlgW < FunctionHook::GetHooks()->Length());
 | 
						|
  PrintDlgWFH* functionHook =
 | 
						|
    static_cast<PrintDlgWFH*>(FunctionHook::GetHooks()->ElementAt(ID_PrintDlgW));
 | 
						|
  MOZ_ASSERT(functionHook);
 | 
						|
  BOOL ret = functionHook->OriginalFunction()(aDlg);
 | 
						|
  aDlg->hwndOwner = hwnd;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
// Hooking CreateFileW for protected-mode magic
 | 
						|
static WindowsDllInterceptor sKernel32Intercept;
 | 
						|
typedef HANDLE (WINAPI *CreateFileWPtr)(LPCWSTR aFname, DWORD aAccess,
 | 
						|
                                        DWORD aShare,
 | 
						|
                                        LPSECURITY_ATTRIBUTES aSecurity,
 | 
						|
                                        DWORD aCreation, DWORD aFlags,
 | 
						|
                                        HANDLE aFTemplate);
 | 
						|
static WindowsDllInterceptor::FuncHookType<CreateFileWPtr> sCreateFileWStub;
 | 
						|
typedef HANDLE (WINAPI *CreateFileAPtr)(LPCSTR aFname, DWORD aAccess,
 | 
						|
                                        DWORD aShare,
 | 
						|
                                        LPSECURITY_ATTRIBUTES aSecurity,
 | 
						|
                                        DWORD aCreation, DWORD aFlags,
 | 
						|
                                        HANDLE aFTemplate);
 | 
						|
static WindowsDllInterceptor::FuncHookType<CreateFileAPtr> sCreateFileAStub;
 | 
						|
 | 
						|
// Windows 8 RTM (kernelbase's version is 6.2.9200.16384) doesn't call
 | 
						|
// CreateFileW from CreateFileA.
 | 
						|
// So we hook CreateFileA too to use CreateFileW hook.
 | 
						|
static HANDLE WINAPI
 | 
						|
CreateFileAHookFn(LPCSTR aFname, DWORD aAccess, DWORD aShare,
 | 
						|
                  LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
 | 
						|
                  HANDLE aFTemplate)
 | 
						|
{
 | 
						|
  while (true) { // goto out
 | 
						|
    // Our hook is for mms.cfg into \Windows\System32\Macromed\Flash
 | 
						|
    // We don't require supporting too long path.
 | 
						|
    WCHAR unicodeName[MAX_PATH];
 | 
						|
    size_t len = strlen(aFname);
 | 
						|
 | 
						|
    if (len >= MAX_PATH) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    // We call to CreateFileW for workaround of Windows 8 RTM
 | 
						|
    int newLen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, aFname,
 | 
						|
                                     len, unicodeName, MAX_PATH);
 | 
						|
    if (newLen == 0 || newLen >= MAX_PATH) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    unicodeName[newLen] = '\0';
 | 
						|
 | 
						|
    return CreateFileW(unicodeName, aAccess, aShare, aSecurity, aCreation, aFlags, aFTemplate);
 | 
						|
  }
 | 
						|
 | 
						|
  return sCreateFileAStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
 | 
						|
                          aFTemplate);
 | 
						|
}
 | 
						|
 | 
						|
static bool
 | 
						|
GetLocalLowTempPath(size_t aLen, LPWSTR aPath)
 | 
						|
{
 | 
						|
  NS_NAMED_LITERAL_STRING(tempname, "\\Temp");
 | 
						|
  LPWSTR path;
 | 
						|
  if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
 | 
						|
                                     nullptr, &path))) {
 | 
						|
    if (wcslen(path) + tempname.Length() < aLen) {
 | 
						|
        wcscpy(aPath, path);
 | 
						|
        wcscat(aPath, tempname.get());
 | 
						|
        CoTaskMemFree(path);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
    CoTaskMemFree(path);
 | 
						|
  }
 | 
						|
 | 
						|
  // XP doesn't support SHGetKnownFolderPath and LocalLow
 | 
						|
  if (!GetTempPathW(aLen, aPath)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
HANDLE WINAPI
 | 
						|
CreateFileWHookFn(LPCWSTR aFname, DWORD aAccess, DWORD aShare,
 | 
						|
                  LPSECURITY_ATTRIBUTES aSecurity, DWORD aCreation, DWORD aFlags,
 | 
						|
                  HANDLE aFTemplate)
 | 
						|
{
 | 
						|
  static const WCHAR kConfigFile[] = L"mms.cfg";
 | 
						|
  static const size_t kConfigLength = ArrayLength(kConfigFile) - 1;
 | 
						|
 | 
						|
  while (true) { // goto out, in sheep's clothing
 | 
						|
    size_t len = wcslen(aFname);
 | 
						|
    if (len < kConfigLength) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    if (wcscmp(aFname + len - kConfigLength, kConfigFile) != 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    // This is the config file we want to rewrite
 | 
						|
    WCHAR tempPath[MAX_PATH+1];
 | 
						|
    if (GetLocalLowTempPath(MAX_PATH, tempPath) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    WCHAR tempFile[MAX_PATH+1];
 | 
						|
    if (GetTempFileNameW(tempPath, L"fx", 0, tempFile) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    HANDLE replacement =
 | 
						|
      sCreateFileWStub(tempFile, GENERIC_READ | GENERIC_WRITE, aShare,
 | 
						|
                       aSecurity, TRUNCATE_EXISTING,
 | 
						|
                       FILE_ATTRIBUTE_TEMPORARY |
 | 
						|
                         FILE_FLAG_DELETE_ON_CLOSE,
 | 
						|
                       nullptr);
 | 
						|
    if (replacement == INVALID_HANDLE_VALUE) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    HANDLE original = sCreateFileWStub(aFname, aAccess, aShare, aSecurity,
 | 
						|
                                       aCreation, aFlags, aFTemplate);
 | 
						|
    if (original != INVALID_HANDLE_VALUE) {
 | 
						|
      // copy original to replacement
 | 
						|
      static const size_t kBufferSize = 1024;
 | 
						|
      char buffer[kBufferSize];
 | 
						|
      DWORD bytes;
 | 
						|
      while (ReadFile(original, buffer, kBufferSize, &bytes, NULL)) {
 | 
						|
        if (bytes == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        DWORD wbytes;
 | 
						|
        WriteFile(replacement, buffer, bytes, &wbytes, NULL);
 | 
						|
        if (bytes < kBufferSize) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      CloseHandle(original);
 | 
						|
    }
 | 
						|
    static const char kSettingString[] = "\nProtectedMode=0\n";
 | 
						|
    DWORD wbytes;
 | 
						|
    WriteFile(replacement, static_cast<const void*>(kSettingString),
 | 
						|
              sizeof(kSettingString) - 1, &wbytes, NULL);
 | 
						|
    SetFilePointer(replacement, 0, NULL, FILE_BEGIN);
 | 
						|
    return replacement;
 | 
						|
  }
 | 
						|
  return sCreateFileWStub(aFname, aAccess, aShare, aSecurity, aCreation, aFlags,
 | 
						|
                          aFTemplate);
 | 
						|
}
 | 
						|
 | 
						|
void FunctionHook::HookProtectedMode()
 | 
						|
{
 | 
						|
  // Legacy code.  Uses the nsWindowsDLLInterceptor directly instead of
 | 
						|
  // using the FunctionHook
 | 
						|
  sKernel32Intercept.Init("kernel32.dll");
 | 
						|
  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Plugin);
 | 
						|
  sCreateFileWStub.Set(sKernel32Intercept, "CreateFileW", &CreateFileWHookFn);
 | 
						|
  sCreateFileAStub.Set(sKernel32Intercept, "CreateFileA", &CreateFileAHookFn);
 | 
						|
}
 | 
						|
 | 
						|
#endif // defined(XP_WIN)
 | 
						|
 | 
						|
#define FUN_HOOK(x) static_cast<FunctionHook*>(x)
 | 
						|
 | 
						|
void
 | 
						|
FunctionHook::AddFunctionHooks(FunctionHookArray& aHooks)
 | 
						|
{
 | 
						|
  // We transfer ownership of the FunctionHook objects to the array.
 | 
						|
#if defined(XP_WIN)
 | 
						|
  aHooks[ID_GetWindowInfo] =
 | 
						|
    FUN_HOOK(new GetWindowInfoFH("user32.dll", "GetWindowInfo",
 | 
						|
                                 &GetWindowInfo, &GetWindowInfoHook));
 | 
						|
  aHooks[ID_PrintDlgW] =
 | 
						|
    FUN_HOOK(new PrintDlgWFH("comdlg32.dll", "PrintDlgW", &PrintDlgW,
 | 
						|
                             PrintDlgWHook));
 | 
						|
#endif // defined(XP_WIN)
 | 
						|
}
 | 
						|
 | 
						|
#undef FUN_HOOK
 | 
						|
 | 
						|
} // namespace plugins
 | 
						|
} // namespace mozilla
 |