Commit the changes to the java code
This commit is contained in:
parent
7596f934d1
commit
32b8353eb4
@ -8,6 +8,7 @@
|
|||||||
void JNICALL AgentThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
void JNICALL AgentThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
|
||||||
{
|
{
|
||||||
CJavaServer *s=new CJavaServer(jvmti_env, jni_env);
|
CJavaServer *s=new CJavaServer(jvmti_env, jni_env);
|
||||||
|
|
||||||
s->Start();
|
s->Start();
|
||||||
|
|
||||||
delete s;
|
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)
|
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved)
|
||||||
{
|
{
|
||||||
jvmtiEnv *env;
|
jvmtiEnv *env;
|
||||||
JNIEnv *jni;
|
JNIEnv *jni;
|
||||||
|
jvmtiError error;
|
||||||
|
|
||||||
jint r=vm->GetEnv((void **)&env, JVMTI_VERSION);
|
jint r=vm->GetEnv((void **)&env, JVMTI_VERSION);
|
||||||
if (r!=JNI_OK)
|
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");
|
jclass threadclass=jni->FindClass("java/lang/Thread");
|
||||||
if (threadclass==0)
|
if (threadclass==0)
|
||||||
{
|
{
|
||||||
|
@ -372,6 +372,10 @@
|
|||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\JavaEventServer.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\JavaServer.cpp"
|
RelativePath=".\JavaServer.cpp"
|
||||||
>
|
>
|
||||||
@ -422,6 +426,10 @@
|
|||||||
RelativePath=".\CEJVMTI.h"
|
RelativePath=".\CEJVMTI.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\JavaEventServer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\JavaServer.h"
|
RelativePath=".\JavaServer.h"
|
||||||
>
|
>
|
||||||
|
276
Cheat Engine/Java/CEJVMTI/CEJVMTI/JavaEventServer.cpp
Normal file
276
Cheat Engine/Java/CEJVMTI/CEJVMTI/JavaEventServer.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
31
Cheat Engine/Java/CEJVMTI/CEJVMTI/JavaEventServer.h
Normal file
31
Cheat Engine/Java/CEJVMTI/CEJVMTI/JavaEventServer.h
Normal 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;
|
@ -1,10 +1,35 @@
|
|||||||
#include "StdAfx.h"
|
#include "StdAfx.h"
|
||||||
#include "JavaServer.h"
|
#include "JavaServer.h"
|
||||||
|
|
||||||
|
|
||||||
CJavaServer::CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env)
|
CJavaServer::CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env)
|
||||||
{
|
{
|
||||||
//create a named pipe
|
//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)
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,36 @@
|
|||||||
#pragma once
|
#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
|
class CJavaServer : Pipe
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
wchar_t pipename[256];
|
||||||
jvmtiEnv* jvmti;
|
jvmtiEnv* jvmti;
|
||||||
JNIEnv* jni;
|
JNIEnv* jni;
|
||||||
|
|
||||||
wchar_t datapipename[256];
|
|
||||||
|
|
||||||
|
|
||||||
|
void CreatePipeandWaitForconnect(void);
|
||||||
public:
|
public:
|
||||||
CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env);
|
CJavaServer(jvmtiEnv* jvmti_env, JNIEnv* jni_env);
|
||||||
~CJavaServer(void);
|
~CJavaServer(void);
|
||||||
|
|
||||||
void Start(void);
|
void Start(void);
|
||||||
|
|
||||||
|
|
||||||
|
void StartCodeCallbacks(void);
|
||||||
|
void StopCodeCallbacks(void);
|
||||||
|
void GetLoadedClasses(void);
|
||||||
|
void DereferenceLocalObject(void);
|
||||||
|
void GetClassMethods(void);
|
||||||
|
void GetClassFields(void);
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
JAVACMD_STARTCODECALLBACKS=0
|
JAVACMD_STARTCODECALLBACKS=0
|
||||||
JAVACMD_STOPCODECALLBACKS=1
|
JAVACMD_STOPCODECALLBACKS=1
|
||||||
|
JAVACMD_GETLOADEDCLASSES=2
|
||||||
|
JAVACMD_DEREFERENCELOCALOBJECT=3
|
||||||
|
JAVACMD_GETCLASSMETHODS=4
|
||||||
|
JAVACMD_GETCLASSFIELDS=5
|
||||||
|
|
||||||
|
|
||||||
JAVACODECMD_METHODLOAD=0
|
JAVACODECMD_METHODLOAD=0
|
||||||
JAVACODECMD_METHODUNLOAD=1
|
JAVACODECMD_METHODUNLOAD=1
|
||||||
JAVACODECMD_DYNAMICCODEGENERATED=2
|
JAVACODECMD_DYNAMICCODEGENERATED=2
|
||||||
|
JAVACODECMD_TERMINATED=255
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
JAVA_TIMEOUT=500000 --500 seconds
|
||||||
|
|
||||||
|
|
||||||
function getFieldFromType(type, field, infloopprotection)
|
function getFieldFromType(type, field, infloopprotection)
|
||||||
@ -42,6 +51,10 @@ function CollectJavaSymbolsNonInjected(thread)
|
|||||||
|
|
||||||
|
|
||||||
s=readPointer("jvm.gHotSpotVMStructs")
|
s=readPointer("jvm.gHotSpotVMStructs")
|
||||||
|
if (s==nil) or (s==0) then
|
||||||
|
return --invalid JVM
|
||||||
|
end
|
||||||
|
|
||||||
VMStructEntryTypeNameOffset=readInteger("jvm.gHotSpotVMStructEntryTypeNameOffset")
|
VMStructEntryTypeNameOffset=readInteger("jvm.gHotSpotVMStructEntryTypeNameOffset")
|
||||||
VMStructEntryFieldNameOffset=readInteger("jvm.gHotSpotVMStructEntryFieldNameOffset")
|
VMStructEntryFieldNameOffset=readInteger("jvm.gHotSpotVMStructEntryFieldNameOffset")
|
||||||
VMStructEntryTypestringOffset=readInteger("jvm.gHotSpotVMStructEntryTypestringOffset")
|
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* typeName; // The type name containing the given field (example: "Klass")
|
||||||
const char* fieldName; // The field name within the type (example: "_name")
|
const char* fieldName; // The field name within the type (example: "_name")
|
||||||
@ -238,7 +253,7 @@ function CollectJavaSymbolsNonInjected(thread)
|
|||||||
CurrentPos=CurrentPos+CodeletSize
|
CurrentPos=CurrentPos+CodeletSize
|
||||||
end
|
end
|
||||||
|
|
||||||
|
JavaHotSpotFieldsLoaded=true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -252,18 +267,38 @@ function javaInjectAgent()
|
|||||||
|
|
||||||
createNativeThread(CollectJavaSymbolsNonInjected)
|
createNativeThread(CollectJavaSymbolsNonInjected)
|
||||||
|
|
||||||
|
|
||||||
if (JavaEventThread~=nil) then
|
|
||||||
JavaEventListener_Terminated=true
|
|
||||||
JavaEventThread.waitfor()
|
|
||||||
JavaEventThread=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if (javapipe ~= nil) then
|
if (javapipe ~= nil) then
|
||||||
javapipe.destroy()
|
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
|
javapipe=nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local alreadyinjected=false
|
||||||
|
|
||||||
|
if javaInjectedProcesses==nil then
|
||||||
|
javaInjectedProcesses={}
|
||||||
|
|
||||||
|
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([[
|
autoAssemble([[
|
||||||
globalalloc(bla,1024)
|
globalalloc(bla,1024)
|
||||||
|
|
||||||
@ -315,11 +350,17 @@ function javaInjectAgent()
|
|||||||
createthread(bla)
|
createthread(bla)
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
javaInjectedProcesses[getOpenedProcessID()]=true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--wait till attached
|
--wait till attached
|
||||||
|
|
||||||
|
local timeout=getTickCount()+JAVA_TIMEOUT
|
||||||
|
|
||||||
local timeout=getTickCount()+5000000; --5 seconds
|
|
||||||
while (javapipe==nil) and (getTickCount()<timeout) do
|
while (javapipe==nil) and (getTickCount()<timeout) do
|
||||||
javapipe=connectToPipe('cejavadc_pid'..getOpenedProcessID())
|
javapipe=connectToPipe('cejavadc_pid'..getOpenedProcessID())
|
||||||
end
|
end
|
||||||
@ -330,7 +371,9 @@ function javaInjectAgent()
|
|||||||
|
|
||||||
java_StartListeneningForEvents()
|
java_StartListeneningForEvents()
|
||||||
|
|
||||||
JavaSymbols.register()
|
JavaSymbols.register() --make these symbols available to all of cheat engine
|
||||||
|
|
||||||
|
return 1;
|
||||||
end
|
end
|
||||||
|
|
||||||
function JavaEventListener(thread)
|
function JavaEventListener(thread)
|
||||||
@ -342,7 +385,7 @@ function JavaEventListener(thread)
|
|||||||
local JavaEventPipe
|
local JavaEventPipe
|
||||||
|
|
||||||
|
|
||||||
local timeout=getTickCount()+5000000; --5 seconds
|
local timeout=getTickCount()+JAVA_TIMEOUT --5 seconds
|
||||||
while (JavaEventPipe==nil) and (getTickCount()<timeout) do
|
while (JavaEventPipe==nil) and (getTickCount()<timeout) do
|
||||||
JavaEventPipe=connectToPipe('cejavaevents_pid'..getOpenedProcessID())
|
JavaEventPipe=connectToPipe('cejavaevents_pid'..getOpenedProcessID())
|
||||||
end
|
end
|
||||||
@ -352,31 +395,57 @@ function JavaEventListener(thread)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
while JavaEventListener_Terminated==false do
|
while true do
|
||||||
local command=JavaEventPipe.readByte()
|
local command=JavaEventPipe.readByte()
|
||||||
if command==EVENTCMD_METHODLOAD then --methodload
|
if command==EVENTCMD_METHODLOAD then --methodload
|
||||||
|
|
||||||
|
local size1, size2, size3,ssize,classname, methodname, methodsig
|
||||||
|
|
||||||
local method=JavaEventPipe.readQword()
|
local method=JavaEventPipe.readQword()
|
||||||
local code_size=JavaEventPipe.readDword()
|
local code_size=JavaEventPipe.readDword()
|
||||||
local code_addr=JavaEventPipe.readQword()
|
local code_addr=JavaEventPipe.readQword()
|
||||||
local ssize=JavaEventPipe.readWord()
|
size1=JavaEventPipe.readWord()
|
||||||
local classname=JavaEventPipe.readString(ssize)
|
if (size1>0) then
|
||||||
ssize=JavaEventPipe.readWord()
|
classname=JavaEventPipe.readString(size1)
|
||||||
local methodname=JavaEventPipe.readString(ssize)
|
else
|
||||||
|
classname=''
|
||||||
|
end
|
||||||
|
|
||||||
ssize=JavaEventPipe.readWord()
|
size2=JavaEventPipe.readWord()
|
||||||
local methodsig=JavaEventPipe.readString(ssize)
|
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
|
elseif command==EVENTCMD_METHODUNLOAD then --methodunload
|
||||||
|
local method=JavaEventPipe.readQword()
|
||||||
|
local code_addr=JavaEventPipe.readQword()
|
||||||
|
|
||||||
print("EVENTCMD_METHODUNLOAD")
|
print("EVENTCMD_METHODUNLOAD")
|
||||||
|
JavaSymbols.deleteSymbol(code_addr)
|
||||||
--
|
--
|
||||||
elseif command==EVENTCMD_DYNAMICCODEGENERATED then --DynamicCodeGenerated
|
elseif command==EVENTCMD_DYNAMICCODEGENERATED then --DynamicCodeGenerated
|
||||||
local ssize
|
local ssize
|
||||||
@ -385,12 +454,16 @@ function JavaEventListener(thread)
|
|||||||
ssize=JavaEventPipe.readWord()
|
ssize=JavaEventPipe.readWord()
|
||||||
local name=JavaEventPipe.readString(ssize)
|
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
|
elseif command==nil then
|
||||||
print("Disconnected")
|
--print("Disconnected")
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
print("Unexpected event received") --synchronize isn't necesary for print as that function is designed to synchronize internally
|
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)
|
javapipe.writeByte(JAVACMD_STARTCODECALLBACKS)
|
||||||
|
|
||||||
|
|
||||||
--the javapipe will now be frozen until a the javaeventpipe makes an connection
|
--the javapipe will now be frozen until a javaeventpipe makes an connection
|
||||||
JavaEventListener_Terminated=false
|
createNativeThread(JavaEventListener);
|
||||||
JavaEventThread=createNativeThread(JavaEventListener);
|
|
||||||
|
|
||||||
local result=javapipe.readByte()==1
|
|
||||||
javapipe.unlock();
|
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
|
return result
|
||||||
end
|
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()
|
||||||
|
Loading…
Reference in New Issue
Block a user