SMC in CTF
1438911687251843 发表于 江西 CTF 669浏览 · 2024-05-26 12:04

SMC in CTF

方法

SMC一般有两种破解方法

第一种是找到对代码或数据加密的函数后通过idapython写解密脚本。

第二种是动态调试到SMC解密结束的地方dump出来。

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

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

  • 在Windows系统中,VirtualProtect函数实现内存权限的修改

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

这里主要使用动态调试这一方法进行分析

实操

[网鼎杯 2020 青龙组]jocker

进入main函数

可以直接找到被smc的函数 VirtualProtect

VitualProtect函数,这里对内存权限进行了修改,大概率是SMC

分析代码,通过scanf让我们输入一个长度为24的flag,又经过wrong函数和omg函数加密

打开encrypt函数时出错

因为在前面VirtualProtect函数包含了encrypt函数,所以显然在encrypt处进行了SMC加密

动态调试

在这里下断点

F7进入这个call

点击__Z7encryptPc 先按U将其设为未定义

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

点击函数按p构造函数

按F5即可反编译

同理,对__Z7finallyPc操作

接下来直接分析伪代码解密即可

buffer = 'hahahaha_do_you_find_me?'
v3 = '%tp&:'
v2 = [14, 13, 9, 6, 19, 5, 88, 86, 62, 6, 12, 60, 31, 87, 20, 107, 87, 89, 13]
for i in range(len(v2)):
    a1=v2[i]^ord(buffer[i])
    print(chr(a1),end='')
for j in range(5):
    a2 = ord(v3[j]) ^ ord(':') ^ ord('}')
    print(chr(a2),end='')

# flag{d07abccf8a410cb37a}

idapython

start = 0x401500
for i in range(187):
    a = idc.get_wide_byte(start + i)
    ida_bytes.patch_byte(start + i,a ^ 0x55 ^ 0x14)

[H&NCTF2024]I_LOVE_SWDD

进入main函数

进入sub_411186函数时,发现无法识别,只有一堆数据

可以猜测是SMC

再看导入表

这下更确定了

动态调试

在这里下断点

点击loc_417000,按u转未定义,再按c分析函数,再按p构造函数

完美

F5反编译成功

之后就是简单的凯撒密码,直接解密即可

str2 = 'S_VYFO_CGNN_GRKD_KLYED_IYE'
str1 = ''
for i in str2:
    if 'A' < i < 'Z':
        str1 += chr((ord(i) - 10 - 65) % 26 + 65)
    else:
        str1 += i
print(str1)
# I_LOVE_SWDD_WHAT_ABOUT_YOU

[羊城杯 2021]BabySmc

进入main函数

这里发现无法分析,可以猜测是SMC,但是无法确定

查看导入表,发现VirtualProtect函数,可以确定了

动态调试

在这里下断点动调

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

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

这里开始

这里结束(return)

然后按F5反编译即可

idapython

脚本一

start = 0x140001085
end = 0x140001D00

import idc
import ida_bytes

def change_byte(uint8):
    return (((uint8 & 7) << 5) | (uint8 >> 3)) ^ 0x5a

size = end - start + 1
b = idc.get_bytes(start, size)
b2 = bytes([change_byte(x) for x in b])
ida_bytes.patch_bytes(start, b2)

脚本二

from idc_bc695 import *
def ROR(i,index):
    tmp bin(i)[2:].rjust(8,"0")
    for _ in range(index):
        tmp = tmp[-1] + tmp[:-1]
    return int(tmp, 2)
def ROL(i,index):   #循环左移
    tmp bin(i)[2:].rjust(8,"0")
    for _ in range(index):
        tmp = tmp[1:] + tmp[0]
    return int(tmp, 2)
addr1=0x140001085
addr2=0x140001d00
for i in range(addr2-addr1):
    PatchByte(addr1+i,ROR(Byte(addr1+i),3)^90)
print('successful')

网上抄的,暂时不清楚原理,猜测是根据VirtualProtect函数来的

总结

  1. 重点在于找到被SMC的函数的起始地址和结束地址,这样才能针对性的对被改变的数据进行还原

  2. 可以使用动调让程序自动解密,然后重新构造被SMC的函数

  3. 也可以使用ida脚本直接对数据修改,得到原来的函数

0 条评论
某人
表情
可输入 255