安卓逆向|菜鸟的FRIDA学习笔记:分析一个简单的APK

本文致谢

本篇文章学到的内容来自且完全来自r0ysue的知识星球,推荐一下(这个男人啥都会,还能陪你在线撩骚)。

打开样本app(文末有下载地址),手机界面显示如下:

将样本app拖入jadx,搜索上面的提示,定位到这里:

判断property的值是否为Russia,写个frida简单Hook下:

Java.use("java.lang.System").getProperty.overload('java.lang.String').implementation = function (str)
{
      console.log("Current Property is: ",str,this.getProperty(str));
      return "Russia";
}

这样强制返回了"Russia",就可以过掉这个判断,Hook后运行:

提示就在上面代码的下一个提示,可以看到是判断了这个:

!str.equals(getResources().getString(R.string.User))

找到 R.string.User,它在这里:

依葫芦画瓢,让getenv方法强制返回:

RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==

即可,代码:

Java.use("java.lang.System").getenv.overload('java.lang.String').implementation = function (str)
{
      console.log("Current getenv is: ",str,this.getenv(str));
      return "RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==";
 }  

这个字符串看起来像base64编码后的字符,解码后,拿到第一个flag:

FLAG{57ERL1NG_4RCH3R}

Hook后,进入了登录界面:

随便输入用户名和密码,看看提示啥:

jdax中搜索红色箭头位置处的字符串,定位到这里:

逻辑也很简单,输入的usename与 R.string.username相比较,在资源文件中找到R.string.username,它的值是:

再看password:,它是在j方法里面进行处理的,一个简单的md5摘要算法,哈希出来的结果与 R.string.password进行比较。

找到R.string.password的值,它是一个30位的字符串:

84e343a0486ff05530df6c705c8bb4

对于这种30位的md5,去掉前6位和后八位,然后再拿到md5加密网站上去解密即可。结果如图:

得到结果:guest,这时,用户名和密码都拿到了,登录后拿到flag:

这是一个聊天记录,随便输入一个字符串,点击SEND按钮,发现毫无反应,猜测需要发送特定的字符串,jadx中尝试搜索 last time,定位到这里:

注意这个 com.tlamb96.kgbmessenger.b.a 方法,发现下面的代码中也有调用:

看到这行代码:

String obj = editText.getText().toString();

以及这个if判断:

if (a(obj.toString()).equals(this.p)) {
        Log.d("MessengerActivity", "Successfully asked Boris for the password.");
        this.q = obj.toString();
        this.o.add(new com.tlamb96.kgbmessenger.b.a(R.string.boris, "Only if you ask nicely", j(), true));
        this.n.c();
 }

输入的字符串经过a方法后与this.p进行比较,而this.p的值是:

"V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003";

a方法是:

private String a(String str) {
        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length / 2; i++) {
            char c = charArray[i];
            charArray[i] = (char) (charArray[(charArray.length - i) - 1] ^ '2');
            charArray[(charArray.length - i) - 1] = (char) (c ^ 'A');
        }
        return new String(charArray);
    }

这个方法很简单,后半段字符(逆序)与'2'异或,变成新的前半段字符;前半段字符逆序与'A'异或,变成新的后半段字符,中间的那个字符e不做处理。

写成Python还原代码:

s = "V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003"
half_len = len(s) // 2
r = ""
for i in range(half_len):
    r += chr(ord(s[i]) ^ ord('2'))
r += 'e'
for i in range(half_len+1,len(s)):
    r += chr(ord(s[i]) ^ ord('A'))
print (r[::-1])

得到结果:

Boris, give me the password

输入后有回应了:

还是没拿到flag,原来后面还是b函数处理:

b(obj.toString()).equals(this.r)

输入的字符串经过b方法后与this.r进行比较,而this.r的值是这样的:

"\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000";

b方法是这样的:

private String b(String str) {
        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            charArray[i] = (char) ((charArray[i] >> (i % 8)) ^ charArray[i]);
        }
        for (int i2 = 0; i2 < charArray.length / 2; i2++) {
            char c = charArray[i2];
            charArray[i2] = charArray[(charArray.length - i2) - 1];
            charArray[(charArray.length - i2) - 1] = c;
        }
        return new String(charArray);
 }

b方法也很简单:先右移,再异或,处理完成后再逆序,总长度未变。

因为i%8的结果会有等于0的情况,而一个数异或本身是等于0的,所以你看到r字符串有很多\u0000,其所在的位置都是8的倍数。写成Python还原后的代码:

r = "\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000"[::-1]
s = ""
for i in range(len(r)):
    for ch in range(256):
        if (ch >> (i%8)) ^ ch == ord(r[i]):
            s += chr(ch)
            break
print (s)

得到结果:

 ay I *P EASE* h ve the  assword

注意前后都有空白字符(\u0000),空白位置(非空格,从0开始数8的倍数位置)替换任意字符都可以的.比如输入如下字符串:

May I *PLEASE* have the password?

显示结果:

成功拿到了flag:"FLAG{p455w0rd_P134SE}"。

为了证实空白位置可以填入任意字符,我写了个主动调用的Hook代码:

Java.choose("com.tlamb96.kgbmessenger.MessengerActivity",{
      onMatch : function (instance){
        console.log("found instance :"+ instance);
        instance.q.value = "Boris, give me the password";
        instance.s.value = "2ay I *PLEASE* have the password3";
        console.log("The flag is: ",instance.i());
      },
      onComplete : function(){
        console.log("Search Completed!");
      }
})

保存后的运行:

这里只需要修改instance.s.value的值,注意只能改空白位置的字符,可以随意运行。

本文完,再次感谢肉丝姐带我入门安卓逆向。

样本app百度网盘下载地址:

链接:https://pan.baidu.com/s/1-wHQAke6P6Ff-S3i9JAlYA 
提取码:GOOG
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值