buzhifou01 发表于 2020-3-26 10:47

ISC训练赛 CrazyAndroid Writeup

# 1.查壳脱壳
1.使用 PKID查壳,发现加了360的壳

2.我在逍遥模拟器中进行脱壳操作,先是运行genymotion,随后运行模拟器,在cmd中输入adb shell,会提示超过了一个设备,关闭genymotion,就能在cmd中操作模拟器。


3.接着使用drizzleDumper进行脱壳,下载好git软件,选中某个文件夹,右键Git bash here,输入git clone https://github.com/DrizzleRisk/drizzleDumper.git就可下载。

4.下好后再x86文件夹可以看到drizzleDumper文件,该文件就为脱壳的关键文件,在说它脱壳的原理前,先简单介绍一下Dex文件,apk程序第一次加载时,系统会把class.dex文件进行优化生成odex文件,这样做是为了提高程序的运行效率。

下面是dex的头部结构:
struct DexOptHeader {
    u1magic;
    u4dexOffset;
    u4dexLength;
    u4depsOffset;
    u4depsLength;
    u4optOffset;
    u4optLength;
    u4flags;
    u4checksum;
};
5.在它的头部结构中有一个magic数组,这个数组的值是固定的,于是就可以当成特征值进行匹配,下面是find_magic_memory函数的代码,该函数是drizzleDumper工具的关键函数,在该函数中可以看出:先是读取整个内存文件,随后判断该文件是否为ELF文件和dex文件,然后与特征值进行匹配。
int find_magic_memory(uint32_t clone_pid, int memory_fd, memory_region *memory , const char *file_name) {
   ......
   while(fscanf(maps_file, "%[^\n]\n", mem_line) >= 0)
   {
    ......
    //获取内存文件的大小
    memory->start = mem_start;
    memory->end = strtoul(mem_address_end, NULL, 16);
    int len =memory->end - memory->start;
    ......
       //扫描内存
          lseek64(memory_fd , 0 , SEEK_SET);       
          off_t r1 = lseek64(memory_fd , memory->start , SEEK_SET);
   ......
   //判断内存文件是否为ELF文件
      if(buffer == 'E' && buffer == 'L' && buffer == 'F')
      {
      free(buffer);
      continue;
      }
//判断是否为dex文件
   if(buffer == 'd' && buffer == 'e' && buffer == 'x' && buffer == '\n'&& buffer == '0' && buffer == '3')
      {
                          DexHeader header;
                          char real_lenstr={0};
                          memcpy(&header , buffer ,sizeof(DexHeader));
                        //对dex文件进行dump
                          if(dump_memory(buffer , len , each_filename)== 1)
                          {
                                printf(" [+] dex dump into %s\n", each_filename);
                                free(buffer);
                                continue;
                          }
                          else
                          {
                                 printf(" [+] dex dump error \n");
                          }

                 }
                  free(buffer);
           }
}
那么脱壳的原理是:在root的权限下运行该工具时,使用ptrace附加到apk程序,接着使用find_magic_memory函数遍历读取内存中的文件并使用ODEX的magic对每个文件进行特征值匹配,匹配好后就找到了相应的dex文件并进行内存dump。
6.开启genymotion中的虚拟机,接下来进行如下脱壳操作:

C:\Users\Lenovo>cd E:\职业\github\drizzleDumper\libs\x86

C:\Users\Lenovo>e:

E:\职业\github\drizzleDumper\libs\x86>dir
驱动器 E 中的卷是 文档
卷的序列号是 B8A0-6DDD

E:\职业\github\drizzleDumper\libs\x86 的目录

2020/03/1911:50    <DIR>          .
2020/03/1911:50    <DIR>          ..
2020/03/1911:50             9,532 drizzleDumper
               1 个文件          9,532 字节
               2 个目录 313,587,281,920 可用字节
E:\职业\github\drizzleDumper\libs\x86>adb push drizzleDumper /data/local/tmp
drizzleDumper: 1 file pushed. 0.1 MB/s (9532 bytes in 0.117s)

E:\职业\github\drizzleDumper\libs\x86>adb shell chmod 0777 /data/local/tmp/drizzleDumper

E:\职业\github\drizzleDumper\libs\x86>adb shell
root@android:/ # su
root@android:/ # pm list packages
...
package:top.phrack.ctf.crazyandroid
package:com.noshufou.android.su
...
root@android:/ # cd /data/local/tmp
root@android:/data/local/tmp # ls
...
CrazyAndroid.apk
drizzleDumper
...
root@android:/data/local/tmp #./drizzleDumper top.phrack.ctf.crazyandroid
...
[*]Try to Find top.phrack.ctf.crazyandroid
[*]pid is 1316
[*]clone pid is 1327
[*]ptrace 1327
[*]Scanning dex ...
...
[+]Done
C:\Users\Lenovo>adb pull /data/local/tmp/top.phrack.ctf.crazyandroid_dumped_5746.dex E:\0ODprogram
/data/local/tmp/top.phrack.ctf.crazyandroid_dumped_5746.dex: 1 file pulled. 3.9 MB/s (868352 bytes in 0.213s)

接着top.phrack.ctf.crazyandroid_dumped_5746.dex放入反编译工具,就可以查看Java代码,把不过在下面的分析中,可能用不上脱壳后的dex文件,因为解题的逻辑都会在so层,而不会在activity层,不过脱壳后可以方便调式.在第二部分涉及到动态调式,输入的用户名为:pctf(题目要求),通过动态调式获取某些字符串的具体值,具体怎样动态调式,我就不说了,比较简单,网上有教程。
# 2.分析so文件

1.用ida加载so文件,没有找到JNI_OnLoad函数,接着寻找Java_类名_方法名的函数,找到Java_top_phrack_ctf_crazyandroid_MainActivity_CheckSerial,进去发现里面的流程图结构非常复杂,感觉代码混淆了。

2.接着摁f5分析伪代码,发现里面调用了hehe1、hehe2、hehe3、hehe4函数,感觉这四个函数应该是寻找突破的地方,从程序中可以看出当四个函数都返回1时,注册才能成功。




3.进入这四个函数,发现它们的流程结构非常复杂,感觉也加了混淆,但内部逻辑还是看得清楚,在hehe1函数中,发现把输入注册码的前40个字符赋值给某字符串,并且检验注册码前6位是否等于Pre6,从此看出:注册码的长度为40且前6位为Pre6。



4.在hehe2函数中,调用了crazy函数,该函数传入的参数为:进入crazy函数,找到关键代码处,看到一些混淆代码行,但这些混淆的代码不影响代码的逻辑分析,该函数主要是对某字符串进行处理新的字符串。

5.在下面可以看出hehe2函数,先是判断input和input是否为'-',接着对input字串进行值变换。



6.在hehe3函数中,可以看出判断input是否为v2,动态调式发现v2为Java代码传来的参数,为170501

7.在hehe4函数中,可以看到padding字符串,使用idapython脚本,可以看出该字符串的值,脚本见下。
def Getpadding(str_addr):
        tpadding=''
        while(1):
                #判断循环是否结束
                if hex(Byte(str_addr))=='0x0':
                        break
                #叠加字符串字符生成字符串
                tpadding+=chr(Byte(str_addr))
                str_addr+=1
        return tpadding
print Getpadding(0x6046)
运行结果:

8.动态分析发现crazy(padding, 88)返回值为'075e191fe314c1e7917d9c71f7b6ed9842090f28f649bad384d0880d103b99a8',随后把返回拼接到input字符串的后面,通过代码可以看出截取input的长度为30,把拼接后的字符串进行运算操作,结果为2765405600。



9.最后把hehe4生成的序列值拼接到input后面,随后对input进行字符变换,生成的字符串为flag,生成的flag的代码如下:
# -*- coding:utf-8 -*-
from random import choice
pre6='pctfef'
hehe3_8="Pctf2016"
hehe3_8_o=[]
javastr='170501'
base='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+'
#把hehe3_8中的字符转换成十进制数
def Hehe3_8ToOrd():
        for i in hehe3_8:
                hehe3_8_o.append(ord(i))

'''
def GetBase(str_addr):
        base=''
        while(1):
                #判断循环是否结束
                if hex(Byte(str_addr))=='0x0':
                        break
                #叠加字符串字符生成字符串
                base+=chr(Byte(str_addr))
                str_addr+=1
        return base
'''
def Getpadding(str_addr):
        tpadding=''
        while(1):
                #判断循环是否结束
                if hex(Byte(str_addr))=='0x0':
                        break
                #叠加字符串字符生成字符串
                tpadding+=chr(Byte(str_addr))
                str_addr+=1
        return tpadding
def getlast():
        #base=GetBase(0x6004)
        last=base[-12:]
        return last
def crazy(a,b):
        t1=a<<4
        t2=~b+1
        t2=0xD0-t2
        ans=(t2 ^ t1) | (t2 &t1 )
        return ans & 0xFF

def hehe2():
        AnsT=''
        AllT=[]
        AnsT=''
        Hehe3_8ToOrd()
        last=getlast()
        for i in range(0,len(hehe3_8_o)):
                t= []
                for j in last:
                        for k in last:
                                if crazy(ord(j), ord(k)) == hehe3_8_o:
                                        t.append(j + k)
                AllT.append(t)
        for i in AllT:
                #在列表I中,找出任意值
                AnsT += choice(i)
        AnsTL = list(AnsT)
        index=
        i=0
        #对列表值进行交换
        while i <len(index):
                i1=index
                i2=index
                i+=2
                t1=AnsTL
                t2=AnsTL
                AnsTL=t2
                AnsTL=t1
        str1=''.join(AnsTL)
        return str1
def hehe4():
        padding = '075e191fe314c1e7917d9c71f7b6ed9842090f28f649bad384d0880d103b99a8'
        str1=hehe2()
        #AnsCode相当于input,len为30
        AnsCode=pre6+'-'+str1+'-'+javastr
        enstr = AnsCode + padding
        ans = 0
        for i in enstr:
                t = ord(i) - (~(0x28 * ans) + 1)
                ans = t & 0xFFFFFFFF
        return AnsCode+str(ans)
keyTokey={}
def GetFlag():
        str1=hehe4()
        key1=base+base+base[-12:]
        key2=key1+key1+key1+key1+key1+key1+key1[-2:]
        #生成key的值对应字典
        for i in range(0,len(key2)):
                keyTokey] = key1
        flag=''
        for i in str1:
                flag+=keyTokey
        print 'flag: ',flag
GetFlag()
运行结果:


buzhifou01 发表于 2020-3-26 11:23

52Douyin 发表于 2020-3-26 10:58
谢谢大神。
所有用到的软件,也能打包,提供下载啊,就好了。

我用到的工具,网上都好下载,百度一搜都有的

52Douyin 发表于 2020-3-26 10:57

大神,录一个视频就好了。

52Douyin 发表于 2020-3-26 10:58

谢谢大神。
所有用到的软件,也能打包,提供下载啊,就好了。

红人馆0910 发表于 2020-3-26 11:28

nice啊 快来下载吧

hyoulin68 发表于 2020-3-26 11:34

谢谢大神。

柒汐 发表于 2020-3-26 13:45

不明觉厉~好好学习~

luxingyu329 发表于 2020-3-26 13:50

现在找不到了!

zoooox 发表于 2020-3-26 16:09

感谢分享,学到了一些工具

双木成林 发表于 2020-3-26 20:01


感谢分享,学到了一些工具
页: [1] 2
查看完整版本: ISC训练赛 CrazyAndroid Writeup