Mobile
1.level 6
解压缩包文件apk,在/assets/bin/data/Managed/Metadata/global-metadata.dat文件,然后在lib里面找到libil2cpp.so文件,将两个文件放入同一个文件夹,用il2cpp dumper跑一下
打开里面的stringliteral.json文件
猜一下查找关键字unnty,直接找到flag
2.level 7
本题还是考查安卓逆向,老样子先把apk文件解压一下,找lib文件里面的arm文件里的.so文件,拖入ida反编译
找到Java_com_swdd_summertrain_MainActivity_Check函数,跟进
可以发现函数就是一个异或取反,主要是找密文
这个是假密文,跑出来是fakeflag
在此处跟进
就可以看到真密文,直接异或0xff逆一下就有flag了
flag{EasyInitArray}
Reverse
Ezsnake:
本题乍一看以为是一道贪吃蛇的题目,实际上比我想象的复杂得多,进到页面,是一个有关贪吃蛇界面
在uodateMap里面发现了花指令
去花过程:
跟进一个jmp到指令中间,即EB FF机器码使得下一条指令从FF开始解析,需要把EB给nop掉。
这样算正常
到下面还有一个基于call的花指令
该指令执行过程大概是:
1.push rbp 将rbp的值压栈
2.call $+5 说明是将call的下一条指令的地址压栈,$+5恰好跳转到下一条指令到pop rbp
3.pop rbp 将rip(下一条)的值弹出至rbp
4.add rbp, 8就是将rbp的值+8,此时rbp中的地址为地址结尾为175D的那个地方,为pop rbp
5.push rbp就是将rbp的值压入栈
6.retn 返回到栈顶的地址,也就是刚刚压栈的rbp的值,就是刚开始压栈的那个rip再+8的值
7.地址结尾为175D的那个地方反编译得到pop rbp,恢复rbp的值,至此花指令结束。
所以综上分析,最开始的push rbp到最后的pop rbp中间都是没用的花指令,都要nop掉
然后f5即可看到关键函数信息
乍一看有点像是魔改的xtea,再退到主函数部分分析一波
可以看到当贪吃蛇长度达到41的时候进入游戏
game.in为新分配的一块大小为地图大小的内存,而game.in前game.total字节被设置为’.’,应该是为储存地图strcpy(&game.in[game.total], a1)存储输入的flag。
scankey主要是只获取输入并按一定规则改变蛇的方向。printMap也没有关于flag输入输出的信息点。
moveSnake函数中位snake贪吃蛇吃*的有关信息点,并调用了updateMap这个关键的函数,所以要从该函数入手。
chakFlag里面是对密文的一个比较,密文数组是aetx,也就是flag加密后的结果
看到movesnake加密部分
NextPos = getNextPos(*(qword_140008088 + dword_140008080), dword_140008078); if ( isDead(NextPos) ) return 0xFFFFFFFFi64; ++dword_140008080; dword_140008080 %= dword_140008048; *(qword_140008088 + dword_140008080) = NextPos; if ( *(Block + NextPos) == 42 ) { if ( dword_14000804C > 50 ) dword_14000804C -= 10; *(Block + NextPos) = 64; v1 = genFoodPos(); if ( v1 != -1 ) *(Block + v1) = 42; ++dword_14000807C; updateMap(); if ( dword_14000807C == dword_140008048 ) return 1i64; } else { *(Block + NextPos) = 64; *(Block + *(qword_140008088 + dword_140008084++)) = 46; dword_140008084 %= dword_140008048; } return 0i64; }
该加密函数每次吃到东西都会调用一次,结合胜利条件当蛇的长度达到总长度255可知总调用次数为255次(初始长度为1),同时dword_14000804C初始值为190,之后每一轮依次递减10至50便不会变化。(相当于密钥key的依次递减)
根据上述关系就可以写脚本来对flag逆向求值
exp
#include <stdio.h> unsigned char aetx_[] = { 0xB7, 0x79, 0xDB, 0x62, 0xA6, 0xDA, 0xF0, 0x86, 0xE9, 0x44, 0x0A, 0xBD, 0x80, 0x0C, 0x0B, 0x66, 0x68, 0x1A, 0xE6, 0x7C, 0x27, 0x44, 0xFD, 0x63, 0xF9, 0x64, 0x15, 0x0A, 0x1D, 0x95, 0x73, 0x84, 0x2A, 0x8C, 0x63, 0xCA, 0xBD, 0x65, 0xA8, 0xC5, 0x46, 0xD2, 0xE2, 0x8C, 0x56, 0xBB, 0xC5, 0x07 }; unsigned int* aetx = (unsigned int*)aetx_; int main() { for(int i=0;i<255;i++) { unsigned int* v5 = aetx + 12; unsigned int key = i<240?50:50+(i-240)*10; unsigned int sum = 256; for(int j=0;j<=5;j++) { v5-=2; unsigned int v4 = *v5; v5[1] -= ((v4 + ((v4 >> 5) ^ (16 * v4))) ^ (sum - 1640531527)); unsigned int v3 = v5[1]; *v5-=((v3 + ((v3 >> 5) ^ (16 * v3))) ^ key); } } puts((char*)aetx); }