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 build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ dependencies {
compileResolvable 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0-Beta'
implementation 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0'
api 'org.apache.commons:commons-text:1.10.0'
}
}
1 change: 0 additions & 1 deletion src/main/kotlin/com/yoavst/jeb/bridge/UIBridge.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.yoavst.jeb.bridge

import com.pnfsoftware.jeb.client.api.IGraphicalClientContext
import com.pnfsoftware.jeb.core.output.IItem
import com.pnfsoftware.jeb.core.units.code.android.dex.IDexItem
import com.pnfsoftware.jeb.core.units.code.android.dex.IDexMethod
import com.pnfsoftware.jeb.core.units.code.android.dex.IDexType
import com.yoavst.jeb.utils.currentFocusedMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.yoavst.jeb.utils.*
import com.yoavst.jeb.utils.renaming.RenameEngine
import com.yoavst.jeb.utils.renaming.RenameReason
import com.yoavst.jeb.utils.renaming.RenameRequest
import java.util.stream.Collectors

class ConstArgMassRenaming(
private val renamers: Map<String, ExtendedRenamer>,
Expand All @@ -24,13 +25,13 @@ class ConstArgMassRenaming(

fun processUnit(unit: IDexUnit, renameEngine: RenameEngine) {
val decompiler = unit.decompilerRef
var seq = getXrefs(unit).asSequence()
seq = if (isOperatingOnlyOnThisClass) {
seq.filter { it.classType == UIBridge.currentClass }
var stream = getXrefs(unit).parallelStream()
stream = if (isOperatingOnlyOnThisClass) {
stream.filter { it.classType == UIBridge.currentClass }
} else {
seq.filter { classFilter.matches(it.classType.implementingClass) }
stream.filter { classFilter.matches(it.classType.implementingClass) }
}
seq.forEach { processMethod(it, unit, decompiler, renameEngine) }
stream.forEach { processMethod(it, unit, decompiler, renameEngine) }
}

fun propagate(unit: IDexUnit, renameEngine: RenameEngine) {
Expand Down Expand Up @@ -86,14 +87,17 @@ class ConstArgMassRenaming(
throw e
}
}

element is IJavaNew && element.constructorSignature in renamers -> {
// the method we were looking for was a constructor
processMatchedMethod(assignee, renamers[element.constructorSignature]!!) { element.arguments[it] }
}

recursive -> {
// Try sub elements
element.subElements.forEach { traverseElement(it, assignee) }
}

else -> {
}
}
Expand Down Expand Up @@ -150,16 +154,19 @@ class ConstArgMassRenaming(
}
renameEngine.renameField(request, field, cls)
}

is IJavaInstanceField -> {
val field = element.field ?: run {
logger.warning("Failed to get field: $element")
return
}
renameEngine.renameField(request, field, cls)
}

is IJavaIdentifier -> {
renameEngine.renameIdentifier(request, element, unit)
}

is IJavaCall -> {
// maybe toString or valueOf on argument
if (element.methodName == "toString" || element.methodName == "valueOf") {
Expand All @@ -169,6 +176,7 @@ class ConstArgMassRenaming(
return
}
}

else -> {
logger.debug("Unsupported argument type: ${element.elementType}")
return
Expand Down Expand Up @@ -220,10 +228,22 @@ class ConstArgMassRenaming(

}

private fun getXrefs(unit: IDexUnit): Set<IDexMethod> = renamers.keys.asSequence().mapNotNull(unit::getMethod).onEach {
logger.info("Found method: ${it.currentSignature}")
}.mapToPair(unit::xrefsFor).onEach { (method, xrefs) ->
if (xrefs.isNotEmpty())
logger.info("Found ${xrefs.size} xrefs for method: ${method.currentSignature}")
}.flatMap { it.second }.mapTo(mutableSetOf(), unit::getMethod)
}

private fun getXrefs(unit: IDexUnit): Set<IDexMethod> = renamers
.keys
.parallelStream()
.mapNotNull(unit::getMethod)
.peek {
logger.info("Found method: ${it.currentSignature}")
}
.mapToPair(unit::xrefsFor)
.peek { (method, xrefs) ->
if (xrefs.isNotEmpty())
logger.info("Found ${xrefs.size} xrefs for method: ${method.currentSignature}")
}
.flatMap { (method, xrefs) ->
xrefs.stream()
}
.map(unit::getMethod)
.collect(Collectors.toSet())
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.yoavst.jeb.plugins.constarg

import com.pnfsoftware.jeb.core.*
import com.pnfsoftware.jeb.core.BooleanOptionDefinition
import com.pnfsoftware.jeb.core.IOptionDefinition
import com.pnfsoftware.jeb.core.IPluginInformation
import com.pnfsoftware.jeb.core.PluginInformation
import com.pnfsoftware.jeb.core.units.code.android.IDexUnit
import com.yoavst.jeb.bridge.UIBridge
import com.yoavst.jeb.plugins.JEB_VERSION
Expand All @@ -12,26 +15,26 @@ import com.yoavst.jeb.utils.renaming.RenameEngine
import java.io.File

class ConstArgMassRenamingPlugin :
BasicEnginesPlugin(
supportsClassFilter = true,
defaultForScopeOnThisClass = false,
defaultForScopeOnThisFunction = false,
) {
BasicEnginesPlugin(
supportsClassFilter = true,
defaultForScopeOnThisClass = false,
defaultForScopeOnThisFunction = false,
) {
private lateinit var signatures: Map<String, ExtendedRenamer>
override fun getPluginInformation(): IPluginInformation = PluginInformation(
"Const arg mass renaming plugin",
"Fire the plugin to change names using information from a constant string argument to function",
"Yoav Sternberg",
PLUGIN_VERSION,
JEB_VERSION,
null
"Const arg mass renaming plugin",
"Fire the plugin to change names using information from a constant string argument to function",
"Yoav Sternberg",
PLUGIN_VERSION,
JEB_VERSION,
null
)

override fun getExecutionOptionDefinitions(): List<IOptionDefinition> {
return super.getExecutionOptionDefinitions() + BooleanOptionDefinition(
USE_BUILTIN,
true,
"""Use the builtin method signature list. It supports Bundle, Intent, ContentValues and shared preferences.
USE_BUILTIN,
true,
"""Use the builtin method signature list. It supports Bundle, Intent, ContentValues and shared preferences.
If you have a suggestion to add to the global list, Please contact Yoav Sternberg."""
)
}
Expand All @@ -53,14 +56,14 @@ If you have a suggestion to add to the global list, Please contact Yoav Sternber
}
} else {
signatures =
RenameSignaturesFileParser.parseSignatures(javaClass.classLoader.getResource("rename_signatures.md")!!.readText(), ".")
RenameSignaturesFileParser.parseSignatures(javaClass.classLoader.getResource("rename_signatures.md")!!.readText(), ".")
}
return true
}

override fun processUnit(unit: IDexUnit, renameEngine: RenameEngine) {
val massRenamer = ConstArgMassRenaming(
signatures, isOperatingOnlyOnThisClass, classFilter
signatures, isOperatingOnlyOnThisClass, classFilter
)

if (isOperatingOnlyOnThisMethod) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.yoavst.jeb.plugins.constarg

import com.pnfsoftware.jeb.core.*
import com.pnfsoftware.jeb.core.units.NotificationType
import com.pnfsoftware.jeb.core.units.UnitNotification
import com.pnfsoftware.jeb.core.units.code.android.IDexUnit
import com.pnfsoftware.jeb.core.units.code.android.dex.IDexMethod
import com.yoavst.jeb.bridge.UIBridge
Expand All @@ -17,43 +15,43 @@ import java.io.File
import kotlin.properties.Delegates

class ConstArgRenamingPlugin :
BasicEnginesPlugin(
supportsClassFilter = true,
defaultForScopeOnThisClass = false,
defaultForScopeOnThisFunction = false,
usingSelectedMethod = true
) {
BasicEnginesPlugin(
supportsClassFilter = true,
defaultForScopeOnThisClass = false,
defaultForScopeOnThisFunction = false,
usingSelectedMethod = true
) {

private var constArgumentIndex by Delegates.notNull<Int>()
private var renamedArgumentIndex = -1
private lateinit var renameMethod: IDexMethod
private lateinit var renamer: (String) -> RenameResult

override fun getPluginInformation(): IPluginInformation = PluginInformation(
"Const arg renaming plugin",
"Fire the plugin to change names using information from a constant string argument to function",
"Yoav Sternberg",
PLUGIN_VERSION,
JEB_VERSION,
null
"Const arg renaming plugin",
"Fire the plugin to change names using information from a constant string argument to function",
"Yoav Sternberg",
PLUGIN_VERSION,
JEB_VERSION,
null
)

override fun getExecutionOptionDefinitions(): List<IOptionDefinition> {
val options = super.getExecutionOptionDefinitions().toMutableList()
options += ListOptionDefinition(
TargetRenameTag,
RenameTarget.Class.name,
"What do we want to renamed based on the argument",
*RenameTarget.values().map(RenameTarget::name).toTypedArray()
TargetRenameTag,
RenameTarget.Class.name,
"What do we want to renamed based on the argument",
*RenameTarget.values().map(RenameTarget::name).toTypedArray()
)
options += OptionDefinition(
TargetConstArgIndex,
"0",
"What is the index of the const argument that will be used as name?"
TargetConstArgIndex,
"0",
"What is the index of the const argument that will be used as name?"
)
options += OptionDefinition(
TargetArgumentToBeRenamedPosition,
"Optional: If renaming an argument, what is its index"
TargetArgumentToBeRenamedPosition,
"Optional: If renaming an argument, what is its index"
)
return options
}
Expand Down Expand Up @@ -99,6 +97,7 @@ class ConstArgRenamingPlugin :
}
scriptRenamer(File(scriptPath).readText())
}

RenameTarget.Class -> classRenamer
RenameTarget.Method -> methodRenamer
RenameTarget.Argument -> {
Expand All @@ -112,16 +111,17 @@ class ConstArgRenamingPlugin :
}
argumentRenamer
}

RenameTarget.Assignee -> assigneeRenamer
}
return true
}

override fun processUnit(unit: IDexUnit, renameEngine: RenameEngine) {
val massRenamer = ConstArgMassRenaming(
mapOf(
renameMethod.getSignature(false) to ExtendedRenamer(constArgumentIndex, renamer, renamedArgumentIndex)
), isOperatingOnlyOnThisClass, classFilter
mapOf(
renameMethod.getSignature(false) to ExtendedRenamer(constArgumentIndex, renamer, renamedArgumentIndex)
), isOperatingOnlyOnThisClass, classFilter
)

if (isOperatingOnlyOnThisMethod) {
Expand Down
15 changes: 11 additions & 4 deletions src/main/kotlin/com/yoavst/jeb/plugins/constarg/GetXPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.yoavst.jeb.plugins.PLUGIN_VERSION
import com.yoavst.jeb.utils.*
import com.yoavst.jeb.utils.renaming.RenameEngine
import java.util.*
import java.util.stream.Collectors

class GetXPlugin : BasicEnginesPlugin(supportsClassFilter = true, defaultForScopeOnThisClass = false) {
override fun getPluginInformation(): IPluginInformation = PluginInformation(
Expand All @@ -21,10 +22,12 @@ class GetXPlugin : BasicEnginesPlugin(supportsClassFilter = true, defaultForScop
)

override fun processUnit(unit: IDexUnit, renameEngine: RenameEngine) {
val visitor = simpleNameMethodVisitor(renameEngine)
val renamers = unit.methods.asSequence().mapToPairNotNull(visitor).associate { (method, result) ->
method.currentSignature to result
}
val visitor: (IDexMethod) -> ExtendedRenamer? = simpleNameMethodVisitor(renameEngine)

val renamers = unit.methods.parallelStream().mapToPairNotNull(visitor).filter { (method, result) ->
result != null
}.collect(Collectors.toMap({ (method, result) -> method.currentSignature }, { (method, result) -> result }))

ConstArgMassRenaming(renamers, isOperatingOnlyOnThisClass, classFilter, recursive = false).processUnit(unit, renameEngine)
}

Expand All @@ -38,9 +41,11 @@ class GetXPlugin : BasicEnginesPlugin(supportsClassFilter = true, defaultForScop
method.parameterTypes.size == 0 -> {
ExtendedRenamer(-1, { RenameResult(assigneeName = fieldName) }, -1)
}

method.isStatic && method.parameterTypes.size == 1 -> {
ExtendedRenamer(-1, { RenameResult(argumentName = fieldName) }, 0)
}

else -> null
}
} else if (name.startsWith("set") && name.length >= 4) {
Expand All @@ -49,9 +54,11 @@ class GetXPlugin : BasicEnginesPlugin(supportsClassFilter = true, defaultForScop
method.parameterTypes.size == 1 -> {
ExtendedRenamer(-1, { RenameResult(argumentName = fieldName) }, 0)
}

method.isStatic && method.parameterTypes.size == 2 -> {
ExtendedRenamer(-1, { RenameResult(argumentName = fieldName) }, 1)
}

else -> null
}
} else null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.yoavst.jeb.plugins.constarg

data class RenameResult(
val className: String? = null,
val methodName: String? = null,
val argumentName: String? = null,
val assigneeName: String? = null
val className: String? = null,
val methodName: String? = null,
val argumentName: String? = null,
val assigneeName: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ object RenameSignaturesFileParser {
}
val constArgIndex = split[2].toIntOrNull() ?: throw IllegalArgumentException("Invalid line: '$it'")
val target = RenameTarget.valueOf(
split[0].lowercase(Locale.getDefault())
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() })
split[0].lowercase(Locale.getDefault())
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() })
split[1] to when (target) {
RenameTarget.Class -> ExtendedRenamer(constArgIndex, classRenamer)
RenameTarget.Method -> ExtendedRenamer(constArgIndex, methodRenamer)
Expand All @@ -32,25 +32,29 @@ object RenameSignaturesFileParser {
throw IllegalArgumentException("Invalid line, no renamed argument index: '$it'")
}
val renamedArgIndex =
split[3].toIntOrNull() ?: throw IllegalArgumentException("Invalid line, renamed argument is not int: '$it'")
split[3].toIntOrNull()
?: throw IllegalArgumentException("Invalid line, renamed argument is not int: '$it'")
ExtendedRenamer(constArgIndex, argumentRenamer, renamedArgIndex)
}

RenameTarget.Assignee -> ExtendedRenamer(constArgIndex, assigneeRenamer)
RenameTarget.Custom -> {
if (split.size < 4) {
throw IllegalArgumentException("Invalid line, no custom path: '$it'")
}
val filename = split[3]
val script = if (filename.startsWith("jar:")) {
javaClass.classLoader.getResourceAsStream(filename.substringAfter("jar:"))?.bufferedReader()?.readText() ?: run {
throw IllegalArgumentException("Invalid line, no such file in jar: '$it'")
}
javaClass.classLoader.getResourceAsStream(filename.substringAfter("jar:"))?.bufferedReader()?.readText()
?: run {
throw IllegalArgumentException("Invalid line, no such file in jar: '$it'")
}
} else {
File(basePath, split[3]).readText()
}
if (split.size == 5) {
val renamedArgIndex =
split[4].toIntOrNull() ?: throw IllegalArgumentException("Invalid line, renamed argument is not int: '$it'")
split[4].toIntOrNull()
?: throw IllegalArgumentException("Invalid line, renamed argument is not int: '$it'")
ExtendedRenamer(constArgIndex, scriptRenamer(script), renamedArgIndex)
} else {
ExtendedRenamer(constArgIndex, scriptRenamer(script))
Expand Down
Loading