Site-T

SUP-project


  • Home
  • Archive
  • Tags
  •  

© 2019 Time Looper

Theme Typography by Makito

Proudly published with Hexo

sup-extra 二进制组周练题解汇总

Posted at 2019-09-16 security 

二进制组周练题解汇总

2019-9-11 ollvm混淆

关于ollvm的混淆所参考的博客,感觉其中的使用部分非常有趣。

该博客中指出原本的ollvm工具提供了三种混淆方式:控制流扁平化、指令替换、虚假控制流程。而本次周练接触到的就是控制流扁平化。控制流扁平化的实现实际上就是将一些if-else语句,嵌套成do-while形式。

本次题目

首先打开IDA查看代码。1

很显然这个程序是用fencode与encode两个函数对输入字符串进行加密后再与s2串进行比较。然后先进入fencode看一下是怎么加密的。

不过fencode里面的整个汇编代码太长了。秉持着太长不看的原则我们F5看一下伪C代码。伪C代码长什么样这里就不贴图了。总的来说也正如上文所说,伪C代码中有大量的嵌套的do-while语句。伪C代码节选

而这个代码稍加分析即可得知,它利用v8的值作为跳转的信号,在各个while语句间进行跳转。所以我们实际上只需要关注v8的值的改变过程,还原出来程序的原本逻辑,就能得出结果。我所采用的方法也是最原始的方法,直接以v8的初始值为开始,一边追踪v8的改变一边做记录,这里简单贴一下自己的记录:

def fencode:
    s=input()
    v15=len(s)
    flag=-1#v14
    mark=0
    a2=[]
    if(v15!=24):
        #-1090034712
        flag=0
        return 0#1267770526
    else:
        #-1770272074
        v12=0
        #789829600
        if v12<6:
            #867656585
            v11=0
            #288393639
            if v11<4:
                #1085938007
                v10=0
                for v9 in range(4) :
                    #117331278
                    v10+=s[4*v12+v9]*m[4*v11+v9]
                    #-1647015695
                    #-2141009135
                a2[mark++]=v10%127

            else :
                ++v12#总之就是这里的循环
                #1667780839
        else:
            #-2078944754
            return 1#126770526

还原程序的逻辑过程是很繁琐的过程,这里直接给出两个程序的逻辑还原后结果:

def fendcode2():
    m=[[2,2,4,-5],[1,1,3,-3],[-1,-2,-3,4],[-1,0,-2,2]]
    mark=0
    s=input()
    if len(s)!=24:
        return 0
    for i in range(6):
        for j in range(4):
            ch=0
            for k in range(4):
                ch+=s[4*i+k]*m[j][k]
            a2[mark]=ch%127
            mark+=1
    return 1
def encode2(ss,l,news):
    a='FeVYKw6a0lDIOsnZQ5EAf2MvjS1GUiLWPTtH4JqRgu3dbC8hrcNo9/mxzpXBky7+'
    mark=0
    i=0
    while i<l:
        x1=ss[i]#v21
        x2=ss[i+1]#v20
        x3=ss[i+2]#v17整个数组开大一点保证后面是0
        i+=3
        news[mark]=a[(x1>>2)&0x3f]
        news[mark+1]=a[(x2>>4)|(x1<<4)&0x3f]
        news[mark+2]=a[(x3>>6)|(x2<<2)&0x3f]
        news[mark+3]=a[x3&0x3f]
        mark+=4
    if mark%3:
        news[mark-1]='='

还原了加密逻辑之后整个程序就很显然了,fencode函数做了一个矩阵乘法,将输入的24个字符的字符串视为4*6的矩阵,与矩阵m相乘得到新的矩阵,然后进入encode2按照题目的规则进行一个base64编码,再与题目自身的base64编码作比较。

所以我们解题的思路也很清晰了。先进行一个base64解码,再将解码过后的结果乘以m的逆矩阵,就能得到结果。不过注意到fencode的加密过程不是普通矩阵乘法的行与列相乘,而更像是行与行相乘,一开始我还考虑过会不会对结果产生影响。不过事实证明虽然调换了运算顺序,但逆矩阵依然能够发挥作用。毕竟矩阵的转置的逆矩阵=矩阵的逆矩阵的转置嘛。不理解的话可以自己写一下试试。 另外至于如何求矩阵的逆可以参考另一篇博客。所以这里只给出前两个的解密算法。

def decode1(st):
    arr1=[]
    alpha = 'FeVYKw6a0lDIOsnZQ5EAf2MvjS1GUiLWPTtH4JqRgu3dbC8hrcNo9/mxzpXBky7+'
    for ch in st:
        for i in range(len(alpha)):
            if ch==alpha[i]:
                arr1.append(i)
                break
    print(arr1,len(arr1))
    mark=0
    arr2=[]
    while mark<len(arr1):
        arr2.append(((arr1[mark]<<2)|(arr1[mark+1]>>4))&0xff)
        arr2.append(((arr1[mark+1]<<4)|(arr1[mark+2]>>2))&0xff)
        arr2.append(((arr1[mark+2]<<6)|arr1[mark+3])&0xff)
        mark+=4
    for i in range(len(arr2)):#mark1
        if arr2[i]>127:
            arr2[i]=-256+arr2[i]
    print(arr2,len(arr2))
    return arr2

def decode2(arr,rev_m):
    res=[]
    for i in range(6):
        for j in range(4):
            ch=0
            for k in range(4):
                ch+=arr[4*i+k]*rev_m[j][k]
            res.append(ch)
    return res

另外正所谓真正的高手是不用F5的,我这次也算是吸取了教训。在decode1函数中原本是没有mark1的处理的,但当我运行解密后却发现有的值是超过了127的,明明伪C代码里面有一个%127的操作,理论上不会超过127才对。并且如果我将decode1得到的数组丢进decode2中时,会发现有一部分的解密结果是对的,比如结尾是‘}’,开头为f。而当我重新回头看fencode的汇编代码时我发现,fencode在运算的时候是使用的int型,然后除以127之后截断成了byte型,所以实际上大于127的值均为负数。所以考虑到有正有负这一点,加上mark1部分的处理后就能得到正确的flag了。最后的flag是flag{dO_y0U_KNoW_0IlVm?}

Share 

 Previous post: sup-008 从零开始配置ubuntu服务器 Next post: sup-007 线性代数相关脚本 

© 2019 Time Looper

Theme Typography by Makito

Proudly published with Hexo