NewStarCTF 2023 Week2 PZthon
本文最后更新于312 天前,其中的信息可能已经过时,如有错误可以直接在文章下留言

这一题,是Reverse方向的,很像广州大学第三届方班预备班X网安学会CTF新生赛Reverse里面的一题,后面再复盘那一题

用IDA打开给的PZthon.exe文件,没什么关键函数,直接 shift + F12看Strings Window,发现字符串数据非常多,没什么特别的字符串,要说特别的就下面这几个

为什么说像广州大学新生赛的那一题,像就像在这里,当时做那一题时这也有图里面的这两种字符串,星期、月份还有26个大小写字母都出现了,当时作为小白啥也不懂,以为是关键数据,这困惑了我很久。好吧,现在也是小白,图中的这些字符串我现在也不明白为啥会出现。这题反正也是没思路,因为广州大学新生赛那一题我也还没搞懂呢。直接看Writeup

NewStarCTF 2023 Week2 官方WriteUp(转载)-CSDN博客

Writeup说如图这些是Python的痕迹,考点也就是py打包成的exe,其实题目的标题也有提示了。学习了一下,是指将python的.py源代码文件打包成.exe可执行文件,作用呢是可以使我们的程序在没有安装Python解释器的环境中运行。需要依靠类似PyInstaller等工具。

第一次接触这种类型的题目,所以啥也不会也正常吧。

所以按照Writeup,我们要做的,就是依据.exe文件获得它的python源代码吧,毕竟flag的线索大概率在源代码里,利用到解包工具pyinstxtractor,又是第一次接触,不过安装使用都不难,Writeup里面给了下载链接,直接解包

在同级目录下可以找到 PZthon.exe_extracted 文件夹,在里面找到 PZthon.pyc,该文件就是python文件的字节码文件。

那什么又是.pyc文件呢?

python运行经过了两步操作:

  • 将源代码编译成为“字节码”
  • 转发“字节码”到“虚拟机”

可以理解为翻译,把print(hello world)翻译成字节码,字节码会保存在后缀名是.pyc的文件里,这文件其实就是编译后的.py源代码。

这些字节码相较于源代码,运行起来速度要快得多。为什么?

  • pyc文件是由.py文件经过编译后生成的字节码文件在下一次运行程序时,如果在上次保存了字节码之后没有修改过源代码了,Python就会加载.pyc文件并且跳过编译这个步骤,就省去了编译的过程,节省了时间。其加载速度就相对于之前的.py文件有所提高,而且还可以实现源码隐藏,以及一定程度上的反编译。因此,不同版本的python可能运行不了同一个.pyc文件。

在这里又牵扯到“字节码”和“虚拟机”两个概念,就不多扩展先。这两个概念其实Java语言里面也是有的,而且Java也有类似.pyc的字节码文件.class,后面是会遇到Java的反编译题目的

所以.pyc文件确实是可以反编译回python的源代码的,我们直接用pycdc反编译,得到如下代码


def hello():
    art = '\n              ___                                                                      \n    //   ) )     / /    //   ) )  // | |     / /        // | |  \\ / / \\    / /       \n   //___/ /     / /    //        //__| |    / /        //__| |   \\  /   \\  / /        \n  / ____ /     / /    //  ____  / ___  |   / /        / ___  |   / /     \\/ /         \n //           / /    //    / / //    | |  / /        //    | |  / /\\     / /          \n//           / /___ ((____/ / //     | | / /____/ / //     | | / /  \\   / /           \n                                                                                       \n     / /        //   / / ||   / / //   / /  / /       /__  ___/ ||   / |  / / //   ) ) \n    / /        //____    ||  / / //____    / /          / /     ||  /  | / / //   / /  \n   / /        / ____     || / / / ____    / /          / /      || / /||/ / //   / /   \n  / /        //          ||/ / //        / /          / /       ||/ / |  / //   / /    \n / /____/ / //____/ /    |  / //____/ / / /____/ /   / /        |  /  | / ((___/ /     \n'
    print(art)
    return bytearray(input('Please give me the flag: ').encode())

enc = [
    115,
    121,
    116,
    114,
    110,
    76,
    37,
    96,
    88,
    116,
    113,
    112,
    36,
    97,
    65,
    125,
    103,
    37,
    96,
    114,
    125,
    65,
    39,
    112,
    70,
    112,
    118,
    37,
    123,
    113,
    69,
    79,
    82,
    84,
    89,
    84,
    77,
    76,
    36,
    112,
    99,
    112,
    36,
    65,
    39,
    116,
    97,
    36,
    102,
    86,
    37,
    37,
    36,
    104]
data = hello()
for i in range(len(data)):
    data[i] = data[i] ^ 21
if bytearray(enc) == data:
    print('WOW!!')
else:
    print('I believe you can do it!')
input('To be continue...')

我一开始写的脚本是这样的,但是一直报错,’ord() expected string of length 1, but int found‘,但是我打印了一次date,发现date里面也没数字啊

enc = [0x73, 0x79, 0x74, 0x72, 0x6e, 0x4c, 0x25, 0x60, 0x58, 0x74, 0x71, 0x70, 0x24, 0x61, 0x41, 0x7d, 0x67, 0x25, 0x60,
0x72, 0x7d, 0x41, 0x27, 0x70, 0x46, 0x70, 0x76, 0x25, 0x7b, 0x71, 0x45, 0x4f, 0x52, 0x54, 0x59, 0x54, 0x4d, 0x4c,
0x24, 0x70, 0x63, 0x70, 0x24, 0x41, 0x27, 0x74, 0x61, 0x24, 0x66, 0x56, 0x25, 0x25, 0x24, 0x68]
date=bytearray(enc)
#在这里print(date)的话结果是bytearray(b"sytrnL%`Xtqp$aA}g%`r}A\'pFpv%{qEORTYTML$pcp$A\'ta$fV%%$h")
for i in range(len(enc)):
    date[i]=chr(ord(date[i])^21)
print(date)

后面问了学校的大佬,才又又又学到了小知识,像这种bytes,bytearray,long_to_bytes的函数,最终输出来的字节串,里面的数据都是以int的形式存储的,但是输出出来会以b”some string”的形式显现出来,我觉得可以用以下python代码来解释就可以明白了

enc = [0x73, 0x79, 0x74, 0x72, 0x6e, 0x4c, 0x25, 0x60, 0x58, 0x74, 0x71, 0x70, 0x24, 0x61, 0x41, 0x7d, 0x67, 0x25, 0x60,
       0x72, 0x7d, 0x41, 0x27, 0x70, 0x46, 0x70, 0x76, 0x25, 0x7b, 0x71, 0x45, 0x4f, 0x52, 0x54, 0x59, 0x54, 0x4d, 0x4c,
       0x24, 0x70, 0x63, 0x70, 0x24, 0x41, 0x27, 0x74, 0x61, 0x24, 0x66, 0x56, 0x25, 0x25, 0x24, 0x68]
date=bytearray(enc)
print(date)
#输出结果为  bytearray(b"sytrnL%`Xtqp$aA}g%`r}A\'pFpv%{qEORTYTML$pcp$A\'ta$fV%%$h")
print(date[0])
#输出结果为数字115
date[0]=65
print(date)
#输出结果为  bytearray(b"AytrnL%`Xtqp$aA}g%`r}A\'pFpv%{qEORTYTML$pcp$A\'ta$fV%%$h")



这里看明明输出是b”sytrnL%`Xtqp$aA}g%`r}A\’pFpv%{qEORTYTML$pcp$A\’ta$fV%%$h”,但是打印出来date[0]却是115,也就是字母s在Ascii码表中对应的值,把它直接改为A在Ascii码表中对应的值65,就显现出A了。

所以改进脚本如下

enc = [0x73, 0x79, 0x74, 0x72, 0x6e, 0x4c, 0x25, 0x60, 0x58, 0x74, 0x71, 0x70, 0x24, 0x61, 0x41, 0x7d, 0x67, 0x25, 0x60,
0x72, 0x7d, 0x41, 0x27, 0x70, 0x46, 0x70, 0x76, 0x25, 0x7b, 0x71, 0x45, 0x4f, 0x52, 0x54, 0x59, 0x54, 0x4d, 0x4c,0x24, 0x70, 0x63, 0x70, 0x24, 0x41, 0x27, 0x74, 0x61, 0x24, 0x66, 0x56, 0x25, 0x25, 0x24, 0x68]
date=bytearray(enc)

for i in range(len(enc)):
    date[i]=(date[i])^21
print(date)
#输出结果为  bytearray(b'flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}')

因此flag即为flag{Y0uMade1tThr0ughT2eSec0ndPZGALAXY1eve1T2at1sC001}

文末附加内容

评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇