第一次做flash逆向的题目,不过这个题目还是比较简单的,简单搜集了一下得到了一个工具: https://github.com/jindrapetrik/jpexs-decompiler
跑起来之后大概这样
翻了下几个目录,得到几个主要的信息:
Action Script
简单读了下发现是这样一个逻辑:
在第1帧里面:
所以第1帧输入 1456
,跳到第3帧
然后跟进第3帧:
所以第3帧输入 25
,跳到第4帧,
然后跟进第4帧:
所以第4帧输入 44
,跳到第2帧,
然后跟进第2帧:
所以第4帧输入 8
,跳到第6帧,关于这个spw和spwd是算最后的key的,所以可以不用管具体怎么算的,因为最后会打印答案的。
然后跟进第6帧:
所以第6帧输入 88
,跳到第5帧,
然后跟进第5帧:
最后输入 20546
,跳到最后一帧打印答案
做题之前先说一下环境安装过程吧,好歹折腾了快俩小时,头疼。题目的readme提示了要win8。
首先在MSDN上下镜像,我用的是这个:
起一个管理员权限的powershell,先设定可以执行ps脚本,再设定运行不受信任的用户发布的软件
set-executionpolicy remotesigned Set-ExecutionPolicy -ExecutionPolicy Unrestricted
然后证书有效期注意
调整系统时间为2013年,之后用 powershell
运行ps1脚本,然后就会弹出一个框要链接服务器获取win8开发者许可证,这个时候先 别点我同意
,因为要连接服务器,需要把系统时间恢复回来,然后再点我同意,之后登录Microsoft账户,然后很快就弹出一个框:
然后关闭之后可能会失败,这个时候不慌,因为win8开发者许可证已经拿到了,我们把系统时间重新回到2013年,然后重新跑一次ps1脚本,然后就安装成功了:
然后查了下,这个appx后缀其实就是个皮包的zip,直接按zip解压就行了,然后看到一个 MetroApp.exe
,放进ida里面,搜字符串找到了判断的关键位置:
然后想着动态调试,很迷很迷,没有调过类似的,并没有经验,每次调试器附加上去之后,只要暂停,一般不过10多秒钟,程序就自动退出了,非常头疼,而且经过调试之后发现上述找到的关键位置应该是个还不够:
即便开头以 MERONG
开头也是wrong,说明后面还有进一步的判断,
这里用的各种 windowsxxxx
的api都是对 HSTRING
结构体操作,从多次调试来看,如下下图的前20字节:
第4-7代表 HSTRING
长度,第16-19字节代表实际的 UTF-16
的字符串的地址。
然后继续往下看代码,整个代码量太大了,而且动态调试应该是我没有掌握到方法,最多只能暂停住进程10来秒的样子,一旦超了进程就退出了。
这里要注意调试的线程是主线程,通过调用堆栈可以定位到用户空间的代码,然后搜索关键字符串例如 wrong
就能找到具体的代码位置,然后下断点就能调试
进过一番调试测试,终于定位到了一个奇怪的地方:
对应的反编译代码如下:
这三个都是对应的我们输入的字符串,再看看接下来这个递归式子,
v80是个计数器,在while之前被置为0,每一轮循环自加一,
v50,v51,v52
都是输入。考虑到其中的字符串编码是UTF-16,每一个字符对应两个字节,所以换算一下,递归式如下:
input[i+1] = byte_4307A8[i] ^ rol(input[i] , input[i] & 7)
Readme.txt
提示了说答案是大写字母+数字
那就很简单了,写个深搜直接爆破所有答案,由于不知道长度,暂时用15来爆破:
byte_4307A8=[0x77,0xAD,0x07,0x02,0xA5,0x00,0x29,0x99,0x28,0x29,0x24,0x5E,0x2E,0x2A,0x2B,0x3F,0x5B,0x5D,0x7C,0x5C,0x2D,0x7B,0x7D,0x2C,0x3A,0x3D,0x21] v80=0 stringtable="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ans="" length=15 def rol(lst_int, k): lst=list('{:0>8}'.format(bin(lst_int)[2:])) tmp= lst[k:] + lst[:k] tmp2=int("0b"+"".join(i for i in tmp),2) return tmp2 def search(char,i,ans): print(char,i,ans) if i==length: print(ans) input("") return else: for j in stringtable: if ord(j) == byte_4307A8[i&7]^rol(ord(char),ord(char)&7): search(j,i+1,ans+j) return for i in stringtable: search(i,0,i)
结果如下:
答案也就是 D34DF4C3
虽然乱七八糟把答案整出来了,但是几个地方还是没弄懂
Correct
和 Wrong
的 HSTRING
明显就是幌子,但是真实的判断点及输出点哪儿? MetroAPP
? 最近时间实在太碎了,这类型的题先留坑,有整块时间再来看。
一个2kb不到的jar文件,直接放到jd里面一看,空空如也。。。
不知道是版本还是混淆的原因,那就换一个在线反编译网站 java Decompilers online
六种反编译器,JDCore出不来,但是CFR出来了,代码如下:
/* * Decompiled with CFR 0.139. */ import java.io.PrintStream; public class JavaCrackMe { public static final synchronized /* bridge */ /* varargs */ strictfp /* synthetic */ void main(String ... arrstring) { try { System.out.println("Reversing.Kr CrackMe!!"); System.out.println("-----------------------------"); System.out.println("The idea came out of the warsaw's crackme"); System.out.println("-----------------------------/n"); long l = Long.decode(arrstring[0]); if ((l *= 26729L) == -1536092243306511225L) { System.out.println("Correct!"); } else { System.out.println("Wrong"); } } catch (Exception exception) { System.out.println("Please enter a 64bit signed int"); } } }
那就很简单了, -1536092243306511225=2**64-1536092243306511225=16910651830403040391
但是 16910651830403040391/26729
不能整除,考虑到无符号 long
型的数据最大为 2**64-1
,那就多叠加几个 2**64
如下:
for i in range(10000000): if (-1536092243306511225+2**64+i*2**64)%26729==0: print((-1536092243306511225+2**64+i*2**64)//26729) print(2**64-(-1536092243306511225+2**64+i*2**64)//26729) exit()
得到结果 9468659231510783855
,但是被说不是 64bit signed int
,那就转换成负数 -(2**64-9468659231510783855)=8978084842198767761
,
最终答案就是 -8978084842198767761