这个FLAG有点怪

APK文件丢apktool里,拆包,转jar,看源码
图1
注意这个func函数,我们要跟进去,但是func是加载so得到的
IDA打开so文件,去找func,但是!!!没有!!!
好的,我忍!
dex加载so的时候,首先会导出函数中查找JNI_Onload函数,默认情况下,不需要我们管,但是可以重写JNI_Onload进行注册函数
我们去找JNI_Onload函数
图2
点进去发现func字样,下面的函数是_cxa_begin_match
图3
点击跟进F5
从上到下看,出现第一个奇怪的函数gun_arm_fini_29
图4
点击跟进去,知道功能为读取字符串用的
图5
返回继续分析源码
中间有很多东西,是关于调用线程和检测程序的,总的来说就是一种简单的对抗gdb调试的思路吧!(猜的)
图6
然后继续看,我们刚刚输入的字符串进行了一个抑或加密,加密是以如下方式text[i]=text[i]^(i+1)进行的
图7
然后我们继续看如下语句
图8
这几个变量m_y,tempSt,tempabc貌似都没有定义啊!去init段找找吧
查看init段,发现函数_cxa_chk_fail
图9
跟进去看
关键代码在这,跟进sub_1A74函数
图10
这些变量类似于全局变量在这里被注册,在这里对m_y和tempabc进行了初始定义
m_y的值为6
tempabc的值为syc
tempabc赋值进过了一次gun_Unwind1函数,跟进去代码很简单,就是逐位转ascii后-2,在转回字符返回,偷个懒不截图了

然后回到_cxa_begin_match继续跟踪逻辑,这里调用了一个imp_Unwind_k函数
进去查看
图11
可以看到是把穿进去的字符串右移6位,赋值给tempStr
至此,刚刚上面3个未定义的变量值就都确定了
_cxa_begin_match函数,看下一句gun_armfini_33函数
图12
关键代码
图13
大概作用就是,把tempabc中的大写字母转小写,tempStr字符串则是移位2位,赋值给v15……【逻辑看的头疼】
然后下面返回imp_Unwind_j函数,继续跟进去看
图14
分析,第一个if段,确定tempStr角标0 1 2 3 9 10的值,分析过程
角标1和2的值相同,为111,转字符为o
其他的根据判断条件,设角标9为x,可得方程(2*(x-1)-29)+(2*(x-1))+x+(x+31)-304==0,解方程x=51,python有个库为sympy,快速解方程

from sympy import *
x=Symbol('x')
print(solve((2*(x-1)-29)+(2*(x-1))+x+(x+31)-304, x))

至此tempStr的值如下

tempStr[0] = 'G'
tempStr[1] = 'o'
tempStr[2] = 'o'
tempStr[3] = 'd'
tempStr[4] = ''
tempStr[5] = ''
tempStr[6] = ''
tempStr[7] = ''
tempStr[8] = ''
tempStr[9] = '3'
tempStr[10] = 'R'

继续看第二个if条件,循环5次,分别计算出角标4~8的值,角标值异或0x11在加循环次数【次数从0开始算】要等于V6,V6的值根据&szCmp得到,每次循环该地址加4
szCmp的值双击跟进去直接看到分别为 R d r u ^
图15
最终得到tempStr的值为GoodCracK3R

回到_cxa_begin_match函数继续分析
看接下来的if段,注意这里的descsrc
图17
去看变量定义
图16
字符串s其实就是我们要找的,目前已经能确定出前11位GoodCracK3R,src是角标8的首地址,v21和s相差11,作为结束位置
11位之后的值将赋值给dest
并且这里我们给seed赋值,他的位置正好是加密后串(s串的第9、10、11位,也就是K3R)这个seed后面有用!之后进入gun_armfini_21函数,首先是进入gun_armfini_23函数,这里利用了seed值对v8生成了一个256长度的int数组!
图18
用python还原一下逻辑

def make(str,lens):
    a=[]
    for i in range(256):
        a.append(i)
    pos=0
    pos_temp=0
    for i in range(256):
        temp = a[i]
        pos_temp=(ord(str[pos])+a[i]+pos_temp)&0xff
        a[i]=a[pos_temp]
        a[pos_temp]=temp
        pos=((pos+1)%lens)&0xff
    return a

然后我们这个v8数组后面还会用到。之后进入gun_armfini_36函数,这个函数主要就是对11位之后的字符串进行了处理
图19

然后我们还是回到_cxa_begin_match函数!接近结束了!
我们看到是用sprintf函数对v18进行赋值(用11位以后,加密过的字符)然后进入gun_arm_ldiv0函数去匹配!
图20
调用了gun_Unwind函数
图21
继续跟进去
图22
功能就是把字符串转ascii逐位-2
最后我们看看它在做什么?11位之后的内容,进过加密,以16进制形式输出

0xa8
0xe5
0x58
0x8f
0x7e
0x03
0xf7
0x58

然后根据上面的分析,我们就可以得到gun_armfini_33加密以后后八位的字符串是啥了!

def test():
    a=make('K3R',3)
    value=[0xa8,0xe5,0x58,0x8f,0x7e,0x03,0xf7,0x58]
    temp1=0
    temp2=0
    temp3=0
    flag=''
    print a
    for i in value:
        temp1=(temp1+1)&0xff
        temp2=a[temp1]
        temp3=(temp3+temp2)&0xff
        a[temp1]=a[temp3]
        a[temp3]=temp2
        flag+=chr(i^a[(a[temp1]+temp2)&0xff])
    print flag

得到GoodCracK3R;{0jN|B6
接下来只需要逆向一下gun_armfini_33函数,再移位回去再抑或一下就得到答案了!解密程序如下

ppp="GoodCracK3R;{0jN|B6"
key = 'syc'
flag=[]
for i in ppp:
    flag.append(ord(i))
print flag
for j in range(len(flag)):
    if flag[j]>=ord('a') and flag[j]<=ord('z'):
        flag[j]=(flag[j]-97+26-ord(key[j%3])+97)%26+97
    elif flag[j]>=ord('A') and flag[j]<=ord('Z'):
        flag[j]=(flag[j]-65+26-ord(key[j%3])+97)%26+65

newflag=''
for i in range(6,6+len(flag)):
    newflag+=chr(flag[i%len(flag)]^(i-5))
print newflag

得到FLAG xctf{hgJ7Q=|8a\wV;A~}}Wc}