Skip to content

Commit

Permalink
Merge pull request #3 from asmjmp0/patch_jre_with_jna
Browse files Browse the repository at this point in the history
Patch jre with jna
  • Loading branch information
asmjmp0 authored Apr 10, 2023
2 parents de355c1 + e3eee07 commit 56c7d7c
Show file tree
Hide file tree
Showing 24 changed files with 562 additions and 18 deletions.
10 changes: 10 additions & 0 deletions PatchJDK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
1. patch jdk_path/...../libjvm.dylib,which make it possible to load class,the name begin with "java"
![](assets/package.png)

2. use the jre you modified(**or use jdk in [appdbg-JDK](https://github.com/asmjmp0/appdbg-JDK)**)

3. change idea settings
- set gradle jdk version with the patched jdk
![](assets/gradle0.png)
- set gradle java home with the patched jdk in [gradle.properties](gradle.properties)
![](assets/gradle1.png)
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,25 @@ make it possible to run android dex file in original Java Virtual Machine.

## Start

1. open the project with IDEA

2. patch jdk_path/...../libjvm.dylib,which make it possible to load class,the name begin with "java"
![](assets/package.png)

3. use the jre you modified(**or use jdk in [appdbg-JDK](https://github.com/asmjmp0/appdbg-JDK)**)
***powred by [patch-jvm](patch-jvm) we do not need patch jvm by myself anymore!***
- if it has any problem, please see [PatchJDK.md](PatchJDK.md)

4. change idea settings
- set gradle jdk version with the patched jdk
![](assets/gradle0.png)
- set gradle java home with the patched jdk in [gradle.properties](gradle.properties)
![](assets/gradle1.png)
1. open the project with IDEA

5. run test suites in [testSuites](core/src/test/java/suites)
2. run test suites in [testSuites](core/src/test/java/suites)

![](assets/1.png)

## Build test app
include test-app module in [settings.gradle](settings.gradle)
```
include ':test-app'
```

## Publish to mavenLocal
1. run command ` ./gradlew publishToMavenLocal`
2. `implementation "jmp0.appdbg:core:1.0-SNAPSHOT"`

## Implement native method with unidbg
**auto implement reflection method by appdbg**
- invoke method
Expand Down
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
implementation project(":thirdparty:dex-translator")
implementation project(":thirdparty:fernflower")
api project(':thirdparty:arsc-decoder')
implementation project(":patch-jvm")
implementation 'org.dom4j:dom4j:2.1.3'
implementation "log4j:log4j:$log4j_version"
api "org.javassist:javassist:$javassist_version"
Expand Down
6 changes: 2 additions & 4 deletions core/src/main/java/jmp0/app/AndroidEnvironment.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package jmp0.app

import io.github.classgraph.ClassGraph
import javassist.*
import jmp0.apk.ApkFile
import jmp0.app.classloader.ClassLoadedCallbackBase
Expand All @@ -11,11 +10,10 @@ import jmp0.app.conversation.IAppdbgConversationHandler
import jmp0.app.interceptor.intf.IInterceptor
import jmp0.app.interceptor.intf.NativeImplementInterceptor
import jmp0.app.interceptor.intf.RuntimeClassInterceptorBase
import jmp0.app.interceptor.unidbg.UnidbgInterceptor
import jmp0.app.mock.annotations.ClassReplaceTo
import jmp0.app.mock.MethodManager
import jmp0.app.mock.system.service.MockServiceManager
import jmp0.conf.CommonConf
import jmp0.patchjvm.PatchMain
import jmp0.util.SystemReflectUtils
import jmp0.util.ZipUtility
import jmp0.util.reflection
Expand All @@ -24,7 +22,6 @@ import java.io.File
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import java.net.URI
import java.util.*

// TODO: 2022/3/9 模拟初始化Android activity,并载入自定义类加载器
Expand Down Expand Up @@ -54,6 +51,7 @@ class AndroidEnvironment(val apkFile: ApkFile,

init {
//create temp dir
PatchMain(File(CommonConf.workDir)).patch()
File(CommonConf.workDir,CommonConf.tempDirName).apply { if (!exists()) mkdir() }
registerToContext()
checkAndReleaseFramework()
Expand Down
25 changes: 25 additions & 0 deletions patch-jvm/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
plugins {
id 'org.jetbrains.kotlin.jvm'
}

group 'jmp0'
version '1.0-SNAPSHOT'

jar.enabled(true)

repositories {
mavenCentral()
}

test{
useJUnitPlatform()
}


dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.9.2')
implementation 'net.java.dev.jna:jna:5.10.0'
}

sourceCompatibility = "1.8"
targetCompatibility = "1.8"
25 changes: 25 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/PatchMain.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package jmp0.patchjvm

import com.sun.jna.Native
import com.sun.jna.Platform
import jmp0.patchjvm.patch.impl.linux.LinuxPatch
import jmp0.patchjvm.patch.impl.osx.OSXPatch
import jmp0.patchjvm.patch.impl.windows.WindowsPatch
import jmp0.patchjvm.library.CLibrary
import java.io.File

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
class PatchMain(private val workDir:File) {
private val cl = Native.load(if (Platform.isWindows()) "msvcrt" else "c", CLibrary::class.java) as CLibrary

fun patch() =
when(Platform.getOSType()){
Platform.MAC-> OSXPatch(workDir,cl)
Platform.WINDOWS -> WindowsPatch(cl)
Platform.LINUX -> LinuxPatch(cl)
else -> throw Exception("patch jvm ${Platform.getOSType()} not support")
}.patch()
}
28 changes: 28 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/PatchUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package jmp0.patchjvm

import java.util.*

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
object PatchUtil {
private fun findSubByteArrayInner(byteArray: ByteArray,idx:Int,find: ByteArray): Boolean {
if(idx + find.size > byteArray.size) return false
for (i in find.indices){
if(find[i] != byteArray[i+idx]) return false
}
return true
}

fun findSubByteArray(byteArray: ByteArray,find:ByteArray):List<Int>{
val list = LinkedList<Int>()
for(idx in byteArray.indices){
if(byteArray[idx] == find[0]){
if(findSubByteArrayInner(byteArray,idx,find))
list.add(idx)
}
}
return list
}
}
19 changes: 19 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/library/CLibrary.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package jmp0.patchjvm.library

import com.sun.jna.Library
import com.sun.jna.Pointer

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
interface CLibrary:Library {
companion object{
const val PROT_READ = 0x1 /* Page can be read. */
const val PROT_WRITE = 0x2 /* Page can be written. */
const val PROT_EXEC = 0x4 /* Page can be executed. */
}
fun malloc(size: Int):Pointer
fun free(p:Pointer)
fun mprotect(adr:Pointer,len:Int,port:Int):Int
}
16 changes: 16 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/patch/DynamicPatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package jmp0.patchjvm.patch

import java.io.File

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/8
*/

//replace java with #
abstract class DynamicPatch : IPatch {
//C style string java\0
protected val pattern:ByteArray get() = byteArrayOf(0x6a,0x61,0x76,0x61,0x0)

protected val replaceString = "####"
}
13 changes: 13 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/patch/IPatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package jmp0.patchjvm.patch

import jmp0.patchjvm.library.CLibrary

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
interface IPatch {
val cLibrary: CLibrary
val jvmLibraryName:String
fun patch()
}
29 changes: 29 additions & 0 deletions patch-jvm/src/main/java/jmp0/patchjvm/patch/StaticPatch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package jmp0.patchjvm.patch

import com.sun.jna.Platform
import java.io.File
import java.lang.Exception

abstract class StaticPatch(workDir:File): DynamicPatch() {
/*
* add x1,x1,xxx
* movz w2,4
* */
private val strARMPtrPattern = byteArrayOf(0x21,0,0, 0x91.toByte(), 0x82.toByte(),0, 0x80.toByte(),0x52)

protected val patchJDKDir = File(workDir,"temp${File.separator}JDKPatch").apply { if (!isDirectory) mkdirs() }

protected abstract fun patchStatic(file:File)

protected fun generateStrPtrPattern(strIdx:Int): ByteArray {
if (Platform.isARM()){
var strPtr = strIdx and 0xfff
strPtr *= 4
val ret = strARMPtrPattern.clone()
ret[1] = (strPtr and 0xff).toByte()
ret[2] = (strPtr shr 8).toByte()
return ret
}
throw Exception("${Platform.ARCH} not support.")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package jmp0.patchjvm.patch.impl.linux

import com.sun.jna.Pointer
import jmp0.patchjvm.PatchUtil
import jmp0.patchjvm.library.CLibrary
import jmp0.patchjvm.patch.DynamicPatch
import java.io.File
import java.util.LinkedList

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
class LinuxPatch(override val cLibrary: CLibrary, override val jvmLibraryName: String = "libjvm.so") : DynamicPatch() {
override fun patch() {
val jvmMapsLines = File("/proc/self/maps").readLines().filter { it.endsWith(jvmLibraryName) }
val segmentList = LinkedList<Pair<Pointer,Long>>()
jvmMapsLines.forEach {
if (it.contains("r-x")){
val spl = it.split(' ')
val ps = spl[0].split('-')
segmentList.push(Pair(Pointer(ps[0].toLong(16)),ps[1].toLong(16) - ps[0].toLong(16)))
}
}
if (!segmentList.isEmpty()){
val pair = segmentList[0]
val bs = pair.first.getByteArray(0,pair.second.toInt())
val find = PatchUtil.findSubByteArray(bs,pattern)
if (find.isEmpty()){
println("ERROR: LinuxPatch not find pattern.")
return
}
if (this.cLibrary.mprotect(pair.first,pair.second.toInt(),CLibrary.PROT_EXEC or CLibrary.PROT_READ or CLibrary.PROT_WRITE) == 0){
pair.first.setString(find[0].toLong(), replaceString)
this.cLibrary.mprotect(pair.first,pair.second.toInt(),CLibrary.PROT_EXEC or CLibrary.PROT_READ)
}else{
println("ERROR: LinuxPatch mprotect error.")
return
}

}else{
println("ERROR: LinuxPatch not find r-w segment.")
return
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package jmp0.patchjvm.patch.impl.osx

import jmp0.patchjvm.patch.impl.osx.structure.MachHeader64
import jmp0.patchjvm.library.CLibrary

/**
* @author jmp0 <[email protected]>
* Create on 2023/4/7
*/
interface DyldLibrary:CLibrary {
fun _dyld_image_count():Int

fun _dyld_get_image_name(idx:Int):String

fun _dyld_get_image_header(idx: Int): MachHeader64

}
Loading

0 comments on commit 56c7d7c

Please sign in to comment.