Commit the changes to the java code

This commit is contained in:
cheatengine@gmail.com 2014-02-02 06:22:14 +00:00
parent 7596f934d1
commit 32b8353eb4
7 changed files with 1068 additions and 76 deletions

View File

@ -8,6 +8,7 @@
void JNICALL AgentThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
{
CJavaServer *s=new CJavaServer(jvmti_env, jni_env);
s->Start();
delete s;
@ -15,10 +16,22 @@ void JNICALL AgentThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
}
jvmtiIterationControl JNICALL initialHeapIterate(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
{
//OutputDebugStringA("Tagging object\n");
*tag_ptr=1;
return JVMTI_ITERATION_CONTINUE;
}
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved)
{
jvmtiEnv *env;
JNIEnv *jni;
jvmtiError error;
jint r=vm->GetEnv((void **)&env, JVMTI_VERSION);
if (r!=JNI_OK)
{
@ -34,6 +47,52 @@ JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved)
}
jvmtiCapabilities cap, wantedcap;
env->GetPotentialCapabilities(&cap);
if (cap.can_tag_objects)
{
env->GetCapabilities(&wantedcap);
wantedcap.can_tag_objects=1;
error=env->AddCapabilities(&wantedcap);
/*
if (error==JVMTI_ERROR_NONE)
{
error=env->IterateOverHeap(JVMTI_HEAP_OBJECT_EITHER, initialHeapIterate, NULL);
if (error==JVMTI_ERROR_NONE)
{
int i;
jlong tags[1];
jint count;
jobject *list;
jlong *taglist;
tags[0]=1;
error=env->GetObjectsWithTags(1, tags, &count, &list, &taglist);
for (i=0; i<count; i++)
{
jobject j1,j2;
j1=list[i];
j2=jni->NewGlobalRef(j1);
if (j2==NULL)
OutputDebugStringA("Failure\n");
}
}
}
*/
}
jclass threadclass=jni->FindClass("java/lang/Thread");
if (threadclass==0)
{

View File

@ -372,6 +372,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\JavaEventServer.cpp"
>
</File>
<File
RelativePath=".\JavaServer.cpp"
>
@ -422,6 +426,10 @@
RelativePath=".\CEJVMTI.h"
>
</File>
<File
RelativePath=".\JavaEventServer.h"
>
</File>
<File
RelativePath=".\JavaServer.h"
>

View File

@ -0,0 +1,276 @@
#include "StdAfx.h"
#include "JavaEventServer.h"
CJavaEventServer *old_eventserver=NULL;
CJavaEventServer *eventserver=NULL;
void JNICALL MethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size, const void* code_addr, jint map_length,
const jvmtiAddrLocationMap* map, const void* compile_info)
{
if (eventserver)
eventserver->MethodLoad(jvmti_env, method, code_size, code_addr);
}
void JNICALL MethodUnload(jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
{
if (eventserver)
eventserver->MethodUnload(jvmti_env, method, code_addr);
}
void JNICALL DynamicCodeGenerated(jvmtiEnv *jvmti_env, const char* name, const void* address, jint length)
{
if (eventserver)
eventserver->DynamicCodeGenerated(jvmti_env, name, address,length);
}
CJavaEventServer::CJavaEventServer(jvmtiEnv *jvmti_env)
{
jvmtiEventCallbacks callbacks;
jvmtiError error;
jvmtiCapabilities cap, wantedcap;
this->jvmti_env=jvmti_env;
if (eventserver) //extra check
{
CJavaEventServer *old=eventserver;
eventserver=NULL;
delete eventserver;
}
swprintf(pipename, 256,L"\\\\.\\pipe\\cejavaevents_pid%d", GetCurrentProcessId());
pipehandle=CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1,256*1024, 16, INFINITE, NULL);
ConnectNamedPipe(pipehandle, NULL);
eventserver=this;
jvmti_env->GetPotentialCapabilities(&cap);
if (cap.can_generate_compiled_method_load_events)
{
jvmti_env->GetCapabilities(&wantedcap);
wantedcap.can_generate_compiled_method_load_events=1;
error=jvmti_env->AddCapabilities(&wantedcap);
if (error!=JVMTI_ERROR_NONE)
{
OutputDebugStringA("Failure adding can_generate_compiled_method_load_events to my capabilities");
}
else
{
memset(&callbacks, 0, sizeof(callbacks));
callbacks.CompiledMethodLoad=::MethodLoad;
callbacks.CompiledMethodUnload=::MethodUnload;
callbacks.DynamicCodeGenerated=::DynamicCodeGenerated;
error=jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
jvmti_env->ForceGarbageCollection();
if (error==JVMTI_ERROR_NONE)
{
jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
error=jvmti_env->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD);
error=jvmti_env->GenerateEvents(JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
}
}
}
else
{
OutputDebugStringA("can_generate_compiled_method_load_events == FALSE");
}
}
CJavaEventServer::~CJavaEventServer(void)
{
Terminate();
}
void CJavaEventServer::MethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size, const void* code_addr)
{
/*
OutputDebugStringA("MethodLoad");
char *name=NULL, *sig=NULL, *gen=NULL;
char *classsig=NULL, *classgen=NULL;
jclass klass;
jvmti_env->GetMethodDeclaringClass(method, &klass);
jvmti_env->GetClassSignature(klass, &classsig, &classgen);
OutputDebugStringA(classsig);
jvmti_env->GetMethodName(method, &name, &sig, &gen);
OutputDebugStringA(name);
OutputDebugStringA("\n");
*/
Lock();
try
{
jclass klass;
char *name=NULL, *sig=NULL, *gen=NULL;
char *classsig=NULL, *classgen=NULL;
WORD len;
WriteByte(EVENTCMD_METHODLOAD);
WriteQword((UINT_PTR)method);
WriteDword(code_size);
WriteQword((UINT_PTR)code_addr);
jvmti_env->GetMethodDeclaringClass(method, &klass); //when this function returns jklass gets dereferenced. If this was the server I'd have to use DeleteLocalRef on this
jvmti_env->GetClassSignature(klass, &classsig, &classgen);
jvmti_env->GetMethodName(method, &name, &sig, &gen);
if (classsig)
{
len=strlen(classsig);
WriteWord(len);
if (len)
Write(classsig, len);
jvmti_env->Deallocate((unsigned char *)classsig);
}
else
WriteWord(0);
if (classgen)
jvmti_env->Deallocate((unsigned char *)classgen);
if (name)
{
len=strlen(name);
WriteWord(len);
if (len)
Write(name, len);
jvmti_env->Deallocate((unsigned char *)name);
}
else
WriteWord(0);
if (sig)
{
len=strlen(sig);
WriteWord(len);
if (len)
Write(sig, len);
jvmti_env->Deallocate((unsigned char *)sig);
}
else
WriteWord(0);
if (gen)
jvmti_env->Deallocate((unsigned char *)gen);
}
catch (char *e)
{
OutputDebugStringA(e);
//no connection yet
}
Unlock();
}
void CJavaEventServer::MethodUnload(jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
{
Lock();
try
{
WriteByte(EVENTCMD_METHODUNLOAD);
WriteQword((UINT_PTR)method);
WriteQword((UINT_PTR)code_addr);
}
catch (char *e)
{
OutputDebugStringA(e);
//no connection yet
}
Unlock();
}
void CJavaEventServer::DynamicCodeGenerated(jvmtiEnv *jvmti_env, const char* name, const void* address, jint length)
{
Lock();
try
{
WriteByte(EVENTCMD_DYNAMICCODEGENERATED);
WriteQword((UINT_PTR)address);
WriteDword(length);
WriteWord(strlen(name));
Write((void *)name, strlen(name));
}
catch (char *e)
{
OutputDebugStringA(e);
//no connection yet
}
Unlock();
}
void CJavaEventServer::Terminate(void)
{
jvmtiCapabilities caps;
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
ZeroMemory(&caps, sizeof(caps));
caps.can_generate_compiled_method_load_events=1;
jvmti_env->RelinquishCapabilities(&caps);
eventserver=NULL;
Lock();
try
{
WriteByte(EVENTCMD_TERMINATED);
}
catch (char *e)
{
OutputDebugStringA(e);
}
Unlock();
Sleep(500);
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "pipe.h"
//pipe for transmitting java events like method load/free
#define EVENTCMD_METHODLOAD 0
#define EVENTCMD_METHODUNLOAD 1
#define EVENTCMD_DYNAMICCODEGENERATED 2
#define EVENTCMD_TERMINATED 255
class CJavaEventServer :
public Pipe
{
private:
wchar_t pipename[256];
jvmtiEnv *jvmti_env;
public:
CJavaEventServer(jvmtiEnv *jvmti_env);
~CJavaEventServer(void);
void MethodLoad(jvmtiEnv *jvmti_env, jmethodID method, jint code_size, const void* code_addr);
void MethodUnload(jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr);
void DynamicCodeGenerated(jvmtiEnv *jvmti_env, const char* name, const void* address, jint length);
void Terminate(void);
};
extern CJavaEventServer *eventserver;
extern CJavaEventServer *old_eventserver;

View File

@ -1,10 +1,35 @@
#include "StdAfx.h"
#include "JavaServer.h"
CJavaServer::CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env)
{
//create a named pipe
swprintf(datapipename, 256,L"\\\\.\\pipe\\cejavadc_pid%d", GetCurrentProcessId());
jvmtiCapabilities cap;
this->jni=jni_env;
this->jvmti=jvmti_env;
jvmti->GetCapabilities(&cap);
swprintf(pipename, 256,L"\\\\.\\pipe\\cejavadc_pid%d", GetCurrentProcessId());
}
void CJavaServer::CreatePipeandWaitForconnect(void)
{
if ((pipehandle) && (pipehandle!=INVALID_HANDLE_VALUE))
{
CloseHandle(pipehandle);
pipehandle=0;
}
pipehandle=CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1,256*1024, 16, INFINITE, NULL);
ConnectNamedPipe(pipehandle, NULL);
}
CJavaServer::~CJavaServer(void)
@ -12,7 +37,275 @@ CJavaServer::~CJavaServer(void)
}
void CJavaServer::Start(void)
void CJavaServer::StartCodeCallbacks(void)
{
if (old_eventserver)
delete old_eventserver;
eventserver=new CJavaEventServer(jvmti);
}
void CJavaServer::StopCodeCallbacks(void)
{
if (eventserver)
delete eventserver;
}
void CJavaServer::GetLoadedClasses(void)
{
int i;
jint classcount;
jclass *classes;
if (jvmti->GetLoadedClasses(&classcount, &classes)==JVMTI_ERROR_NONE) //note: this creates to the returned classes. Should be managed
{
WriteDword(classcount);
for (i=0; i<classcount; i++)
{
char *sig=NULL;
char *gen=NULL;
WriteQword((UINT_PTR)classes[i]);
jvmti->SetTag(classes[i], i+1); //let's tag this class while we're at it
if (jvmti->GetClassSignature(classes[i], &sig, &gen)==JVMTI_ERROR_NONE)
{
int len;
if (sig)
{
len=(int)strlen(sig);
WriteWord(len);
Write(sig, len);
jvmti->Deallocate((unsigned char *)sig);
}
else
WriteWord(0);
if (gen)
{
len=(int)strlen(gen);
WriteWord(len);
Write(gen, len);
jvmti->Deallocate((unsigned char *)gen);
}
else
WriteWord(0);
}
else
{
WriteWord(0);
WriteWord(0);
}
}
jvmti->Deallocate((unsigned char *)classes);
}
else
WriteDword(0); //0 classes
}
void CJavaServer::DereferenceLocalObject(void)
{
jobject object;
object=(jobject)ReadQword();
jni->DeleteLocalRef(object);
}
void CJavaServer::GetClassMethods(void)
{
jclass klass=(jclass)ReadQword();
jint count;
jmethodID *methods=NULL;
if (jvmti->GetClassMethods(klass, &count, &methods)==JVMTI_ERROR_NONE)
{
int i;
WriteDword(count);
for (i=0; i<count; i++)
{
int len;
char *name, *sig, *gen;
WriteQword(UINT64(methods[i]));
if (jvmti->GetMethodName(methods[i], &name, &sig, &gen)==JVMTI_ERROR_NONE)
{
if (name)
{
len=(int)strlen(name);
WriteWord(len);
Write(name, len);
jvmti->Deallocate((unsigned char *)name);
}
else
WriteWord(0);
if (sig)
{
len=(int)strlen(sig);
WriteWord(len);
Write(sig, len);
jvmti->Deallocate((unsigned char *)sig);
}
else
WriteWord(0);
if (gen)
{
len=(int)strlen(gen);
WriteWord(len);
Write(gen, len);
jvmti->Deallocate((unsigned char *)gen);
}
else
WriteWord(0);
}
else
{
WriteWord(0);
WriteWord(0);
WriteWord(0);
}
}
jvmti->Deallocate((unsigned char *)methods);
}
else
WriteDword(0);
}
void CJavaServer::GetClassFields(void)
{
jint count;
jfieldID *fields=NULL;
jclass klass=(jclass)ReadQword();
if (jvmti->GetClassFields(klass, &count, &fields)==JVMTI_ERROR_NONE)
{
int i;
WriteDword(count);
for (i=0; i<count; i++)
{
int len;
char *name=NULL;
char *sig=NULL;
char *gen=NULL;
WriteQword((UINT_PTR)fields[i]);
if (jvmti->GetFieldName(klass, fields[i], &name, &sig, &gen)==JVMTI_ERROR_NONE)
{
if (name)
{
len=(int)strlen(name);
WriteWord(len);
Write(name, len);
jvmti->Deallocate((unsigned char *)name);
}
else
WriteWord(0);
if (sig)
{
len=(int)strlen(sig);
WriteWord(len);
Write(sig, len);
jvmti->Deallocate((unsigned char *)sig);
}
else
WriteWord(0);
if (gen)
{
len=(int)strlen(gen);
WriteWord(len);
Write(gen, len);
jvmti->Deallocate((unsigned char *)gen);
}
else
WriteWord(0);
}
else
{
WriteWord(0);
WriteWord(0);
WriteWord(0);
}
}
}
}
void CJavaServer::Start(void)
{
BYTE command;
while (TRUE)
{
CreatePipeandWaitForconnect();
try
{
while (TRUE)
{
command=ReadByte();
switch (command)
{
case JAVACMD_STARTCODECALLBACKS:
StartCodeCallbacks();
break;
case JAVACMD_STOPCODECALLBACKS:
StopCodeCallbacks();
break;
case JAVACMD_GETLOADEDCLASSES:
GetLoadedClasses();
break;
case JAVACMD_DEREFERENCELOCALOBJECT:
DereferenceLocalObject();
break;
case JAVACMD_GETCLASSMETHODS:
GetClassMethods();
break;
case JAVACMD_GETCLASSFIELDS:
GetClassFields();
break;
}
}
}
catch (char *e)
{
//Pipe error, or something else that wasn't caught. Exit the connection and start over
OutputDebugStringA("Pipe error:\n");
OutputDebugStringA(e);
old_eventserver=eventserver;
eventserver=NULL;
if (old_eventserver)
old_eventserver->Terminate();
}
catch (...)
{
OutputDebugStringA("Unexpected pipe error\n");
old_eventserver=eventserver;
eventserver=NULL;
}
}
}

View File

@ -1,18 +1,36 @@
#pragma once
#include "JavaEventServer.h"
#define JAVACMD_STARTCODECALLBACKS 0
#define JAVACMD_STOPCODECALLBACKS 1
#define JAVACMD_GETLOADEDCLASSES 2
#define JAVACMD_DEREFERENCELOCALOBJECT 3
#define JAVACMD_GETCLASSMETHODS 4
#define JAVACMD_GETCLASSFIELDS 5
class CJavaServer : Pipe
{
private:
wchar_t pipename[256];
jvmtiEnv* jvmti;
JNIEnv* jni;
wchar_t datapipename[256];
void CreatePipeandWaitForconnect(void);
public:
CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env);
~CJavaServer(void);
void Start(void);
void StartCodeCallbacks(void);
void StopCodeCallbacks(void);
void GetLoadedClasses(void);
void DereferenceLocalObject(void);
void GetClassMethods(void);
void GetClassFields(void);
};

View File

@ -1,10 +1,19 @@
JAVACMD_STARTCODECALLBACKS=0
JAVACMD_STOPCODECALLBACKS=1
JAVACMD_GETLOADEDCLASSES=2
JAVACMD_DEREFERENCELOCALOBJECT=3
JAVACMD_GETCLASSMETHODS=4
JAVACMD_GETCLASSFIELDS=5
JAVACODECMD_METHODLOAD=0
JAVACODECMD_METHODUNLOAD=1
JAVACODECMD_DYNAMICCODEGENERATED=2
JAVACODECMD_TERMINATED=255
JAVA_TIMEOUT=500000 --500 seconds
function getFieldFromType(type, field, infloopprotection)
@ -42,6 +51,10 @@ function CollectJavaSymbolsNonInjected(thread)
s=readPointer("jvm.gHotSpotVMStructs")
if (s==nil) or (s==0) then
return --invalid JVM
end
VMStructEntryTypeNameOffset=readInteger("jvm.gHotSpotVMStructEntryTypeNameOffset")
VMStructEntryFieldNameOffset=readInteger("jvm.gHotSpotVMStructEntryFieldNameOffset")
VMStructEntryTypestringOffset=readInteger("jvm.gHotSpotVMStructEntryTypestringOffset")
@ -54,6 +67,8 @@ function CollectJavaSymbolsNonInjected(thread)
--[[
const char* typeName; // The type name containing the given field (example: "Klass")
const char* fieldName; // The field name within the type (example: "_name")
@ -238,7 +253,7 @@ function CollectJavaSymbolsNonInjected(thread)
CurrentPos=CurrentPos+CodeletSize
end
JavaHotSpotFieldsLoaded=true
end
@ -252,74 +267,100 @@ function javaInjectAgent()
createNativeThread(CollectJavaSymbolsNonInjected)
if (JavaEventThread~=nil) then
JavaEventListener_Terminated=true
JavaEventThread.waitfor()
JavaEventThread=nil
end
if (javapipe~=nil) then
javapipe.destroy()
if (javapipe ~= nil) then
javapipe.destroy() --this will cause the pipe listener to destroy the java event server, which will stop the javaeventthread (so no need to wait for that)
javapipe=nil
end
autoAssemble([[
globalalloc(bla,1024)
globalalloc(cmd,16)
globalalloc(arg0,256)
globalalloc(arg1,256)
globalalloc(arg2,256)
globalalloc(result,4)
globalalloc(pipename,256)
cmd:
db 'load',0
arg0:
db 'F:\svn\Cheat Engine\bin\autorun\dlls\CEJVMTI64',0
arg1:
db 0
arg2:
db 0
pipename:
db '\\.\pipe\cejavapipe',0
bla:
sub rsp,8
sub rsp,30
local alreadyinjected=false
mov rcx,cmd
mov rdx,arg0
mov r8,arg1
mov r9,arg2
if javaInjectedProcesses==nil then
javaInjectedProcesses={}
mov [rsp],cmd
mov [rsp+8],arg0
mov [rsp+10],arg1
mov [rsp+18],arg2
mov [rsp+20],pipename
local oldstate=errorOnLookupFailure(false)
local address=getAddress('CEJVMTI64.dll')
if (address~=nil) and (address~=0) then
javaInjectedProcesses[getOpenedProcessID()]=true
alreadyinjected=true
print("opened a process with the JVMTI agent already running")
end
errorOnLookupFailure(oldstate)
else
--check if already injected
alreadyinjected=javaInjectedProcesses[getOpenedProcessID()]==true
end
if (alreadyinjected==false) then
autoAssemble([[
globalalloc(bla,1024)
globalalloc(cmd,16)
globalalloc(arg0,256)
globalalloc(arg1,256)
globalalloc(arg2,256)
globalalloc(result,4)
globalalloc(pipename,256)
cmd:
db 'load',0
arg0:
db 'F:\svn\Cheat Engine\bin\autorun\dlls\CEJVMTI64',0
arg1:
db 0
arg2:
db 0
pipename:
db '\\.\pipe\cejavapipe',0
bla:
sub rsp,8
sub rsp,30
mov rcx,cmd
mov rdx,arg0
mov r8,arg1
mov r9,arg2
mov [rsp],cmd
mov [rsp+8],arg0
mov [rsp+10],arg1
mov [rsp+18],arg2
mov [rsp+20],pipename
call jvm.JVM_EnqueueOperation
mov [result],eax
add rsp,38
ret
createthread(bla)
]])
javaInjectedProcesses[getOpenedProcessID()]=true
end
call jvm.JVM_EnqueueOperation
mov [result],eax
add rsp,38
ret
createthread(bla)
]])
--wait till attached
local timeout=getTickCount()+5000000; --5 seconds
local timeout=getTickCount()+JAVA_TIMEOUT
while (javapipe==nil) and (getTickCount()<timeout) do
javapipe=connectToPipe('cejavadc_pid'..getOpenedProcessID())
end
@ -330,7 +371,9 @@ function javaInjectAgent()
java_StartListeneningForEvents()
JavaSymbols.register()
JavaSymbols.register() --make these symbols available to all of cheat engine
return 1;
end
function JavaEventListener(thread)
@ -342,7 +385,7 @@ function JavaEventListener(thread)
local JavaEventPipe
local timeout=getTickCount()+5000000; --5 seconds
local timeout=getTickCount()+JAVA_TIMEOUT --5 seconds
while (JavaEventPipe==nil) and (getTickCount()<timeout) do
JavaEventPipe=connectToPipe('cejavaevents_pid'..getOpenedProcessID())
end
@ -352,31 +395,57 @@ function JavaEventListener(thread)
end
while JavaEventListener_Terminated==false do
while true do
local command=JavaEventPipe.readByte()
if command==EVENTCMD_METHODLOAD then --methodload
local size1, size2, size3,ssize,classname, methodname, methodsig
local method=JavaEventPipe.readQword()
local code_size=JavaEventPipe.readDword()
local code_addr=JavaEventPipe.readQword()
local ssize=JavaEventPipe.readWord()
local classname=JavaEventPipe.readString(ssize)
ssize=JavaEventPipe.readWord()
local methodname=JavaEventPipe.readString(ssize)
size1=JavaEventPipe.readWord()
if (size1>0) then
classname=JavaEventPipe.readString(size1)
else
classname=''
end
ssize=JavaEventPipe.readWord()
local methodsig=JavaEventPipe.readString(ssize)
size2=JavaEventPipe.readWord()
if (size2>0) then
methodname=JavaEventPipe.readString(size2)
else
methodname=''
end
local name=classname.."."..methodname..methodsig
size3=JavaEventPipe.readWord()
if (size3>0) then
methodsig=JavaEventPipe.readString(size3)
else
methodsig=''
end
local endpos=classname:match'^.*();'
if endpos~=nil then
classname=string.sub(classname,1,endpos-1)
end
local name=classname.."::"..methodname..methodsig
print(string.format("Methodload: %s - (%x) %x-%x", name, method, code_addr, code_addr+code_size))
JavaSymbols.addSymbol("",classname.."::"..methodname,code_addr,code_size)
--print(string.format("s1=%d s2=%d s3=%d (cn=%s mn=%s ms=%s)", size1,size2,size3, classname, methodname, methodsig))
--print(string.format("Methodload: %s - (%x) %x-%x", name, method, code_addr, code_addr+code_size))
--
elseif command==EVENTCMD_METHODUNLOAD then --methodunload
local method=JavaEventPipe.readQword()
local code_addr=JavaEventPipe.readQword()
print("EVENTCMD_METHODUNLOAD")
JavaSymbols.deleteSymbol(code_addr)
--
elseif command==EVENTCMD_DYNAMICCODEGENERATED then --DynamicCodeGenerated
local ssize
@ -385,12 +454,16 @@ function JavaEventListener(thread)
ssize=JavaEventPipe.readWord()
local name=JavaEventPipe.readString(ssize)
print(string.format("DynamicCode: %s - %x-%x", name, address, address+length))
--print(string.format("DynamicCode: %s - %x-%x", name, address, address+length))
JavaSymbols.addSymbol("",name,address,length)
--
elseif command==JAVACODECMD_TERMINATED then
--print("eventserver terminated")
break
elseif command==nil then
print("Disconnected")
--print("Disconnected")
break
else
print("Unexpected event received") --synchronize isn't necesary for print as that function is designed to synchronize internally
@ -406,12 +479,246 @@ function java_StartListeneningForEvents()
javapipe.writeByte(JAVACMD_STARTCODECALLBACKS)
--the javapipe will now be frozen until a the javaeventpipe makes an connection
JavaEventListener_Terminated=false
JavaEventThread=createNativeThread(JavaEventListener);
--the javapipe will now be frozen until a javaeventpipe makes an connection
createNativeThread(JavaEventListener);
local result=javapipe.readByte()==1
javapipe.unlock();
end
function java_getLoadedClasses()
javapipe.lock()
javapipe.writeByte(JAVACMD_GETLOADEDCLASSES)
local classcount=javapipe.readDword()
local classes={}
if (classcount==nil) then
return nil
end
if classcount>0 then
local i=0
local length
for i=1,classcount do
classes[i]={}
classes[i].jclass=javapipe.readQword() --this is a pointer to a pointer to java.lang.class. To get the offset where klass is stored use getFieldFromType("java_lang_Class", "_klass_offset") (The klass contains a _fields field which points to a array which contains the offset of the fields. Might be useful)
length=javapipe.readWord()
classes[i].signature=javapipe.readString(length);
length=javapipe.readWord()
classes[i].generic=javapipe.readString(length);
end
end
javapipe.unlock()
return classes
end
function java_dereferenceLocalObject(object)
javapipe.lock()
javapipe.writeByte(JAVACMD_DEREFERENCELOCALOBJECT)
javapipe.writeQword(object)
javapipe.unlock()
end
function java_cleanClasslist(classlist)
local i
for i=1, #classlist do
java_dereferenceLocalObject(classlist[i].jclass)
end
end
function java_getClassMethods(class)
javapipe.lock()
javapipe.writeByte(JAVACMD_GETCLASSMETHODS)
javapipe.writeQword(class)
local count=javapipe.readDword()
local i
local result={}
local length
for i=1,count do
result[i]={}
result[i].jmethodid=javapipe.readQword()
length=javapipe.readWord()
result[i].name=javapipe.readString(length)
length=javapipe.readWord()
result[i].signature=javapipe.readString(length)
length=javapipe.readWord()
result[i].generic=javapipe.readString(length)
end
javapipe.unlock()
return result
end
function java_getClassFields(class)
javapipe.lock()
javapipe.writeByte(JAVACMD_GETCLASSFIELDS)
javapipe.writeQword(class)
local count=javapipe.readDword()
local i
local result={}
local length
for i=1,count do
result[i]={}
result[i].jfieldid=javapipe.readQword()
length=javapipe.readWord()
result[i].name=javapipe.readString(length)
length=javapipe.readWord()
result[i].signature=javapipe.readString(length)
length=javapipe.readWord()
result[i].generic=javapipe.readString(length)
end
javapipe.unlock()
return result
end
function miJavaActivateClick(sender)
javaInjectAgent()
end
function javaForm_treeviewExpanding(sender, node)
local allow=true
print("javaForm_treeviewExpanding "..node.level)
if node.Level==0 then
if node.Count==0 then
--expand the class this node describes
local jklass=node.Data
local methods=java_getClassMethods(jklass);
local fields=java_getClassFields(jklass);
local i
for i=1, #fields do
node.add(string.format("%x: %s: %s (%s)", fields[i].jfieldid, fields[i].name, fields[i].signature,fields[i].generic))
end
node.add('---');
for i=1, #methods do
node.add(string.format("%x: %s(%s) %s", methods[i].jmethodid, methods[i].name, methods[i].signature, methods[i].generic))
end
--java_getClassFields(jklass);
end
end
return allow
end
function miJavaDissectClick(sender)
--I coudl also implement the same method as mono, but as an example I'll be creating the form with code only
if (javaForm==nil) then
javaForm={}
javaForm.form=createForm()
javaForm.form.Borderstyle=bsSizeable
javaForm.treeview=createTreeview(javaForm.form)
javaForm.treeview.align=alClient
javaForm.treeview.OnExpanding=javaForm_treeviewExpanding
end
if (java_classlist~=nil) then
java_cleanClasslist(java_classlist) --prevent a memory leak
end
java_classlist=java_getLoadedClasses()
if (java_classlist~=nil) then
local i
for i=1,#java_classlist do
local node=javaForm.treeview.Items.Add(string.format("%x : %s (%s)", java_classlist[i].jclass, java_classlist[i].signature, java_classlist[i].generic ))
node.Data=java_classlist[i].jclass
node.HasChildren=true
end
end
javaForm.form.show()
end
function java_OpenProcessAfterwards()
local usesjava=false
local m=enumModules()
local i
java_classlist=nil
for i=1, #m do
if m[i].Name=='jvm.dll' then
usesjava=true
break
end
end
if usesjava then
if (miJavaTopMenuItem==nil) then
local mfm=getMainForm().Menu
local mi
miJavaTopMenuItem=createMenuItem(mfm)
miJavaTopMenuItem.Caption="Java"
mfm.Items.insert(mfm.Items.Count-1, miJavaTopMenuItem) --add it before help
mi=createMenuItem(miJavaTopMenuItem)
mi.Caption="Activate java features"
mi.OnClick=miJavaActivateClick
miJavaTopMenuItem.Add(mi)
mi=createMenuItem(miJavaTopMenuItem)
mi.Caption="Dissect java"
mi.Shortcut="Ctrl+Alt+J"
mi.OnClick=miJavaDissectClick
miJavaTopMenuItem.Add(mi)
end
end
end
function java_OpenProcess(processid)
if java_oldOnOpenProcess~=nil then
java_oldOnOpenProcess(processid)
end
synchronize(java_OpenProcessAfterwards) --call this function when the whole OpenProcess routine is done (next sync check)
end
function javaAA_USEJAVA(parameters, syntaxcheckonly)
--called whenever an auto assembler script encounters the USEMONO() line
--the value you return will be placed instead of the given line
--In this case, returning a empty string is fine
--Special behaviour: Returning nil, with a secondary parameter being a string, will raise an exception on the auto assembler with that string
if (syntaxcheckonly==false) and (javaInjectAgent()==0) then
return nil,"The java handler failed to initialize"
end
return "" --return an empty string (removes it from the internal aa assemble list)
end
function java_initialize()
--register a function to be called when a process is opened
if (java_init1==nil) then
java_init1=true
java_oldOnOpenProcess=onOpenProcess
onOpenProcess=java_OpenProcess
registerAutoAssemblerCommand("USEJAVA", javaAA_USEJAVA)
end
end
java_initialize()