Showing posts with label WinAPI. Show all posts
Showing posts with label WinAPI. Show all posts

12 September, 2007

Java code injection via WinAPI's CreateRemoteThread function

There is the way to inject some functionality into JVM (Java Virtual Machine) from another process or another JVM.

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 a jbyte 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

29 August, 2007

Windows Service Simple Sample

Some years ago I was C/C++ developer and I wrote several windows services.
I know that writing of service programs is quite difficult for beginners.

In this post I'm publishing simple working example.
This service only beeps with one second's interval after starts.


service.c

#include <windows.h>

HANDLE hServerStopEvent = NULL;
VOID ServiceBody();
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv);
VOID WINAPI ServiceControlHandler(DWORD dwCtrlCode);
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);


SERVICE_STATUS ssStatus;
SERVICE_STATUS_HANDLE sshStatusHandle;

void _cdecl main(int argc, char **argv)
{
SERVICE_TABLE_ENTRY dispatchTable[] =
{{"", (LPSERVICE_MAIN_FUNCTION)ServiceMain }, { NULL, NULL }};
StartServiceCtrlDispatcher(dispatchTable);
}

void WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
sshStatusHandle = RegisterServiceCtrlHandler( "", ServiceControlHandler);

if (!sshStatusHandle)
goto cleanup;

ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode = 0;

if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
goto cleanup;

ServiceBody();

cleanup:
if (sshStatusHandle)
(VOID)ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
return;
}

VOID WINAPI ServiceControlHandler(DWORD dwCtrlCode)
{
if(dwCtrlCode==SERVICE_CONTROL_STOP)
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
if ( hServerStopEvent )
SetEvent(hServerStopEvent);
}
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}

BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
if (dwCurrentState == SERVICE_START_PENDING)
ssStatus.dwControlsAccepted = 0;
else
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWaitHint;

if ( ( dwCurrentState == SERVICE_RUNNING )
|| ( dwCurrentState == SERVICE_STOPPED ) )
ssStatus.dwCheckPoint = 0;
else
ssStatus.dwCheckPoint++;

return SetServiceStatus( sshStatusHandle, &ssStatus);
}


//This sample only beeps.
VOID ServiceBody ()
{
hServerStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hServerStopEvent)
goto cleanup;

if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
goto cleanup;

do
{
MessageBeep(-1);
} while (WaitForSingleObject(hServerStopEvent, 1000 )== WAIT_TIMEOUT);

cleanup:
if (hServerStopEvent)
CloseHandle(hServerStopEvent);
}



Script for compiling with Visual C++ 6.0:

make_vc6.bat
@call "D:\Program Files\Microsoft Visual Studio\VC98\Bin\vcvars32.bat"
@cl /nologo service.c user32.lib advapi32.lib
@del service.obj

If you use Visual C++ Express, you need additional Platform SDK from Microsoft.

Install (register) service via command:

service_create.bat
sc create "XQX Service" binPath= %CD%\service.exe


Start service via command:

service_start.bat
net start "XQX Service"


Stop service via command:

service_stop.bat
net stop "XQX Service"


Uninstall (remove) service via command:

service_delete.bat
sc delete "XQX Service"

09 August, 2007

HowTo remove service in Windows

Sometimes it is necessary to remove service from the Service List in the Windows Managment Console.
In the past I used program, which I compiled from the MSDN's sources (MSDN Library - October 2001: Samples\VC98\sdk\winbase\winnt\service).

But I found another way: Windows XP contains special program SC.exe, which can communicates with the Service Controller and installed services (start, stop, remove, create, query, etc.).
After that I use this command in my shell scripts.

E.g.: for removal of MySQL service, execute command:
sc delete MySQL
(! You may restore MySQL service via command mysqld-nt.exe --install)

But if you want to do this from your C++ program, you may use sample's sources from MSDN.

Part of these is listed below:


service.c
...
void CmdRemoveService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;

schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if ( schSCManager )
{
schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);

if (schService)
{
// try to stop the service
if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
{
_tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
Sleep( 1000 );

while( QueryServiceStatus( schService, &ssStatus ) )
{
if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
{
_tprintf(TEXT("."));
Sleep( 1000 );
}
else
break;
}

if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
_tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
else
_tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );

}

// now remove the service
if( DeleteService(schService) )
_tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
else
_tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));


CloseServiceHandle(schService);
}
else
_tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));

CloseServiceHandle(schSCManager);
}
else
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
}
...