[2020 GeekChallange] Re 刘壮的BaseXX

it2023-02-12  84

[2020 GeekChallange] Re 刘壮的BaseXX

0x00 逆向分析

把文件丢进IDA64 可以看到套了两层循环,如果执行了break即输出Correct。 切换到汇编界面分析: 通过分析汇编代码结构可以猜测出程序大致分为加密、比较两部分。

0x01 加密部分

观察汇编代码部分,可以看到循环里调用了两个函数: sub_140001420和sub_1400010E0 反编译看看。

sub_140001420

通过分析代码,不难看出它将我们输入的字符串,用for循环,一个一个字符进行加密操作。 关键的加密操作即图中红框位置。 先不管开头的 ‘i ^’,我们先分析

((*(_BYTE *)(a1 + i) >> 4) | (16 * *(_BYTE *)(a1 + i)))

这里要特别注意管道符|后的**不是幂乘,而是一个乘号和一个指针符号。 乍一看这似乎是一步很难逆向的运算,但是经过仔细分析会发现,管道符左边是右移4位,右边是*16,也相当于左移四位。 注意这个函数的输入参数a1是__int64数组指针 即我们所操作的这个数长度是8位的,那么当我们把这个数左移4位以后,右边就空出了4个0,左边的4位被挤出去了。右移则是把右边4位挤出去了。 那么此时这两个数按位或,由于互相的位置都空出来了4位,其中不存在进位,那就相当于十进制两个数相加。 举个例子:

a = 'W' print(bin(ord(a))) print(bin((ord(a) << 4) % 0b100000000)) print(bin(ord(a) >> 4)) print(bin((ord(a) << 4) % 0b100000000|(ord(a) >> 4))) #%0b100000000只是为了保持8位 #输出结果: # 0b01010111 # 0b01110000 # 0b00000101 # 0b01110101 #我偷偷在前面补了几个0,方便观察

用二进制表示可能不太直观,因为它是4位一操作,4个二进制位等于1个16进制位,那么用16进制表示就很直观了:

a = 'W' print(hex(ord(a))) print(hex((ord(a) << 4) % 0x100)) print(hex(ord(a) >> 4)) print(hex((ord(a) << 4) % 0x100|(ord(a) >> 4))) #同上#0x100也只是为了保持变量位数 #输出结果: # 0x57 # 0x70 # 0x05 # 0x75

可以很容易地发现,它就是交换了16进制位的前后两位(即交换二进制位的前四位和后四位)。 那么解密就只需要把每一个字符的前四位和后四位交换即可。

sub_1400010E0

打开就发现满屏幕的代码,一看就很不想去分析。(我也懒得分析) 但是在这里能看到有一个一直用到的一个字符串 是不是跟base64的字母表长度一模一样? 这边我直接猜测换表了。

0x02 比较部分

sub_140001490

可以看到main函数这里如果返回了0就错了,如果正确应该返回1。 可以看到循环外输出0,要正确就不能跳出循环。 看到循环内,有一个简单地按位比较,因此这个比较部分就是简单地按位字符比较。 跳转到密文: 就是由之前的表组成的。 题目也告诉我们是某Base加密,大胆猜测是base64换表。 拉进脚本里跑一下:

import base64 import string str1 = "maj7TmztjquUN8Xm-hKplvaYfEAxrUnIc51qxlKOwCKN4XsdzBmjOd_-"#密文 string1 = "zyxwvutsrqponmlkjihgfedcbaABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210-_"#改过的表 string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#原表 print (base64.b64decode(str1.translate(str.maketrans(string1,string2)))) #输出结果:b'5\x946\xb4\xd0\x06@\x91n\x9f\\M\xf9)\n8FrQ\xe6\x82"\xe3"_\x8f\t\x08\xe9(\r\xc9\'\xe7\x11\xd6\x01\xb3P\xa1o\xfe'

把二进制结果转换成数字数组:

[53, 148, 54, 180, 208, 6, 64, 145, 110, 159, 92, 77, 249, 41, 10, 56, 70, 114, 81, 230, 130, 34, 227, 34, 95, 143, 9, 8, 233, 40, 13, 201, 39, 231, 17, 214, 1, 179, 80, 161, 111, 254]

到这一步,还没有验证到底是否真的是Base64换表怎么办? 我们可以先试试输入SYC(固定flag的开头)进去看看是不是这样。 在第一次加密之后下断点 双击V6看其中的值 可以看到前三个字符为:5(\x35) \x94 6(\x36) 和我们之前换表的出的字符串前三位一模一样。 到这里基本就已经解出来了,放脚本:

import base64 import string str1 = "maj7TmztjquUN8Xm-hKplvaYfEAxrUnIc51qxlKOwCKN4XsdzBmjOd_-"#密文 string1 = "zyxwvutsrqponmlkjihgfedcbaABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210-_"#改过的表 string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"#原表 result = base64.b64decode(str1.translate(str.maketrans(string1,string2))) b = [] for i in result: b.append(int(i)) print(b) for i in range(len(b)): b[i] = i ^ b[i] print(chr((b[i]>>4) + b[i]%16*16) ,end = "")

得到flag:SYC{M0dified_B@se64_is_Sti11_S1mpl3_Right}

最新回复(0)