天天看點

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

這個題目之前比賽寫的時候就是一臉懵。比賽之後看了大神們的wp才知道還是我太弱了,學習的太少了。

1.查殼

下載下傳附件後先查殼。

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

發現帶有upx殼,我麼先脫殼。

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

2.将python打包的exe檔案轉化為pyc檔案

通過觀察檔案圖示可以發現,這個檔案是使用python打包的一個exe檔案我們需要使用

pyinstxtractor.py

将python打包的.exe檔案還原成.py檔案

python pyinstxtractor.py notsudoku.exe 
 //注意:要将被還原檔案和 pyinstxtractor.py放在同一檔案夾下哦!
           
[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

轉化出來後會得到一個

notsudoku.exe_extracted

檔案夾

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

紅圈标出的就是等下要還原的檔案。

3.将檔案還原成可閱讀的.py檔案

使用

010editor

打開上圖紅圈标記的檔案

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

notsudoku.exe_extracted

檔案夾找到

struct

檔案也用

010editor

打開

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析
[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

建立一頁:複制上圖紅圈裡的内容到建立的頁面中。再将

2

檔案的所有内容複制到建立的頁面中 ,儲存并命名為

xxx.pyc

檔案

3.2 使用uncompyle6對.pyc檔案進行反編譯。

使用這條指令

uncompyle6.exe 111.pyc > 111.py
           
[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

這樣就得到了可以直接閱讀的.py 檔案。

4.代碼分析

通過分析代碼可以看出,這個題其實就是一個五階幻方。

import time, sys, hashlib

class あ:

    def __init__(self):
        self.う = {}
        self.な = []
        self.に = ''
        self.ぬ = []
        self.ね = 65

    def え(self, えひ):

        def の(f):
            self.う[えひ] = f
            return f

        return の

    def お(self, は):
        return self.う.get(は)

    def か(self):
        き = 0
        while True:
            く = self.な[き][0]
            け = self.な[き][1]
            こ = self.な[き][2]
            さ = self.お(く)
            さ(け, こ)
            き += 1


い = あ()

@い.え('し')
def f(a, b):
    if a == 1:
        い.ぬ += b


@い.え('す')
def f(a, b):
    if a == 1:
        print(い.に)
    else:
        if a == 2:
            print(い.ぬ)
        else:
            if a == 3:
                print((い.flag), end='')
            else:
                print(a, end='')


@い.え('せ')
def f(a, b):
    sys.exit()


@い.え('そ')
def f(a, b):
    い.に = input()  #輸入flag


@い.え('た')
def f(a, b):
    time.sleep(a)


@い.え('ち')
def f(a, b):
    if len(い.に) % 2 != 0:
        sys.exit()
    for i in い.に:
        if ord(i) > 52 or ord(i) < 48:
            sys.exit()

    x = str(hashlib.new('md5', bytes((い.に), encoding='utf8')).hexdigest())#對輸入的flag進行MD5操作
    if x[:6] != 'e3a912':   #對MD5後的flag前六位進行判斷,判斷是否為正确的flag
        sys.exit()
    い.flag = x


@い.え('と')
def f(a, b):               #對五階幻方進行指派,從1開始指派到25結束
    ふ = 0
    for i in range(0, len(い.に), 2):#這裡也可以看出輸入的flag其實就是坐标,變量a是橫坐标,變量b是縱坐标。flag每兩位是一組
        ふ += 1                      
        a = int(い.に[i])
        b = int(い.に[(i + 1)])
        い.ぬ[a][b] = ふ


@い.え('つ')
def f(a, b):                #對指派了的五階幻方進行判斷。判斷是否為正确的五階幻方。其實,這裡也就是給出了五階幻方中的幾個值友善之後逆向破解。
    if い.ぬ[0][1] != 24 or い.ぬ[4][3] != 2:
        sys.exit()
    if い.ぬ[0][2] != 1 or い.ぬ[2][3] != 20:
        sys.exit()
    if い.ぬ[1][0] != 23 or い.ぬ[3][4] != 3:
        sys.exit()


@い.え('て')
def f(a, b):
    ね = 0
    if b == -1:
        for i in range(5):
            ね += い.ぬ[a][i]

        if ね != い.ね:
            sys.exit()
    else:
        for i in range(5):
            ね += い.ぬ[i][b]

        if ね != い.ね:
            sys.exit()


い.な = [
 [
  'す', 'welcome baby~ ', 0],
 [
  'す', 'input your flag~:', 0],
 [
  'そ', 0, 0],
 [
  'す', 'your input is:', 0],
 [
  'す', 1, 0],
 [
  'す', "let's check......", 0],
 [
  'た', 0.5, 0],
 [
  'し', 1, [[0 for i in range(5)]]],
 [
  'し', 1, [[0 for i in range(5)]]],
 [
  'し', 1, [[0 for i in range(5)]]],
 [
  'し', 1, [[0 for i in range(5)]]],
 [
  'し', 1, [[0 for i in range(5)]]],
 [
  'ち', 0, 0],
 [
  'と', 0, 0],
 [
  'つ', 0, 0],
 [
  'て', 0, -1],
 [
  'て', 1, -1],
 [
  'て', 2, -1],
 [
  'て', 3, -1],
 [
  'て', 4, -1],
 [
  'て', 0, 0],
 [
  'て', 0, 1],
 [
  'て', 0, 2],
 [
  'て', 0, 3],
 [
  'て', 0, 4],
 [
  'す', 'Goodjob!', 0],
 [
  'す', 'The flag is vnctf{', 0],
 [
  'す', 3, 0],
 [
  'す', '}', 0],
 [
  'せ', 0, 0]]
い.か()
           

解出來的五階幻方是這樣子的

[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

附上解密腳本:

#include<cstdio>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
int main()
{
	int a[100][100];
	for (int i = 0; i <= 4; i++)
	{
		for (int j = 0; j <= 4; j++)
		{
			cin >> a[i][j];
		}
	}
	int k = 1;
	while (k <= 25) 
	{
		for (int i = 0; i <= 4; i++)
		{
			for (int j = 0; j <= 4; j++)
			{
				if (a[i][j] == k)
				{
					cout << i << j;
					k++;
				}

			}
		}
	}
	return 0;
	system("pause");
}
//這裡的數字需要自己輸入哦我比較懶就沒有直接給數組初始化了
//嘻嘻,其實我就是菜忘記怎麼二維數組初始化了,有會的大佬歡迎在評論區教我!!
           
[VNCTF 2021] notsudoku wp1.查殼2.将python打包的exe檔案轉化為pyc檔案3.将檔案還原成可閱讀的.py檔案4.代碼分析

将輸出的數字MD5就得到了flag:

e3a912c1e911ad82544af0c3d753f44f

最終就是

vnctf{e3a912c1e911ad82544af0c3d753f44f}