首页
社区
课程
招聘
看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本
发表于: 2020-1-2 17:25 5691

看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本

2020-1-2 17:25
5691
发现很多都用X32Debug/X64Debug进行脱壳,发一个IDA脱壳的脚本。
脚本主要功能是查找SMC和代码拷贝执行的特征:
1)从当前EIP开始查找SMC代码和拷贝执行代码
2)如果发现SMC代码,没发现拷贝执行代码,则让程序运行到SMC代码结束位置,继续到1)循环
3)如果发现拷贝代码,没发现SMC代码,则将拷贝代码全部NOP,并让程序执行到拷贝结束位置,继续到1)循环
4)如果既发现SMC代码也发现拷贝代码,将让程序运行到地址小的位置,继续循环
5)发现0x4EED14位置存在SEH反调试,单独处理下即可。

脚本使用方法:
1)首先手动在start函数入口设置断点,并让IDA断在start入口,执行一下脚本
2)输入用户名和密码
3)此时程序会断在0x4013F7位置,再次执行脚本,脚本运行5分钟左右断在0x4FB939,后面就是解密后的算法。

虽然程序在代码拷贝后会清除前面的代码,但是清除的位置都是在0x508000开始的段中,而我们的代码在0x401000-0x506000范围,因此不会影响。但是如果不管它,清除会越界。由于每次清除都是以EDI值开始,因此在每次NOP掉拷贝代码后将EDI设置成0x508000即可。
import struct
from idaapi import *
from idc import *
from idautils import *

def addBptByAddr(addr):
    AddBpt(addr)
    SetBptAttr(addr, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)

def FindDataFromRange(segStart, segEnd, target):
    ea = segStart
    while ea < segEnd:
        readLen = 1024
        if (ea +  readLen) >= segEnd:
            readLen = segEnd - ea
        rawdex1 = idaapi.dbg_read_memory(ea, readLen)
        if rawdex1 == None:
            return 0
        a = rawdex1.find(target)
        if a>= 0:
            return ea + a
        if readLen == 1024:
            ea = ea + 512
        else:
            ea = ea + readLen
    return 0

def findXXX(startEA, endEA):
    ea = startEA
    while ea < endEA:
        #print (str(hex(ea)))
        #addr = find_binary(ea, SEARCH_DOWN | SEARCH_NEXT, 'E8 00 00 00 00 59 81', radix=16)
        addr = FindDataFromRange(ea, ea + 0x400, '\xE8\x00\x00\x00\x00\x59\x81')
        if addr == 0:
            return 0
        if idc.Dword(addr + 0x24) == 0xB9310F51:
            return addr
        ea = addr + 1
    return 0

def bypassCopy(pcValue):
    #pcValue=GetRegValue('eip')
    print 'bypassCopy start Addr = ' + (str(hex(pcValue)))
    ea = findXXX(pcValue, pcValue+0x1000)
    copyStartCode = ea
    print 'copyStartCode          = ' + (str(hex(ea)))
    if ea > 0:
        if copyStartCode - pcValue > 0x200:
            print 'copyStartCode size more 0x200 ....fail'
            return 0, 0
        ea = FindDataFromRange(ea, ea + 0x400, '\x9D\x61\x5F\xFF\xD0')
        if ea > 0:
            patch_bytes(copyStartCode, '\x90' * (ea + 6 - copyStartCode))
            refresh_debugger_memory()
            pachCodeSize = ea + 6 - copyStartCode;
            print 'pach code endAddr  = ' + (str(hex(ea+6)))
            print 'pach code size     = ' + (str(hex(pachCodeSize)))
            MakeCode(ea+6)
            #AddBpt(ea+6)
            #SetBptAttr(ea+6, BPTATTR_FLAGS, BPT_ENABLED | BPT_BRK)
            print 'bypassCopy success1'
            return ea+6, copyStartCode
        ea = FindDataFromRange(copyStartCode, copyStartCode + 0x400, '\x9D\x61\x5F\xE8\x01\x00\x00')
        if ea > 0:
            pachCodeEndAddr = copyStartCode + 5 + idc.Dword(copyStartCode + 0x0e) - idc.Dword(copyStartCode + 0x08)
            pachCodeSize = pachCodeEndAddr - copyStartCode;
            patch_bytes(copyStartCode, '\x90' * pachCodeSize)
            refresh_debugger_memory()
            print 'pach code endAddr  = ' + (str(hex(pachCodeEndAddr)))
            print 'pach code size     = ' + (str(hex(pachCodeSize)))
            print 'bypassCopy success2'
            return  pachCodeEndAddr, copyStartCode
        print 'find copy fail1'
        return 0, 0
    print 'find copy fail0'
    return 0, 0

def findSMC(pcValue):
    print 'findSMC1 startAddr = ' + (str(hex(pcValue)))
    ea = pcValue
    smcStartAddr = 0
    curEa1 = ea
    while curEa1 < pcValue + 0x400:
        curEa = FindDataFromRange(curEa1, pcValue + 0x400, '\xE8\x00\x00\x00\x00\x5E\x81\xEE')
        if curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xB9 and idc.Byte(curEa + 0x17) == 0xFC:
            smcStartAddr = curEa
            break;
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xB9 and idc.Byte(curEa + 0x17) == 0xEB:
            offset = idc.Byte(curEa + 0x18)
            print 'offset1 = ' + (str(hex(offset)))
            tempAddr = curEa + 0x17 + 2 + offset
            print 'tempAddr = ' + (str(hex(tempAddr)))
            if idc.Byte(tempAddr) == 0xFC or idc.Byte(tempAddr + 3) == 0xFC:
                smcStartAddr = curEa
                break
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Word(curEa + 0x12) == 0x2EB and idc.Byte(curEa + 0x16) == 0xB9 and idc.Byte(curEa + 0x1B) == 0xFC:
            smcStartAddr = curEa
            break
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Word(curEa + 0x12) == 0x2EB and idc.Byte(curEa + 0x16) == 0xB9 and idc.Byte(curEa + 0x1E) == 0xFC:
            smcStartAddr = curEa
            break
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Word(curEa + 0x12) == 0x2EB and idc.Byte(curEa + 0x16) == 0xB9 and idc.Byte(curEa + 0x22) == 0xFC:
            smcStartAddr = curEa
            break
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xB9 and idc.Word(curEa + 0x17) == 0x2EB and idc.Byte(curEa + 0x1B) == 0xFC:
            smcStartAddr = curEa

        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xB9 and idc.Word( curEa + 0x17) == 0x2EB and idc.Byte(curEa + 0x1E) == 0xFC:
            smcStartAddr = curEa
            break
        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xB9 and idc.Word(curEa + 0x1A) == 0x2EB and idc.Byte(curEa + 0x1E) == 0xFC:
            smcStartAddr = curEa
            break

        elif curEa != 0 and idc.Word(curEa + 0x0C) == 0xC681 and idc.Byte(curEa + 0x12) == 0xEB:
            offset = idc.Byte(curEa + 0x13)
            print 'offset2 = ' + (str(hex(offset)))
            tempAddr = curEa + 0x13 + 1 + offset
            print 'tempAddr = ' + (str(hex(tempAddr)))
            if idc.Byte(tempAddr) == 0xB9 and idc.Byte(tempAddr + 0x05) == 0xFC:
                smcStartAddr = curEa
                break
            if idc.Byte(tempAddr) == 0xB9 and idc.Byte(tempAddr + 0x0C) == 0xFC:
                smcStartAddr = curEa
                break
        if curEa != 0:
            curEa1 = curEa + 1
            continue
        curEa1 = curEa1 + 1
    print 'smcStartAddr = ' + (str(hex(smcStartAddr)))
    esiAddr = FindDataFromRange(pcValue, pcValue + 0x400, '\x88\x46\xFF')
    if 0 == esiAddr:
        print 'find smc false, esiAddr is 0'
        return 0, 0
    print 'esiAddr = ' + (str(hex(esiAddr)))
    ea = FindDataFromRange(pcValue, pcValue + 0x400, '\x85\xc9')
    if ea > 0 and idc.Byte(ea + 0x02) == 0x75:
        print 'findSMC1 endAddr = ' + (str(hex(ea + 4)))
        if ea - esiAddr > 0x100:
            print 'find smc10 success: esiAddr'
            return esiAddr + 3, smcStartAddr
        print 'find smc1 success'
        return ea + 4, smcStartAddr
    elif ea > 0 and idc.Word(ea + 0x02) == 0x850F:
        print 'findSMC1 endAddr = ' + (str(hex(ea + 8)))
        if ea - esiAddr > 0x100:
            print 'find smc20 success: esiAddr'
            return esiAddr + 3, smcStartAddr
        print 'find smc2 success'
        return ea + 8, smcStartAddr

    elif ea != 0  and idc.Word(ea + 0x02) == 0x2EB and idc.Byte(ea + 0x06) == 0x75:
        print 'findSMC1 endAddr = ' + (str(hex(ea + 8)))
        if ea - esiAddr > 0x100:
            print 'find smc30 success: esiAddr'
            return esiAddr + 3, smcStartAddr
        print 'find smc3 success'
        return ea + 8, smcStartAddr

    elif ea != 0 and idc.Word(ea + 0x02) == 0x2EB and idc.Word(ea + 0x06) == 0x850F:
        print 'findSMC1 endAddr = ' + (str(hex(ea + 12)))
        if ea - esiAddr > 0x100:
            print 'find smc40 success: esiAddr'
            return esiAddr + 3, smcStartAddr
        print 'find smc4 success'
        return ea + 12, smcStartAddr
    print 'find smc false'
    return 0, 0

if not 'setflag' in dir():
    print 'set breakpoint'
    patch_bytes(0x4013F7, '\xE9\x41\x02\x00\x00')
    addBptByAddr(0x4013F7)

cnt = 3124  #4FB939
pcValue=GetRegValue('eip')
i = 0
while i < cnt:
    print '=============================================i = ' + str(i)
    if pcValue == 0x4FB939:
        break
    if pcValue == 0x4eed14:
        print '****** SEH anti debug ************'
        patch_bytes(pcValue, '\x90' * 0x1cc)
        refresh_debugger_memory()
        pcValue = 0x4EEEE0
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x46589D:
        print '******pcValue = 0x46589D handle************'
        pcValue = 0x4658D5
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x465FC5:
        print '******pcValue = 0x465FC5 handle************'
        pcValue = 0x466001
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x466208:
        print '******pcValue = 0x466208 handle************'
        pcValue = 0x46623C
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x4689EC:
        print '******pcValue = 0x4689EC handle************'
        pcValue = 0x468A24
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x46C118:  #1345
        print '******pcValue = 0x46C118 handle************'
        pcValue = 0x46C14C
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x46D82F:  #1364
        print '******pcValue = 0x46D82F handle************'
        pcValue = 0x46D85F
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x46DBD4:  #1366
        print '******pcValue = 0x46DBD4 handle************'
        pcValue = 0x46DC0C
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x4A5B3D:  #1366
        print '******pcValue = 0x4A5B3D handle************'
        pcValue = 0x4A5B69
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x4ADA7A:  #2164
        print '******pcValue = 0x4ADA7A handle************'
        pcValue = 0x4ADAA6
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    if pcValue == 0x4B78FF:  #2164
        print '******pcValue = 0x4B78FF handle************'
        pcValue = 0x4B7927
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        i = i + 1
        continue
    print '******findSMC start************'
    smcValue, smcStartAddr = findSMC(pcValue)
    print '******findSMC end  and bypassCopy start ************'
    copyValue ,copyStartAddr= bypassCopy(pcValue)
    print '******bypassCopy end************'
    print 'smcValue = ' + (str(hex(smcValue))) + ', smcStartAddr = ' + (str(hex(smcStartAddr)))
    print 'copyValue = ' + (str(hex(copyValue))) + ', copyStartAddr = ' + (str(hex(copyStartAddr)))
    if (smcValue==0 and copyValue == 0) or (smcValue >= 0x506000 or copyValue >= 0x506000) :
        print '******error************'
        print 'smcStartAddr = ' + (str(hex(smcStartAddr)))
        print 'smcValue = ' + (str(hex(smcValue)))
        print 'copyStartAddr = ' + (str(hex(copyStartAddr)))
        print 'copyValue = ' + (str(hex(copyValue)))
        break
    if smcValue > 0 and smcStartAddr == 0:
        print '******smcStartAddr error************'
        print 'smcStartAddr = ' + (str(hex(smcStartAddr)))
        print 'smcValue = ' + (str(hex(smcValue)))
        break
    if copyValue > 0 and copyStartAddr == 0:
        print '******copyStartAddr error************'
        print 'copyStartAddr = ' + (str(hex(copyStartAddr)))
        print 'copyValue = ' + (str(hex(copyValue)))
        break
    if (copyValue == 0) or ((smcStartAddr > 0) and (smcStartAddr < copyStartAddr)):
        print '******findSMC run_to start ************'
        pcValue = smcValue
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        print '******findSMC run_to end ************'
    else:
        print '******bypassCopy run_to start ************'
        pcValue = copyValue
        run_to(pcValue)
        GetDebuggerEvent(WFNE_SUSP, -1)
        SetRegValue(0x508000, 'edi')
        print '******bypassCopy run_to end ************'
    i = i + 1



[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//