418 lines
12 KiB
Lua
418 lines
12 KiB
Lua
JAVACMD_STARTCODECALLBACKS=0
|
|
JAVACMD_STOPCODECALLBACKS=1
|
|
|
|
|
|
JAVACODECMD_METHODLOAD=0
|
|
JAVACODECMD_METHODUNLOAD=1
|
|
JAVACODECMD_DYNAMICCODEGENERATED=2
|
|
|
|
|
|
function getFieldFromType(type, field, infloopprotection)
|
|
if type==nil then return nil end
|
|
|
|
if infloopprotection==nil then
|
|
infloopprotection=0
|
|
else
|
|
infloopprotection=infloopprotection+1
|
|
if infloopprotection>20 then
|
|
return nil
|
|
end
|
|
end
|
|
|
|
type=type:gsub("<.->(.-)","<%1>") --replace the <xxx> part with <>
|
|
local Struct=JavaStructs[type]
|
|
|
|
if (Struct==nil) or (Struct[field]==nil) then
|
|
return getFieldFromType(JavaTypes[type].Alternate, field, infloopprotection) --check the super type if that one has fields
|
|
else
|
|
return Struct[field]
|
|
end
|
|
|
|
end
|
|
|
|
function getKlassFromObject(object)
|
|
return readQword(object+getFieldFromType("oopDesc","_metadata._klass").Offset)+JavaTypes["oopDesc"].Size
|
|
end
|
|
|
|
function CollectJavaSymbolsNonInjected(thread)
|
|
JavaStructs={}
|
|
JavaTypes={}
|
|
|
|
local s,s2
|
|
|
|
|
|
s=readPointer("jvm.gHotSpotVMStructs")
|
|
VMStructEntryTypeNameOffset=readInteger("jvm.gHotSpotVMStructEntryTypeNameOffset")
|
|
VMStructEntryFieldNameOffset=readInteger("jvm.gHotSpotVMStructEntryFieldNameOffset")
|
|
VMStructEntryTypestringOffset=readInteger("jvm.gHotSpotVMStructEntryTypestringOffset")
|
|
VMStructEntryIsStaticOffset=readInteger("jvm.gHotSpotVMStructEntryIsStaticOffset")
|
|
VMStructEntryOffsetOffset=readInteger("jvm.gHotSpotVMStructEntryOffsetOffset")
|
|
VMStructEntryAddressOffset=readInteger("jvm.gHotSpotVMStructEntryAddressOffset")
|
|
VMStructEntryArrayStride=readInteger("jvm.gHotSpotVMStructEntryArrayStride")
|
|
|
|
|
|
|
|
|
|
|
|
--[[
|
|
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* Typestring; // Quoted name of the type of this field (example: "Symbol*";
|
|
// parsed in Java to ensure type correctness
|
|
int32_t isStatic; // Indicates whether following field is an offset or an address
|
|
uint64_t offset; // Offset of field within structure; only used for nonstatic fields
|
|
void* address; // Address of field; only used for static fields
|
|
// ("offset" can not be reused because of apparent SparcWorks compiler bug
|
|
// in generation of initializer data)
|
|
--]]
|
|
|
|
|
|
|
|
|
|
while readString(readQword(s+VMStructEntryTypeNameOffset))~=nil do
|
|
local a,b,c,d;
|
|
a=readString(readPointer(s+VMStructEntryTypeNameOffset),255)
|
|
b=readString(readPointer(s+VMStructEntryFieldNameOffset),255)
|
|
c=readString(readPointer(s+VMStructEntryTypestringOffset),255)
|
|
|
|
d=readPointer(s+VMStructEntryIsStaticOffset)
|
|
|
|
if a and b and c then
|
|
if JavaStructs[a]==nil then
|
|
JavaStructs[a]={}
|
|
end
|
|
|
|
JavaStructs[a][b]={}
|
|
JavaStructs[a][b].Typestring=c
|
|
|
|
if d==0 then
|
|
JavaStructs[a][b].Offset=readPointer(s+VMStructEntryOffsetOffset)
|
|
else
|
|
JavaStructs[a][b].Address=readPointer(s+VMStructEntryAddressOffset)
|
|
end
|
|
|
|
|
|
|
|
--if d~=0 then
|
|
-- print(a.." - "..b.." - "..c.." : "..string.format("%x ( %x )",readPointer(s+VMStructEntryAddressOffset), readPointer(readPointer(s+VMStructEntryAddressOffset)) ))
|
|
--else
|
|
-- print(a.." - "..b.." - "..c.." : "..string.format("%x",readPointer(s+VMStructEntryOffsetOffset)))
|
|
--end
|
|
end
|
|
s=s+VMStructEntryArrayStride
|
|
end
|
|
|
|
|
|
|
|
--print("--------------------------------------------------------------------------------")
|
|
|
|
|
|
s2=readPointer("jvm.gHotSpotVMTypes")
|
|
VMTypeEntryTypeNameOffset=readInteger("jvm.gHotSpotVMTypeEntryTypeNameOffset")
|
|
VMTypeEntrySuperclassNameOffset=readInteger("jvm.gHotSpotVMTypeEntrySuperclassNameOffset")
|
|
VMTypeEntryIsOopTypeOffset=readInteger("jvm.gHotSpotVMTypeEntryIsOopTypeOffset")
|
|
VMTypeEntryIsIntegerTypeOffset=readInteger("jvm.gHotSpotVMTypeEntryIsIntegerTypeOffset")
|
|
VMTypeEntryIsUnsignedOffset=readInteger("jvm.gHotSpotVMTypeEntryIsUnsignedOffset")
|
|
VMTypeEntrySizeOffset=readInteger("jvm.gHotSpotVMTypeEntrySizeOffset")
|
|
VMTypeEntryArrayStride=readInteger("jvm.gHotSpotVMTypeEntryArrayStride")
|
|
|
|
|
|
|
|
|
|
|
|
while readString(readPointer(s2+VMTypeEntryTypeNameOffset))~=nil do
|
|
local a,b,isInteger, isOop, size;
|
|
a=readString(readPointer(s2+VMTypeEntryTypeNameOffset),255)
|
|
b=readString(readPointer(s2+VMTypeEntrySuperclassNameOffset),255)
|
|
|
|
|
|
isOop=readInteger(s2+VMTypeEntryIsOopTypeOffset)
|
|
isInteger=readInteger(s2+VMTypeEntryIsIntegerTypeOffset)
|
|
size=readInteger(s2+VMTypeEntrySizeOffset)
|
|
|
|
|
|
if a then
|
|
local _a,_b
|
|
_a=a:gsub("<.->(.-)","<%1>")
|
|
JavaTypes[_a]={}
|
|
JavaTypes[_a].Size=size
|
|
|
|
if b then
|
|
_b=b:gsub("<.->(.-)","<%1>")
|
|
JavaTypes[_a].Alternate=_b
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local r=''
|
|
if a then
|
|
r=r..a
|
|
end
|
|
|
|
if b then
|
|
r=r.." - "..b
|
|
end
|
|
|
|
|
|
--print(r.." (size="..size..")")
|
|
s2=s2+VMTypeEntryArrayStride
|
|
end
|
|
|
|
|
|
-- print("-------------------------------------------------")
|
|
s=readPointer("jvm.gHotSpotVMIntConstants")
|
|
VMIntConstantEntryNameOffset=readInteger("jvm.gHotSpotVMIntConstantEntryNameOffset")
|
|
VMIntConstantEntryValueOffset=readInteger("jvm.gHotSpotVMIntConstantEntryValueOffset")
|
|
VMIntConstantEntryArrayStride=readInteger("jvm.gHotSpotVMIntConstantEntryArrayStride")
|
|
|
|
|
|
while readString(readPointer(s+VMIntConstantEntryNameOffset))~=nil do
|
|
local name,value
|
|
name=readString(readPointer(s+VMIntConstantEntryNameOffset))
|
|
value=readInteger(s+VMIntConstantEntryValueOffset)
|
|
|
|
--print(name.."="..string.format("%x",value))
|
|
|
|
s=s+VMIntConstantEntryArrayStride
|
|
end
|
|
|
|
--print("-------------------------------------------------")
|
|
s=readPointer("jvm.gHotSpotVMLongConstants")
|
|
VMLongConstantEntryNameOffset=readInteger("jvm.gHotSpotVMLongConstantEntryNameOffset")
|
|
VMLongConstantEntryValueOffset=readInteger("jvm.gHotSpotVMLongConstantEntryValueOffset")
|
|
VMLongConstantEntryArrayStride=readInteger("jvm.gHotSpotVMLongConstantEntryArrayStride")
|
|
|
|
while readString(readPointer(s+VMLongConstantEntryNameOffset))~=nil do
|
|
local name,value
|
|
name=readString(readPointer(s+VMLongConstantEntryNameOffset))
|
|
value=readQword(s+VMLongConstantEntryValueOffset)
|
|
|
|
--print(name.."="..string.format("%x",value))
|
|
|
|
s=s+VMLongConstantEntryArrayStride
|
|
end
|
|
|
|
|
|
--Fetch the interpreter functions
|
|
local InterpreterFunctionList=getFieldFromType('AbstractInterpreter', '_code').Address
|
|
local BufferOffset=getFieldFromType('StubQueue', '_stub_buffer').Offset
|
|
local QueueEndOffset=getFieldFromType('StubQueue', '_queue_end').Offset
|
|
|
|
local InterpreterCodeletSizeOffset=getFieldFromType('InterpreterCodelet', '_size').Offset
|
|
local InterpreterCodeletDescriptionOffset=getFieldFromType('InterpreterCodelet', '_description').Offset
|
|
local InterpreterCodeletHeaderSize=JavaTypes['InterpreterCodelet'].Size
|
|
local InterpreterCodeletHeaderSizeAligned
|
|
|
|
InterpreterCodeletHeaderSizeAligned=InterpreterCodeletHeaderSize
|
|
|
|
if targetIs64Bit() then
|
|
--increase InterpreterCodeletHeaderSizeAligned so it's dividable by 32
|
|
if (InterpreterCodeletHeaderSizeAligned % 32)~=0 then
|
|
InterpreterCodeletHeaderSizeAligned=(InterpreterCodeletHeaderSizeAligned+32) - (InterpreterCodeletHeaderSizeAligned % 32)
|
|
end
|
|
else
|
|
--increase InterpreterCodeletHeaderSizeAligned so it's dividable by 16
|
|
if (InterpreterCodeletHeaderSizeAligned % 16)~=0 then
|
|
InterpreterCodeletHeaderSizeAligned=(InterpreterCodeletHeaderSizeAligned+16) - (InterpreterCodeletHeaderSizeAligned % 16)
|
|
end
|
|
end
|
|
|
|
StubQueueAddress=readPointer(InterpreterFunctionList)
|
|
BufferStart=readPointer(StubQueueAddress+BufferOffset)
|
|
BufferEnd=BufferStart+readInteger(StubQueueAddress+QueueEndOffset)
|
|
|
|
CurrentPos=BufferStart
|
|
while (CurrentPos<BufferEnd) do
|
|
local CodeletSize=readInteger(CurrentPos+InterpreterCodeletSizeOffset)
|
|
local Description=readString(readInteger(CurrentPos+InterpreterCodeletDescriptionOffset))
|
|
local Codestart=CurrentPos+InterpreterCodeletHeaderSizeAligned
|
|
|
|
--print(string.format("%x = %s", Codestart, Description))
|
|
|
|
JavaSymbols.addSymbol("","jInterpreter_"..Description,Codestart, CodeletSize-InterpreterCodeletHeaderSizeAligned)
|
|
|
|
|
|
|
|
CurrentPos=CurrentPos+CodeletSize
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
function javaInjectAgent()
|
|
if (JavaSymbols==nil) then
|
|
JavaSymbols=createSymbolList()
|
|
else
|
|
JavaSymbols.clear()
|
|
end
|
|
|
|
|
|
createNativeThread(CollectJavaSymbolsNonInjected)
|
|
|
|
|
|
if (JavaEventThread~=nil) then
|
|
JavaEventListener_Terminated=true
|
|
JavaEventThread.waitfor()
|
|
JavaEventThread=nil
|
|
end
|
|
|
|
if (javapipe~=nil) then
|
|
javapipe.destroy()
|
|
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
|
|
|
|
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)
|
|
]])
|
|
|
|
--wait till attached
|
|
|
|
|
|
|
|
local timeout=getTickCount()+5000000; --5 seconds
|
|
while (javapipe==nil) and (getTickCount()<timeout) do
|
|
javapipe=connectToPipe('cejavadc_pid'..getOpenedProcessID())
|
|
end
|
|
|
|
if (javapipe==nil) then
|
|
return 0 --failure
|
|
end
|
|
|
|
java_StartListeneningForEvents()
|
|
|
|
JavaSymbols.register()
|
|
end
|
|
|
|
function JavaEventListener(thread)
|
|
--this code runs in another thread
|
|
local EVENTCMD_METHODLOAD=0
|
|
local EVENTCMD_METHODUNLOAD=1
|
|
local EVENTCMD_DYNAMICCODEGENERATED=2
|
|
|
|
local JavaEventPipe
|
|
|
|
|
|
local timeout=getTickCount()+5000000; --5 seconds
|
|
while (JavaEventPipe==nil) and (getTickCount()<timeout) do
|
|
JavaEventPipe=connectToPipe('cejavaevents_pid'..getOpenedProcessID())
|
|
end
|
|
|
|
if (JavaEventPipe==nil) then
|
|
return --failure
|
|
end
|
|
|
|
|
|
while JavaEventListener_Terminated==false do
|
|
local command=JavaEventPipe.readByte()
|
|
if command==EVENTCMD_METHODLOAD then --methodload
|
|
|
|
|
|
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)
|
|
|
|
ssize=JavaEventPipe.readWord()
|
|
local methodsig=JavaEventPipe.readString(ssize)
|
|
|
|
local name=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
|
|
print("EVENTCMD_METHODUNLOAD")
|
|
--
|
|
elseif command==EVENTCMD_DYNAMICCODEGENERATED then --DynamicCodeGenerated
|
|
local ssize
|
|
local address=JavaEventPipe.readQword()
|
|
local length=JavaEventPipe.readDword()
|
|
ssize=JavaEventPipe.readWord()
|
|
local name=JavaEventPipe.readString(ssize)
|
|
|
|
print(string.format("DynamicCode: %s - %x-%x", name, address, address+length))
|
|
|
|
|
|
--
|
|
elseif command==nil then
|
|
print("Disconnected")
|
|
break
|
|
else
|
|
print("Unexpected event received") --synchronize isn't necesary for print as that function is designed to synchronize internally
|
|
break --unknown command
|
|
end
|
|
end
|
|
|
|
JavaEventPipe.destroy();
|
|
end
|
|
|
|
function java_StartListeneningForEvents()
|
|
javapipe.lock();
|
|
javapipe.writeByte(JAVACMD_STARTCODECALLBACKS)
|
|
|
|
|
|
--the javapipe will now be frozen until a the javaeventpipe makes an connection
|
|
JavaEventListener_Terminated=false
|
|
JavaEventThread=createNativeThread(JavaEventListener);
|
|
|
|
local result=javapipe.readByte()==1
|
|
javapipe.unlock();
|
|
|
|
return result
|
|
end
|