menu 牢记自己是菜
ISC2016训练赛——phrackCTF FindKey 简单的py逆向引起的种种疑问
2323 浏览 | 2020-05-30 | 阅读时间: 约 4 分钟 | 分类: 春秋实验室 | 标签:
请注意,本文编写于 1419 天前,最后修改于 1419 天前,其中某些信息可能已经过时。

0x1 前言

前几天队伍里面的大佬们交换了一下友链,我发现了一个严重的问题,师傅们人均文学带师,就我一个老二刺螈。不过能收获一群师傅的友链我还是蛮开心的,努力学习。这周除了复现了网鼎杯的题目,还看了看GKCTF(BUUCTF),题目不算太难,我不打算单独的写博客了,等我慢慢的把几道题目摸完,把我觉得有意义的知识点统一的写一篇博客吧。主要是今天再看XCTF的re题目,奈何能力有限,实在是摸不出来,想在春秋上找一道题目放松一下,然后我就发现了这道题目。题目很简单,逻辑也很清楚,但是居然把我卡了一下下。这是一道py逆向的题目,也是我re以来做的第三道py逆向。第一道是子洋师傅给的入门py签到题,第二道是比赛上遇见的py字节码的题目(具体题目可以看看子洋师傅写的wp),这道题很新颖,有兴趣的同学可以看看。第三道就是这道,这道题目的算法难度算是入门级的,但是题目并没有告诉我们这是一道py逆向。所以这篇文章主要是记录一下我对py的理解与特点判断。


0x2 FindKey

我们先来看一下这道题目,下载一看,明显不是exe可执行文件,一般遇见这种情况大概率是Linux下的可执行文件。于是我将文件放入虚拟机,结果发现也无法识别。没有办法,我们将文件放入IDA,同样的无法识别。这时候我猜测,这有可能是PE头发生了损坏,导致文件无法识别。于是上winhex,嗯,这哪是文件头损坏,根本就没有文件头。

但是我们发现了一个很奇怪的现象,就是在文件后面几行居然可以看见部分的代码。到这里我才反应过来这很有可能是py的文件(具体关于py的问题放在下一个板块,这里先做题)。于是我们上工具EasyPythonDecompiler,直接对这个文件进行反编译,py有一点好处就是,可以直接看见源码,是直接可以运行的那种源码。下面就是反编译代码,逻辑很简单。

# Embedded file name: findkey
import sys
lookup = [196,
 153,
 149,
 206,
 17,
 221,
 10,
 217,
 167,
 18,
 36,
 135,
 103,
 61,
 111,
 31,
 92,
 152,
 21,
 228,
 105,
 191,
 173,
 41,
 2,
 245,
 23,
 144,
 1,
 246,
 89,
 178,
 182,
 119,
 38,
 85,
 48,
 226,
 165,
 241,
 166,
 214,
 71,
 90,
 151,
 3,
 109,
 169,
 150,
 224,
 69,
 156,
 158,
 57,
 181,
 29,
 200,
 37,
 51,
 252,
 227,
 93,
 65,
 82,
 66,
 80,
 170,
 77,
 49,
 177,
 81,
 94,
 202,
 107,
 25,
 73,
 148,
 98,
 129,
 231,
 212,
 14,
 84,
 121,
 174,
 171,
 64,
 180,
 233,
 74,
 140,
 242,
 75,
 104,
 253,
 44,
 39,
 87,
 86,
 27,
 68,
 22,
 55,
 76,
 35,
 248,
 96,
 5,
 56,
 20,
 161,
 213,
 238,
 220,
 72,
 100,
 247,
 8,
 63,
 249,
 145,
 243,
 155,
 222,
 122,
 32,
 43,
 186,
 0,
 102,
 216,
 126,
 15,
 42,
 115,
 138,
 240,
 147,
 229,
 204,
 117,
 223,
 141,
 159,
 131,
 232,
 124,
 254,
 60,
 116,
 46,
 113,
 79,
 16,
 128,
 6,
 251,
 40,
 205,
 137,
 199,
 83,
 54,
 188,
 19,
 184,
 201,
 110,
 255,
 26,
 91,
 211,
 132,
 160,
 168,
 154,
 185,
 183,
 244,
 78,
 33,
 123,
 28,
 59,
 12,
 210,
 218,
 47,
 163,
 215,
 209,
 108,
 235,
 237,
 118,
 101,
 24,
 234,
 106,
 143,
 88,
 9,
 136,
 95,
 30,
 193,
 176,
 225,
 198,
 197,
 194,
 239,
 134,
 162,
 192,
 11,
 70,
 58,
 187,
 50,
 67,
 236,
 230,
 13,
 99,
 190,
 208,
 207,
 7,
 53,
 219,
 203,
 62,
 114,
 127,
 125,
 164,
 179,
 175,
 112,
 172,
 250,
 133,
 130,
 52,
 189,
 97,
 146,
 34,
 157,
 120,
 195,
 45,
 4,
 142,
 139]
pwda = [188,
 155,
 11,
 58,
 251,
 208,
 204,
 202,
 150,
 120,
 206,
 237,
 114,
 92,
 126,
 6,
 42]
pwdb = [53,
 222,
 230,
 35,
 67,
 248,
 226,
 216,
 17,
 209,
 32,
 2,
 181,
 200,
 171,
 60,
 108]
flag = raw_input('Input your Key:').strip()
if len(flag) != 17:
    print 'Wrong Key!!'
    sys.exit(1)
flag = flag[::-1]   #取反
for i in range(0, len(flag)):
    if ord(flag[i]) + pwda[i] & 255 != lookup[i + pwdb[i]]:
        print 'Wrong Key!!'
        sys.exit(1)

print 'Congratulations!!'

首先给出了三个数组,然后对输入的flag进行判断,假若满足每次判断,则输出成功,否则失败。由于逻辑很简单,直接采取爆破的手段就可以解决问题。下面就是解题代码。虽然丑但有效!

lookup = [196,
 153,
 149,
 206,
 17,
 221,
 10,
 217,
 167,
 18,
 36,
 135,
 103,
 61,
 111,
 31,
 92,
 152,
 21,
 228,
 105,
 191,
 173,
 41,
 2,
 245,
 23,
 144,
 1,
 246,
 89,
 178,
 182,
 119,
 38,
 85,
 48,
 226,
 165,
 241,
 166,
 214,
 71,
 90,
 151,
 3,
 109,
 169,
 150,
 224,
 69,
 156,
 158,
 57,
 181,
 29,
 200,
 37,
 51,
 252,
 227,
 93,
 65,
 82,
 66,
 80,
 170,
 77,
 49,
 177,
 81,
 94,
 202,
 107,
 25,
 73,
 148,
 98,
 129,
 231,
 212,
 14,
 84,
 121,
 174,
 171,
 64,
 180,
 233,
 74,
 140,
 242,
 75,
 104,
 253,
 44,
 39,
 87,
 86,
 27,
 68,
 22,
 55,
 76,
 35,
 248,
 96,
 5,
 56,
 20,
 161,
 213,
 238,
 220,
 72,
 100,
 247,
 8,
 63,
 249,
 145,
 243,
 155,
 222,
 122,
 32,
 43,
 186,
 0,
 102,
 216,
 126,
 15,
 42,
 115,
 138,
 240,
 147,
 229,
 204,
 117,
 223,
 141,
 159,
 131,
 232,
 124,
 254,
 60,
 116,
 46,
 113,
 79,
 16,
 128,
 6,
 251,
 40,
 205,
 137,
 199,
 83,
 54,
 188,
 19,
 184,
 201,
 110,
 255,
 26,
 91,
 211,
 132,
 160,
 168,
 154,
 185,
 183,
 244,
 78,
 33,
 123,
 28,
 59,
 12,
 210,
 218,
 47,
 163,
 215,
 209,
 108,
 235,
 237,
 118,
 101,
 24,
 234,
 106,
 143,
 88,
 9,
 136,
 95,
 30,
 193,
 176,
 225,
 198,
 197,
 194,
 239,
 134,
 162,
 192,
 11,
 70,
 58,
 187,
 50,
 67,
 236,
 230,
 13,
 99,
 190,
 208,
 207,
 7,
 53,
 219,
 203,
 62,
 114,
 127,
 125,
 164,
 179,
 175,
 112,
 172,
 250,
 133,
 130,
 52,
 189,
 97,
 146,
 34,
 157,
 120,
 195,
 45,
 4,
 142,
 139]
pwda = [188,
 155,
 11,
 58,
 251,
 208,
 204,
 202,
 150,
 120,
 206,
 237,
 114,
 92,
 126,
 6,
 42]
pwdb = [53,
 222,
 230,
 35,
 67,
 248,
 226,
 216,
 17,
 209,
 32,
 2,
 181,
 200,
 171,
 60,
 108]
flag=""
for j in range(0,17):
    for i in range(0,150):
        if(i+pwda[j]&255)==lookup[j+pwdb[j]]:
            flag+=chr(i)
print(flag[::-1])

#print('ok')


0x3 浅谈py

python用过的人都不会对他陌生,这是一种轻量级解释行的语言,主要的有点就是方便。Python 常被称为胶水语言,能把用其他语言编写的各模块 (尤其是 C/C++) 轻松地联结在一起,这就是python为什么会有那么多的库函数。在我学习py的时候,我觉得py的语法很简单,但是各种的库就没有那么容易了。无论是RSA的依赖库还是爬虫的"靓汤"库,一个比一个难记,在我们需要用到的时候,往往还要去看看他们的语法规则。学习c++的时候,我们都知道,一个程序需要经过1.预处理(Preprocessing),2.编译(Compilation),3.汇编(Assemble),4.链接(Linking),四个步骤才可以形成exe程序。但是c++与py是不同的。那么PY到底是怎么运行的呢?Python 在执行时,会先将 .py 文件中的源代码编译成 byte code (字节码),然后再由 Python Virtual Machine 来执行这些编译 byte code。这种方式很像java的虚拟机。这就牵扯到了几个与py有关的文件了,如果你有动手操作这道题目的话,你可能已经发现了,下载的原始文件并不可以被EasyPythonDecompiler识别,我们要将文件后缀改为pyc才可以完成反编译。那么这些文件到底有什么区别呢?

  • .py文件:
    以 .py 作扩展名的文件是 Python 源代码文件,由 python.exe 解释,可在控制台下运行。当然,也可用文本编辑器或其它专用 Python IDE (集成开发环境) 工具进行修改。
  • .pyc文件
    以 .pyc 作扩展名的文件是 python 编译文件。.pyc 文件是不能直接用文本编辑器进行编辑,其优点是 .pyc 文件的执行速度要远快于 .py 文件。这里最直观的区别就是.py我们是可以使用记事本打开并进行编辑的,.pyc则不可以,本道题目我们拿到的就是一个pyc文件。但 .pyc 文件只是经简单编译,并未加密,因此,有些工具还能反编译它得出源代码。
  • .pyw
    .pyw 文件格式主要是设计用来运行 Python 纯 GUI (图形用户界面) 程序的。纯 GUI (图形用户界面) 程序的用户不需要看到类似 CMD 命令的黑色 shell 控制台窗口。有一说一我并没怎么见过pyw的文件,因为我们写的py大多都是脚本,在cmd下运行。并且在生活中我也没有怎么接触过纯py编写的软件,所以对这个类型不太了解,理解比较浅显。
  • .pyd文件格式
    .pyd 文件是非 Python,由其它编程语言 "编写-编译" 生成的 Python 扩展模块。

这就是py的几种主要文件格式。这就决定了python编写的程序几乎很难在进行相应的加密(可能有但是我不太清楚,之后碰见的话会再进行补充的)。之后要是发现有些文件不能以正常的方式打开的话可以尝试把它当成py。emmmmmmmmm就在刚才,子洋师傅发现了ghidra神器,成功解决了cipher的反编译问题,不说了,读代码去了。

发表评论

email
web

全部评论 (共 2 条评论)

    2020-06-01 12:38
    怎么发现这个给出的文件其实是python代码的?我没太看懂,可以讲一下嘛 |´・ω・)ノ
      2020-06-05 00:42
      @iyzyi这玩意真的算是三分靠运气,七分靠猜,我是IDA没打开,winhex没看见PE头,最后是在winhex里面看见了一点点代码,才反应过来是python的。当时的想法是,python是解释型的语言,多多少少应该可以在winhex里面看见点东西。但是现在我还不清楚python会不会真的存在一些恶心的混淆,毕竟PHP都有。所以师傅要是发现了更靠谱的方法,dingding我一下。 (☆ω☆)