NSSCTF刷题日志1day(SMC知识)

[网鼎杯 2020 青龙组]jocker

SMC逆向的学习。SMC是一种代码动态加密技术,以牺牲代码运行的开销为代价增大代码逆向的难度或者是复杂度,SMC动态代码加密技术的实现方式可以通过:修改PE文件的section header,或者是api hook方法,还有使用如VMprotect这样的第三方工具对代码的一部分进行加密。以这次写的网鼎杯的题目为学习例子
首先下载文件之后进行扫壳。
img
img
得到了其的基本信息是32位,并且是无壳的。放入IDA32位看看。
img
通过对字符串的引用索引到代码的逆向部分进行分析。
可以看到这里使用了VMprotect的第三方技术对加密代码对加密代码也进行了加密处理,因为这里的加密代码是调用的一种dll函数,所以无法看其本质逻辑,单结合SMC原理,其的保护原理就是在运行前是加密的,运行程序之后对加密代码部分进行解密,现在处理这种加密方法的思路我们就有了,我们可以在其运行解密之后看看能否变成IDA可以正常看的代码。
在输入之后的地方下一个断点,其实在哪里都可以,理论上只要是运行了解密函数的地方都是可以的。
img
f9开始动态调试:
然后如何判断这个函数是否被成功解密呢?最有力的证明就是当这个程序开始调用并运行到这个函数的时候,这个函数必定是解密完成的,因为只有解密后的数据才是可执行的,而解密之前的代码数据仅仅是可读可执行的数据,所以当程序调用其这个加密后的函数的时候,这个函数必须是要已经被解密之后的代码数据才行,所以这里设置完断点之后还要继续往下面进行调试,直到我们单步进入到这个函数中。
img
先输入flag的总长度满足24个字符,以此满足第一个if条件,使得我们的程序能够顺利进入到下一个函数中去。
img
可以看到这里还有个函数omg,前面那个函数的名字是wrong,所以先跳过了,把这个omg的尝试解一下可以看到:
img
img
结果观察一下发现,这个字符串是来自wrong这个函数的,结合这一点,这个应该是个骗人的函数,最多就是个fakeflag。
并且下面的加密处理的并不是被wrong处理之后的flag,而是没有被处理之前的flag,现在尝试还原encrypt函数:
img
img
img
if处设置一个断点,然后f7步入encrypt函数,以确保encrypt函数确实是变成可执行的代码了。
img
成功步入之后,先把函数转化为没有被定义的,因为下面还有很明显的一串数据是没有被成功IDA变化为汇编语言的:
img
因为这里已经步入进去函数了,所以这里的数据应该是可以全部转化为正确的可执行函数全选函数的头到尾部
img
img
然后摁U将所有都先转化为数据:
img
然后再选择这个函数名字,然后摁p重新识别为函数,然后看看是否反汇编成功:
img
img
可以看到反汇编成功了。
然后开始对这个函数进行解密;
可以看到是把我们的字符串依次异或buffer里面字符串的值,进行解密:
img

v2=[0xE,0xD,9,6,0x13,5,0x58,0x56,0x3E,6,0xC,0x3c,0x1F,0x57,0x14,0x6B,0x57,0x59,0xD]
buffer='hahahaha_do_you_find_me?'
for i in range(19):
    print(chr(ord(buffer[i])^v2[i]),end='')
#flag{d07abccf8a410c

运行解密脚本,发现只有一半,然后去检查刚刚的函数部分看看:
img
发现这一部分还没有进行处理。
跟上文一样如法炮制处理这一串数据,把其处理成伪代码:
img
img
可以看到伪代码如上:对代码进行分析可以得到如下的逻辑,对v3用其本身下标为5的值索引v3的某个值或字符,然后判断这个字符跟a1同样用v3[5]索引的值是否相等,不相等为0,相等为1,这个不同为1,相同为0的逻辑,实际上就是个异或。但是其比较的操作就比较迷惑了,因为v4实际上是不固定的,而且很有可能大于1。再结合了别人的wp之后我发现,这里是尝试猜测其的操作,更具猜到的操作逻辑是某个值跟字符串作异或操作,并且这个值是固定的然后根据flag最后肯定是}的逻辑可以得到这个key,然后把字符串异或回去:

str0='%tp&:'
key=ord('}')^ord(':')
print("flag{d07abccf8a410c",end='')
for i in str0:
    print(chr(ord(i)^key),end='')
#flag{d07abccf8a410cb37a}

img
并且这个题目即便是正确的flag也不会给与正确回答。

posted @ 2025-04-24 20:40  喵老师哒哟  阅读(67)  评论(0)    收藏  举报