首页
社区
课程
招聘
[原创]UnCrackable App 三部曲学习记录分享
发表于: 2019-11-1 18:30 9507

[原创]UnCrackable App 三部曲学习记录分享

2019-11-1 18:30
9507

1、root监测
    public void onCreate(Bundle bundle) {
        if (c.a() || c.b() || c.c()) {
            a("Root detected!");
        }
        if (b.a(getApplicationContext())) {
            a("App is debuggable!");
        }
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
    }
    public void onCreate(Bundle bundle) {
        if (c.a() || c.b() || c.c()) {
            a("Root detected!");
        }
        if (b.a(getApplicationContext())) {
            a("App is debuggable!");
        }
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
    }
2、输入字符进行验证
public class a {
    public static boolean a(String str) {
        byte[] a;
        String str2 = "8d127684cbc37c17616d806cf50473cc";
        byte[] bArr = new byte[0];
        try {
            a = sg.vantagepoint.a.a.a(b(str2), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("AES error:");
            stringBuilder.append(e.getMessage());
            Log.d("CodeCheck", stringBuilder.toString());
            a = bArr;
        }
        return str.equals(new String(a));
    }

    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[(length / 2)];
        for (int i = 0; i < length; i += 2) {
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
        return bArr;
    }
}

public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher instance = Cipher.getInstance("AES");
        instance.init(2, secretKeySpec);
        return instance.doFinal(bArr2);
    }
}
3、hook 代码
public class a {
    public static boolean a(String str) {
        byte[] a;
        String str2 = "8d127684cbc37c17616d806cf50473cc";
        byte[] bArr = new byte[0];
        try {
            a = sg.vantagepoint.a.a.a(b(str2), Base64.decode("5UJiFctbmgbDoLXmpL12mkno8HT4Lv8dlat8FxR2GOc=", 0));
        } catch (Exception e) {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("AES error:");
            stringBuilder.append(e.getMessage());
            Log.d("CodeCheck", stringBuilder.toString());
            a = bArr;
        }
        return str.equals(new String(a));
    }

    public static byte[] b(String str) {
        int length = str.length();
        byte[] bArr = new byte[(length / 2)];
        for (int i = 0; i < length; i += 2) {
            bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
        }
        return bArr;
    }
}

public class a {
    public static byte[] a(byte[] bArr, byte[] bArr2) {
        SecretKeySpec secretKeySpec = new SecretKeySpec(bArr, "AES/ECB/PKCS7Padding");
        Cipher instance = Cipher.getInstance("AES");
        instance.init(2, secretKeySpec);
        return instance.doFinal(bArr2);
    }
}
3、hook 代码
Java.perform(function () {
	send("hook start");
	
    var c = Java.use("sg.vantagepoint.a.c");
    c.a.overload().implementation = function(){
        send("c.a() " + this.a());
        return false;
    }
    
    c.b.overload().implementation = function(){
        send("c.b() " + this.b());
        return false;
    }
    
    c.c.overload().implementation = function(){
        send("c.c() " + this.c());
        return false;
    }

    var a = Java.use("sg.vantagepoint.a.a");
    a.a.overload('[B', '[B').implementation = function(arg1,arg2){
        var ret = this.a(arg1,arg2);
        console.log(byte2string(ret));
        return ret;
    }

	send("hook end");
});
Level 1比较简单,使用jadx查看代码,大概逻辑是 hook root判断和获取字符sg.vantagepoint.a.a.a(byte[] bArr, byte[] bArr2)
Java.perform(function () {
	send("hook start");
	
    var c = Java.use("sg.vantagepoint.a.c");
    c.a.overload().implementation = function(){
        send("c.a() " + this.a());
        return false;
    }
    
    c.b.overload().implementation = function(){
        send("c.b() " + this.b());
        return false;
    }
    
    c.c.overload().implementation = function(){
        send("c.c() " + this.c());
        return false;
    }

    var a = Java.use("sg.vantagepoint.a.a");
    a.a.overload('[B', '[B').implementation = function(arg1,arg2){
        var ret = this.a(arg1,arg2);
        console.log(byte2string(ret));
        return ret;
    }

	send("hook end");
});
Level 1比较简单,使用jadx查看代码,大概逻辑是 hook root判断和获取字符sg.vantagepoint.a.a.a(byte[] bArr, byte[] bArr2)

UnCrackable App for Android Level 2

字符串验证放到了native层
   static {
        System.loadLibrary("foo");
    }

   static {
        System.loadLibrary("foo");
    }

用ida看一下

"Thanks for all the fish"是答案 很简单

UnCrackable App for Android Level 3

使用frida时,app崩溃 “Process crashed: Trace/BPT trap

根据控制台的log 
V/UnCrackable3: Tampering detected! Terminating...
发现so中进行了frida的反调试
V/UnCrackable3: Tampering detected! Terminating...
发现so中进行了frida的反调试

hook住,继续找字符验证的地方。
java层
public void verify(View view) {
        String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
        AlertDialog create = new Builder(this).create();
        if (this.check.check_code(obj)) {
            create.setTitle("Success!");
            create.setMessage("This is the correct secret.");
        } else {
            create.setTitle("Nope...");
            create.setMessage("That's not it. Try again.");
        }
        create.setButton(-3, "OK", new OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
            }
        });
        create.show();
    }

    static {
        System.loadLibrary("foo");
    }

public void verify(View view) {
        String obj = ((EditText) findViewById(R.id.edit_text)).getText().toString();
        AlertDialog create = new Builder(this).create();
        if (this.check.check_code(obj)) {
            create.setTitle("Success!");
            create.setMessage("This is the correct secret.");
        } else {
            create.setTitle("Nope...");
            create.setMessage("That's not it. Try again.");
        }
        create.setButton(-3, "OK", new OnClickListener() {
            public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
            }
        });
        create.show();
    }

    static {
        System.loadLibrary("foo");
    }


native层

v9指向的是加密字符串的内存地址

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-1-31 20:50 被kanxue编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 27
活跃值: (1673)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好东东,mark下
2019-11-2 16:53
0
雪    币: 10944
活跃值: (7329)
能力值: ( LV12,RANK:219 )
在线值:
发帖
回帖
粉丝
3
bluegatar 好东东,mark下
里面的反调试还是值得学习的 比较典型
2019-11-3 08:29
0
雪    币: 26205
活跃值: (63302)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
4
感谢分享!
2019-11-18 09:36
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
UnCrackable App for Android Level 1
这里为什么使用overload hook
我尝试了没有加overload和加了overload的2中方法,但是还是没有send 回来消息, 没有检测到c.a函数的执行

2019-11-20 11:58
0
游客
登录 | 注册 方可回帖
返回
//