[2020 GeekChallange] Re 刘壮的BaseXX

3 篇文章 0 订阅

[2020 GeekChallange] Re 刘壮的BaseXX

0x00 逆向分析

在这里插入图片描述
把文件丢进IDA64
可以看到套了两层循环,如果执行了break即输出Correct。
切换到汇编界面分析:
main函数总览
第一部分
第二部分
通过分析汇编代码结构可以猜测出程序大致分为加密、比较两部分。

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值