附件:见[原创]frida基础 闯关训练 七层关卡-Android安全-看雪-安全社区|安全招聘|kanxue.com
LoginActivity
onClick()
方法中判断了输入不能为空,且要满足LoginActivity.a(obj, obj).equals(obj2)
才行,方法如下:
很简单,也就是密码是账号的HmacSha256加密,加密使用的密钥是账号本身。
这里我们使用frida来操作,编写js脚本来hooka()
方法,打印我们需要的返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function login(){ Java.perform( function(){ var clazz = Java.use("com.example.androiddemo.Activity.LoginActivity"); clazz.a.overload("java.lang.String", "java.lang.String").implementation = function(str, str2){ var result = this.a(str, str2); console.log("HmacSHA256: " + result); return Java.use("java.lang.String").$new(result); }
} ) }
setImmediate(login)
|
输出结果如下:
1
| HmacSHA256: 4e4feaea959d426155a480dc07ef92f4754ee93edbe56d993d74f131497e66fb
|
我们可以通过adb shell input text "xxx"
将这段值输入到获得焦点的EditText控件中。
FridaActivity1
整个UI界面就一个按钮可以触发,对应代码如下:
由于我们无法输入,所以得hooka()
方法,使其直接返回后面这串字符。
1 2 3 4 5 6 7 8 9 10 11 12
| function FridaActivity1(){ Java.perform( function(){ var clazz = Java.use("com.example.androiddemo.Activity.FridaActivity1"); clazz.a.implementation = function(bArr){ return Java.use("java.lang.String").$new("R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL="); } } ) }
setImmediate(FridaActivity1)
|
FridaActivity2
CheckSuccess()
为父类方法,是个空的,可以不用管它。分析可知,我们需要hook FridaActivity2实例,篡改这两个变量的值就行了(直接改或者调用set方法改).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function FridaActivity2(){ Java.perform( function(){ var clazz = Java.use("com.example.androiddemo.Activity.FridaActivity2"); Java.choose("com.example.androiddemo.Activity.FridaActivity2",{ onMatch: function(obj){ console.log("found instance: FridaActivity2"); obj.static_bool_var.value = true; obj.bool_var.value = true; console.log("static_bool_var = " + obj.static_bool_var + "; bool_var = " + obj.bool_var); }, onComplete: function(){ console.log("finish") } }) } ) }
setImmediate(FridaActivity2)
|
FridaActivity3
整个操作跟FridaActivity2的一样,不过需要注意的是:如果字段名与方法名一样,则需要给字段名前加下划线”_”,否则获取到的是方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function FridaActivity3(){ Java.perform( function(){ Java.choose("com.example.androiddemo.Activity.FridaActivity3",{ onMatch: function(obj){ console.log("found instance: FridaActivity3"); obj.static_bool_var.value = true; obj.bool_var.value = true; obj._same_name_bool_var.value = true; console.log("static_bool_var = " + obj.static_bool_var.value + "; bool_var = " + obj.bool_var.value + "; obj.same_name_bool_var = " + obj._same_name_bool_var.value); console.log(obj.same_name_bool_var()); }, onComplete: function(){ console.log("finish"); } }) } ) }
setImmediate(FridaActivity3)
|
FridaActivity4
这个很简单,只要将这些方法全部hook一遍,修改返回值为true就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function FridaActivity4(){ Java.perform( function(){ var clazz = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses"); clazz.check1.implementation = function(){ return true; }; clazz.check2.implementation = function(){ return true; }; clazz.check3.implementation = function(){ return true; }; clazz.check4.implementation = function(){ return true; }; clazz.check5.implementation = function(){ return true; }; clazz.check6.implementation = function(){ return true; };
} ) }
setImmediate(FridaActivity4)
|
FridaActivity5
仔细分析整个代码的话,不难知道,程序通过loaddex()
方法创建DexClassLoader来动态加载dex文件,不过它将DexClassLoader强转为CheckInterface接口类,里面的check()
方法由其子类DynamicCheck实现,也就是说,当调用getDynamicDexCheck().check()
是,执行的是子类DynamicCheck的check()
方法。所以,我们需要hook该方法,使其返回true。
但是,由于当前的类加载器是加载AndoridDemo.apk的,而check()
方法在加载DynamicPlugin.dex的类加载器中,所以需要遍历类加载器寻找。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function FridaActivity5(){ Java.perform( function(){
Java.enumerateClassLoaders({ onMatch: function(loader){ try { if(loader.loadClass("com.example.androiddemo.Dynamic.DynamicCheck")){ console.log("success"); Java.classFactory.loader = loader; console.log(loader); var clazz = Java.use("com.example.androiddemo.Dynamic.DynamicCheck"); clazz.check.implementation = function () { return true; } } } catch (error) { } }, onComplete: function(){ console.log("classloader change"); } }) } ) }
setImmediate(FridaActivity5)
|
FridaActivity6
跟FridaActivity4一样,hook这些方法修改返回值就可以了(不需要像FridaActivity5一样,因为这些方法又不是动态加载来的)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function FridaActivity6(){ Java.perform( function(){ var Frida6Class0 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class0"); Frida6Class0.check.implementation = function () { return true; }
var Frida6Class1 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class1"); Frida6Class1.check.implementation = function () { return true; }
var Frida6Class2 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class2"); Frida6Class2.check.implementation = function () { return true; } } ) }
setImmediate(FridaActivity6)
|
然后到了第七关FridaActivity7,看源码可以知道整个练习就结束了。