CTF小白学习笔记(Reverse)-i春秋 juckcode

这道题主要考察花指令和动态调试。(看了很多大神的wp才看出门道)
动态调试也是看着别人的wp慢慢调出来的(还是太菜了)
对花指令不太了解的朋友可以参考以下视频:
IDA如何patch掉花指令?

一.解题过程

拿到题目后解压,发现一个是flag.enc,一个exe,运行exe。
程序运行结果

去除花指令

提示打不开flag文件,用ida打开看看。
main函数开始的一些指令 花指令1
花指令1 花指令2

花指令2

发现一大堆花指令,有个字符串./flag,不过error in open flag提示找不到引用,所以猜测程序的输入可能是flag文件(不是flag.enc),我们先创建一个flag文件,内容写上1234567890。

关于去花指令,上面的视频有讲到,不过这里的花指令实在是多,只要把main函数里的花指令去完就可以了。(这里纯手动patch,去花脚本网上有很多,不过好像不管用)

花指令去完后,在main函数开头右键->create function,就可以反编译main函数了。
main函数

动态调试过程

创建4个关键字符串

如图所示,接下来就是漫长的动态调试过程,具体过程不再详述,我们来看看关键部分。
在这里插入图片描述

这里的v50即输入的字符串,73行的这个for循环主要功能就是把输入字符串的ascii码 + 64赋值给v35
。然后是下一个for循环

在这里插入图片描述

这里,将v35字符串每个字符左移7位赋值给v34(别被v50迷惑了,这也是动态调试才能看出来)。然后是下一个for循环
在这里插入图片描述

这里,将v34每个字符-158赋值给v13

至此,程序以及创建了4个字符串, v50(输入,1234567890), v35(v50 + 64, qrstuvwxyp), v34 (v34 <<7),v13(v34 - 158)。

对4个关键字符串进行base64编码,并将编码后的字符串重新组合

接下来就是如下的函数片段:
在这里插入图片描述

动态调试的时候会发现:
v49的值为MTIzNDU2Nzg5MA== (v50 base64编码)
v45为cXJzdHV2d3h5cA== (v35 base64)
v46为gACAAIAAgACAAA== (v34base64)
v47为4mLiYuJi4mLiYg== (v13 base64)

src为 Mc4gTXmA… (v49v45v47v46*(v49 + 1)…)
dst指针指向src后一位,没太大用。

对重新组合过的字符串的变换

接着往下看:
在这里插入图片描述

这里135行的for循环中v23为对src进行base64编码后的字符串,v51为将v23转为16进制后的字符串(比如字符串’10’,ascii码分别为0x31,0x30,变成’3130’)

下一个for循环将v51每个字符 + 16,结果保存在flag.enc中,至此程序流程结束。

解密脚本

import base64

message = open("../datas/flag.enc").read()[:-1]
v51 = ''.join([chr(ord(c) - 16) for c in message])
v23 = ""
v51_list = [c for c in v51]

for i in range(int(len(v51) / 2)):
    v23 += chr(int(''.join(v51_list[i * 2: i * 2 + 2]), 16))

src = base64.b64encode(v23.encode("latin-1")).decode('utf-8')
print(src)

input_b64 = src.replace("\n","")[::4]
print(input_b64)
print(len(input_b64))
input = base64.b64decode((input_b64 + '==').encode('utf-8'))
print(input)

解密完成后得到flag{juck_code_cannot_stop_you_reversing}

这里需要注意,其他wp大部分都是用python2写的,我这是python3写的。这里的v23包括一些不可见字符,python2和python3的base64在对不可见字符编码时,结果会不同,待会会讲一下。

二.ida动态调试

我用的是IDA7.0, IDA7.x默认集成了F5插件,idapython等还包括一些动态调试器。在%IDAPATH%/dbgsrv文件夹下可以看到
在这里插入图片描述

这个程序是windows 32位的程序,所以在本机上运行win32_remote.exe.
在这里插入图片描述

之后在ida debugger中选择remote windows debugger
在这里插入图片描述

在参数选择界面中把ip地址填成127.0.0.1就行。然后就可以开始动态调试了。不得不说IDA7还是很牛逼的。

三.python2和python3的base64

这道题还有一个问题就是在解密过程中会涉及到对不可见字符的base64编码。
相关讨论可以参考:Python2/3 的 base64 对不可见字符编码结果不同
在python2中,字符串base64编码过程如下:

s3 = base64.b64encode(s2)

其中, s2,s3都是str类型的变量。

而在python3中,应该按下面方式写:

s3 = base64.b64encode(s2.encode("utf-8")).decode('utf-8')

base64.b64encode传入参数必须位bytes类型,返回值也是bytes类型。
而python3中 str.encode可以将str变成bytes。 bytes.decode可以将bytes变成str。

在python3中,我们可以做以下试验,看看0x00-0xFF中,非ascii码范围内(0x80-0xFF)的字符和ascii码范围内的字符utf-8编码的结果:

print('\xef'.encode('utf-8'))
print('\x30'.encode('utf-8'))

执行结果:

b'\xc3\xaf'
b'0'

可以看出,ascii码范围内的字符utf-8编码后字符值并未改变,而非ascii范围内的变了。这里就需要引入latin-1(ISO-8859-1)编码。

print('\xef'.encode('latin-1'))
print('\x30'.encode('latin-1'))

执行结果:

b'\xef'
b'0'

可见,这道题在对v23 base64编码前,应该用latin-1编码v23,base64过后依旧可以用utf-8解码。

src = base64.b64encode(v23.encode("latin-1")).decode('utf-8')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值