首页
社区
课程
招聘
[原创] 第六题 寻回宝剑 writeup
2021-5-19 15:33 5691

[原创] 第六题 寻回宝剑 writeup

2021-5-19 15:33
5691

拖入IDA分析,可以看到大量结构类似的重复指令,调试可以看出这部分的作用是跳转到下一条指令。

可以使用idapython清除来接近程序原本的面目。

def patch():
	startAddr = 0x140001000 
	endAddr = 0x1400FA68A
	i = startAddr
	print (hex(startAddr),hex(endAddr))
	while i <= endAddr:
		addr = i
		addr1 = next_head(addr)
		addr2 = next_head(addr1)
		addr3 = next_head(addr2)
		addr4 = next_head(addr3)
		addr5 = next_head(addr4)
		addr6 = next_head(addr5)
		addr7 = next_head(addr6)
		addr8 = next_head(addr7)
		addr9 = next_head(addr8)
		addr10 = next_head(addr9)
		if idc.GetDisasm(addr) == 'push    rax' \
		and idc.GetDisasm(addr1) == 'push    rax' \
		and idc.GetDisasm(addr2) == 'pushfq' \
		and idc.GetDisasm(addr3) == 'call    $+5' \
		and idc.GetDisasm(addr4) == 'pop     rax' \
		and idc.GetDisasm(addr5).find('xor     rax,') != -1 \
		and idc.GetDisasm(addr6).find('mov     ') != -1 \
		and idc.GetDisasm(addr7) == 'popfq' \
		and idc.GetDisasm(addr8) == 'pop     rax' \
		and idc.GetDisasm(addr9) == 'retn':
			addrj = (addr4 ^ idc.get_operand_value(addr5,1)) - addr4
			addrptch = addr
			while(addrptch < addr3):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			patch_byte(addr3,0xE9)
			patch_dword(addr3+1,addrj)
			addrptch = addr4
			while(addrptch <= addr9):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			i = next_head(addr9)
		elif idc.GetDisasm(addr) == 'push    rax'\
		and idc.GetDisasm(addr1) == 'pop     rax':
			addrptch = addr
			while(addrptch <= addr1):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			i = next_head(addr1)
		elif idc.GetDisasm(addr) == 'push    rbx'\
		and idc.GetDisasm(addr1) == 'pop     rbx':
			addrptch = addr
			while(addrptch <= addr1):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			i = next_head(addr1)
		elif idc.GetDisasm(addr) == 'push    rcx'\
		and idc.GetDisasm(addr1) == 'pop     rcx':
			addrptch = addr
			while(addrptch <= addr1):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			i = next_head(addr1)
		elif idc.GetDisasm(addr) == 'push    rdx'\
		and idc.GetDisasm(addr1) == 'pop     rdx':
			addrptch = addr
			while(addrptch <= addr1):
				patch_byte(addrptch,0x90)
				addrptch = addrptch + 1
			i = next_head(addr1)
		else:
			i = next_head(addr)

清除后动态调试分析,在以下可能的导入函数下段。

最开始会和1746(即36*49结果)比较,相等的话会提示错误。

然后取输入的长度,如果不等于84则也提示错误。

判断输入字符在0~9A~Z+-*/%=42个字符内,索引为0~41

输入的字符两两为一组,一共42组转换成数值表(第一位*42 + 第二位),后面的数字不能比前面的小,所以推断出格式应每组数第一位肯定是不能减小的。

然后会判断使用数值表的数依次42取商取余(第一位索引即为商,第二位索引即为余)不重复,即可推断出第一位数字应该不相同的,递增的,为0_ 1_ 2_ ……/_%_=_,每组数的第二位也是不同的。

按照以上规则输入(001122…//%%==),也还是有问题的,进一步分析可得:依次使用数值表后面(第二位,第三位。。。)与42商余减第一位,得到一个组成一个二维表,使用(第三位,第四位。。。)与42商余,得到一个组成一个二维表。。。依次到最后,所有的二维表不能重复。并且由于第一位数是递增的,可由此推断,第二位索引两两相距位置相同的数字之差不能有重复。这样如果用来跑结果的话数据量还太大。

按照以上规则输入(001122…//%%==),跳过其中的检查,会到后面一步有比较,可以得到正确的码的前28位(02152S3X4Z5Q6C7T819/ADB%C*DL)。这样的话前面固定,就可以写程序来跑后面的结果了。

程序如下:

class Program
{
    static string chartable = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%=";
    public static bool IsRepeat(int[] array)
    {
        Hashtable ht = new Hashtable();
        for (int i = 0; i < array.Length; i++)
        {
            if (ht.Contains(array[i]))
            {
                return true;
            }
            else
            {
                ht.Add(array[i], array[i]);
            }
        }
        return false;
    }
    
    public static bool Test(int[] xxx)
    {
        bool flag = true;
        for (int i = 0; i < xxx.Length - 1; i++)
        {
            int[] xxxx = new int[xxx.Length - i - 1];
            for (int j = 0; j < xxx.Length - i - 1; j++)
            {
                xxxx[j] = xxx[j + i + 1] - xxx[j];
            }
            if (IsRepeat(xxxx))
            {
                flag = false;
                break;
            }
        }
        if (flag)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    static void Guess(int[] now,int[] nothave)
    {
        int have = now.Length - nothave.Length;
        int[] test = new int[now.Length + 1];
        Array.Copy(now, 0, test, 0, now.Length);
        foreach (var item in nothave)
        {
            test[test.Length - 1] = item;

            if (Test(test))
            {
                if (nothave.Length -1>0)
                {
                    int[] nothave2 = new int[nothave.Length - 1];
                    int index = 0;
                    for (int i = 0; i < nothave.Length; i++)
                    {
                        if (test.Contains(nothave[i]))
                        {
                            continue;
                        }
                        else
                        {
                            nothave2[index++] = nothave[i];
                        }
                    }
                    Test4(test, nothave2);
                }
                else
                {
                    if (Test(test))
                    {
                        foreach (var item1 in test)
                        {
                            Console.Write(item1 + ",");
                        }
                    }
                }
                
            }
            else
            {
                continue;
            }
        }
    }
    static void Main(string[] args)
    {
        int[] now = new int[14] { 2, 5, 28, 33, 35, 26, 12, 29, 1, 39, 13, 40, 38, 21 };//每组第二位
        int[] nothave = new int[28] { 0, 3, 4, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 27, 30, 31, 32, 34, 36, 37, 41 };
        Guess(now , nothave);

    }
}

跑的结果:

02152S3X4Z5Q6C7T819/ADB%C*DLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8*F/-%V=A



[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2021-5-19 15:37 被xwwei编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回