Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

implementation 'com.github.xxdark:ssvm:6e795448e4'
implementation 'com.github.xxdark:ssvm:df30743'
implementation 'com.android.tools:r8:3.3.28'
}
46 changes: 46 additions & 0 deletions app/src/main/java/ma/ssvmandroid/DefaultVMInitializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ma.ssvmandroid

import dev.xdark.ssvm.VMInitializer
import dev.xdark.ssvm.VirtualMachine
import ma.ssvmandroid.native.*

class DefaultVMInitializer : VMInitializer {

private val nativeInitializers = setOf(
FileChannelImplNatives(),
FileDescriptorNatives(),
RandomAccessFileNatives(),
OldFileSystemNativesEx(),
SunFileDispatcherNatives(),
SunFileKeyNatives(),
SunSharedFileLockTableNatives(),
SunIOUtilNatives(),
SunNativeThreadNatives()
)

override fun initBegin(vm: VirtualMachine) {
vm.properties.apply {
setProperty("sun.stderr.encoding", "UTF-8")
setProperty("sun.stdout.encoding", "UTF-8")
setProperty("sun.jnu.encoding", "UTF-8")
setProperty("line.separator", "\n")
setProperty("path.separator", ":")
setProperty("file.separator", "/")
setProperty("user.dir", "/home/mike")
setProperty("user.name", "mike")
setProperty("os.version", "10.0")
setProperty("os.arch", "amd64")
setProperty("os.name", "Linux")
setProperty("file.encoding", "UTF-8")
}

// Contains android stuffs
vm.getenv().clear()
}

override fun nativeInit(vm: VirtualMachine) {
nativeInitializers.forEach {
it.init(vm)
}
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/ma/ssvmandroid/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class MainActivity : AppCompatActivity() {
val time = System.currentTimeMillis()

catchVMException {
ssvmTest.addProperty("user.home", getExternalFilesDir("user_home")!!.absolutePath)
ssvmTest.addProperty("java.home", getExternalFilesDir("java_home")!!.absolutePath)
// init VM
ssvmTest.initVM()

Expand Down
82 changes: 36 additions & 46 deletions app/src/main/java/ma/ssvmandroid/SSVMTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,61 +32,43 @@ import java.util.zip.ZipFile
class SSVMTest(
private val rtJar: ZipFile,
) {
private lateinit var vm: VirtualMachine
private val vm: VirtualMachine = object : VirtualMachine(DefaultVMInitializer()) {
override fun createFileDescriptorManager() = HostFileDescriptorManager()

private var initialized: Boolean = false
val isInitialized: Boolean
get() = initialized

fun initVM() {
vm = object : VirtualMachine() {
override fun createFileDescriptorManager() = HostFileDescriptorManager()

override fun createManagementInterface() = object : ManagementInterface {
override fun getVersion() = "null"
override fun createManagementInterface() = object : ManagementInterface {
override fun getVersion() = "null"

override fun getStartupTime() = System.currentTimeMillis()
override fun getStartupTime() = System.currentTimeMillis()

override fun getInputArguments() = listOf<String>()
}
override fun getInputArguments() = listOf<String>()
}

override fun createBootClassLoader() = BootClassLoader {
println("[VM] Loading: $it.class")
override fun createBootClassLoader() = BootClassLoader {
println("[VM] Loading: $it.class")

try {
val entry = rtJar.getEntry("$it.class")
?: return@BootClassLoader null
try {
val entry = rtJar.getEntry("$it.class")
?: return@BootClassLoader null

rtJar.getInputStream(entry).use { stream ->
val cr = ClassReader(stream)
val node = ClassUtil.readNode(cr)
rtJar.getInputStream(entry).use { stream ->
val cr = ClassReader(stream)
val node = ClassUtil.readNode(cr)

return@BootClassLoader ClassParseResult(cr, node)
}
} catch (e: IOException) {
System.err.println("[VM] Couldn't load class $it: ${Log.getStackTraceString(e)}")
return@BootClassLoader ClassParseResult(cr, node)
}

return@BootClassLoader null
} catch (e: IOException) {
System.err.println("[VM] Couldn't load class $it: ${Log.getStackTraceString(e)}")
}
}

vm.properties.apply {
setProperty("sun.stderr.encoding", "UTF-8")
setProperty("sun.stdout.encoding", "UTF-8")
setProperty("sun.jnu.encoding", "UTF-8")
setProperty("line.separator", "\n")
setProperty("path.separator", ":")
setProperty("file.separator", "/")
setProperty("java.home", "/usr/lib/jvm")
setProperty("user.home", "/home/mike")
setProperty("user.dir", "/home/mike")
setProperty("user.name", "mike")
setProperty("os.version", "10.0")
setProperty("os.arch", "amd64")
setProperty("os.name", "Linux")
return@BootClassLoader null
}
}

private var initialized: Boolean = false
val isInitialized: Boolean
get() = initialized

fun initVM() {
initialized = try {
vm.bootstrap()

Expand Down Expand Up @@ -120,6 +102,10 @@ class SSVMTest(
}
}

fun init() {

}

private fun getVMSystemClassLoader(): Value {
val ctx = vm.helper.invokeStatic(
vm.symbols.java_lang_ClassLoader(),
Expand Down Expand Up @@ -190,7 +176,6 @@ class SSVMTest(
)

helper.invokeStatic(
klass,
method,
arrayOf(),
arrayOf(helper.emptyArray(symbols.java_lang_String()))
Expand All @@ -212,13 +197,18 @@ class SSVMTest(
}
}

private class JitDexClassLoader: JitInstaller.ClassDefiner {
fun addProperty(key: String, value: String) {
vm.properties.setProperty(key, value)
}

private class JitDexClassLoader : JitInstaller.ClassDefiner {
override fun define(jitClass: JitClass): Class<*> {
val code = jitClass.code
val buffer = transformBytecodeToDex(code)
?: throw IllegalStateException("D8 failed to translate")

val inMemoryDexClassLoader = InMemoryDexClassLoader(buffer, jitClass::class.java.classLoader)
val inMemoryDexClassLoader =
InMemoryDexClassLoader(buffer, jitClass::class.java.classLoader)
return inMemoryDexClassLoader.loadClass(jitClass.className)
}

Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/ma/ssvmandroid/native/FileChannelImplNatives.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ma.ssvmandroid.native

import dev.xdark.ssvm.VirtualMachine
import dev.xdark.ssvm.execution.Result
import dev.xdark.ssvm.mirror.InstanceJavaClass
import dev.xdark.ssvm.value.LongValue
import org.objectweb.asm.Type

class FileChannelImplNatives : NativeInitializer {
override fun init(vm: VirtualMachine) {
val fileChannelImpl = vm.findBootstrapClass("sun/nio/ch/FileChannelImpl") as InstanceJavaClass

vm.`interface`.setInvoker(
fileChannelImpl,
"initIDs",
Type.getMethodDescriptor(Type.LONG_TYPE)
) {
it.result = LongValue.of(0)
return@setInvoker Result.ABORT
}
}

operator fun invoke(vm: VirtualMachine) {
init(vm)
}
}
19 changes: 19 additions & 0 deletions app/src/main/java/ma/ssvmandroid/native/FileDescriptorNatives.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ma.ssvmandroid.native

import dev.xdark.ssvm.VirtualMachine
import dev.xdark.ssvm.api.MethodInvoker
import dev.xdark.ssvm.mirror.InstanceJavaClass
import org.objectweb.asm.Type

class FileDescriptorNatives : NativeInitializer {
override fun init(vm: VirtualMachine) {
val fileDescriptor = vm.findBootstrapClass("java/io/FileDescriptor") as InstanceJavaClass

vm.`interface`.setInvoker(
fileDescriptor,
"init",
Type.getMethodDescriptor(Type.VOID_TYPE),
MethodInvoker.noop()
)
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/ma/ssvmandroid/native/NativeInitializer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ma.ssvmandroid.native

import dev.xdark.ssvm.VirtualMachine

interface NativeInitializer {

fun init(vm: VirtualMachine)
}
62 changes: 62 additions & 0 deletions app/src/main/java/ma/ssvmandroid/native/OldFileSystemNativesEx.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ma.ssvmandroid.native

import dev.xdark.ssvm.VirtualMachine
import dev.xdark.ssvm.execution.Result
import dev.xdark.ssvm.mirror.InstanceJavaClass
import dev.xdark.ssvm.value.InstanceValue
import dev.xdark.ssvm.value.IntValue
import dev.xdark.ssvm.value.Value
import org.objectweb.asm.Type
import java.io.File

class OldFileSystemNativesEx : NativeInitializer {
override fun init(vm: VirtualMachine) {
val fs: InstanceJavaClass = (vm.findBootstrapClass("java/io/WinNTFileSystem")
?: vm.findBootstrapClass("java/io/UnixFileSystem")) as InstanceJavaClass

vm.`interface`.setInvoker(
fs,
"checkAccess",
Type.getMethodDescriptor(
Type.BOOLEAN_TYPE,
Type.getType(File::class.java),
Type.INT_TYPE
)
) {
val value = it.locals.load<Value>(1)
val path: String =
vm.helper.readUtf8((value as InstanceValue).getValue("path", "Ljava/lang/String;"))
val result = if (File(path).canRead()) 1 else 0
it.result = IntValue.of(result)
return@setInvoker Result.ABORT
}

vm.`interface`.setInvoker(
fs,
"delete0",
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(File::class.java))
) {
val value = it.locals.load<Value>(1)
val path: String =
vm.helper.readUtf8((value as InstanceValue).getValue("path", "Ljava/lang/String;"))
val result = if (File(path).delete()) 1 else 0
it.result = IntValue.of(result)
return@setInvoker Result.ABORT
}

vm.`interface`.setInvoker(
fs, "createDirectory", Type.getMethodDescriptor(
Type.BOOLEAN_TYPE, Type.getType(File::class.java)
)
) {
val value = it.locals.load<Value>(1)
val path: String =
vm.helper.readUtf8((value as InstanceValue).getValue("path", "Ljava/lang/String;"))
val result = if (File(path).mkdir()) 1 else 0
it.result = IntValue.of(result)
return@setInvoker Result.ABORT
}
}


}
55 changes: 55 additions & 0 deletions app/src/main/java/ma/ssvmandroid/native/RandomAccessFileNatives.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ma.ssvmandroid.native

import dev.xdark.ssvm.VirtualMachine
import dev.xdark.ssvm.api.MethodInvoker
import dev.xdark.ssvm.execution.Result
import dev.xdark.ssvm.mirror.InstanceJavaClass
import dev.xdark.ssvm.value.IntValue
import dev.xdark.ssvm.value.Value
import org.objectweb.asm.Type

class RandomAccessFileNatives : NativeInitializer {
override fun init(vm: VirtualMachine) {
val randomAccessFile = vm.findBootstrapClass("java/io/RandomAccessFile") as InstanceJavaClass

vm.`interface`.setInvoker(
randomAccessFile,
"initIDs",
Type.getMethodDescriptor(Type.VOID_TYPE),
MethodInvoker.noop()
)

vm.`interface`.setInvoker(
randomAccessFile,
"open",
Type.getMethodDescriptor(
Type.VOID_TYPE,
Type.getType(String::class.java),
Type.INT_TYPE
)
) {
val value = it.locals.load<Value>(1)
val path: String = vm.helper.readUtf8(value)
val modeValue = it.locals.load<IntValue>(2)
vm.fileDescriptorManager.open(path, modeValue.asInt())
return@setInvoker Result.ABORT
}

// no-op, handled in the open() method
vm.`interface`.setInvoker(
randomAccessFile,
"open0",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE),
MethodInvoker.noop()
)

vm.`interface`.setInvoker(
randomAccessFile,
"close0",
Type.getMethodDescriptor(Type.VOID_TYPE)
) {
// TODO: read the path field on the random access file and close that
return@setInvoker Result.ABORT
}
}
}
Loading