网鼎杯2022 青龙组 Handmake

5.1k words

Handmake

Analyse

1. 查看文件类型
m1sceden4@DESKTOP-H37I3CV:/reverse/Handmake$ file challenge                                             
challenge: ASCII text, with CRLF line terminators

发现是文本文件,cat一下

可以看到这是go代码,篇幅很长,共有15w行之多。将文件后缀改为.go,通过任意编辑器打开文件

2. 分析文件内容

这段go代码定义了很多很多函数,在不知道题目意思的情况下,大概可以感觉这些函数应该是起到混淆和加大逆向难度的作用

找到main函数,代码如下:

func main() {
    var nFAzj, CuSkl string
    jjxXf := []byte{
        37, 73, 151, 135, 65, 58, 241, 90, 33, 86, 71, 41, 102, 241, 213, 234, 67, 144, 139, 20, 112, 150, 41, 7, 158, 251, 167, 249, 24, 129, 72, 64, 83, 142, 166, 236, 67, 18, 211, 100, 91, 38, 83, 147, 40, 78, 239, 113, 232, 83, 227, 47, 192, 227, 70, 167, 201, 249, 156, 101, 216, 159, 116, 210, 152, 234, 38, 145, 198, 58, 24, 183, 72, 143, 136, 234, 246}
    KdlaH := []byte{
        191, 140, 114, 245, 142, 55, 190, 30, 161, 18, 200, 7, 21, 59, 17, 44, 34, 181, 109, 116, 146, 145, 189, 68, 142, 113, 0, 33, 46, 184, 21, 33, 66, 99, 124, 167, 201, 88, 133, 20, 211, 67, 133, 250, 62, 28, 138, 229, 105, 102, 125, 124, 208, 180, 50, 146, 67, 39, 55, 240, 239, 203, 230, 142, 20, 90, 205, 27, 128, 136, 151, 140, 222, 92, 152, 1, 222, 138, 254, 246, 223, 224, 236, 33, 60, 170, 189, 77, 124, 72, 135, 46, 235, 17, 32, 28, 245}
    fmt.Print(MPyt9GWTRfAFNvb1(jjxXf))
    fmt.Scanf("%20s", &nFAzj)
    fmt.Print(kZ2BFvOxepd5ALDR(KdlaH))
    fmt.Scanf("%20s", &CuSkl)
    vNvUO := GwSqNHQ7dPXpIG64(nFAzj)
    YJCya := ""
    mvOxK := YI3z8ZxOKhfLmTPC(CuSkl)
    if mvOxK != nil {
        YJCya = mvOxK()
    }

    if YJCya != "" && vNvUO != "" {
        fmt.Printf("flag{%s%s}\n", vNvUO, YJCya)
    }
}

那么当程序运行时,应该会先print一段字符串,接着接收用户输入,再print第二段字符串,最后如果变量YJCya和vNvUO都不为空的情况下,会输出flag

print的部分调用了MPyt9GWTRfAFNvb1函数和kZ2BFvOxepd5ALDR函数,传入了jjxXfKdlaH这两个变量,定位到这两个函数

MPyt9GWTRfAFNvb1

func MPyt9GWTRfAFNvb1(gfqOc []byte) string {
    mYxFI := make([]byte, 80)
    spVwk := [78]byte{
        108, 39, 231, 242, 53, 26, 133, 50, 68, 118, 33, 64, 20, 130, 161, 202, 37, 229, 229, 119, 4, 255, 70, 105, 178, 219, 208, 145, 113, 226, 32, 96, 59, 239, 213, 204, 117, 50, 163, 5, 41, 71, 62, 246, 92, 43, 157, 2, 200, 50, 141, 75, 224, 151, 46, 194, 233, 141, 244, 12, 170, 251, 84, 188, 249, 135, 67, 245, 230, 93, 84, 254, 32, 221, 178, 202, 252}

    for i := 0; i < 77; i++ {
        mYxFI[i] = spVwk[i] ^ gfqOc[i]
    }

    return string(mYxFI)
}

这段代码接收了一个[]byte类型的参数gfqOc,并返回一个srting类型的结果。函数内部首先创造了一个长度为80的[]byte类型变量mYxFI,然后定义了一个长度为78的数组spVwk,数组中存储了一系列的整数值。接下来通过一个循环将spVwk数组中的每个元素与gfqOc数组中对应位置的元素进行异或,并将结果存储到mYxFI数组中并将该变量返回。

kZ2BFvOxepd5ALDR函数同样是将KdlaH`变量进行异或,那么可以得到这两段输出内容

jjxXf = [37, 73, 151, 135, 65, 58, 241, 90, 33, 86, 71, 41, 102, 241, 213, 234, 67, 144, 139, 20, 112, 150, 41, 7, 158, 251, 167, 249, 24, 129, 72, 64, 83, 142, 166, 236, 67, 18, 211, 100, 91, 38, 83, 147, 40, 78, 239, 113, 232, 83, 227, 47, 192, 227, 70, 167, 201, 249, 156, 101, 216, 159, 116, 210, 152, 234, 38, 145, 198, 58, 24, 183, 72, 143, 136, 234, 246]
KdlaH = [191, 140, 114, 245, 142, 55, 190, 30, 161, 18, 200, 7, 21, 59, 17, 44, 34, 181, 109, 116, 146, 145, 189, 68, 142, 113, 0, 33, 46, 184, 21, 33, 66, 99, 124, 167, 201, 88, 133, 20, 211, 67, 133, 250, 62, 28, 138, 229, 105, 102, 125, 124, 208, 180, 50, 146, 67, 39, 55, 240, 239, 203, 230, 142, 20, 90, 205, 27, 128, 136, 151, 140, 222, 92, 152, 1, 222, 138, 254, 246, 223, 224, 236, 33, 60, 170, 189, 77, 124, 72, 135, 46, 235, 17, 32, 28, 245]
spVwk = [108, 39, 231, 242, 53, 26, 133, 50, 68, 118, 33, 64, 20, 130, 161, 202, 37, 229, 229, 119, 4, 255, 70, 105, 178, 219, 208, 145, 113, 226, 32, 96, 59, 239, 213, 204, 117, 50, 163, 5, 41, 71, 62, 246, 92, 43, 157, 2, 200, 50, 141, 75, 224, 151, 46, 194, 233, 141, 244, 12, 170, 251, 84, 188, 249, 135, 67, 245, 230, 93, 84, 254, 32, 221, 178, 202, 252]
jutvH = [246, 226, 2, 128, 250, 23, 202, 118, 196, 50, 187, 98, 118, 84, 127, 72, 2, 211, 24, 26, 241, 229, 212, 43, 224, 93, 32, 86, 70, 209, 118, 73, 98, 11, 29, 212, 233, 107, 165, 119, 178, 47, 233, 159, 76, 111, 170, 132, 7, 2, 93, 21, 190, 194, 93, 249, 38, 84, 23, 132, 135, 174, 198, 232, 97, 52, 174, 111, 233, 231, 249, 172, 176, 61, 245, 100, 186, 170, 157, 190, 133, 150, 217, 78, 76, 146, 207, 2, 17, 36, 198, 69, 137, 39, 26, 60, 255]
sentence1 = []
sentence2 = []
for i in range(len(jjxXf)):
    sentence1.append(jjxXf[i] ^ spVwk[i])
for i in range(len(KdlaH)):
    sentence2.append(KdlaH[i] ^ jutvH[i])
print("sentence1 : ")
for i in sentence1:
    print(chr(i), end="")
print("sentence2 : ")
for i in sentence2:
    print(chr(i), end="")

得到:

sentence1 : 
Input the first function, which has 6 parameters and the third named gLIhR: 
sentence2 : 
Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6: 
  • 亦或者可以对该go文件进行编译,或者直接运行,可以在终端得到输出

知道了这两段输出,大概就知道题目的意思了

解题

func 1

要求找的第一个函数需要有六个参数并且第三个参数的名字是gLIhR

func \w+\(\w+\s+\[\]\w+,\s+\w+\s+\w+,\s+gLIhR\s+\w+,\s+\w+\s+\w+,\s+\w+\s+\w+,\s+\w+\s+\w+\)

\w代表一个单词字符,匹配以下字符:

  • 所有大小写字母(A-Z,a-z)

  • 所有数字(0-9)

  • 下划线(_)

\s代表空白字符,匹配以下字符:

  • 空格

  • 制表符

  • 换行符

  • 回车符

  • 垂直制表符

  • 换页符

那么第一个函数我们应该输入ZlXDJkH3OZN4Mayd

根据源程序

func GwSqNHQ7dPXpIG64(cJPTR string) string {
    YrXQd := hex.EncodeToString([]byte(cJPTR))
    return fmt.Sprintf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", YrXQd[22], YrXQd[19], YrXQd[20], YrXQd[21], YrXQd[28], YrXQd[10], YrXQd[20], YrXQd[7], YrXQd[29], YrXQd[14], YrXQd[0], YrXQd[18], YrXQd[3], YrXQd[24], YrXQd[27], YrXQd[31])
}

将字符串ZlXDJkH3OZN4Mayd每一位转为十六进制,接着按照顺序取出得到前半段flag

3a4e76449355c414

当然也可以直接在源程序中添加fmt.Println()输出fmt.Sprintf("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", YrXQd[22], YrXQd[19], YrXQd[20], YrXQd[21], YrXQd[28], YrXQd[10], YrXQd[20], YrXQd[7], YrXQd[29], YrXQd[14], YrXQd[0], YrXQd[18], YrXQd[3], YrXQd[24], YrXQd[27], YrXQd[31]),接着运行,输出结果

func 2

需要找到一个函数有 3 个调用者并调用名为 cHZv5op8rOmlAkb6 的函数

找到UhnCm82SDGE0zLYO符合要求

简单的异或

Ek08m = [167, 238, 45, 89, 160, 95, 34, 175, 158, 169, 20, 217, 68, 137, 231, 54]
Sythk = [159, 141, 72, 106, 196, 62, 16, 205, 170, 159, 36, 232, 125, 239, 208, 3]
ans = []
for i in range(len(Ek08m)):
    ans.append(Ek08m[i] ^ Sythk[i])
for i in ans:
    print(chr(i), end="")
#8ce3da2b46019f75

拼接得到 flag{3a4e76449355c4148ce3da2b46019f75}