ISCC2024 Reverse部分题解

目录

Reverse1 迷失之门

Reverse2 CrypticConundrum

Reverse3 Badcode

Reverse4 DLLCode

Reverse5 Find_All

Reverse6 I_am_the_Mathematician

Reverse7 AI

Reverse1 迷失之门

该用哪吧钥匙开门呢?

1.用Exeinfo PE打开附件中的ez.exe文件,该文件是64位可执行文件,没有加壳

2.用IDA Pro(64-bit)打开,直接反编译附件里的主函数main() ,即F5 查看伪代码,在此进行分析:

(1)使用 gets_s 获取用户输入并存储在 Buffer 中

(2)Buffer的长度 <= 0x1B,v7设为1。遍历 Buffer 的第 5 到第 25 个字符,检查是否都是小写字母或者下划线,如果有任何一个字符不是小写字母且不等于下划线,则将 v7 设为 0。后面再将Buffer传给check()函数进行检查

(3)Buffer的长度 > 0x1B,暂停程序

4.将我们输入的值做了一系列的计算,最后又把输入的值通过return check_2(a1) 传给了check_2() 函数里面

继续跟进分析 check() 函数(N对符号重命名)

(1)预先设置好一些字符数组,包含大写字母、小写字母和符号。

(2)遍历输入字符串的每个字符 a1[i] ,如果字符不是 ASCII 127 且大于 ASCII 32 ,进行进一步处理

(3)计算其与预定义字符数组对应字符的差值,根据计算的差值,将输入字符串的字符替换为预定义字符数组中的字符。如果某个字符的差值不符合条件,输出错误信息

(4)将经过处理的字符串传递给 check_2() 函数进行进一步处理 

5.在check_2() 函数中发现flag,继续跟进分析 check_2() 函数(R将ASCII码转字符)

(1)逐字符验证输入字符串 a1 是否与预定义的字符串 "FSBBhKHKKdyXkDSJQPTJbpxgbH6" 完全匹配

(2)如果字符匹配,则继续比较下一个字符

(3)如果任何一个字符不匹配,则返回当前字符的 ASCII 值,函数结束 

6.实现解密过程,利用字符集和 key 生成加密过程中使用的映射,根据映射和 key 还原原始字符串。写出并执行解密脚本拿到flag  

def find_character_index(character, reference_string, base_offset):
    return reference_string.find(character) + base_offset if character in reference_string else -1
        
def decode_sequence(encoded_sequence, cipher_key):
    mapping = []
    # Add additional mapping characters as needed.
    alpha_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    alpha_lower = "abcdefghijklmnopqrstuvwxyz"
    special_char_mapping = "0123456789+/-=!#&*()?;:*^%"

    for character in encoded_sequence:
        char_idx = find_character_index(character, alpha_upper, 0)
        if char_idx == -1: 
            char_idx = find_character_index(character, alpha_lower, 26) # 4*6+2
        if char_idx == -1: 
            char_idx = find_character_index(character, special_char_mapping, 52) # 4*13
        
        if char_idx != -1:
            mapping.append(char_idx)
        else:
            print("Invalid character, stopping.")
            break

    return ''.join(chr(cipher_key[i] + offset) for i, offset in enumerate(mapping))

encoded_message = "FSBBhKHHKdyXkDSJQPTJbpxgbH6" 
cipher_key = [word for word in b"DABBZXQESVFRWNGTHYJUMKIOLPC"]

decoded_output = decode_sequence(encoded_message, cipher_key)
print(decoded_output)

Reverse2 CrypticConundrum

Do not get lost!

1.用Exeinfo PE打开附件中的Cryptic.exe文件,该文件是64位可执行文件,加了UPX壳

2.使用upx工具脱壳:Releases · upx/upx · GitHub

  1. 打开cmd命令行,cd+路径到达upx.exe所在目录

  2. 输入upx.exe或拖入upx.exe可以打开看指令

  3. 输入upx -d然后拖入待脱壳文件回车 

3.去壳成功,用IDA Pro(64-bit)打开,直接反编译附件里的主函数main(),即F5 查看伪代码,在此进行分析:

(1)在处理输入后,验证其是否与预定义的值匹配

(2)mix() 和 Encryption() 函数对输入进行转换

4.继续跟进分析 mix() 函数

(1)mix() 函数经过一系列复杂的操作混淆输入字符串 input

(2)操作包括字符的加减法、字符串反转、根据辅助字符串 Str 的奇偶性调整字符等,最终将原始输入字符串的副本返回

(3)mix() 并非关键函数

5.继续跟进分析 Encryption() 函数,Encryption() 函数对输入字符串 input 进行复杂的多步骤加密处理。具体步骤如下:

(1)调用 NewEncryption() 函数对字符串进行初步加密

(2)反转字符串

(3)每隔一个字符进行异或操作

(4)所有字符与 key[2] 进行异或操作

(5)从倒数第二个字符开始,每个字符减去下一个字符的值

(6)将每个字符加上10

通过这些步骤,输入字符串 input 经过一系列复杂的变换,使得原始字符串变得更加混淆和加密 

6.继续跟进分析 NewEncryption() 函数,NewEncryption() 函数对输入字符串 input 进行简单的加密处理,具体步骤如下:

(1)每个字符依次减去密钥字符串 key 中的字符值,密钥字符串 key 循环使用前四个字符

(2)反转输入字符串的前半部分和后半部分的字符位置

7.由以上分析可知,Encryption()函数为关键函数,通过动态调试寻找密文和key

动态调试中找到 v7 即 key:ISCC

 动态调试中找到密文:0xA4 ,0x7A ,0xDD ,0x37 ,0x20 ,0x2C ,0x7D ,0xCB ,0xAD ,0x5E ,0x50 ,0xCA ,0xE7 ,0x35 ,0x79 ,0xA4 ,0x2F ,0xC5 ,0x9F ,0x6D ,0x20 ,0x22 ,0x99 ,0x87 ,0xE0 ,0x34

 8.根据加密过程写出并执行解密脚本拿到flag

#include <stdio.h>
#include <string.h>

void Decrypt(char *enc, char *key, int len) {

    // 所有字符减去10
    for (int i = 0; i < len; ++i) { 
        enc[i] -= 10; 
    }   

    // 依次加上下一个字符的值
    for (int i = 0; i < len - 1; ++i) {
        enc[i] += enc[i + 1];
    }

    // 所有字符与 key[2] 进行异或操作
    for (int i = 0; i < len - 1; ++i) {
        enc[i] ^= key[2];
    }

    // 每隔一个字符进行异或操作
    for (int i = 0; i < len; i += 2) {
        enc[i] ^= key[i % 4];
    }

    // 反转字符串
    for (int i = 0; i < len / 2; ++i) {
        char temp = enc[i];
        enc[i] = enc[len - i - 1];
        enc[len - i - 1] = temp;
    }

    for (int i = 0; i < len / 2; ++i) {
        char temp = enc[i];
        enc[i] = enc[len - i - 1];
        enc[len - i - 1] = temp;
    }

    // 每个字符加上 key 的相应字符值
    for (int i = 0; i < len; ++i) {
        enc[i] += key[i % 4];
    }
}

int main() {
    char enc[] = {0xA4 ,0x7A ,0xDD ,0x37 ,0x20 ,0x2C ,0x7D ,0xCB ,0xAD ,0x5E ,0x50 ,0xCA ,0xE7 ,0x35 ,0x79 ,0xA4 ,0x2F ,0xC5 ,0x9F ,0x6D ,0x20 ,0x22 ,0x99 ,0x87 ,0xE0 ,0x34 };
    char key[] = "ISCC"; 
    int len = strlen(enc);

    // 解密
    Decrypt(enc, key, len);

    // 打印解密后的结果
    printf("Decrypted data: %s\n", enc);

    return 0;
}

Reverse3 Badcode

好学的小明又开始学习c++了,他猛猛写了一堆代码,并且很高兴实现了功能,但是我们发现,他的代码写的真的很差,这次他又将自己的秘密藏在里面,你能揭穿他的秘密吗?

1.用Exeinfo PE打开附件中的Badcode.exe文件,该文件是32位可执行文件,没有加壳

 2.用IDA Pro(32-bit)打开,直接反编译附件里的主函数main() ,即F5 查看伪代码,在此分析关键代码

3.sub_401B60() 这个函数是接受两个参数的,IDA只识别出来一个参数,重新定义该函数并反编译它

用U将函数名称设为无定义,选中下面所有数据内容,按C转换为代码,再用F5反编译

4.从unknown_libname_3(input) ==24和跟进分析unknown_libname_3() 函数可以得知unknown_libname_3() 函数用于获取字符串的长度

跟进分析sub_401B60() 函数、sub_401B40() 函数和下方Buf1的赋值可知sub_401B40() 和sub_401B60(k)函数用于获取内存地址

5.跟进分析sub_201620

使用固定的种子值 0x18u 初始化随机数生成器,生成 0 到 9 之间的固定随机数,并转换为 ASCII 字符 '0' 到 '9'。

6.此处:

(1)判断输入字符串是否长度为24

(2)循环遍历input中的每个字符

(3)对每个字符进行变换。如果索引 j 是偶数,字符的ASCII值加2;如果是奇数,字符的ASCII值减3

7.此处:

(1)遍历 input 中的每个字符

(2)将v16中字符的ASCII值减去 48 转换成对应的整数值,然后与input中的字符进行异或运算

(3)将异或结果存储回 input的相应位置中

8.继续跟进分析 sub_4014C0() 函数

通过观察我们可以发现这是标准的XXTEA加密,密钥为 &unk_407018:0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210(小端序)

参考对比XXTEA的算法实现:TEA XTEA XXTEA-CSDN博客

 密文:0x211D94C1 ,0xA4EBE805 ,0xAD8C722D ,0XC643DAD4 ,0XC5B19919 ,0X54B0B6B2

 9.根据加密过程写出并执行解密脚本拿到flag

#include <stdio.h>  
#include <stdint.h>  
#define DELTA 0x9e3779b9  
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  

void btea(uint32_t* v, int n, uint32_t const key[4])
{
	uint32_t y, z, sum;
	unsigned p, rounds, e;
	if (n > 1)            /* Coding Part */
	{
		rounds = 6 + 52 / n;
		sum = 0;
		z = v[n - 1];
		do
		{
			sum += DELTA;
			e = (sum >> 2) & 3;
			for (p = 0; p < n - 1; p++)
			{
				y = v[p + 1];
				z = v[p] += MX;
			}
			y = v[0];
			z = v[n - 1] += MX;
		}         while (--rounds);
	}
	else if (n < -1)      /* Decoding Part */
	{
		n = -n;
		rounds = 6 + 52 / n;
		sum = rounds * DELTA;
		y = v[0];
		do
		{
			e = (sum >> 2) & 3;
			for (p = n - 1; p > 0; p--)
			{
				z = v[p - 1];
				y = v[p] -= MX;
			}
			z = v[n - 1];
			y = v[0] -= MX;
			sum -= DELTA;
		}         while (--rounds);
	}
}
int main(){

	uint32_t Buf2[6]= {0x211D94C1 ,0xA4EBE805 ,0xAD8C722D ,0xC643DAD4 ,0xC5B19919 ,0x54B0B6B2};
	uint32_t key[] = { 0x12345678,0x9ABCDEF0,0x0FEDCBA98,0x76543210 };

	btea(Buf2, -6, key);
	unsigned char* p = (unsigned char*)Buf2;
	for (int i = 0; i < 24; i++)
	{
		printf("%u,", p[i]);  	//将输出的p填充到下方a中
	}

	unsigned char a[] = { 64,82,68,69,113,78,56,125,45,122,109,61,73,92,78,122,104,80,82,113,80,65,99,120 };
	char encbuf[] = "674094872038771148666737";
	for (int i = 0; i < 24; i++)
	{
		a[i]=(encbuf[i] - '0') ^ a[i];
	}
	for (int i = 0; i < 24; i++)
	{
		if (i % 2)
		{
			a[i] -= 2;
		}
		else {
			a[i] += 3;
		}
	}
	for(int i = 0; i < 24; i++)
	{
		printf("%c",a[i]);
	}
}

Reverse4 DLLCode

把鸡蛋放在同一个篮子里是一个错误的决定

解压附件拿到得到一个exe文件和一个dll文件

1.用Exeinfo PE打开附件中的BEIXUAN-6.exe文件,该文件是32位可执行文件,没有加壳

2.用IDA Pro(32-bit)打开,直接反编译附件里的主函数main() ,即F5 查看伪代码,在此分析关键代码:

(1)程序调用了Encode函数对明文进行操作,进到Encode()函数中,发现此处调用了外部的DLL动态库文件

3.IDA Pro(32-bit)打开附件里面的动态库文件BH_Dll.dll,反编译里面的Encode()函数,进行分析:

(1)检查a2[4]是否为 12,如果满足条件,对 a2的数据进行编码并存储在 a1中

(2)如果不满足条件,则直接在 a1中存储错误信息

(3)key为”ISCC“

4.回到main()函数中,经分析sub_4014D0() 进行了加密,在这个函数中:

(1)重新排序

(2)索引修改后为密文的后半部分

 5.获取密文v8:[0 ,16 ,56 ,44 ,10 ,61 ,118 ,43 ,27 ,0 ,20 ,3 ,67 ,99 ,83 ,89 ,70 ,84 ,64 ,103 ,116 ,125 ,117 ,64 ]

8.根据加密过程写出并执行解密脚本拿到flag

data = [0,16,56,21,10,61,113,43,11,0,20,3,67,89,83,89,70,84,64,103,116,125,117,98]
first_part, second_part = data[:12], data[12:]
reordering = [2, 0, 3, 1, 6, 4, 7, 5, 10, 8, 11, 9] 
s = [0] * 12
key = "ISCC"
for i in range(len(s)):
    s[i] = second_part[reordering[i]]

for i in range(len(first_part)):
    first_part[i] ^= ord(key[i % len(key)])
    
result = ""
for i in range(len(first_part)):
    result += chr(first_part[i]) + chr(s[i])
print(result)

Reverse5 Find_All

当你走出这片森林,未来的光明将是你的收获,路途的脚印亦是你的宝藏

1.用Exeinfo PE打开附件中的ez.exe文件,该文件是32位可执行文件,没有加壳

2.用IDA Pro(32-bit)打开,直接反编译附件里的主函数main() ,即F5 查看伪代码

进行简单分析可知,该题为迷宫问题,密文数据在sub_4015F0() 函数里面

 3.转到调用sub_4015F0() 函数的sub_401410() 函数,可以找到加密逻辑

 4.提取出密文,构造解密的脚本,用ida自带的python环境跑,如下所示即可拿到flag

v4 = [get_wide_byte(0x00401625+i*7) for i in range(24)]
for i in range(0,len(v4) - 1,4):
	v4[i + 2] ^= v4[i + 3]
	v4[i + 1] ^= v4[i + 2]
	v4[i] ^= v4[i + 1]
print(bytes(v4).decode())

Reverse6 I_am_the_Mathematician

The mathematician has a codebook.

Who is the mathematician and where is the true code?

1.用Exeinfo PE打开附件中的main.exe文件,该文件是32位可执行文件,没有加壳

2.用IDA Pro(32-bit)打开,直接反编译附件里的主函数main() ,即F5 查看伪代码

看到关键词:Fibonacci,题目似乎涉及斐波那契数列

 3.分析代码发现代码进行简单的逐个字符累计减少前面的数值,写出并执行脚本code_book_21.txt密文进行解密

def fib(n):
    a, b = 0, 1
    lis = []
    for _ in range(n):
        lis.append(a)
        a, b = b, a + b
    return lis

with open(r"./code_book_21.txt", "r") as file:
    data = file.read()
    file.close()

target = fib(20)
assert target[-1] > len(data)  
print(f"ISCC{{{''.join(data[i - 1] if i < len(data) else '' for i in target)}}}")

Reverse7 AI

小明刚刚学会深度学习,于是他信心满满制作了自己第一个人工智能模型,但是貌似训练出了一点问题。于是他很羞涩地将模型和按顺序读取的样本藏了起来。他认为你们永远发现不了,于是悄悄地又放了一个秘密在里面……(无需包裹ISCC{})

1.pyc文件是py文件编译后生成的字节码文件

使用pyc在线编译工具对附件中的pyc文件进行反编译得到源码 在线Python pyc文件编译与反编译

得到一个用于加密的Python脚本,将用户输入的长度为24的字符串 user_input 逐字符加密,然后与预期的 Base64 字符串进行比较。

简单阐述加密过程:

(1)遍历 user_input 的每个字符及其索引 i,根据索引 i 的奇偶性,调整当前字符的 ASCII 值ascii_val 如果 i 是偶数,则新 ASCII 值为 ascii_val + offset 如果 i 是奇数,则新 ASCII 值为 ascii_val - offset

(2)使用异或操作 (^) 对新的 ASCII 值进行加密,得到加密后的字符 encrypted_char。

(3)将加密后的字符添加到 encrypted 列表中。

 2.根据加密过程写出并执行解密脚本拿到key1

import base64

def decrypt(encrypted_base64, offset_str):
    encrypted_bytes = base64.b64decode(encrypted_base64)
    encrypted_str = encrypted_bytes.decode('utf-8')
    
    if len(encrypted_str) != 24:
        return 'Invalid encrypted string length'
    
    decrypted = []
    for i, char in enumerate(encrypted_str):
        offset = int(offset_str[i])
        new_ascii = ord(char) ^ offset
        if i % 2 == 0:
            original_ascii = new_ascii - offset
        else:
            original_ascii = new_ascii + offset
        decrypted_char = chr(original_ascii)
        decrypted.append(decrypted_char)
    
    return ''.join(decrypted)

offset_str = '123456789012345678901234'
encrypted_base64 = 'TWF/c1sse19GMW5gYVRoWWFrZ3lhd0B9'
decrypted_str = decrypt(encrypted_base64, offset_str)
print('Decrypted string: {}'.format(decrypted_str))

 3.解压压缩包需要密码,输入key1,输入Key{Y0u_F1nd_The_key_w@}进行解压

4.查看model_net.png,该图片展现了使用 PyTorch 定义并加载神经网络模型的代码,由获取的图片和名称可以得知该模型用于数字识别和分类

(1)定义了包含三层全连接层的网络结构 Net

(2)从confused_digit_recognition_model.pt加载预训练的模型权重

(3)定义了一系列图像预处理步骤:将图像转换为灰度图像,调整图像大小为 28x28,将图像转换为 PyTorch 张量,归一化图像数据,使其均值为 0.5,标准差为 0.5

 5.补全代码,识别图片得到key2

import torch
import os
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from PIL import Image

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(28*28, 128)
        self.fc2 = nn.Linear(128, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        x = x.view(-1, 28*28)  
        x = F.relu(self.fc1(x))  
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

model = torch.load('confused_digit_recognition_model.pt')
model.eval()

transform = transforms.Compose([
    transforms.Grayscale(num_output_channels=1),
    transforms.Resize((28, 28)),
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

def process_image(image_path):
    try:
        image = Image.open(image_path)  # 打开图像文件
        image = transform(image)  # 应用预处理管道
        image = image.unsqueeze(0)  # 增加一个批次维度,因为模型期望输入是 [batch_size, channels, height, width]
        return image
    except Exception as e:
        print(f"Error processing image {image_path}: {e}")
        return None

def predict(image, model):
    output = model(image)  
    _, predicted = torch.max(output, 1) 
    return predicted.item()  

def predict_images_in_folder(folder_path, model):
    results = {}
    for i in range(1, 25):
        image_path = os.path.join(folder_path, f"{i}.png")
        image = process_image(image_path)
        if image is not None:
            predicted_class = predict(image, model)
            results[image_path] = predicted_class
        else:
            results[image_path] = 'Error processing image'
    return results

folder_path = r'D:\\A________________iscc\\myISCC\\题目\\reverse\\AI\\AI\\PNG'

predictions = predict_images_in_folder(folder_path, model)
for image_name, prediction in predictions.items():
    print(prediction,end='')

 6.用密码key2解压压缩包对照表.7z,拿到对照表

 7.依据对照表写出并执行脚本拿到flag

str='538863262298483714602759'
arry={'0':'@nd','1':'a!','2':'_', '3':'F', '4':'SSS','5':'W@','6':'K','7':'1','8':'C','9':'d'}
for i in str:
    print(arry[i],end='')

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值