吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8015|回复: 14
收起左侧

[Android CTF] ISC训练赛 CrazyAndroid Writeup

[复制链接]
buzhifou01 发表于 2020-3-26 10:47

1.查壳脱壳


1.使用 PKID查壳,发现加了360的壳
2345截图20200319114632.png
2.我在逍遥模拟器中进行脱壳操作,先是运行genymotion,随后运行模拟器,在cmd中输入adb shell,会提示超过了一个设备,关闭genymotion,就能在cmd中操作模拟器。
2345截图20200321105415.png
2345截图20200319161756.png
3.接着使用drizzleDumper进行脱壳,下载好git软件,选中某个文件夹,右键Git bash here,输入git clone https://github.com/DrizzleRisk/drizzleDumper.git就可下载。
2345截图20200319161245.png
4.下好后再x86文件夹可以看到drizzleDumper文件,该文件就为脱壳的关键文件,在说它脱壳的原理前,先简单介绍一下Dex文件,apk程序第一次加载时,系统会把class.dex文件进行优化生成odex文件,这样做是为了提高程序的运行效率。
2345截图20200319173347.png
下面是dex的头部结构:
[Asm] 纯文本查看 复制代码
struct DexOptHeader {
    u1  magic[8];
    u4  dexOffset;
    u4  dexLength;
    u4  depsOffset;
    u4  depsLength;
    u4  optOffset;
    u4  optLength;
    u4  flags;
    u4  checksum;
};

5.在它的头部结构中有一个magic[8]数组,这个数组的值是固定的,于是就可以当成特征值进行匹配,下面是find_magic_memory函数的代码,该函数是drizzleDumper工具的关键函数,在该函数中可以看出:先是读取整个内存文件,随后判断该文件是否为ELF文件和dex文件,然后与特征值进行匹配。
[C++] 纯文本查看 复制代码
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[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F')
      {
        free(buffer);
        continue;
      }
  //判断是否为dex文件
     if(buffer[0] == 'd' && buffer[1] == 'e' && buffer[2] == 'x' && buffer[3] == '\n'  && buffer[4] == '0' && buffer[5] == '3')
      {
			  DexHeader header;
			  char real_lenstr[10]={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中的虚拟机,接下来进行如下脱壳操作:
[Asm] 纯文本查看 复制代码
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/19  11:50    <DIR>          .
2020/03/19  11:50    <DIR>          ..
2020/03/19  11: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 [clone_pid] 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,进去发现里面的流程图结构非常复杂,感觉代码混淆了。
2345截图20200321095821.png
2.接着摁f5分析伪代码,发现里面调用了hehe1、hehe2、hehe3、hehe4函数,感觉这四个函数应该是寻找突破的地方,从程序中可以看出当四个函数都返回1时,注册才能成功。
2345截图20200321100331.png
2345截图20200321100342.png
2345截图20200321100356.png
2345截图20200321100404.png
3.进入这四个函数,发现它们的流程结构非常复杂,感觉也加了混淆,但内部逻辑还是看得清楚,在hehe1函数中,发现把输入注册码的前40个字符赋值给某字符串,并且检验注册码前6位是否等于Pre6,从此看出:注册码的长度为40且前6位为Pre6。
hehe1.png
hehe11.png
hehe12.png
4.在hehe2函数中,调用了crazy函数,该函数传入的参数为:进入crazy函数,找到关键代码处,看到一些混淆代码行,但这些混淆的代码不影响代码的逻辑分析,该函数主要是对某字符串进行处理新的字符串。
crazy.png
5.在下面可以看出hehe2函数,先是判断input[23]和input[6]是否为'-',接着对input[6:23]字串进行值变换。
hehe2.png
hehe21.png
hehe23.png
6.在hehe3函数中,可以看出判断input[25:31]是否为v2,动态调式发现v2为Java代码传来的参数,为170501
hehe3.png
7.在hehe4函数中,可以看到padding字符串,使用idapython脚本,可以看出该字符串的值,脚本见下。
[Python] 纯文本查看 复制代码
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)

运行结果:
padding.png
8.动态分析发现crazy(padding, 88)返回值为'075e191fe314c1e7917d9c71f7b6ed9842090f28f649bad384d0880d103b99a8',随后把返回拼接到input字符串的后面,通过代码可以看出截取input的长度为30,把拼接后的字符串进行运算操作,结果为2765405600。
hehe41.png
hehe44.png
呵呵43.png
9.最后把hehe4生成的序列值拼接到input后面,随后对input进行字符变换,生成的字符串为flag,生成的flag的代码如下:
[Python] 纯文本查看 复制代码
# -*- 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[i]:
					t.append(j + k)
		AllT.append(t)
	for i in AllT:
		#在列表I中,找出任意值
		AnsT += choice(i)
	AnsTL = list(AnsT)
	index=[5,6,9,11,12,13,14,15]
	i=0
	#对列表值进行交换
	while i <len(index):
		i1=index[i]
		i2=index[i+1]
		i+=2
		t1=AnsTL[i1]
		t2=AnsTL[i2]
		AnsTL[i1]=t2
		AnsTL[i2]=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[26:52]+base[0:26]+base[-12:]
	key2=key1[13:26]+key1[0:13]+key1[39:52]+key1[26:39]+key1[57:62]+key1[52:57]+key1[-2:]
	#生成key的值对应字典
	for i in range(0,len(key2)):
		keyTokey[key2[i]] = key1[i]
	flag=''
	for i in str1:
		flag+=keyTokey[i]
	print 'flag: ',flag
GetFlag()

运行结果:
flag.png

CrazyAndroid.rar

1.06 MB, 下载次数: 41, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 3威望 +2 吾爱币 +103 热心值 +3 收起 理由
qtfreet00 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
为海尔而战 + 2 + 1 我很赞同!

查看全部评分

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

 楼主| 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

感谢分享,学到了一些工具
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-15 12:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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