2015 0CTF Simple 150

20150CTF的Mobile第二题,分值150

Java层简单明了的写了从res/raw文件夹读取flag.txt,然后输入数据进行对比

对着目录找到flag.txt

flag:0ctf{Too_Simple_Sometimes_Naive!!!}

仿佛是在嘲笑我

抱着打死不信出题人半个字的原则,输入APP验证,然而Wrong

发现有一个so文件

IDA打开,发现有.init_array段,调用了my_init()

__int64 my_init()
{
    int PID; // r0@3
    __int64 v1; // ST00_8@3

    j_j_set_logfunction(nullsub_2);
    if ( CheckSig() )
        j_j_exit(0);
    PID = j_j_getpid();
    j_j_hook(&unk_6004, PID, "libc.", "read", CheckStrace, CheckPtrace, 0);
    return v1;
}

看着这命名,目测是签名验证反调试,然后有一个hook操作

回想在Java层输入的flag不正确,再结合这里,应该就是有坑,这个坑目测就是hook了某个函数

再从传入的参数来看,应该是read()

通常在自定义的函数里有异或操作往往说明这里是一个关键

注意前面有一个v5,其中的两个参数用在了后面的异或操作中,v3可能是某数组的起始地址,v10可能是长度

再进一步猜测,它是read()想到这里,我们把dest[]数组从so里拷贝出来

这里有个小技巧,可以使用Winhex的拷贝功能,找到偏移后,右键用C Source

unsigned AnsiChar data[35] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x1B, 0x48, 0x2C, 0x0C, 0x24, 0x02, 0x02, 0x09, 0x3A, 0x0B, 
	0x3B, 0x0E, 0x03, 0x3A, 0x39, 0x0C, 0x08, 0x11, 0x00, 0x00, 0x1A, 0x09, 0x0C, 0x29, 0x20, 0x58, 
	0x44, 0x00, 0x00
};

写个简单的脚本异或一下

# coding = utf-8

data = [
    0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x1B, 0x48, 0x2C, 0x0C, 0x24, 0x02, 0x02, 0x09, 0x3A, 0x0B, 
    0x3B, 0x0E, 0x03, 0x3A, 0x39, 0x0C, 0x08, 0x11, 0x00, 0x00, 0x1A, 0x09, 0x0C, 0x29, 0x20, 0x58, 
    0x44, 0x00, 0x00]

old_flag = "0ctf{Too_Simple_Sometimes_Naive!!!}"

def main():
    flag = []
    for i in range(len(old_flag)):
        flag.append(chr(ord(old_flag[i]) ^ data[i]))
    print "".join(flag)

if __name__ == '__main__':
    main()

输出

0ctf{It's_More_Than_Meets_The_Eye!}

到这里可以确定我们的猜测,so里hook了read()函数,我们输入的字符串被异或后再和flag.txt里的数据对比

相比另一道150的Mobile,我觉得这题很值

Last updated