Bug 677247 - Unregister Dll hooks when WindowsDllInterceptor is destructed. r=ehsan
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 11 Aug 2011 07:54:57 +0200
changeset 74201 3948d561f905727d10bb285b9420eb513f863629
parent 74200 84ce41f8cec7abf76d97d9c6822da1e1dd83bbf2
child 74202 be17ceae8d600dabc4eadc7c84c53d9dfe031bdf
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
reviewersehsan
bugs677247
milestone8.0a1
Bug 677247 - Unregister Dll hooks when WindowsDllInterceptor is destructed. r=ehsan
toolkit/xre/nsWindowsDllInterceptor.h
--- a/toolkit/xre/nsWindowsDllInterceptor.h
+++ b/toolkit/xre/nsWindowsDllInterceptor.h
@@ -51,31 +51,68 @@
  *
  * 3. After N bytes of the trampoline, add a jump to OrigFunction+N to
  *    continue original program flow.
  *
  * 4. Hook function needs to call the trampoline during its execution,
  *    to invoke the original function (so address of trampoline is
  *    returned).
  * 
+ * When the WindowsDllInterceptor class is destructed, OrigFunction is
+ * patched again to jump directly to the trampoline instead of going
+ * through the hook function. As such, re-intercepting the same function
+ * won't work, as jump instructions are not supported.
  */
 
 class WindowsDllInterceptor
 {
   typedef unsigned char *byteptr_t;
 public:
   WindowsDllInterceptor() 
     : mModule(0)
   {
   }
 
   WindowsDllInterceptor(const char *modulename, int nhooks = 0) {
     Init(modulename, nhooks);
   }
 
+  ~WindowsDllInterceptor() {
+    int i;
+    byteptr_t p;
+    for (i = 0, p = mHookPage; i < mCurHooks; i++, p += kHookSize) {
+#if defined(_M_IX86)
+      size_t nBytes = 1 + sizeof(intptr_t);
+#elif defined(_M_X64)
+      size_t nBytes = 2 + sizeof(intptr_t);
+#else
+#error "Unknown processor type"
+#endif
+      byteptr_t origBytes = *((byteptr_t *)p);
+      // ensure we can modify the original code
+      DWORD op;
+      if (!VirtualProtectEx(GetCurrentProcess(), origBytes, nBytes, PAGE_EXECUTE_READWRITE, &op)) {
+        //printf ("VirtualProtectEx failed! %d\n", GetLastError());
+        continue;
+      }
+      // Remove the hook by making the original function jump directly
+      // in the trampoline.
+      intptr_t dest = (intptr_t)(p + sizeof(void *));
+#if defined(_M_IX86)
+      *((intptr_t*)(origBytes+1)) = dest - (intptr_t)(origBytes+5); // target displacement
+#elif defined(_M_X64)
+      *((intptr_t*)(origBytes+2)) = dest;
+#else
+#error "Unknown processor type"
+#endif
+      // restore protection; if this fails we can't really do anything about it
+      VirtualProtectEx(GetCurrentProcess(), origBytes, nBytes, op, &op);
+    }
+  }
+
   void Init(const char *modulename, int nhooks = 0) {
     if (mModule)
       return;
 
     mModule = LoadLibraryExA(modulename, NULL, 0);
     if (!mModule) {
       //printf("LoadLibraryEx for '%s' failed\n", modulename);
       return;
@@ -296,16 +333,21 @@ protected:
 #error "Unknown processor type"
 #endif
 
     if (nBytes > 100) {
       //printf ("Too big!");
       return 0;
     }
 
+    // We keep the address of the original function in the first bytes of
+    // the trampoline buffer
+    *((void **)tramp) = origFunction;
+    tramp += sizeof(void *);
+
     memcpy(tramp, origFunction, nBytes);
 
     // OrigFunction+N, the target of the trampoline
     byteptr_t trampDest = origBytes + nBytes;
 
 #if defined(_M_IX86)
     tramp[nBytes] = 0xE9; // jmp
     *((intptr_t*)(tramp+nBytes+1)) = (intptr_t)trampDest - (intptr_t)(tramp+nBytes+5); // target displacement