吾爱破解 - LCG - LSG |安卓破解|病毒分析|破解软件|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 1311|回复: 10
上一主题 下一主题

[Android ReverseMe] CTF-Ogeek之安卓逆向,mblockchain

[复制链接]
跳转到指定楼层
楼主
qdam 发表于 2019-8-26 10:36 回帖奖励
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。

本帖最后由 qdam 于 2019-8-26 10:48 编辑

第一次在比赛中挑战安卓逆向题,神奇地做了出来,在此发帖纪念一下。
附件链接 https://pan.baidu.com/s/173IyPx85Y9aeoJJerfWr3Q , 提取码 ccem

改后缀为zip解压,dex2jar,然后上jd-gui,进行源码分析。


首先看到关键的验证部分,也就是checkFlag函数,然后我们进去看一下函数逻辑。
[Asm] 纯文本查看 复制代码
public static boolean checkFlag(String paramString1, String paramString2)
    throws Exception
  {
    paramString1 = hash(paramString1.getBytes());
    paramString1 = hash(new byte[] { paramString1[0], paramString1[(paramString1.length / 2)], paramString1[(paramString1.length - 1)] });
    paramString2 = paramString2.getBytes();
    int i = 0;
    while (i < 10)
    {
      paramString2 = encrypt(paramString2, paramString1);
      paramString1 = hash(paramString1);
      i += 1;
    }
    return toHex(paramString2).equals("74f0b165db8a628716b53a9d4f6405980db2f833afa1ed5eeb4304c5220bdc0b541f857a7348074b2a7775d691e71b490402621e8a53bad4cf7ad4fcc15f20a8066e087fc1b2ffb21c27463b5737e34738a6244e1630d8fa1bf4f38b7e71d707425c8225f240f4bd2b03d6c2471e900b75154eb6f9dfbdf5a4eca9de5163f9b3ee82959f166924e8ad5f1d744c51416a1db89638bb4d1411aa1b1307d88c1fb5");
  }

可以看到首先对paramString1进行经行了哈希(MD5),然后是10轮加密,最后paramString2要等于一长串字符。
这里hash()和toHex()函数功能就如名字一样,就不分析了。主要是对encrypt()函数的分析。
再来具体看一下源码。
[Asm] 纯文本查看 复制代码
public static byte[] encrypt(byte[] paramArrayOfByte1, byte[] paramArrayOfByte2)
    throws Exception
  {
    Object localObject = new SecretKeySpec(paramArrayOfByte2, "AES");
    paramArrayOfByte2 = Cipher.getInstance("AES/ECB/PKCS5Padding");
    paramArrayOfByte2.init(1, (Key)localObject);
    localObject = new ByteArrayOutputStream();
    paramArrayOfByte2 = new CipherOutputStream((OutputStream)localObject, paramArrayOfByte2);
    paramArrayOfByte2.write(paramArrayOfByte1);
    paramArrayOfByte2.flush();
    paramArrayOfByte2.close();
    return (B)((ByteArrayOutputStream)localObject).toByteArray();
  }

这里出现了很对没有见到过的函数,但是不要紧,我们可以从函数名字去猜函数的功能,有些不好理解的我们可以去查阅android手册。
我们可以大致猜测出这里是进行了AES加密,而且是把paramArrayOfByte2作为密钥,paramArrayOfByte1作为明文加密。实际的情况也就是这样。
所以总的来说就是经行了10轮AES加密,每次的密钥是上一个密钥的MD5字符串(刚好是16个字符)。问题来了,怎么解密呢,我们知道MD5是单向散列的,不可逆的,只能顺着来。
其实在checkFlag中的前几步操作已经给了我们提示,paramString1 = hash(new byte[] { paramString1[0], paramString1[(paramString1.length / 2)], paramString1[(paramString1.length - 1)] });
这里只对三个字符求哈希值,咦,三个字符,好像很少,可以爆破哎(滑稽)。
然后我们就可以爆破这三个字符,把10个密钥求出来,再反解,看最初的明文有没有“flag”字符即可。
脚本如下,写的有点丑,大家懂意思就行了。
[Python] 纯文本查看 复制代码
# -*- encoding:utf-8 -*-

import hashlib
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
all='74f0b165db8a628716b53a9d4f6405980db2f833afa1ed5eeb4304c5220bdc0b541f857a7348074b2a7775d691e71b490402621e8a53bad4cf7ad4fcc15f20a8066e087fc1b2ffb21c27463b5737e34738a6244e1630d8fa1bf4f38b7e71d707425c8225f240f4bd2b03d6c2471e900b75154eb6f9dfbdf5a4eca9de5163f9b3ee82959f166924e8ad5f1d744c51416a1db89638bb4d1411aa1b1307d88c1fb5'
enc=a2b_hex(all)
for i in range(256):
        print(i)
        for j in range(256):
                for k in range(256):
                        dec=enc
                        key=chr(i)+chr(j)+chr(k)
                        keys=[hashlib.md5(key).digest()]
                        for x in range(9):
                                keys.append(hashlib.md5(keys[x]).digest())
                        for y in range(10):
                                aes=AES.new(keys[9-y], 1)
                                dec=aes.decrypt(dec)
                        if "flag" in dec:
                                print(b2a_hex(dec))

这里爆破过程中dec有两个值,转一下字符看一下就行了。


免费评分

参与人数 5吾爱币 +4 热心值 +5 收起 理由
zhengyg + 1 + 1 谢谢@Thanks!
全好网 + 1 + 1 热心回复!
冰雪冬樱250 + 1 + 1 谢谢@Thanks!
m01236546 + 1 热心回复!
2673 + 1 + 1 哈哈

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
syncking 发表于 2019-8-26 11:23
参加CTF比赛 ,安卓逆向也就只能做出来java层的加密了 。加密一放到so层就蒙圈了
3#
krypton12138 发表于 2019-8-26 23:06
感谢楼主的分享,收获颇多,看来以后要耐心看这些代码,不能太急躁了。
4#
flowtcw 发表于 2019-8-27 18:13
5#
zhengyg 发表于 2019-8-28 22:16
这个题目时干啥的呀,key和falg都要输入的吗?

为啥是爆破三个字符,10个密钥是啥,怎么出来的,字符串不是无限个???我哪里理解错了吗
6#
 楼主| qdam 发表于 2019-8-29 08:45 <
zhengyg 发表于 2019-8-28 22:16
这个题目时干啥的呀,key和falg都要输入的吗?

为啥是爆破三个字符,10个密钥是啥,怎么出来的,字符串 ...

对,你把apk装到手机上看一下就知道了,key和flag都是需要自己输入的。然后你说的10个密钥是指在checkFlag()函数里面的while循环中的AES的密钥,因为有10轮AES,所以是10个密钥。
7#
zhengyg 发表于 2019-8-29 10:29
qdam 发表于 2019-8-29 08:45
对,你把apk装到手机上看一下就知道了,key和flag都是需要自己输入的。然后你说的10个密钥是指在checkFla ...

主要是我还没明白,key和flag都是随意输入的吗,随意一个key肯定会有flag与之对应吗,题意我还没明白,昨天才知道有OGeek这个东西,原谅我的无知啊
8#
 楼主| qdam 发表于 2019-8-29 13:02 <
zhengyg 发表于 2019-8-29 10:29
主要是我还没明白,key和flag都是随意输入的吗,随意一个key肯定会有flag与之对应吗,题意我还没明白,昨 ...

就针对这道题而言,flag是唯一的,key的话不唯一,但是应该没有人会去解这个key,因为他之后是经过md5处理的。我觉得你还是需要重点关注一下checkFlag这个函数,好好理一下里面的逻辑关系。
9#
sketch_pl4ne 发表于 2019-8-29 14:01
感谢楼主的题解!
10#
陈小胖 发表于 2019-9-3 00:31
感谢楼主的分享,我有几个问题,希望楼主解答一下:
1. Python代码中为什么要range(256)呢?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:禁止回复非技术或与主题无关水贴,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2019-9-19 18:34

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表