Bugku安卓逆向

Bugku安卓逆向

六月 24, 2019

前几天刚接触安卓逆向,做了几道安卓逆向题,bugku的几道入门题,惊为天人,这Java代码如此清晰明了,不像ida的C语言伪代码让人看得头都爆炸,虽说简单而且很多人都做过,也记录一下入坑过程。

Timer

安装打开是一个倒计时,提示200000秒后出现flag
查看Java代码(可以用不同的工具,我用的Jeb2和Androidkiller,jeb2中按Q可以转化smali代码和Java代码,Androidkiller也有工具可以查看Java代码),beg是开始时间+200000s,也就是出现flag的时间,now是现在实时时间

关键代码:一个判断,判断begnow时间差小于0则输出答案,还有个关键变量k,初始值为0

可以直接修改判断条件绕过判断,剩下的问题就在于关键变量k的值了,代码意思是对从200000遍历到1的所有值用is2函数判断,再根据判断结果改变k的值,我们跟进is2函数:

照样写脚本,跑出k的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def is1(x):
r = True
if x > 3:
if(x % 2 != 0 and x % 3 != 0):
p = 5
while True:
if p*p <= x:
if(x % p != 0 and x % (p+2) != 0):
p += 6
continue
return False
else:
return r
return False
r = False
elif x <= 1:
r = False
return r

k = 0
for i in range(200000, 0, -1):
if is1(i):
k += 100
else:
k -= 1
print(k)

#k=1616384

jeb2中在java代码中找到判断点按Q找到对应的smali代码位置,修改smali源码(可以用AndroidKiller或者apktool等),可以将gtz(大于等于)换成ltz(小于等于),也可以用其他操作,逻辑上能跳过等待都行。

然后还要解决k值的问题,从下面iget(取值,用于操作int这种的值类型)语句可以看出v3是k的值,在这句后面加上const v3,1616384(赋值给v3)然后编译,签名(AndroidKiller可以签名),再安装就会直接出现flag了,记得换flag格式。

LoopAndLoop

安装打开让你输入密码得到flag,直接查看Java代码,找到输出flag的位置:

跟进判断函数(check):

发现一个原生(native)函数:Java中使用其他语言编写的函数
现在一些app,为了安全或者效率问题,会把一些重要的功能放到native层,Android中一般native层使用的是so库文件
然后apktool反编译后用IDA调试liblhm.so文件,找到chec函数:

意思大概是传入两个参数v1v2,再根据2*v2%3的值确定调用check1,2,3中的一个函数,以v1v2-1作为参数,最后v2<=1则返回v1
check1,2,3在Java代码里,都比较简单:

我们观察代码并照样写逆向脚本,原来v1是从输入的值到1835996258,v2从99到2,逆向脚本v2就从2到99,v1从1835996258到需要我们输入的正确密码,3个check函数里面的加减给变一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def fun(a,b):
if(b>99):
return a
else:
if(2*b%3==0):
return fun1(a,b+1)
elif(2*b%3==1):
return fun2(a,b+1)
else:
return fun3(a,b+1)

def fun1(a,b):
for i in range(1,100):
a-=i
return fun(a,b)

def fun2(a,b):
if(b%2==0):
for i in range(1,1000):
a-=i
return fun(a,b)
else:
for i in range(1,1000):
a+=i
return fun(a,b)
def fun3(a,b):
for i in range(1,10000):
a-=i
return fun(a,b)

print(fun(1835996258,2))

#算出密码为236492408

再打开app输入密码就能得到flag了

easy-100

安装打开还是常见的让你输入key,jeb查看Java代码,加上main一共有6个函数,看类名估计都有用:

先看MainActivityonCreate方法,执行了p方法,之后对class d创建了一个按钮监听事件,p方法是把url.png以二进制方式打开,从144的位置开始读取16字符赋值给v,apktool反编译后Winhex查看可以确定v值为this_is_the_key.


跟进class d分析,发现调用了MainActivity.a()函数对输入进行校检:

再回去看MainActivity.a(),发现有重载,一个参数,两个参数,三个参数的MainActivity.a()函数,d中外层调用了三个参数的MainActivity.a()函数,MainActivity作为第一个参数,一个参数的MainActivity.a()函数作为第二个参数,输入的字符串作为第三个参数,三个参数的MainActivity.a()函数返回的是两个参数的MainActivity.a()函数,一层层分析其实最后就是a("this_is_the_key.",输入的字符串)

两个参数的MainActivity.a()函数返回class c.a()函数,再跟进,又有重载………先调用一参数的class c.a()"this_is_the_key."每两个字符交换位置得到"htsii__sht_eek.y",然后将这个和输入的字符串传到class a的函数去:

跟进class a,是一个AES加密,ECB模式,PKCS5Padding填充,"htsii__sht_eek.y"作为密钥,加密后返回与两个参数的MainActivity.a()中的一长串相等就ok了,网上找在线解密就行,我试了好几个网站才搞定。

网友写的解密脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES

data = [0x15, 0xa3, 0xbc, 0xa2, 0x56, 0x75, 0xed, 0xbc,
0xa4, 0x21, 0x32, 0x76, 0x10, 0x0d, 0x01, 0xf1,
0xf3, 0x03, 0x04, 0x67, 0xee, 0x51, 0x1e, 0x44,
0x36, 0xa3, 0x2c, 0xe9, 0x5d, 0x62, 0x05, 0x3b]

with open('url.png', 'rb') as f:
content = f.read()[144:144+16]

key = ''
for i in range(0, len(content), 2):
key += content[i + 1]
key += content[i]

data = ''.join([chr(c) for c in data])

def decrypt(data, key):
aes = AES.new(key, AES.MODE_ECB)
text = aes.decrypt(data)
return text

print decrypt(data, key)

SafeBox

安装打开,还是输入key…..,没有提交按钮,但是不影响,还是先看Java代码,MainActivity函数:

照样写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import math
v6="NJCTF{"
for v4 in range(10000001,99999999):
v7=1
v8=10000000
v3=1
if(abs(math.floor(v4/1000)%100-36)==3 and v4%1000%584==0):
v5=0
while(v5<4):
if(math.floor(v4/v7)%10!=math.floor(v4/v8)%10):
v3=0
else:
v7*=10
v8/=10
v5+=1
continue
break
if(v3==1):
print(v4)
print(v6+chr(math.floor(v4/1000000))+chr(math.floor(v4/10000)%100)+chr(math.floor(v4/100)%100)+"f4n}")
#48533584
#NJCTF{05#f4n}

题上有提示flag只含大小写字母和数字,这个答案是错的,交上去也过不了,再找找发现androidTest类里面和MainActivity很像,只有一些细节不同:

改脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import math
v6="NJCTF{have"
for v4 in range(10000001,99999999):
v7=1
v8=10000000
v3=1
if(abs(math.floor(v4/1000)%100-36)==3 and v4%1000%584==0):
v5=0
while(v5<3):
if(math.floor(v4/v7)%10!=math.floor(v4/v8)%10):
v3=0
else:
v7*=10
v8/=10
v5+=1
continue
break
if(v3==1):
print(v4)
print(v6+chr(math.floor(v4/1000000))+chr(math.floor(v4/10000)%100)+chr(math.floor(v4/100)%100+10)+"f4n}")
#48533584
#NJCTF{have05-f4n}
#48539584
#NJCTF{have05if4n}

第二个flag满足提示的条件,交上去A了。

easyeasy-200

MainAcivity中接收输入的字符串,先判断长度,然后用Format.form()函数截取,之后用Check.check()判断,然后调用到了native层的checkEmulatorcheckPasswd函数,checkPipes函数检查路径是否存在,查看后知道恒返回假,最后关键就在checkPasswd里:

apktool反编译后ida调试so文件,找到checkPasswd,先对传入的字符串进行了反转:

然后有一个加密,比较复杂,我看不懂,尝试在字符串里找密文,发现可疑字符串:

下面的明显是base64,上面的也像,把最后的”.”换成”=”解码在反转得到flag.

signin

签到题,看Java代码,很明显就是把输入的字符串反转再base64解码后与id2131427360(0x7f0b0020)处密文比较:

Androidkiler逐步搜索直接就能找到密文.

mobile1

看Java代码,用checkSN()函数校检"Tenshine"和输入的字符串:

checkSN()函数,先判断字符串长度,后对"Tenshine"进行md5加密并转化成十六进制再截取奇数位(下标从0开始),拼上flag格式与输入的flag比较(忽略大小写):

分析完后用网上的在线工具就能解题。

mobile2

解压后是一个文件夹,不是apk,也不能编译生成apk,其实是一道杂项题,flag在AndroidManifest.xml里:

First_Mobile(xman)

主函数:监听,把输入的字符串传给encode.check()校检

跟进观察,算法很清晰明了:将函数里的字符串经过简单加密后与输入的字符串比较

脚本:

1
2
3
4
5
6
arr=[23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32]
for i in range(len(arr)):
for j in range(127):
if(((arr[i]+j)%61)*2-i==j):
print(chr(j),end='')
#LOHILMNMLKHILKHI

跑出来答案怎么交都不对,flag其实是XMAN{LOHILMNMLKHILKHI}…..

HelloSmali2

这道题更像是教学性质的题吧,给你一个smali代码和一个Java代码,相互翻译其实是一样的,要过题的话直接跑Java代码就行了,我放个smali文件链接感兴趣的同学可以试着读一下:smali代码反正我是读不懂……………………