Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / Win32

Portable JRE API Hooking (IAT)

Rate me:
Please Sign up or sign in to vote.
4.45/5 (6 votes)
22 Nov 2008CPOL4 min read 39.2K   366   18   3
Making JRE truely portable by API hooking.

Introduction

This is an illustration of an approach to make the Java Runtime Environment truly portable by API Hooking. The most hot and happening stuff in Desktop development is Desktop Virtualization. We always had a need for carrying out our favorite software on a USB drive to make it portable. But there comes a major hindrance, the installation of the application on to the end Desktop. In other words, the application needs to make Registry entries. Making a Registry entry is not a problem though. The actual problem is making Registry entries on HKEY_CLASSES_ROOT as all Windows machines need administrative privileges to make an entry under this node.

Background

Now, let us consider a simple way of making an application truly portable, by making it less dependant on the actual Registry entries of the end Desktop (virtualized Registry).

Personally, I had a need to carry JRE along with me on USB, so that irrespective of whether the end machine has JRE or not, I wanted JRE which could be detected by Internet Explorer. This is done with the help of API Hooking (IAT patching).

IAT patching is a concept of changing the function pointers of an executable so that instead of calling the actual underlying function, the replacement function that we have in a DLL is called. Every application in Windows is in the form of a PE (Portable EXE). This can be viewed through the PE Viewer. Good articles about IAT are available here in CodeProject.

Internet Explorer uses Registry entries to determine the Java plug-in to be loaded and the location to find the Java DLLs. Any Windows application would use Registry APIs to read and set Registry values. So, we need to hook these Registry functions available in Advapi32.dll.

We can fake Internet Explorer on the key values it's looking at, and make it to load the JRE DLLs in the USBs that we carry, thus making JRE truly portable.

This article is like a proof of concept that we can have virtualized JRE .It’s not in anyway suitable for a real time scenario, at least for now.

How it's done

I found out that IE 6.0 uses the following Registry functions:

  • RegOpenKeyEx()
  • RegOpenKey()

In addition to most of the Registry functions found in advapi32.dll, Internet Explorer also uses the following keys:

  • HKEY_CLASSES_ROOT\CLSID\{8AD9C840-044E-11D1-B3E9-00805F499D93}
  • HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Plug-in\1.6.0

to determine the Java plug-in available on the machine and the Java home directory from where the Java DLLs are loaded.

We create a node PortableJre under HKEY_CURRENT_USER, which will not have a problem even in non-Admin mode, and add the nodes looked upon by IE with values for the keys pointing to the Java home in the USB as well as to the ssv.dll in the USB.

Then, we hook the functions RegOpenKeyEx and RegOpenKey.

LONG WINAPI RegOpenKey(
  __in      HKEY hKey,
  __in_opt  LPCTSTR lpSubKey,
      __out     PHKEY phkResult
      );

LONG WINAPI RegOpenKeyEx(
  __in        HKEY hKey,
  __in_opt    LPCTSTR lpSubKey,
  __reserved  DWORD ulOptions,
  __in        REGSAM samDesired,
  __out       PHKEY phkResult
  );

Code snippet to create keys

//Portable JRE and Keys under them are created by the below code Snippet
        
if(RegCreateKey(HKEY_CURRENT_USER,"PortableJRE",&hPortableJRE)==ERROR_SUCCESS)
{
    HKEY hJavaCLISD;
    std::string strJavaPlugin("Java Plug-in 1.6.0");
    if(RegCreateKey(hPortableJRE,"{8AD9C840-044E-11D1-B3E9-00805F499D93}", 
                    &hJavaCLISD)==ERROR_SUCCESS)
    {
        RegSetValueEx(hJavaCLISD,"",0,REG_SZ,
          (unsigned char *)strJavaPlugin.c_str(),strJavaPlugin.length());

        HKEY hInproc;
        std::string strDefault(JREPath+"\\bin\\ssv.dll");
        std::string strThreadModel("Apartment");
        if(RegCreateKey(hJavaCLISD,"InprocServer32",&hInproc)==ERROR_SUCCESS)
        {
            RegSetValueEx(hInproc,"",0,REG_SZ,
               (unsigned char *)strDefault.c_str(),strDefault.length());

            RegSetValueEx(hInproc,"ThreadingModel",0,REG_SZ, 
              (unsigned char *)strThreadModel.c_str(),strThreadModel.length());

        }
    }
        
    HKEY hSoftware;
    if(RegCreateKey(hPortableJRE,"SOFTWARE",&hSoftware)==ERROR_SUCCESS)
    {
        HKEY hJavaSoft;
        if(RegCreateKey(hSoftware,"JavaSoft",&hJavaSoft)==ERROR_SUCCESS)
        {
            HKEY hJavaPlugin,hJRE;
            if(RegCreateKey(hJavaSoft,"Java Plug-in",&hJavaPlugin)==ERROR_SUCCESS)
            {
                HKEY hplugin160;
                if(RegCreateKey(hJavaPlugin,"1.6.0",&hplugin160)==ERROR_SUCCESS)
                {
                    MessageBox(NULL,"plgun1.6.0success","PortableJRE",NULL);
                    RegSetValueEx(hplugin160,"JavaHome",0,REG_SZ,
                                 (unsigned char *)JREPath.c_str(),JREPath.length());
                }
            }
            if(RegCreateKey(hJavaSoft,"Java Runtime Environment",&hJRE)==ERROR_SUCCESS)
            {
                HKEY hplugin160;
                if(RegCreateKey(hJRE,"1.6.0",&hplugin160)==ERROR_SUCCESS)
                {
                    MessageBox(NULL,"JRE1.6.0success","PortableJRE",NULL);
                    RegSetValueEx(hplugin160,"JavaHome",0,REG_SZ,
                                 (unsigned char *)JREPath.c_str(),JREPath.length());
                }

            }

        }
    }
}

As you can see, the RegOpenKey and RegOpenKeyEx use the lpSubKey parameter to open the corresponding subkey. So, whenever we get a request to open either 8AD9C840-044E-11D1-B3E9-00805F499D93 or JavaSoft, we call the OpenKey for the PortableJRE node that we created under HKEY_CURRENT_USER, and then return the phkResult which will point to our JRE entries under PortableJRE. From then on, IE might use RegEnumKey, RegEnumKeyEx, RegQueryValue, RegQueryValueEx which will all result in pointing to JRE DLLs on the USB drive.

Below is the hook function that was used by me:

LONG WINAPI MyREGOpenKeyW(HKEY hKey,LPCWSTR lpSubKey,PHKEY phkResult)
{
    REGOpenKeyW_Type oldFn = 
      (REGOpenKeyW_Type)TextHook.Functions[ADVAPI32_REGOpenKeyW].OrigFn;

    std::wstring strJavasoft(L"JavaSoft");
    std::wstring strJRE(L"Java Runtime Environment");
    std::wstring strJRECLSID(L"");
    
    REGOpenKeyW_Type OpenKeyfun = 
      (REGOpenKeyW_Type)TextHook.Functions[ADVAPI32_REGOpenKeyW].OrigFn;

    OutputDebugStringA("MyREGOpenKeyW");
    if(lpSubKey!=NULL)
    {
    
        std::wstring strSubKey(lpSubKey);
        OutputDebugString("inside lpsubkey check");

        TCHAR  test1=(TCHAR)lpSubKey;
    
        OutputDebugString(&test1);
  
        if(strSubKey.compare(L"JavaSoft")==0)
        {
            OutputDebugStringA("In Jaavasoft\n"); 
            HKEY hPortableJRE;
            LONG lret  = OpenKeyfun(HKEY_CURRENT_USER, 
              L"PortableJRE\\SOFTWARE",&hPortableJRE);
            if(lret==ERROR_SUCCESS)
            {
                OutputDebugString("Changing the Key\n"); 
                LONG retVal = oldFn(hPortableJRE,lpSubKey,phkResult);
                OutputDebugString("RegOpenKeyExA = "); 
                OutputDebugStringW(lpSubKey); 
                OutputDebugString("\n"); 
                

                return retVal;
            }

        }
        else if(strSubKey.find(L"{8AD9C840-044E-11D1-B3E9-00805F499D93}")!=wstring::npos )
        {
            OutputDebugString("founda a request for ssv.dll"); 
            
            HKEY hPortableJRE;
            LONG lret  = OpenKeyfun(HKEY_CURRENT_USER,L"PortableJRE",&hPortableJRE);
            if(lret==ERROR_SUCCESS)
            {
                OutputDebugString("Changing the Key for 8ad9c8\n"); 
                LONG retVal = oldFn(hPortableJRE, 
                  L"{8AD9C840-044E-11D1-B3E9-00805F499D93}",phkResult);
                OutputDebugString("RegOpenKeyExA = "); 
                OutputDebugStringW(lpSubKey); 
                OutputDebugString("\n"); 
                

                return retVal;
            }

        }
        else if(strSubKey.find(L"SOFTWARE\\JavaSoft\\Java Plug-in\\1.6.0")!=wstring::npos)
        {
            OutputDebugString("In Java-plug-in\n"); 
            HKEY hPortableJRE;
            LONG lret  = OpenKeyfun(HKEY_CURRENT_USER,L"PortableJRE",&hPortableJRE);
            if(lret==ERROR_SUCCESS)
            {
                OutputDebugString("Changing the Key\n"); 
                LONG retVal = oldFn(hPortableJRE,lpSubKey,phkResult);
                OutputDebugString("RegOpenKeyExA = "); 
                OutputDebugStringW(lpSubKey); 
                OutputDebugString("\n"); 
                

                return retVal;
            }

        }

        OutputDebugString("after lpsubkey check");
    
        OutputDebugString("No Match for Hooking registry"); 
    }

    LONG retVal = oldFn(hKey,lpSubKey,phkResult);

    OutputDebugString("RegOpenKeyW = "); 
    OutputDebugStringW(lpSubKey); 
    OutputDebugString("\n"); 
    

    return retVal;
}

The hooked function that was implemented by me will look at the keys under PortbaledJRE that was created by us and will eventually load the JRE DLLs from a USB Drive.

Testing the PortbaleJRE

  1. Copy the Java directory containing JRE 1.6.0 and the subdirectories on to a USB drive from a machine which has JRE 1.6 installed.
  2. Start the PortableJRE.EXE on a Win2K machine. You should be seeing a message box saying that the hook is installed.
  3. You can start Internet Explorer and look at a page which has an applet embedded in it.

You should be seeing that the JRE from the USB is loaded, and from the Java console, you should be seeing that JRE 1.6 is used.

The files should be like below on the USB pen drive:

  • /PortableJRE.Exe
  • /TestDll.dll
  • /Java/jre1.6.0/

Dependencies

  1. Have tested it with JRE 1.6 only.
  2. Have tested it for Win2K only.
  3. Have tested it on IE 6.0.

Also, please make sure that the page that you use has the <object> to load Java applets, like below:

HTML
<OBJECT 
  classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
  width="200" height="200">
  <PARAM name="code" value="Applet1.class">
</OBJECT>

Conclusion

This article was an illustration of the power of API hooking and the advantages of virtualized applications. Please let me know if you need any more info on this.

References

History

Initial version which will run only on Win2K and Internet Explorer 6. Will come up with one which works for WinXP and IE 7 as well.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer California Software Company
India India
Sun Certified Java Programmer
Sun Certified Web Component Developer

Interests:
Network Programming,Windows Programming,Network Security,RTOS.

Comments and Discussions

 
Generalgood article Pin
aldo hexosa23-Nov-08 19:02
professionalaldo hexosa23-Nov-08 19:02 
could you give us a sample project? it would be nice if can give us some samples that works
GeneralRe: good article Pin
Thilak Raj S1-Dec-08 2:29
Thilak Raj S1-Dec-08 2:29 
GeneralJRE in USB Pin
Ganesh SathyaNarayanan M23-Nov-08 18:28
Ganesh SathyaNarayanan M23-Nov-08 18:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.