Bug 1121829 - Support redirection of kernel32.dll for hooking function. r=dmajor, a=sylvestre
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Fri, 16 Jan 2015 23:07:09 +0900
changeset 243028 d340f3d3439d
parent 243027 9bfc57be3f2c
child 243029 89ea80802586
push id4367
push userm_kato@ga2.so-net.ne.jp
push date2015-01-26 14:01 +0000
treeherdermozilla-beta@d340f3d3439d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmajor, sylvestre
bugs1121829
milestone36.0
Bug 1121829 - Support redirection of kernel32.dll for hooking function. r=dmajor, a=sylvestre
xpcom/build/nsWindowsDllInterceptor.h
--- a/xpcom/build/nsWindowsDllInterceptor.h
+++ b/xpcom/build/nsWindowsDllInterceptor.h
@@ -131,16 +131,18 @@ public:
     }
 
     byteptr_t fn = reinterpret_cast<byteptr_t>(GetProcAddress(mModule, aName));
     if (!fn) {
       //printf ("GetProcAddress failed\n");
       return false;
     }
 
+    fn = ResolveRedirectedAddress(fn);
+
     // Ensure we can read and write starting at fn - 5 (for the long jmp we're
     // going to write) and ending at fn + 2 (for the short jmp up to the long
     // jmp).
     DWORD op;
     if (!VirtualProtectEx(GetCurrentProcess(), fn - 5, 7,
                           PAGE_EXECUTE_READWRITE, &op)) {
       //printf ("VirtualProtectEx failed! %d\n", GetLastError());
       return false;
@@ -197,16 +199,28 @@ public:
 
     // I think this routine is safe without this, but it can't hurt.
     FlushInstructionCache(GetCurrentProcess(),
                           /* ignored */ nullptr,
                           /* ignored */ 0);
 
     return true;
   }
+
+private:
+  static byteptr_t ResolveRedirectedAddress(const byteptr_t aOriginalFunction)
+  {
+    // If function entry is jmp [disp32] such as used by kernel32,
+    // we resolve redirected address from import table.
+    if (aOriginalFunction[0] == 0xff && aOriginalFunction[1] == 0x25) {
+      return (byteptr_t)(**((uint32_t**) (aOriginalFunction + 2)));
+    }
+
+    return aOriginalFunction;
+  }
 #else
   bool AddHook(const char* aName, intptr_t aHookDest, void** aOrigFunc)
   {
     // Not implemented except on x86-32.
     return false;
   }
 #endif
 };
@@ -307,16 +321,18 @@ public:
     }
 
     void* pAddr = (void*)GetProcAddress(mModule, aName);
     if (!pAddr) {
       //printf ("GetProcAddress failed\n");
       return false;
     }
 
+    pAddr = ResolveRedirectedAddress((byteptr_t)pAddr);
+
     CreateTrampoline(pAddr, aHookDest, aOrigFunc);
     if (!*aOrigFunc) {
       //printf ("CreateTrampoline failed\n");
       return false;
     }
 
     return true;
   }
@@ -648,16 +664,29 @@ protected:
     }
 
     byteptr_t p = mHookPage + mCurHooks * kHookSize;
 
     mCurHooks++;
 
     return p;
   }
+
+  static void* ResolveRedirectedAddress(const byteptr_t aOriginalFunction)
+  {
+#if defined(_M_IX86)
+    // If function entry is jmp [disp32] such as used by kernel32,
+    // we resolve redirected address from import table.
+    if (aOriginalFunction[0] == 0xff && aOriginalFunction[1] == 0x25) {
+      return (void*)(**((uint32_t**) (aOriginalFunction + 2)));
+    }
+#endif
+
+    return aOriginalFunction;
+  }
 };
 
 } // namespace internal
 
 class WindowsDllInterceptor
 {
   internal::WindowsDllNopSpacePatcher mNopSpacePatcher;
   internal::WindowsDllDetourPatcher mDetourPatcher;