一次Reverse出题手记

释放双眼,带上耳机,听听看~!

出坑人题真开心啊~

学ctf的时候,一直有前辈教导,不要过度依赖工具,解题要优雅(x 要精准解题,不要滥用fuzz及其工具,要学会从逻辑层分析漏洞,找出漏洞特征,并利用漏洞解题,才是CTF to learn的真谛

于是出了一道这样的逆向题 基于老古董–visual basic

当你把它拖到IDA里看到一片db的opcode的时候你就应该知道出什么大问题了
这是一个pcode模式编译的vb6程序
这里推荐选手同时使用多个版本的decomplier进行分析,因为历代decomplier在应对嵌套过多的表达式时均会出现不同的错误
同时推荐选手使用过程中灵活开启与关闭分析优化选项来最快分析

解答本题需要一定vb pcode逆向经验来手动处理decomplier分析时产生的错误,如除去无意义常量后把多余的参数逐个左移到对应的表达式或者运算符左侧
此处不再赘述,如果无经验那么非常需要手动编译几个多嵌套参数的pcode程序即可找到大致规律
全篇中需要进行大量手动修复与计算,需要提前拥有经验

1.大致浏览

入眼第一个模块ThreadLib,看起来跟多线程有关,但是由于这道题是pcode编译的,所以无视即可。s
Module1应为关键模块,分析Form1的事件过程,发现Command1的Click事件应为关键事件,跟进发现关键函数是Proc_1_0_414B58
看一眼API,大致没用,都是多线程相关

2.分析函数

发现关键比较,比较字符串为”4974517441444E294A70596A49524D2A406E56704A70476C49745B7441444E294A70656A49524D2C406E6C704A60472F49745574415E4E724A704B6A4E644D2E406E4A704B4E472249746774415E4E714A704F6A49644D77406E56704B4E47244974457440444E294A70596A4E424D2C406E64704A6047214974397441444E284A704B6A4F424D2D406E56704A3E476B4974557441444E354A70596A4E524D75406E6C704B6047214974417440344E294A704B6A49644D75406E60704B4E472449745574415E4E284A70596A4F424D2B406E56704A3E476A497451744147″
顺着往上浏览上下文处理子函数。
407C:根据关键数据可以很快的分析出子函数功能,如65 90 77 97 122 109 48 57 52可以很明显发现这就是个ROT18
3384:很明显的对称移位,即字符串倒置
2EB8和351C同时分析:可以发现作用即为把字符对应ASC的HEX格式化两位进行输出(左补0)
3108:数学函数,特判了2,循环从2开始又到N-1结束,还有取模i验证来修改返回值,为朴素素数判断函数
3BF0:很复杂,引用了strconv以及判断了一个输入表的大小是否为64,不是的话则初始化,发现模3,与3,与15,即可直接判断这是Base64编码函数
371C:同407C,不过这次判断范围更大而且If逻辑更少,参考范围与+-47即可知这是ROT47
3198:数学函数,有算法基础的选手可以很简单的发现这是快速幂
3084:数学函数,有算法基础的选手可以很简单的发现这是GCD
2D2C:数学函数,乘三运算,无他
2CEC:运算符变形,出自VMP的NNA的表达式之一,是sub运算符
3234:未发现引用,不再进行无意义分析,稍作浏览一下发现是类似于Stub的存在
2E50:两行代码一看很显然是字符串翻倍

3.关键分析

PS:此处需要选手提前了解不透明谓词,流平整,数据变形
分析关键函数4B58
var_AC为多次调用的基础表
往下看发现了一个恶意除零异常触发SEH,为反调试手段,由于是静态分析,无视即可
下方发现基本数据都被变形保护了,需要手动还原
又发现Not((Not这种sub运算符变形,手动处理还原,发现此处其实是和一个快速幂结合的数据变形(不透明常量)
发现下方的If是不透明谓词,运算之后发现是永真,去掉这个逻辑判断,发现是两个变量的初始化,依然是数据变形,需要手动还原
下方的两个If又是不透明谓词,且一个永真,一个永假,运算后发现此处GCD两个数互质,值为1,则第一个If为真,第二个If为假,删去第二个If块
代换运算符变形以及数据变形后发现其内部作用即为利用素数判断来生成一个var_EC素数表
继续向下走发现先对输入进行了一次ROT47,又进行了一次字符串倒置,即为ROT47->字符串倒置
这里看到有一个i用GCD进行变形了,稍微一看就知道是初始化1的变形
看到下方两个相似度很像的If块知道,又是一组不透明谓词,稍作化简分析可以发现这是一个数论定理
参考素数表可判断真假性,得到第一个If为假,第二个If为真,删去第一个If块,分析第二个If块
第二个If块逻辑如果感觉难以看懂,可以关闭优化器逐行分析,发现是对输入逐个减去处理后的var_AC表的数据与对i进行取模的和,向下即为继续异或一个处理后的var_AC表的数据
继续向下分析除了两个不透明常量外未发现不透明谓词,来到下一个循环,发现逻辑是对数据做乘var_EC素数表的运算与加var_EC素数表的运算
向下的一个大If块使用了很多变形,需要逐个计算还原,发现逻辑是判断位数来补0,即把输入数据经过处理后每四位一组
下方连续if以及同一个Goto地址显然是顺序流平整后的逻辑,而且还运用了不透明谓词来控制路径,需要逐个手动计算来去平坦理清执行顺序
理清完之后发现内部甚至插入了垃圾代码,出题人虾仁猪心增大作业量
此流平整内的有效执行代码顺序依次是ROT18->字符串倒置->每个字符进行HEX编码->Base64编码
来到了最终的一个加密循环
依旧是先手动运算数据变形来还原,可以发现是数据对var_EC素数表的运算,先是减法再是异或,再经过上面更复杂的计算之后这个结尾甚至有点平淡无奇
然后将最终得到的数据逐个进行Chr变为字符串与比较字符串进行比较判断是否是flag,关键过程到此结束
发现下方又对控件的操作,大概是防止爆破操作与符号执行

4.编写解题脚本

对加密内容进行解密
直接也选用vb6进行编写

Private Sub Command1_Click()
Dim DES As String
Dim Mul_arry(10) As Long
Dim Xor_arry(16) As Byte
Xor_arry(1) = &H14
Xor_arry(2) = &H15
Xor_arry(3) = &H92
Xor_arry(4) = &H65
Xor_arry(5) = &H35
Xor_arry(6) = &HF1
Xor_arry(7) = &HE3
Xor_arry(8) = &HC7
Dim CounterJ As Integer, CounterK As Integer
CounterJ = 1
CounterK = 2
Do While CounterJ <= 6
    If PrimeGet(CounterK) = True Then
        Mul_arry(CounterJ) = CounterK
        CounterJ = CounterJ + 1
    End If
    CounterK = CounterK + 1
Loop
DES = DecodeHex(Text1.Text)
CounterJ = 1
Dim Tmpbyte As Byte, Retn As String
Do While CounterJ <= Len(DES)
    Tmpbyte = Asc(Mid(DES, CounterJ, 1)) Xor Mul_arry(((CounterJ - 1) Mod 4) + 1)
    Tmpbyte = Tmpbyte + Mul_arry(((CounterJ - 1) Mod 6) + 1)
    Retn = Retn + Chr(Tmpbyte)
    CounterJ = CounterJ + 1
Loop
Retn = XXXBase64Decode(Retn)
Retn = DecodeHex(Retn)
Retn = ReStr(Retn)
Retn = ROT18(Retn)
Text1.Text = Retn
CounterJ = 1
CounterK = 1
Dim Byte_arry(1024) As Byte
Dim Next_long_arry As Long
Do While CounterJ < Len(Retn)
    Next_long_arry = Val(Mid(Retn, CounterJ, 4))
    Next_long_arry = Next_long_arry + 1 - Mul_arry(((CounterK - 1) Mod 4) + 1)
    Byte_arry((CounterJ + 3) / 4) = Next_long_arry / Mul_arry(((CounterK - 1) Mod 6) + 1)
    CounterJ = CounterJ + 4
    CounterK = CounterK + 1
Loop
Retn = ""
CounterJ = 1
Do While CounterJ <= CounterK - 1
    Tmpbyte = Byte_arry(CounterJ) Xor Xor_arry(((CounterJ - 1) Mod 8) + 1)
    Tmpbyte = Tmpbyte + (((CounterJ - 1) Mod 8 + 1) + 1)
    Tmpbyte = Tmpbyte + Int(Math.Sqr(Xor_arry((CounterJ - 1) Mod 4 + 1)))
    Retn = Retn + Chr(Tmpbyte)
    CounterJ = CounterJ + 1
Loop
Retn = ReStr(Retn)
Retn = ROT47(Retn)
Text1.Text = Retn
End Sub
Public Function DecodeHex(ByVal StrIn As String) As String
Dim Retn As String, Strlen As Integer, CounterI As Integer
CounterI = 1
Strlen = Len(StrIn)
Do While CounterI <= Strlen
    If Mid(StrIn, CounterI, 1) <> " " Then
        If Mid(StrIn, CounterI + 1, 1) <> " " Then
            Retn = Retn + Hex2Str(Mid(StrIn, CounterI, 2))
            CounterI = CounterI + 2
        Else
            Retn = Retn + Hex2Str(Mid(StrIn, CounterI, 1))
            CounterI = CounterI + 1
        End If
    Else
        Retn = Retn + " "
        CounterI = CounterI + 1
    End If
Loop
DecodeHex = Retn
End Function
Public Function XXXBase64Decode(ByVal srcCode As String, Optional ByVal Base64Table As String = "") As String
    Dim I As Integer, C As Integer, Result() As Byte, Arr() As Byte
    srcCode = Replace(srcCode, "=", "")
    If Len(Base64Table) <> 64 Then
        Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    End If
    For I = 1 To Len(srcCode)
        If InStr(Base64Table, Mid(srcCode, I, 1)) = 0 Then Exit Function
    Next
    ReDim Result(Len(srcCode) * 3 \ 4 - 1)
    For I = 0 To UBound(Result)
        C = I * 4 \ 3 + 1
        Result(I) = InStr(Base64Table, Mid(srcCode, C, 1)) - 1
        Select Case I Mod 3
            Case 0
                Result(I) = Result(I) * 4
                If C + 1 <= Len(srcCode) Then
                    Result(I) = Result(I) + (InStr(Base64Table, Mid(srcCode, C + 1, 1)) - 1) \ 16
                End If
            Case 1
                Result(I) = (Result(I) And 15) * 16
                If C + 1 <= Len(srcCode) Then
                    Result(I) = Result(I) + (InStr(Base64Table, Mid(srcCode, C + 1, 1)) - 1) \ 4
                End If
            Case 2
                Result(I) = (Result(I) And 3) * 64 + InStr(Base64Table, Mid(srcCode, C + 1, 1)) - 1
        End Select
    Next
    XXXBase64Decode = StrConv(Result, vbUnicode)
End Function
Public Function Hex2Str(Hex As String)
Dim Retnstr As String
Hex = UCase(Hex)
Hex = "&H" + Hex
Retnstr = Chr(Val(Hex))
Hex2Str = Retnstr
End Function

将比较字符串输入Text1中按下Command1,解出答案flag{Vb666_#000000}

5.后记
本题严重引起了无vb pcode逆向经验者的不适与过度依赖ida选手的不适

本文来自先知社区

人已赞赏
安全教程

红队测评技巧:对公司发起OSINT

2020-4-24 0:48:14

安全教程

防火墙深入总结

2020-4-24 0:48:30

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索