It works only in Windows NT/200/XP and uses WinAPI functions.
Today I publish this solution.
How it works:
- User compiles Injector.class, Injector.dll, Insider.dll from sources (via make.bat)
- User starts java application (e.g.: start java -jar %JAVA_HOME%\demo\jfc\Notepad\notepad.jar) in the JVM-1
- User recognises the PID (process id) of started application (via Task Manager)
- User executes
java -Djava.library.path=. Injector
(starts JVM-2) and enters PID of JVM-1 - JVM-1 calls Injector.dll's native function
- Injector.dll calls CreateRemoteThread WinAPI function and loads Insider.dll into JVM-1
- Insider.dll attaches to JVM-1 via JNI, defines new class from bytes array and loads it.
!!! In this case class's bytecode stores as ajbyte clazz[] array
within the Insider.dll - And then new class works in the JVM-1
Injected class only prints numbers within JVM-1's console:
Sources:
Bin2H.java
Injector.cpp
Injector.java
Insider.java
insider.cpp
make.bat
listed below:
Bin2H.java
public class Bin2H {
public static void main(String[] args) throws Exception {
System.out.print("#include <jni.h>\nconst jbyte clazz[]={");
for (int i = System.in.read(); i >= 0; i = System.in.read())
System.out.print(Integer.toString(i) + ",");
System.out.print("};");
}
}
Injector.cpp
#include <windows.h>
#include <jni.h>
#include "injector.h"
void Inject (unsigned long PID, const char *dllname)
{
DWORD hLibModule;
HMODULE hKernel32 = GetModuleHandle (TEXT ("Kernel32"));
void *hProcess = OpenProcess (PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, false, PID);
int cch = strlen (dllname) + 1;
void *pLibRemote = VirtualAllocEx (hProcess, NULL, cch, MEM_COMMIT,
PAGE_READWRITE);
WriteProcessMemory (hProcess, pLibRemote, (void *) dllname, cch, NULL);
HANDLE hThread = CreateRemoteThread (hProcess, NULL, 0,
(PTHREAD_START_ROUTINE)
GetProcAddress (hKernel32,
"LoadLibraryA"),
pLibRemote, 0, NULL);
WaitForSingleObject (hThread, INFINITE);
GetExitCodeThread( hThread, &hLibModule );
CloseHandle (hThread);
VirtualFreeEx (hProcess, pLibRemote, sizeof (dllname), MEM_RELEASE);
hThread = CreateRemoteThread (hProcess, NULL, 0,
(PTHREAD_START_ROUTINE) GetProcAddress (hKernel32,
"FreeLibrary"),
(void *) hLibModule, 0, NULL);
WaitForSingleObject (hThread, INFINITE);
CloseHandle (hThread);
}
void JNICALL Java_Injector_inject (JNIEnv * env, jclass, jint pid, jstring dll)
{
try
{
Inject (pid, env->GetStringUTFChars (dll, NULL));
} catch (...)
{
MessageBox (NULL, "Exception::Inject", "Injector", MB_ICONERROR);
}
}
Injector.java
import java.io.File;
import java.io.IOException;
public class Injector {
public static native void inject(int pid, String dll);
public static void main(String[] args) {
System.loadLibrary("Injector");
byte[] str = new byte[5];
try {
System.in.read(str);
System.out.println(new File("").getAbsolutePath()+"\\insider.dll");
inject(Integer.parseInt(new String(str).trim()), new File("").getAbsolutePath()+"\\insider.dll");
} catch (IOException e) {
e.printStackTrace();
}
}
}
insider.cpp
#include <windows.h>
#include <jni.h>
#include "insider.h"
BOOL APIENTRY
DllMain (HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
JavaVM *vmBuf;
JNIEnv *env;
jsize nVMs;
jint res = 0;
jclass resjclass = NULL;
try
{
res = JNI_GetCreatedJavaVMs (&vmBuf, 1, &nVMs);
if (res != JNI_OK || nVMs < 1)
{
MessageBox (NULL, "JVMs not found", "Insider", MB_ICONERROR);
return FALSE;
}
}
catch (...)
{
MessageBox (NULL, "Exception:JNI_GetCreatedJavaVMs", "Insider",
MB_ICONERROR);
return FALSE;
}
try
{
res = vmBuf[0].AttachCurrentThread ((void **) &env, NULL);
if (res != JNI_OK)
{
MessageBox (NULL, "Can't attach to JVM", "Insider", MB_ICONERROR);
return FALSE;
}
}
catch (...)
{
MessageBox (NULL, "Exception:AttachCurrentThread", "Insider",
MB_ICONERROR);
return FALSE;
}
try
{
resjclass = env->DefineClass ("Insider", NULL, clazz, sizeof (clazz));
if (resjclass == NULL)
{
MessageBox (NULL, "Error Define Class", "Insider", MB_ICONERROR);
return FALSE;
}
resjclass = env->FindClass ("Insider");
if (resjclass == NULL)
{
MessageBox (NULL, "Error Load Class", "Insider", MB_ICONERROR);
return FALSE;
}
}
catch (...)
{
MessageBox (NULL, "Exception:DefineClass,FindClass", "Insider",
MB_ICONERROR);
}
try
{
vmBuf[0].DetachCurrentThread ();
}
catch (...)
{
MessageBox (NULL, "Exception:DetachCurrentThread", "Insider",
MB_ICONERROR);
return FALSE;
}
}
return TRUE;
}
Insider.java
//Warning: Make Insider as single class!
public class Insider implements Runnable {
static {
Thread t = new Thread(new Insider());
t.setPriority(Thread.MIN_PRIORITY);
t.setDaemon(true);
t.start();
}
public void run() {
int i = 0;
while (true) {
System.out.println(i++);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
break;
}
}
}
}
make.bat
@echo off
call "E:\Devel\Microsoft Visual Studio\VC98\Bin\vcvars32.bat"
set JAVA_HOME=E:\Devel\jdk1.5.0_09
set PATH=%PATH%;%JAVA_HOME%\bin
rd /Q /S out
md out
javac -d out Injector.java
javah -classpath out Injector
javac -source 1.3 -target 1.1 Insider.java
javac Bin2H.java
type Insider.class |java Bin2H >insider.h
del Bin2H.class
del Insider.class
cl.exe /c -GX /I%JAVA_HOME%\include /I%JAVA_HOME%\include\win32 Injector.cpp
link /DLL /OUT:out/Injector.dll kernel32.lib user32.lib gdi32.lib Injector.obj
cl.exe /c -GX /I%JAVA_HOME%\include /I%JAVA_HOME%\include\win32 Insider.cpp
link /DLL /OUT:out/Insider.dll kernel32.lib user32.lib gdi32.lib %JAVA_HOME%\lib\jvm.lib Insider.obj
del Insider.obj
del Injector.obj
del Injector.h
del Insider.h
del out\Injector.exp
del out\Injector.lib
echo java -Djava.library.path=. Injector>out\injector.bat
echo start java -jar %JAVA_HOME%\demo\jfc\Notepad\notepad.jar Notepad >out\demo.bat
How do you like it?
You may download these sources from Xantorohara.blogspot.com samples