2023 安询杯 ez_cpp

题目分析

首先把题拖到IDA中,跳到main函数,但是显示JUMPOUT,反编译失败了
在这里插入图片描述
查看汇编代码,手动修正代码
在这里插入图片描述
看到一处红色,在Generral打开显示汇编指令,这里很明显的花指令
这是属于假分支跳转类型的花指令

cmp eax, ecx
jnz LABEL1

xor eax, eax
jz LABEL1

这两种花指令都是很常见的,xor eax,eax这让eax为0,逻辑运算指令会影响ZF标志位的,所以会置ZF为1,那么永远会跳转到LABEL1处,这样LABEL1处之前的代码全部是垃圾指令,不管看起来多么正常,统统都是垃圾指令。对于第一种cmp eax,ecx,则会导致ZF标志位为1,从而必定跳转。在这个题当中就是会强制跳转到loc_413BB4+3位置,因此需要删除中间的花指令。

先按U,然后patch
在这里插入图片描述
填充为nop,这时候就已经恢复了,往下看到了同样的花指令,因为加花指令一般都是类似的,我们可以alt+B 搜索二进制特征
在这里插入图片描述
总共找到五处花指令,修改完后移动到main函数头,按P,然后F5,就可以看到伪代码了。
在这里插入图片描述
总共三个关键加密函数,最后的判断条件是加密后的数据和V13的值比较,V13又是从V14拷贝过来的,这里循环了32次,因此V14应该是int[32],修改下类型,然后动态调试获取V14,V7数组的值。编写代码还原第三层加密

第三层加密

关键是这个函数sub_411177,手搓逆向代码
在这里插入图片描述

def re(inputstr,a2):
    inputstr-=1
    result=0
    for i in range(0,8):
        result |= ((inputstr >> i) & 1) << a2-i-1
    return result

第二层加密

这里是C++的虚函数,只有在运行的时候才能看到函数,V22 v21就是函数的地址,因此类型应该是char *,修改下,动态调试时跳到这个地址,然后查看代码,这里返回值是void,修改下代码好看些
在这里插入图片描述
在这里插入图片描述

然后编写第二个算法的逆算法,这里的话,异或的不需要改,然后-改成+ 就行,V7数组的值动态调试获得。

def trans(arr):
    v7 = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0]
    for i in range(le(arr)):
        if i<=16:
            if i>=16:
                arr[i]^=4
            else:
                match v7[i]:
                    case 1:
                        arr[i] ^= 9
                    case 0:
                        arr[i] += 2
        else:
            match v7[i]:
                case 1:
                    arr[i] ^= 6
                case 0:
                    arr[i] += 5

同理第一个加密函数,动态调试跟进去是rot13加密

def rot13(text):
    decrypted_text = ''
    for char in text:
        if char.isalpha():
            if char.isupper():
                decrypted_char = chr((ord(char) - 65 - 13) % 26 + 65)
            else:
                decrypted_char = chr((ord(char) - 97 - 13) % 26 + 97)
        else:
            decrypted_char = char
        decrypted_text += decrypted_char
    return decrypted_text

全部代码

def trans(arr):
    v7 = [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0]
    for i in range(len(arr)):
        if i<=16:
            if i>=16:
                arr[i]^=4
            else:
                match v7[i]:
                    case 1:
                        arr[i] ^= 9
                    case 0:
                        arr[i] += 2
        else:
            match v7[i]:
                case 1:
                    arr[i] ^= 6
                case 0:
                    arr[i] += 5


def rot13(text):
    decrypted_text = ''
    for char in text:
        if char.isalpha():
            if char.isupper():
                decrypted_char = chr((ord(char) - 65 - 13) % 26 + 65)
            else:
                decrypted_char = chr((ord(char) - 97 - 13) % 26 + 97)
        else:
            decrypted_char = char
        decrypted_text += decrypted_char
    return decrypted_text

def re(inputstr,a2):
    inputstr-=1
    result=0
    for i in range(0,8):
        result |= ((inputstr >> i) & 1) << a2-i-1
    return result

inputstr=[0x22,0xFFFFFFA2,0x72,0xFFFFFFE6,0x52,0xFFFFFF8C,0xFFFFFFF2,0xFFFFFFD4,0xFFFFFFA6,0xA,0x3C,0x24,0xFFFFFFA6,0xFFFFFF9C,0xFFFFFF86,0x24,0x42,0xFFFFFFD4,0x22,0xFFFFFFB6,0x14,0x42,0xFFFFFFCE,0xFFFFFFAC,0x14,0x6A,0x2C,0x7C,0xFFFFFFE4,0xFFFFFFE4,0xFFFFFFE4,0x1E]
for i in range(0,32):
    inputstr[i]^=1
    inputstr[i]=re(inputstr[i],8)

trans(inputstr)
out=''
for i in inputstr:
    out+=chr(i)
print(rot13(out))

在这里插入图片描述

把a改成{

方法二

看其他人的wp看到了一种方法也很有趣,因为这里的加密有一个鲜明的特征就是逐字节加密的,因此可以单字节爆破,看了下他的方法,将这里exit返回值改成j
在这里插入图片描述

import string
import os
import time

table = string.ascii_letters+string.digits+'!-{}'
# table = string.printable
# 'SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}'
theflag = ''
while len(theflag) < 32:
    for ch in table:
        flag = (theflag+ch).ljust(32, '#')
        exitcode = os.system(f"echo {flag} | ez_cpp.exe 1>&0")

        if exitcode >= len(theflag) + 1:
            theflag += ch
            print(theflag, exitcode)
            break
        else:
            print('not found')
            # time.sleep(0.1)

速度也很快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值