出题团队简介
战队介绍:专注于虚拟化技术保护Android, Linux, IOS, Windows全系统平台。
赛题设计思路
背景
题目信息
文件名:KCTF2022-sprint-android-crackme.apk
设计思路
本题算法延续了KCTF2021-秋季赛-第八题群狼环伺的设计方法:
-
对输入的name字符串通过SHA1算法计算得到16字节的hash值
-
对hash值做rc4加密运算得到16字节value1值
-
选取部分代码计算SHA256得到16字节的密钥Key值
-
将输入的64字符长度password转为16字节的16进制表示(如:前8个字符64613231转换后为2字节的0xda21)和Key做3DES解密运算得到value2,当password不足64字节时提示错误
-
比较value1 == value2时,则为正确的密钥对,提示输入正确
增加防护技巧
-
题目设计为双进程模式,算法的校验分别放在两个进程中,并通过管道通信且父子进程使用相互ptrace防调试处理
-
管道通信读写及部分操作如: open/read/getpid等系统调用通过中断svc指令实现
-
父子进程均增加/proc/self/status调试检测
-
算法及防护代码编译后的文件以二进制方式,对函数指令做了vm保护处理
解题思路
主要是去除防调试功能及调试检测功能
-
对父进程的ptrace操作进行nop填充
-
对父进程中fork后创建ptrace线程pthread_create操作进行nop填充
-
对父子进程中/proc/self/status调试检测均进行nop填充
-
跟踪管道通信时,子进程read读数据操作,读取到value值后会进行校验,重点关注eor指令对数据进行的运算操作
vm保护原理
-
反汇编器:负责解析输入二进制文件,输出函数指令和数据流
-
解释器:负责对vm指令和数据流进行解释执行
-
链接器:负责将vmachine嵌入新二进制文件中,并对地址相关的指令做重定位
解释器工作原理
-
ldr指令进行分析做重定位如下
-
BL指令是相对当前地址到跳转目标地址=0x16D8+0x1BA8 = 0x3280
赛题解析
本赛题解析由看雪论坛专家 ThTsOd 给出:
dump出附近内存,用作对比,没啥想法。
mylogfile = new File("/data/data/a.b.c/d1.txt","wb");
Interceptor.attach(baseAddr.add(0x4d15),{
onEnter:function(args){
var mylog = "";
mylog += "DES Enc:" + (this.context as any).lr.sub(baseAddr) + "n";
// mylog += JSON.stringify(this.context) +"n";
// mylog += (this.context as any).lr.sub(baseAddr) + "n";
// // mylog += hexdump(args[0],{
// // offset:0,
// // length:0x100,
// // header:true,
// // ansi:true
// // })
// // mylog+="n";
// mylog += hexdump(args[1],{
// offset:0,
// length:0x10,
// header:true,
// ansi:true
// })
// mylog+="n";
// mylog += hexdump(args[2],{
// offset:0,
// length:0x10,
// header:true,
// ansi:true
// })
// mylog+="n";
mylogfile.write(mylog);
mylogfile.flush();
},onLeave:function(ret){
var mylog = "";
mylog += "After DES Enc:" + (this.context as any).lr.sub(baseAddr) + "n";
// mylog += JSON.stringify(this.context) +"n";
// mylog += hexdump((this.context as any).r2,{
// offset:0,
// length:0x10,
// header:true,
// ansi:true
// })
// mylog+="n";
mylogfile.write(mylog);
mylogfile.flush();
count+=1
if(count==2){
//debugger;
}
}
});
f=open("libcrackme.so","rb")
data = f.read()
f.close()
result = 0
while(result != -1):
result = data.find(bytearray.fromhex("44 F0 0D E5"),result+4)
print(hex(result+0x1000))
function hookart(){
var baseAddr = Module.findBaseAddress("/apex/com.android.runtime/lib/libart.so");
//var baseAddr = Module.findExportByName(null,"_ZN3art12_GLOBAL__N_18CheckJNI12NewStringUTFEP7_JNIEnvPKc");
console.log("Art",baseAddr)
Interceptor.attach(baseAddr.add(0x2C85D1),
{
onEnter: function (args)
{
if(args[1].readCString() == "您输错了" || args[1].readCString() == "顺利过关"){
console.log(args[1].readCString(),args[1]);
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].add(0xe0),{
offset:0,
length:128,
header:true,
ansi:true
}));
console.log(JSON.stringify(this.context));
console.log(hexdump(this.context.sp.sub(0),{
offset:0,
length:128,
header:true,
ansi:true
}));
memset_log = false;
mylogfile.close();
//debugger;
}
},
onLeave: function (ret)
{
}
}
);
}
计算下最后输出字符串位置返回是14664:
Interceptor.attach(baseAddr.add(0xf628),{
onEnter:function(args){
if(true || (this.context as any).sp.sub(0x44).readPointer().sub(baseAddr) == ptr(0x145e8)){
var mylog = "";
mylog += (this.context as any).sp.sub(0x44).readPointer().sub(baseAddr) + " Result " + (this.context as any).lr.sub(baseAddr) +"n";
mylog += JSON.stringify(this.context)+"n";
// mylog += hexdump((this.context as any).r3,{
// offset:0,
// length:(this.context as any).r0.sub((this.context as any).r3).toUInt32(),
// header:true,
// ansi:true
// })
mylog+="n";
console.warn("!! ",JSON.stringify(this.context))
mylogfile.write(mylog);
mylogfile.flush();
debugger;
}
},onLeave:function(ret){
}
});
发现1e48c 跳转到xref较少的地方。
第九题《同归于尽》正在进行中
球分享
球点赞
球在看
原文始发于微信公众号(看雪学苑):看雪2022 KCTF 春季赛 | 第八题设计思路及解析