1625-5 王子昂 总结《2017年12月28日》 【连续第454天总结】
A. 34c3ctf - m0rph
B.
国际的CTF难度真是感人……OTZ虽然确实很好玩就是了
64位elf文件,拖入IDA打开,找到main函数
哎哟,这么清晰的结构~真是Easy啊~
太年轻了
仔细看看,len要求为23,再往下….v6是函数?qword_202020+8*i这里放着啥函数啊 点过去也没发现任何东西
查看交叉引用,发现在sub_8D0和sub_987里还有玄机
sub_8D0
v1是申请的16个字节的空间,将a1+0x11*i放入v1中,然后第9和第10个单位分别放0x11*i和i
list | a1 + 0x11 * i (FunctionAddress) | 0x11*i (Start) | i (Index) | (empty) |
---|---|---|---|---|
v1 | 0-7 | 9 | 10 | 11 - 15 |
wide/bytes | 8 | 1 | 1 | 6 |
sub_987
这里的随机数让人有点懵逼
意思倒很明显,就是将qword_202020以后的23个地址进行256次随机交换
也就是说这23个函数被打乱顺序了
在main函数中还要依次调用这23个函数
这可咋整呀
回头看sub_8D0的参数,也就是函数集合们
这调用个锤子啊?!
哦,又是IDA没识别出来
手动按C
只能识别这一小段,其他部分就不是合法指令了
可以看到,这里是将某个字符与’3’做比较了,接下来两个跳转
不等时执行exit()
那么很明显,该字符必须是3了
而相等时会跳到这里
pop出来的分别是刚才的rsi和rdx,然而并不知道是啥玩意儿╮(╯_╰)╭
继续往下看,计数器和0x11比较…
这个0x11是不是挺眼熟的,好像是每个函数的长度来着?
再往下将rdi指向的串和常数al异或
如果不够敏感的话(比如我)还可以用gdb动态调试看一下这里的寄存器值
其实IDA挺靠谱的,这里的常数rax和串rdi都来自于刚进入函数时的rsi和rdx
虽然不知道这是哪门子的调用约定,不过IDA认出来了
a2[1]就是输入的字符串,那很明显v6+9就是指定的下标了,第一次调用是恒为1
这个+9其实也很熟悉,还记得刚才那个表格吗,第9比特是什么来着?
对了!就是超威蓝猫!
对了!就是该函数所对应的下标i
v7则指向下一个函数的地址,v7+8则是下一个函数的0x11*i
一共3个参数,前面取input值很明显用过了,那么异或的常数和串当然就是v7和v7+8咯
也就是说,所有的函数都被异或加密了,加密的值是i*0x11
而函数们虽然被改变顺序了,但是它们对应校验的值是不变的(由下标v6+9决定)
逻辑理清了,把函数对应解密就行咯
这里利用IDC脚本即可:
auto i;
auto j;
auto p;
auto x;
x = 0xc78;
for(i=0;i<23;i++)
{
for(j=0;j<0x11;j++)
{
p = x+i*0x11+j;
PatchByte(p, Byte(p)^(0x11*i));
}
}
解密完成后选中所有代码块,按C后选择Force强制识别即可得到代码
格式都是一样的,一个一个复制太蠢啦~
反正函数之间的间隔为0x11是已知的,我只要把对应的byte提取出来就好了嘛
毕竟虽然汇编不好处理,但汇编是由机器码转来的啊~
查看HEX
这个3C就是cmp al, x啦
因此提取每个3C后的byte输出即可
(连python脚本都不用写噜)
auto i;for(i=0;i<23;i++){Message("%c", Byte(0xc7d + 0x11*i));}
一行得到flag,完成~
其实理清结构以后这个题目就很简单了,但是我做了很久…
因为我没搞懂qword_202020、v1、a1这些地址间的关系,纳闷了很久
没注意src应该是可执行代码,甚至还以为在操作BSS段中的qword_202020后面的函数表
其实qword_20202020作为全局变量,只是一个8字节的变量而已
它其中存放的是一段空间的值,是一个指针
但是使用的时候又没有以指针的形式,而是作为整型地址直接操作
这个变量的命名真是严重的误导我了……
qword_202020 + 8*i 不是[0x202020 + 8*i],而是[0x202020] + 8*i,即新申请的空间中的8*i
qword_202020这个变量就是指[0x202020],即存放于202020处的变量的值
C语言里指针和值的区别真是一个大坑..OTZ
如果理解透彻的话题目本身而言不算太难,只是一个动态解密代码而已
来来回回调试了这么久希望能给自己留下点深刻的印象吧…OTZ不该浪费这么多时间的
C. 明日计划
JarvisOJ