Article Directory
learning target
Today I will take you to do a simple Frida Hook Java
multi-level question. There are seven small checkpoints in total. Each checkpoint has a small inspection point to examine our Frida
basic knowledge. Students who have already learned it can also use it as a reference.
APP: Frida
Test questions
Download address: see the end of the article
first round
First install and run the APP, each level has a requirement and inspection point
Inspection point: modification of method parameters
Analysis: Take a general look at the logic, that is, click the next level, the
onClick
method will be called, and the methodonClick
will callcheck
the method, but there is one parameter.false
Incheck
the method, according to this parameter, choose whether to enter the next level or prompt failure. If we don't make any modifications, y will never be able to enter the next level, so we need to use Frida to modifycheck
the parameters of the method to becometrue
, to help us enter the next level.
function main(){
Java.perform(function(){
// Frist
Java.use("com.dta.test.frida.activity.FirstActivity").check.implementation = function(z){
z = true
this.check(z)
}
})
}
setImmediate(main)
second level
Inspection point: modification of method return value
Analysis: The calling process is the same, or call
onClick
the method, and then analyze the logic. It is also very simple, callcheck
the method, andcheck
choose whether to enter the next level or prompt failure according to the return value of the method. So we can directly modifycheck
the return value of the methodtrue
function main(){
Java.perform(function(){
//Second
Java.use("com.dta.test.frida.activity.SecondActivity").check.implementation = function(){
return true
}
})
}
setImmediate(main)
third level
Inspection point: modification of class member variables, value of enumeration class
Analysis: This question is to judge
unkown
whether the value of the member variable is equalLevel.Fouth
, sounkown
the value we need to modifyLevel.Fouth
, the default valueLevel.Unkown
is relatively simple, right?
The first point of investigation is how to modify the value of this member variable, which is divided into two situations:
1. Static member variable, modify the value of the static member variable and use it directly to getJava.use
a classwraper
, directly. Variable namevalue
. Modify its value directly.
2. For instance member variables, we need toJava.choose
obtain this instance first, and then modify it by means of .
The second point of investigation is the value of the enumeration class, because ourunkown
member variable wants to assign a value to itLevel.Fouth
, so we need to get thisLevel.Fouth
, and thisLevel
is an enumeration class, as can be seen from the name, enumeration A class is nothing more than a special class, and its value can also be obtained directly by using the method of .name.value. Look at the code
function main(){
Java.perform(function(){
//Third
Java.choose("com.dta.test.frida.activity.ThirdActivity",{
onMatch: function(ins){
console.log(ins)
ins.unknown.value = Java.use("com.dta.test.frida.base.Level").Fourth.value
},onComplete: function(){
console.log("Search Completed!")
}
})
})
}
setImmediate(main)
A classmate asked a question about this topic. He did not modify the value of the class member variable to enter the next level. This is what we have said in the first topic. Do not use any methods other than the inspection point to reach the next level. , otherwise there will be many solutions to a problem, and the purpose of our investigation will not be achieved.
fourth pass
Inspection point: active call of the method
Analysis: The purpose of this question is to let us learn
Frida
how to actively call a method, and the active call is also divided into two situations
1. The active call of a static method can be called directly byJava.use
getting the class directly. 2. To actively call an instance method, you need to obtain an instance of the class first. There are many ways to get an instance of a class, such as an object, to get an existing instance of the class in memory, method When , the object is also an instance of the class, and with this instance, the instance method can be called actively. look at the codewraper
Frida
$new()
new
Java.choose
Hook
this
function main(){
Java.perform(function(){
//Fourth
Java.choose("com.dta.test.frida.activity.FourthActivity",{
onMatch: function(ins){
console.log(ins)
ins.next()
},onComplete: function(){
console.log("Search Completed!")
}
})
})
}
setImmediate(main)
Fifth level
Inspection point:
Frida
the construction of the array
Analysis: When we want to actively call a method, the most important thing is how to construct the parameters of this method. For example, this topic is also a
check
method. Its parameter is an array, which is judged internally. If the length of the array is judged to be 5, it can pass, otherwise the prompt fails. So we needHook check
a method, just modify its parameter to an array of length 5String
. The construction of the arrayFrida
also providesAPI
:Java.array
, the first parameter is the data type to be constructed, the basic data type can be written directly, for exampleint
char
, and the complex data type needs to fill in the fully qualified class name, for examplejava.lang.String
, see the code
function main(){
Java.perform(function(){
//Fifth
var strarr = Java.array("java.lang.String",["d","t","a","b","c"])
Java.use("com.dta.test.frida.activity.FifthActivity").check.implementation = function(arr){
arr = strarr
this.check(arr)
}
})
}
setImmediate(main)
Sixth hurdle
Inspection point:
Frida
custom class
Analysis: This question is a more interesting one. It was not considered when the question was written at the time
ClassLoader
. I only found out that this question has pitfalls when I was doing it. Let's solve this problem according to the normal way of thinking: just a few lines of code, first passClass.forName
to load a class, getcom.dta.test.frida.activity.RegisterClass
thisClass
object, then callgetDeclaredMethod
the method to get the next method in this class, and finally call thisnext
method, get After reaching the return value, callbooleanValue
the method to get aboolean
type of result, and use this result to choose whether to enter the next level or prompt failure
In fact, the above analysis process is also relatively easy to understand, which is equivalent to the fact that we need a class, as follows
package com.dta.test.frida.activity;
public class RegisterClass{
public RegisterClass{
}
public boolean next(){
return true;
}
}
The topic is to call the method RegisterClass
in this class , so we build such a class next
through the Frida
provided API according to this topicJava.registerClass
function main(){
Java.perform(function(){
//Sixth
var RegisterClass = Java.registerClass({
name: "com.dta.test.frida.activity.RegisterClass",
methods: {
next: {
returnType: "boolean",
argumentTypes:[],
implementation: function(){
return true
}
}
}
})
})
}
setImmediate(main)
We used Frida to help us construct the classes we need, and they will be automatically loaded into the memory, but we found that the problem is still not passable. At this time, we have to think about where the problem lies? If you think from the top down, Class.forName
is the execution of the first line successful? Did the method on the second line getDeclaredMethod
find the method we need next
? Is the return value obtained successfully?
With these questions in mind, let's investigate. Because catch
the exception in the block in the title has not been processed print
, we use other methods to troubleshoot. Check the simple items first, getDeclaredMethod
have you found the method? We can call the next method by using our custom object RegisterClass
, and find that it can be printed, and the result isnew
true
console.log(RegisterClass.$new().next())
// true
Then it means that our custom Class
is successfully created and can be used normally. Then the question arises in the first one, Class.forName
is the loading of this class successful? In fact, it was unsuccessful. When we click the next level button, the exception thrown here is actually that we cannot find the custom class ClassNotFoundException
we use . Frida
Where is the reason? let's look down
First, let's look at Class.forName
the process
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName(className, true, VMStack.getCallingClassLoader());
}
The overload that is called internally forName
, note that the third parameter isVMStack.getCallingClassLoader
/**
* Returns the defining class loader of the caller's caller.
*
* @return the requested class loader, or {@code null} if this is the
* bootstrap class loader.
*/
@FastNative
native public static ClassLoader getCallingClassLoader();
It is a native
method, the translation of the comment is to return the request class loader
, if it null
is returned bootstrap class loader
, then what we call this method here is the SixthActivity
same asClassLoader
This method has only three parameters, the first one is className
, ours className
is correct, so we have to ClassLoader
start from scratch to solve this problem. ClassLoader
The following knowledge will be supplemented
JVM
class loader
-
JVM
The class loader includes three types: -
Bootstrap ClassLoader
(Bootstrap class loader):C/C++
The loader implemented by the code is used to load the specifiedJDK
core class library, such as java.lang.*, java.util.* and other system classes.Java
The startup of the virtual machine is throughBootstrap
, which cannot be obtainedClassLoader
in it, and is only responsible for the loaded classes.Java
/lib
-
Extensions ClassLoader
(Extended class loader):Java
The implementation class in isExtClassLoader
, which provides functions other than system classes, canJava
be obtained in it, and is responsible for loading/lib/ext
the next class.
-
Application ClassLoader
(Application class loader):Java
The implementation class in isAppClassLoader
, which is the class loader that we have the most contact with. The code written by developers is loaded by it by default, andClassLoader.getSystemClassLoader
it is what is returned.
-
- To customize the class loader, you only need to
java.lang.ClassLoader
implement your own class loader by inheriting the class.
- To customize the class loader, you only need to
[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-u6n1o1lO-1628489892248)(http://www.dtasecurity.cn:20080/tmp/pic/08.png "ClassLoader")]
We have several
ClassLoader
inheritance relationships in the figure, and the red arrow describes the parental delegation mechanism. When our custom class loader wants to load a class, it will not think about loading this class first, but will first ask theApplication
class loader, can you help me load this class?Application
The class loader said, I still have your grandfather's class loader on it, and that's it, untilBootstrap
the class loader is found, ifBootstrap
the class loader can't load this class, then it will reverse and let its own subclass find a way to handle the loading. If the upper-level class loader can load the class, it will be directly loaded successfully. To put it simply, every son is unwilling to work, and every time there is work, his father will do it. Until the father says that I can't do it, let the son find a way to complete it. This is the parental delegation mechanism.
What are the benefits of the parental delegation mechanism?
- Security: We already know that
Bootstrap
the class loader will load the system class library, for example, it loads aString
class, and our custom class loader wants to load an identical class, it must not work, because the upper layer has already loaded The class cannot be reloaded in the lower layer, so the system core library can be protected from tampering. - Efficiency: This is how to ensure that a class can only be loaded once, will not be loaded repeatedly, and can directly read the loaded ones
Class
.
when the class is loaded
- Implicit loading: Developers don't deliberately want to load a class, or they don't know the concept of class loading
-
- Example of creating a class
-
- Access static variables of a class
-
- Calling a static method of a class
-
- Use reflection to force the creation of
java.lang.Class
objects corresponding to a class or interface
- Use reflection to force the creation of
-
- Initialize a subclass of a class
- Explicit loading:
-
LoadClass
load using
-
forName
load using
Android
class loader in the system
Android
The class loader of the platform is not Android
unique, but Java
inherited from it, so what is the difference between Android
the class loader and the one in it? Java
Let's introduce them one by one:
ClassLoader
: an abstract class, all class loaders inherit it directly or indirectlyBootClassLoader
: Preload the commonly used class loader, which is a singleton mode.Java
Unlike in ,BootStrapClassLoader
it is notC
implemented by the code, but byJava
the codeBaseDexClassLoader
It isPathClassLoader
the parent class ofDexClassLoader
,InMemoryDexClassLoader
, and the main logic of class loading is beingBaseDexClassLoader
completed.SecureClassLoader
Inherit the abstract class of the classClassLoader
, expand the classClassLoader
class, add the function of the class permission, and strengthen the security. Its subclassURLClassLoader
usesURL
the path to load the class from the network resourcePathClassLoader
It isAndroid
the class loader used by default, and the classesapk
in oneActivity
are loaded by itDexClassLoader
dex
Can load ,jar
,apk
,zip
files in any directory , which isPathClassLoader
more flexible thandex
InMemoryDexClassLoader
is loaded directly from memorydex
, which wasAndroid8.0
introduced later
Note: The classes of the commonly used
Framwork
layers in the system are all loadedBootClassLoader
by the source . The classes ofAPP
the system used to develop a systemAPI
are all loaded by it, andAPP
the classes in the system are allPathClassLoader
loaded by the source.
Going back to the sixth level, in fact, the root cause is that the one used to Frida
load our custom class is not the same one , so it will appear when we use it to load . Knowing the problem, we can solve this problem. The following provides Two solutions, thanks to the solution provided by Simp1erRegisterClass
ClassLoader
SisthActivity
PathClassLoader
ClassLoader
PathClassLoader
ClassNotFoundException
- The first way of thinking: the parental delegation mechanism
Since we can't load it with the default one PathClassLoader
, we know that its loading process is first loaded through the parent loader, that is, it will be called to BootClassLoader
load our target class, and of course BootClassLoader
it cannot be loaded successfully, so we can do it in PathClassLoader
the BootClassLoader
middle Insert ours RegisterClass
, ClassLoader
and it can change from PathClassLoader
-> to -> of -> , so that the class that was originally used to load our class will be entrusted to the father to load first, and the loading will fail, and finally we will load it, and this time can be completed loaded. Insertion is also very simple, because one of the middle marks is the father of the other , which is represented by using, we can directly modify this value, see the first implementation belowBootClassLoader
PathClassLoader
RegisterClass
ClassLoader
BootClassLoader
PathClassLoader
PathClassLoader
BootClassLoader
RegisterClass
ClassLoader
ClassLoader
ClassLoader
ClassLoader
parent
function main(){
Java.perform(function(){
//Sixth
var RegisterClass = Java.registerClass({
name: "com.dta.test.frida.activity.RegisterClass",
methods: {
next: {
returnType: "boolean",
argumentTypes:[],
implementation: function(){
return true
}
}
}
})
var targetClassLoader = RegisterClass.class.getClassLoader()
Java.enumerateClassLoaders({
onMatch: function(loader){
try{
if(loader.findClass("com.dta.test.frida.activity.SixthActivity")){
// PathClassLoader
var PathClassLoader = loader
var BootClassLoader = PathClassLoader.parent.value
PathClassLoader.parent.value = targetClassLoader
targetClassLoader.parent.value = BootClassLoader
}
}catch(e){
}
},onComplete: function(){
console.log("Completed!")
}
})
})
}
setImmediate(main)
- The second way of thinking: the method
Hook
Class
of the classforName
, you can modify the third parameter to oursRegisterClass
,ClassLoader
so thatClass.forName
it can be loaded correctly
function main(){
Java.perform(function(){
//Sixth
var RegisterClass = Java.registerClass({
name: "com.dta.test.frida.activity.RegisterClass",
methods: {
next: {
returnType: "boolean",
argumentTypes:[],
implementation: function(){
return true
}
}
}
})
var targetClassLoader = RegisterClass.class.getClassLoader()
var Class = Java.use('java.lang.Class')
Class.forName.overload('java.lang.String', 'boolean', 'java.lang.ClassLoader').implementation = function (str, init, loader) {
console.log('loader', loader)
console.log('className', str)
console.log('iniit', init)
return this.forName(str, init, targetClassLoader)
}
})
}
setImmediate(main)
Seventh pass
Paste the source code of the seventh level below
package com.dta.test.frida.activity;
import android.view.View;
import com.dta.test.frida.R;
import com.dta.test.frida.base.BaseActivity;
import com.dta.test.frida.base.Level;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import dalvik.system.InMemoryDexClassLoader;
public class SeventhActivity extends BaseActivity {
private Class<?> MyCheckClass;
@Override
protected String getDescription() {
return getString(R.string.seventh);
}
@Override
public void onClick(View v) {
super.onClick(v);
try {
loadDex();
Method check = MyCheckClass.getDeclaredMethod("check");
Object handle = MyCheckClass.newInstance();
boolean flag = (boolean) check.invoke(handle);
if (flag){
gotoNext(Level.Eighth);
}else {
failTip();
}
} catch (Exception e) {
failTip();
}
}
private void loadDex() {
if (MyCheckClass != null){
return;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
try {
InputStream is_dex = getAssets().open("mycheck.dex");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ( ( len = is_dex.read(bytes,0,bytes.length) ) != -1 ){
bos.write(bytes,0,len);
}
bos.flush();
ByteBuffer buffer = ByteBuffer.wrap(bos.toByteArray());
InMemoryDexClassLoader classLoader = new InMemoryDexClassLoader(buffer, getClassLoader());
MyCheckClass = classLoader.loadClass("com.dta.frida.MyCheck");
}catch (Exception e){
e.printStackTrace();
failTip();
}
}
}
@Override
protected String getActivityTitle() {
return "第七关";
}
}
Inspection point:
Frida
switchClassLoader
Analysis: This question is to load a
dex
file from the outside, then reflectively loadcom.dta.frida.MyCheck
the class, and call the method in itcheck
. And we want to use the MyCheck class inFrida
the middle , it is not possible directly, it is also because of the problem, now that we have understood , this topic is very simple, we only need to learn how to switch in the middle , use to enumerate , Then judge which one is what we want, and then assign it to what we need , let’s look at the codeHook
use
ClassLoader
ClassLoader
Frida
ClassLoader
Java.enumerateClassLoaders
ClassLoader
ClassLoader
Java.classFactory.loader
loader
function main(){
Java.perform(function(){
//Seven
Java.enumerateClassLoaders({
onMatch: function(loader){
try{
if(loader.findClass("com.dta.frida.MyCheck")){
console.log("Found!")
Java.classFactory.loader = loader
}
}catch(e){
}
},onComplete: function(){
console.log("Completed!")
}
})
Java.use("com.dta.frida.MyCheck").check.implementation = function(){
return true
}
})
}
setImmediate(main)
Summarize
This article mainly introduces the usage of Frida Hook Java layer. The APIs are dead, but we need to master them flexibly and use different API combinations according to different purposes to achieve our goals. These seven topics are also relatively basic. content, because Android's Java is inherently very simple. Of course, it is necessary to know why, so in the sixth question, the content of ClassLoader is explained, so that we can understand the essence through the problem, so that we can improve.
To download the APP practice questions, please scan the QR code to visit: