SMC简介

SMC,即Self Modifying Code,动态代码加密技术,指通过修改代码或数据,阻止别人直接静态分析,然后在动态运行程序时对代码进行解密,达到程序正常运行的效果。

SMC的实现方式有很多种,可以通过修改PE文件的Section Header、使用API Hook实现代码加密和解密、使用VMProtect等第三方加密工具等。

CTF中的SMC

SMC一般有俩种破解方法,第一种是找到对代码或数据加密的函数后通过idapython写解密脚本。第二种是动态调试到SMC解密结束的地方dump出来。

SMC的实现是需要对目标内存进行修改的,.text一般是没有写权限的。那么就需要拥有修改目标内存的权限:

  • 在linux系统中,可以通过mprotect函数修改目标内存的权限
  • 在Windows系统中,VirtualProtect函数实现内存权限的修改

因此也可以观察是否有这俩个函数来判断是否进行了SMC。 

CTF 题目复现

[网鼎杯 2020 青龙组]jocker

axios 逆向 逆向smc_axios 逆向

文件先查壳,无壳,32bit文件,一打开就可以发现VitualProtect函数,这里对内存权限进行了修改,大概率是SMC。

这里的逻辑大致看下,通过scanf让我们输入一个长度为24的flag,再wrong函数和omg。

axios 逆向 逆向smc_安全_02

axios 逆向 逆向smc_安全_03

key = 0x66, 0x6B, 0x63, 0x64, 0x7F, 0x61, 0x67, 0x64, 0x3B, 0x56, 0x6B, 0x61, 0x7B, 0x26, 0x3B, 0x50, 0x63, 0x5F, 0x4D, 0x5A, 0x71, 0x0C, 0x37, 0x66
flag = ''
 
 
for i in range(24):
    if i % 2 == 1:
        flag += chr(key[i] + i)
    else:
        flag += chr(key[i] ^ i)
 
 
print(flag)

这里解出一个flag{fak3_alw35_sp_me!!} 是个假flag。

接着往下看,可以看到encrypt,并且encrypt函数打开出错了。

axios 逆向 逆向smc_数据_04

可以判断是在encrypt处进行了SMC加密,随便下个断点,用 Local windows debugger调试

axios 逆向 逆向smc_axios 逆向_05

axios 逆向 逆向smc_安全_06

根据前面得判断,输入长度为24得flag 123456789123456789123456

axios 逆向 逆向smc_数据_07

这里,F7单步走到00401833的call处,单步进入_Z7函数内

axios 逆向 逆向smc_安全_08

点击__Z7encryptPc 先用U将其设为无定义

axios 逆向 逆向smc_密码学_09

接着选中下面所有数据内容,按C转换为代码。

axios 逆向 逆向smc_网络安全_10

axios 逆向 逆向smc_安全_11

选择Force,再点击yes

axios 逆向 逆向smc_安全_12

之后再点击_Z7进行P定义为函数,再用F5反编译。这里可以得到encrypt函数

axios 逆向 逆向smc_密码学_13

下面还有一个函数不要忽略了,同样P定义为函数,再F5反编译。

axios 逆向 逆向smc_数据_14

axios 逆向 逆向smc_密码学_15

通过第一个encrpyt函数 逆向一下,

hh = 'hahahaha_do_you_find_me?'
v2 = [0x0E, 0x0D, 0x9, 0x6, 0x13, 0x5, 0x58, 0x56, 0x3E, 0x6,
      0x0C, 0x3C, 0x1F, 0x57, 0x14, 0x6B, 0x57, 0x59, 0x0D]
flag = []
 
 
for i in range(19):
    flag.append(chr(v2[i] ^ ord(hh[i])))

解出flag{d07abccf8a410c   明显还有后半部分,看第二个函数,大致的意思就是%tp&:这五个字符和某个数字异或得到最后的flag,已知是flag的最后一位一定是},那么就很好求了。

v3 = [37, 116, 112, 38, 58]
key = ord('}') ^ 58
 
for i in range(5):
    flag.append(chr(v3[i] ^ key))
 
print(''.join(flag))

这样就可以解出flag{d07abccf8a410cb37a}

[羊城杯 2021]BabySmc

题目打开

axios 逆向 逆向smc_密码学_16

在导入表中看到VirtualProtect函数

axios 逆向 逆向smc_数据_17

axios 逆向 逆向smc_安全_18

在最下面可以看到一个错误地址。点进去 看汇编,

axios 逆向 逆向smc_网络安全_19

大量的数据,可以直接尝试下断点动态调试。用本地win就好

axios 逆向 逆向smc_网络安全_20

F8步过,进入数据处,这里会提示是否让IDA自己根据RIP生成代码,选no,因为这里IDA已经不能自主分辨主函数的结构了。

axios 逆向 逆向smc_安全_21

No了后,从上方的main头一直选到第一个retn处,按C后选择Force强制转换为代码,之后直接F5反编译就好了。 

axios 逆向 逆向smc_数据_22