记一些比赛遇到的题目

害,惨痛的参赛经历们

太难了太难了,持续更新

1.ViQinere

(安恒五月赛和BJDCTF一起办的)

这个题目其实就是普通的逆向,也没什么花里胡哨的,逻辑也很清楚,为什么我写脚本的时候这么菜啊呜呜呜
64位拖进ida
记一些比赛遇到的题目_第1张图片
然后看看sub_1209()
记一些比赛遇到的题目_第2张图片
然后是exp

a1='zyxwvutsrqponmlkjihgfedcba'  #byte_4060
b='TaQini'   #byte_4180
flag=''
key='FQD{GfjuJ5UbLrWjZjpvErXkiAZzlvO0xTa!cwnLLAsy3B0iEvEy}'
def sub_1209(a):
    x=ord(a)
    if 96<x<=122:
        x=x-97
        return x
    elif  65<x<=90:
        x=(x-65)^(-0x80)  #后来看别的师傅也可以x=(x-65)^0xffffff80-0x100000000
        return x
    else:
        return x

def resub(a):
    if a<0:
        a=a^(-0x80)
        a=a+65
        return chr(a)
    else:
        a=a+97
        return chr(a)
v5=0
for i in range(len(key)):
    if 96<ord(key[i])<=122:
        v2=sub_1209(b[v5&5])
        v5+=1
        for j in range(26):
            if ord(key[i])==ord(a1[(v2&0x7f+j)%26]):
                flag+=resub(j)
                
    elif 64 <ord(key[i])<=90:
        v1=sub_1209(b[v5&5])
        v5+=1
        for k in range(26):#这里下面是+128提到了上面所以是26,所以最后逆的时候-128
            if ord(key[i])+32==ord(a1[(k+v1&0x7f)%26]):
                flag+=resub(k-128)
    else:
        flag+=key[i]

print(flag)

exp我真的想了好久好久怎么去实现,明明逻辑很简单,也挺好逆的,太菜了太菜了唉,这个比赛对我来说真的太难了唉
这题有个小点
就是我写resub的时候

print((-127)^(-0x80)+65)#输出64,然而我想让他输出66

俺才知道原来py中异或的优先级没有±高,果然是一个fw
这个应该算是这次re签到了,签了好久,嗯

2.blink

出处同上(和上一题一样应该都是100分的题目),这题我当时没做出来,赛后复现了一下,发现自己的一些问题,没遇到类似的题目就会很迷茫,也懒得去想
比如这题打开之后是满屏blingbling的星星(大雾),ida打开也没发现什么特别的,然后就不知道该怎么入手了
这个题还蛮好玩的,目前看到了师傅们的两种解法都蛮有意思的,这里就不写了
记录一下学到的点

方法一:把星星都打印下来,是一个二维码
这个要用的python的PIL库
学习链接

这里有个奇怪的小点我一开始from PIL import Image没有成功,但是直接import PIL却成功了emmm然后试了试import PIL.Image成功了,据说卸了重装会好?

方法二:patch掉jle条件,然后运行直接显示全部星星
参考链接

有点想放一下这个题目
记录一下要学的一个:ida下的patch用法(花指令可太烦liao)

3.MiscVm

(同上)
这题冷静分析其实没有那么难,得冷静下来
先大体看一下主函数
记一些比赛遇到的题目_第3张图片
先看最后一个关键判断,通过我们的opcode来进行变换,看起来很复杂,但是仔细研究的话
比如这个
记一些比赛遇到的题目_第4张图片
这一步变换前面的三步其实是等价的,相当于只++v9和++v10
同理还有很多,这样我们可以简化我们的opcode
在这里插入图片描述
在这里插入图片描述
3和6是相反操作,这样36在一起的我们可以删去,还有一些超过12的还有别的可以化简的,我们的opcode最后得出

opcode=[4,1,7,9,10,9,4,1,7,9,10,9,4,1,7,
   9,10,9,4,1,7,9,10,9,4,1,7,9,10,9,4,1,7,9,10,
        9,4,1,7,9,10,9,4,1,7,9,10,9]    #opcode

可以看出,只在1,4,7,9,10进行了变化
据此写出这一段的exp

#coding=utf-8
v15=[0x42,0x4a,0x44,0x7b,0x33,0x370,0x46,0xd4,0x3c,0x610,0x4f,0xc8,0x6c,0x320,
   0x1e,0x190,0x6f,0x630,0x46,0x190,0x3b,0x610,0x1d,0xc4,0x3e,0x660,0x4b,0xd0,
   0x6c,0x310,0x46,0x188,0x33,0x370,0x4c,0xcc,0x7d]  #off_203020
#print(len(v15))
opcode=[4,1,7,9,10,9,4,1,7,9,10,9,4,1,7,
   9,10,9,4,1,7,9,10,9,4,1,7,9,10,9,4,1,7,9,10,
        9,4,1,7,9,10,9,4,1,7,9,10,9]    #opcode
#print(len(opcode))
v9=4
v13=9999
for a in opcode:
    if a==1:
        v15[v9]//=16
        v9+=1
    #elif a==2:
        #v15[v9]*=v9
        #v15[v9]-=128   
    #elif a==3:
        #v15[v9]//=10
        #v9-=1
    elif a==4:
        v15[v9]^=0xa
        v9+=1
    #elif a==5:
    #elif a==6:
        #v9+=1
        #v15[v9]*=10
    elif a==7:
        v15[v9] -= 128
        v15[v9] = ~v15[v9]
    #elif a==8:
        #v15[v9]+=1
        #v15[v9]-=v13
        #v13=v13%1234-2019
        #v9+=1
    elif a==9:
        v9+=1
    elif a==10:
        v15[v9]//=4
    #elif a==11:
    #elif a==12:
        #v9-=1
        #v15[v9]+=32
        #v15[v9]^=0x22
        
    else:
        continue
#print(v15)

然后继续分析上面的加密
sub_1551()给了两组数据,进行替换,
这里我卡了挺久的,主要是因为可以理解原算法但是不是很清楚应该怎么逆(还是太蠢了)
记一些比赛遇到的题目_第5张图片
exp如下

#sub_1551
v11=[1,2,3,4,19,31,25,14,23,33,13,9,24,6,26,34,17,10,8,29,12,15,22,11,
         18,16,32,28,21,36,20,7,5,27,30,35,37]
v48=[1,2,3,4,31,29,7,35,14,21,9,16,27,18,25,10,20,15,17,22,28,26,36,
         33,32,5,8,12,23,34,13,30,24,11,19,6,37]
temp=[0]*37
flag1=[0]*37
for i in range(37):
    temp[v48[i]-1]=v15[i]
for j in range(37):
    flag1[v11[j]-1]=temp[j]
print(flag1)

然后是将除了BJD{}剩余的前16位与后16位替换

#sub_19E2
for i in range(4,20):
    pass1=flag1[i+16]
    flag1[i+16]=flag1[i]
    flag1[i]=pass1
flag=''
for i in flag1:
    flag+=chr(i)
print(flag)

顺便这题找off_203020的数据时,因为眼神不好,看错好几个,俺的idapy和idc还不能熟练运用

然后关于case x==4 那里
我后来看到了别的师傅的wp
在这里插入图片描述
可以直接化简成v15[v9]^=0xA
然后我后来去试了一下,第二个v4算出来的结果都是0,第二个我的理解是16*所以左移了4位,所以lobyte(v15[v9])都是0了,导致最后结果都是0,所以可以直接化简,不知道对不对,如果有幸被师傅看到了,希望得到一些指点

下一个小坑:机器码和opcode结合的vm逆向

4.安恒四月赛第三题

差点坑掉了这题,找了有一会的题目。。。俺也不记得当初放在那里了

当初并不会做,后来赛后看了同学的wp,同学是手逆做的(真的tql)
后来看了别的师傅的wp才知道sm4算法,所以在这里写一下
学习链接

SM4密码算法是一个分组算法,其算法设计简沽,结构有特点,安全高效。数据分组长度为128比特,密钥长度为128 比特。加密算法与密钥扩展算法均采取32轮迭代结构。SM4密码算法以字节(8位)和字节(32位)作为单位进行数据处理。SM4密码算法是对合运算,因此解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

记一些比赛遇到的题目_第6张图片
然后在github上找了一下
sm4解密参考
用法如下(转载自上述连接)

1. encrypt和decrypt
>>> from pysm4 import encrypt, decrypt
# 明文
>>> clear_num = 0x0123456789abcdeffedcba9876543210
# 密钥
>>> mk = 0x0123456789abcdeffedcba9876543210
# 加密
>>> cipher_num = encrypt(clear_num, mk)
>>> hex(cipher_num)[2:].replace('L', '')
'681edf34d206965e86b3e94f536e4246'
# 解密
>>> clear_num == decrypt(cipher_num, mk)
True
2. encrypt_ecb和decrypt_ecb
>>> from pysm4 import encrypt_ecb, decrypt_ecb
# 明文
>>> plain_text = 'pysm4是国密SM4算法的Python实现'
# 密钥
>>> key = 'hello, world!'  # 密钥长度小于等于16字节
# 加密
>>> cipher_text = encrypt_ecb(plain_text, key)
>>> cipher_text
'ng3L4ldgvsZciAgx3LhplDvIzrd0+GXiNqNmd1VW0YOlwo+ojtpownOCbnxbq/3y'
# 解密
>>> plain_text == decrypt_ecb(cipher_text, key)
True
3. encrypt_cbc和decrypt_cbc
>>> from pysm4 import encrypt_cbc, decrypt_cbc
# 明文
>>> plain_text = 'pysm4是国密SM4算法的Python实现'
# 密钥
>>> key = 'hello, world!'  # 密钥 长度小于等于16字节
# 初始化向量
>>> iv = '11111111'        # 初始化向量  长度小于等于16字节
# 加密
>>> cipher_text = encrypt_cbc(plain_text, key, iv)
'cTsdKRSH2FqIJf22NHMjX5ZFHghR4ZtJ10wbNwj2//bJSElBXVeMtFycjdlVKP15'
# 解密
>>> plain_text == decrypt_cbc(cipher_text, key, iv)
True

然后在虚拟机里安装好之后
记一些比赛遇到的题目_第7张图片

5.GKCTF chellys_identity

小声说all alone with you真的好听,pp真的好看
32位拖进ida,很多函数,很多套娃,索性这题比较好定位主函数
记一些比赛遇到的题目_第8张图片
看一下二次判断里面
记一些比赛遇到的题目_第9张图片
给出了一组数组,最后拿来比较的
然后看看加密那里
记一些比赛遇到的题目_第10张图片
这里我一开始看有点看晕了,因为for循环那里吧三句话都看成for循环的子句了,后来才发现只有第一句(认真点啊)
生成质数那里代码还是比较明显的(说不定数据结构试验就考了)
记一些比赛遇到的题目_第11张图片
记一些比赛遇到的题目_第12张图片
加密函数那一段大大概就是,生成的数中,若比我输入的这个数小,就把它们都加起来,然后异或我输入的那个数,然后依次16位,在于我给定的数组相比较
exp

def primenum(n):
    a=[]
    for i in range(2,n+1):
        for j in range(2,i):
            if i%j==0:
                break
        else:
            a.append(i)
    return a

flag=''
v9=[438,1176,1089,377,377,1600,924,377,1610,924,637,639,376,566,836,830]
b=[]
b=primenum(128)
print(b)
for i in v9:
    for j in range(30,127):
        v6=0
        k=0
        for k in b:
            if k<j:
                v6+=k
            else:
                break
            v8=j^v6
        if v8==i:
            flag+=chr(j)
print(flag)

6.tree

出自2020网鼎杯朱雀组re
这是一道二叉树的题目,没怎么做过与数据结构有关系的题目摸一摸,就当是复习数据结构实验了,hehe
32位拖进ida
记一些比赛遇到的题目_第13张图片
主函数简单好定位,查看chkflag
记一些比赛遇到的题目_第14张图片
emmm大概就是先判断长度,然后把我们输入的当中的数变成二进制的,比如第一个0对应0000,1对应0001,底下有一个如果不想等就不变

查看parse
记一些比赛遇到的题目_第15张图片
这个两个函数一起看的意思呢,就是我们的输入的先进行01换算,然后呢顺着这个树找到根节点,根节点输出呢与最后那一个相同就好了
先看,parse的参数是root,当我们跟进root,查看他在内存当中的地址

.bss:00406040 _root           dd ?                    ; DATA XREF: init(void)+1D7↑w
.bss:00406040                                         ; _main+43↑r

后面还有一个函数调用了它,跟进这个函数,f5。。反汇编之后的代码很长,很难看(对我来说很难了呜呜呜)硬解应该是能解出来的
od动调看看吧,字符串定位,下断,查看
记一些比赛遇到的题目_第16张图片
然后跟进0x406530看看二叉树长啥样子
记一些比赛遇到的题目_第17张图片
我们根节点是0x406530,跟着这个,可以开始画图了,怎么画呢,想到我们之前的函数,我们的v3分别左边+12,右边+16,这两个就是我们的左右子女结点,然后一路顺着,就找到对应的字母,如果一开始还是比较模糊,od跟进下面那个函数动调差不多能确定前几个
我的图如下(到这里为止自我感觉都很良好)
记一些比赛遇到的题目_第18张图片
然后可以开始倒着推编写脚本了(呵呵我感觉都不用写脚本可以直接倒着推了)

#flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
v2='zvzjyvosgnzkbjjjypjbjdvmsjjyvsjx'
a={'y':'0000','b':'00010','q':'00011','g':'0010','f':'0011','j':'010','w':'01100',
   'p':'01101','x':'011100','d':'0111010','i':'0111011','k':'01111','s':'100',
   'z':'1010','n':'1011','c':'11000','t':'110010','e':'110011','h':'1101','o':'11100',
   'l':'1110100','u':'11101010','r':'111010110','a':'111010111','m':'111011','v':'1111'}
b=list(a.keys())
c=list(a.values())
x=''
for i in v2:
    for j in range(26):
        if i==b[j]:
            x+=c[j]
print(x)
flag=''
for i in range(0,len(x),4):
    flag+=hex(int(x[i:i+4],2)) #二进制转十六进制,先转十进制再转十六
print(flag.replace('0x',''))

打印出来结果后按照他给的排就好了
呵呵,憨憨做完这道题目之后都是自我感觉良好的,做完之后去看了师傅们的wp
果然是一个废物,这里记录一下师傅们的写法
师傅的方法
重新回到ida,可以发现一个outtree函数(我我我我我哦我。。)
记一些比赛遇到的题目_第19张图片
这标准的树。。连我这个没怎么好好听数据结构课的都(我有罪我忏悔)
然后神奇的地方来了,可以把原来调用parse的地方patch成outtree
在这里插入图片描述
然后再运行就能直接输出结构了

还有一种方法,利用idapython(呵呵我就是fw)
参考链接师傅的方法2

def traverse_leaf(pnode):
if pnode != 0:
if Dword(pnode + 12) == 0 and Dword(pnode + 16) == 0:
print(chr(Byte(pnode)))
print("".join(a))
lujing.append([chr(Byte(pnode)), “”.join(a)])
a.append(‘0’)
traverse_leaf(Dword(pnode + 12))
a.append(‘1’)
traverse_leaf(Dword(pnode + 16))
if pnode != 0X0406530:
a.pop()
traverse_leaf(0X0406530)
print(lujing)

这个脚本我还没研究懂,等我看透。。

你可能感兴趣的:(笔记)