查看原文
其他

看雪·众安 2021 KCTF 秋季赛 | 第八题设计思路及解析

2021 KCTF 看雪学苑 2022-07-01

看雪·众安 2021 KCTF秋季赛的第八题《群狼环伺》已于今天中午12点截止答题!
本题共有3支战队成功破解,分别是辣鸡战队、金左手、mininep。

恭喜辣鸡战队用时100442秒拿下“一血”,接下来和我一起来看看该赛题的设计思路和相关解析吧~

出题团队简介


第八题《群狼环伺》出题方: 【ArmVMP】战队



赛题设计思路


本题目是安卓平台的crackme,算法简单,可玩性高,有兴趣可以随时交流。


规则2的demo为:KCTF2021-android-crackme.apk


其中规则2的两组序列号如下:


第一组序列号:
name:KCTF
serial:3633386636373733353933626439316437383865383931653663663432656661

 

第二组序列号:
name:4DD6F06301B04D13
serial:6461323135643835663832623133666234313635636637383266613665363961
(通过命令shasum -a 256 crackme.apk计算apk得文件hash:
4dd6f06301b04d13f76c513326be681de153ff743ce17f411a35e09a08a90d37)

 

设计思路:


1、对输入name字符串通过SHA1算法,计算得到16字节的hash值;
2、hash值做rc4加密运算,得到16字节value1值;
3、对部分代码计算SHA256得到16字节的密钥Key;
4、将输入64个字符password转为16字节的16进制表示(如:前四个字节64613231转换后为0xda21)和Key做3DES解密得到value2,当password不足64字节时提示错误;
5、比较value1 == value2时,则为正确的密钥对。

 

保护方法:


1、代码中有效隐藏了系统函数调用,仅保留了一个memset;
2、增加了常规的检测非法运行手段;
3、通过自研的保护方案将原so中的原始指令进行替换,转换后一条指令对应多条指令,并且部分指令经过编码生成数据,运行时对数据进行解析运行。原函数内部的字符串和函数访问通过模拟指令执行,能够有效隐藏相关调用。

 

解题思路:


由于对代码段的指令做了变形保护,通过相同功能的函数实现指令替代运行,所以反编译时,较难看出算法逻辑,需要对模拟代码标识出相应的指令来分析逻辑,当然也存在不需要标记的情况.


春季赛中4为选手均是通过对数据流分析,比对每种指令运行次数,以及数据输入及输出做观察跟踪出的序列号。当然也可以通过人肉找到关键比较处跟踪到序列号。

 

关于作者:喜欢阅读与运动,专注于互联网安全行业从业十多年之久。


主攻方向研究二进制文件保护技术,基于指令虚拟化保护技术,研发的安全产品覆盖诸多平台包括Android,Linux, IOS及物联网平台,致力于通过技术手段,以减少对用户的恶意攻击及破坏行为,让世界多一些友善。



赛题解析


本赛题解析由看雪论坛ThTsOd给出:

IDA上来一看,没啥函数:
找一下密码学常量,发现有个DES:查找引用:发现有部分函数没有识别,手动Create Function。 sub_788就是DES过程了,hook下打印三个参数:
Interceptor.attach(baseAddr.add(0x789),{ onEnter: function (args){ console.log((this.context as any).lr.sub(baseAddr)); console.log(JSON.stringify(this.context)); console.log(hexdump((this.context as any).r0,{ offset:0, length:128*3, header:true, ansi:true })); //Enc Data console.log(hexdump((this.context as any).r1,{ offset:0, length:8, header:true, ansi:true })); }, onLeave: function (ret){ //After Enc console.log(hexdump((this.context as any).r2,{ offset:0, length:8, header:true, ansi:true })); }});
可以看到将输入转成hex再转hex后,加密了一次,随后是加密相同的内容:
 这里可以将DES轮秘钥倒过来,解密。
function swapkey(addr:NativePointer){ var key = [] for(var i = 0;i<48;i+=1){ key.push(addr.add(i*8).readU64()); } for(var i = 0;i<48;i+=1){ addr.add(i*8).writeU64(key[47-i]); }}
当提交成功时,会出现"恭喜成功",但是在java层代码和native层代码没有找到这个字符串,这里无意尝试把以下内容修改了。程序崩溃,查看logcat:
 UTF-8转换相关,hook下libart.so的CheckJNI::NewStringUTF(dump自己的so文件,ida找一下这个函数)
Interceptor.attach(baseAddr.add(0xae765), { onEnter: function (args){ //console.log(args[1].readCString(),args[1]); if(args[1].readCString() == "恭喜成功" || args[1].readCString() == "输入错误"){ var mainAddr = Module.findBaseAddress("libcrackme.so"); console.log((this.context as any).lr.sub(mainAddr)); for(var i=0;i<64;i++){ //console.log((this.context as any).sp.add(i*4).readPointer(),(this.context as any).sp.add(i*4).readPointer().sub(mainAddr)); } console.log(hexdump(args[1])); console.log(JSON.stringify(this.context)); console.log(hexdump(this.context.sp.add(0xB0),{ offset:0, length:192, header:true, ansi:true })); debugger; } }, onLeave: function (ret){ } });
这样可以在判断完结果后将程序断下(frida的debugger命中会暂停当前线程)。 搜一下正确输入的加密结果,运行程序时保持name相同,serial不同。 bd 3a b0 69 39 40 f8 cd 42 0d e3 8a 79 db 52 bd 找到一个:运行程序时保持name不同(这里输入KCTF),serial相同。 同样也找到一个:这时就能猜出DES加密结果应该为: 45 68 97 A3 29 2A 7F D4 F5 90 73 57 46 02 AE D5 就可以得到正确答案了。
if(true){ //DES Decrypt swapkey((this.context as any).r0); //Data 1 if((this.context as any).lr.sub(baseAddr) == 0xe8b5){ var encdata = [0x45,0x68,0x97,0xa3,0x29,0x2a,0x7f,0xd4]; (this.context as any).r1.writeByteArray(encdata); } //Data 2 if((this.context as any).lr.sub(baseAddr) == 0xe8e5){ var encdata = [0xf5,0x90,0x73,0x57,0x46,0x02,0xae,0xd5]; swapkey((this.context as any).r0);//Swap Again (this.context as any).r1.writeByteArray(encdata); }}

应该输入的hex 为 63 8f 67 73 59 3b d9 1d 78 8e 89 1e 6c f4 2e fa 再转换一次: 3633386636373733353933626439316437383865383931653663663432656661,即为正确答案。 部分代码如下:
function swapkey(addr:NativePointer){ var key = [] for(var i = 0;i<48;i+=1){ key.push(addr.add(i*8).readU64()); } for(var i = 0;i<48;i+=1){ addr.add(i*8).writeU64(key[47-i]); }} function hook(){ var baseAddr = Module.findBaseAddress("libcrackme.so"); Interceptor.attach(baseAddr.add(0x789), { onEnter: function (args){ console.log((this.context as any).lr.sub(baseAddr)); //console.log(JSON.stringify(this.context)); // console.log(hexdump((this.context as any).r0,{ // offset:0, // length:128*3, // header:true, // ansi:true // })); if(true){ //DES Decrypt swapkey((this.context as any).r0); //Data 1 if((this.context as any).lr.sub(baseAddr) == 0xe8b5){ var encdata = [0x45,0x68,0x97,0xa3,0x29,0x2a,0x7f,0xd4]; (this.context as any).r1.writeByteArray(encdata); } //Data 2 if((this.context as any).lr.sub(baseAddr) == 0xe8e5){ var encdata = [0xf5,0x90,0x73,0x57,0x46,0x02,0xae,0xd5]; swapkey((this.context as any).r0);//Swap Again (this.context as any).r1.writeByteArray(encdata); } } //Enc Data console.log(hexdump((this.context as any).r1,{ offset:0, length:8, header:true, ansi:true })); }, onLeave: function (ret){ //After Enc console.log(hexdump((this.context as any).r2,{ offset:0, length:8, header:true, ansi:true })); } } );} function hookart(){ var baseAddr = Module.findBaseAddress("/system/lib/libart.so"); //var baseAddr = Module.findExportByName(null,"_ZN3art12_GLOBAL__N_18CheckJNI12NewStringUTFEP7_JNIEnvPKc"); console.log("Art",baseAddr) Interceptor.attach(baseAddr.add(0xae765), { onEnter: function (args){ //console.log(args[1].readCString(),args[1]); if(args[1].readCString() == "恭喜成功" || args[1].readCString() == "输入错误"){ var mainAddr = Module.findBaseAddress("libcrackme.so"); console.log((this.context as any).lr.sub(mainAddr)); for(var i=0;i<64;i++){ //console.log((this.context as any).sp.add(i*4).readPointer(),(this.context as any).sp.add(i*4).readPointer().sub(mainAddr)); } console.log(hexdump(args[1])); console.log(JSON.stringify(this.context)); console.log(hexdump(this.context.sp.add(0xB0),{ offset:0, length:192, header:true, ansi:true })); debugger; } }, onLeave: function (ret){ } } );}

往期解析


1、看雪·众安 2021 KCTF 秋季赛 | 第二题设计思路及解析


2、看雪·众安 2021 KCTF 秋季赛 | 第三题设计思路及解析


3、看雪·众安 2021 KCTF 秋季赛 | 第四题设计思路及解析


4、看雪·众安 2021 KCTF 秋季赛 | ‍第五题设计思路及解析


5、看雪·众安 2021 KCTF 秋季赛 | 第六题设计思路及解析


6、看雪·众安 2021 KCTF 秋季赛 | 第七题设计思路及解析




第九题《万事俱备》正在火热进行中,

👆还在等什么,快来参赛吧!



- End -


公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com




球分享

球点赞

球在看



戳“阅读原文”展开第9题的角逐!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存