- 最近犯懒,没看新题,想起来之前安洵杯做过一道 SMC + 反调试的题,当时是动调 + 瞎蒙做出来的,今天来整理一下里面的知识点
- 题目链接:https://github.com/D0g3-Lab/i-SOON_CTF_2020/tree/main/re/EasyCM
- 需要用到的 IDA 插件(能够简化大量操作):IDACode & IDAPython
概述
- 入口点: 这题用到了
TLSCallback
在main
函数前执行各种解密操作, 在 IDA 中按下Ctrl+E
可以找到所有的入口点 - 置换用的码表在
TLSCallback
中进行了解密, 调试环境下会置换为垃圾数据 - 关键的加密函数是 SMC 技术保护的
详细
反调
- 使用了
CheckRemoteDebuggerPresent
这个 API, 处于调试环境下时返回值为 1 - 下图的函数在其中一个
TLSCallback
中被调用, 对置换用的码表进行解密. 可见当处于调试环境时不会进行解密的操作.
花指令
- 花指令用于误导 IDA 的静态反汇编. 本题中的花指令都比较简单, 都是通过控制
retn
时栈顶的eip
控制跳转. 当时做题的时候傻乎乎的动调, 现在反应过来了, 应该直接推算出跳转到哪, 然后用 IDA patch 上就行了 - 举例来说, 在 SMC 进行自揭密的函数中, 明显有花指令的干扰
- 把没用的全 nop 掉, 条件跳转改成
jmp
即可
SMC
- 这里进行了 SMC 的自解密, 当然也有几处花指令, 全部改了之后非常清晰
- 可以写个 IDAPython 脚本修改 idb
def unpack_cyzcc(): f = open("backup", "wb") key = b'D0g3' start = 0x41e000 length = 0x1200 for i in range(length): ea = start+i old = idc.Byte(ea) f.write(bytes(old)) k = key[i % 4] new = old ^ k idaapi.patch_byte(ea, new)
写脚本解密
- 按照上面说的把所有该 patch 的都 patch 了其实这道题就非常简单了
- 解密脚本:
import idc import