(昨天没写完,今天继续。我明明只是保存为草稿,怎么自动发布了,这是咋回事?)

二、内核程序

进行一些输入操作,发现有个5个指令,但只有help/ls/wr是可以使用的。

继续用IDA分析,但为了方便分析,对原镜像中第2-5个扇区用1337进行异或解密,同时为了使设置加载地址为0x07C00时,第二个扇区能在0×08000地址处(字符串偏移对了就不自己再计算了)。因此我在镜像中第一个扇区后增加一个空扇区。

内核程序先做了下初始化(交换了中断向量表中10h和13h内容,将0:90F0h的内容设置为0A00h),之后显示了logo,进入main过程中。(这些是异或解密后的代码)

在main过程中,先显示提示输入符(user@bctf#),之后接受输入指令,再调用cmd过程处理所输入指令。

在cmd过程中,通过字节比较后执行相应的指令(help/wr/ls/rd/dl)。rd/dl只是简单回显'Error: Permission deny!',help/ls也差不多,主要看wr的处理过程:

1)验证文件名是否合理(长度小于23),

2)根据时间戳生成一个[min, max)范围中的随机数(这个gen_number很重要,后面经常见到它),这里的随机数我们记录为key,后面会用它来加密文件内容。

3)显示提示信息,接受输入

文件结束输入后,调用两个最重要的过程(create_fileheader, savefile)来保存文件到磁盘中。

create_fileheader:创建文件信息头,并保存在0面1磁道1扇区(0x7e00开始,一共8个扇区),savefile保存文件内容。

文件信息头,保存的文件内容结构的结构如下,这构成一条文件链,由结构里的header/cylinder/sector/index找到下一个节点的信息,依次连接起来;当header/cylinder/sector/index都为0xFF时结束。

struct fileheader{
    word isExist;    //1表示该块已经使用,否则为0
    word filelength;
    word key;
    byte header;    //磁头
    byte cylinder;  //磁道
    byte index;     //这里将一个扇区分成16个小块,每块32个字节
    byte sector;    //扇区
    byte[22] encrypt_filename;    //采用异或0xCC加密
}

struct filecontent{
    word isExist;    //1表示该块已经使用,否则为0
    byte header;
    byte cylinder;
    byte index;
    byte sector;
    byte[26] encrypt_filecontent;    //采用异或key再异或字符下标加密
}

简单看下,还是通过gen_number生成随机的header/cylinder/sector/index,然后调用filecheck检查该块是否已经使用。如果已经使用,通过加1调整。

class ReadFile(object):
    def __init__(self, file):
        self.fin = file

    def read(self, offset):
        self.filename = ''
        self.content = []
        self.key = 0
        self.__getContent(offset, True)
        return self.__decode()

    def __getOffset(self, hander, cylinder, sector, index):
        return ((hander+2*cylinder)*63+sector-1)*512+index*32
    
    def __getContent(self, offset, isHeader=False):
        if isHeader:
            self.fin.seek(offset+5)
            self.key = ord(self.fin.read(1))
        else:
            self.fin.seek(offset+2)
        header = ord(self.fin.read(1))
        cylinder = ord(self.fin.read(1))
        index = ord(self.fin.read(1))
        sector = ord(self.fin.read(1))
        if isHeader:
            self.filename = self.fin.read(22)
        else:
            self.content.append(self.fin.read(26))
        if header != 255:
            self.__getContent(self.__getOffset(header, cylinder, sector, index))

    def __decode(self):
        name = [chr(ord(ch)^0xCC) for ch in self.filename if ord(ch) != 0]
        content = [chr(ord(ch)^self.key^i)
                   for i, ch in enumerate(''.join(self.content))]
        return 'read file:%s\n%s' % (''.join(name), ''.join(content))

if __name__ == '__main__':
    fin = open('bctfos.bin', 'rb')
    rd = ReadFile(fin)
    print rd.read(0x7e00)
    fin.close()

key

read file:key
Dear CTFer, if you see this message, you have completely understood my OS. 
Congratulations!Here is what you want: BCTF{6e4636cd8bcfa93213c83f4b8314ef00}

over, thanks.

源链接

Hacking more

...