当前位置: 首页 > news >正文

2024年网鼎杯青龙组逆向2题wp

把附件拖入ida

shift+F12查看可疑字符串 这里很明显看到了AES加密,还有一个base64编码表。猜测解密方式和AES加密,base64编码有关

进入主函数查看 F5反编译查看伪c代码

这里我们一点一点搓代码

1.除二解密

  1. 提示用户输入标志。
  2. 检查用户输入的长度是否为 40,以及是否以 "wdflag{" 开头且第 32 个字符为 '}'。
  3. v20 的前 32 个字符复制到 dest
  4. dest 中的前 8 个元素乘以 2 并存储到 s1 中。

这里的加密过程很简单,将s2数组的前八位数字都乘以2。逆向解密过程只要将s2数组的前八位都除2就得到了flag的前八位了。

解密脚本

# 定义给定的十进制数列表
decimal_numbers = [96, 98, 110, 96, 196, 102, 114, 198]# 除以2并将结果转换为对应的字符
characters = [chr(num // 2) for num in decimal_numbers]# 打印结果
print(characters)

并且得到前八位

2.异或加密

  • 定义了一个字符串 v22,赋值为 "XorrLord"。
  • v11 数组的索引位置 2 到 5 分别赋值为 22, 64, 120, 12。
  • 通过循环,计算 dest 数组中索引从 8 到 15 的元素与 v22 字符串对应位置的元素的异或结果,保存到数组 v13 中。

这里有个点,数组的值给的不全,是ida编译时可能出了点问题,这里我们只需要按tab键进入流程窗口,查看数组的值即可

加密的过程就是将V11数组的值与XorrLord进行异或,解密的过程就是逆向一下就好啦。

解密脚本

# 给定的十进制数列表
nums1 = [109, 10, 22, 64, 120, 12, 68, 87]
# 另一个十进制数列表
nums2 = [88, 111, 114, 114, 76, 111, 114, 100]# 进行逐个异或运算
result = [num1 ^ num2 for num1, num2 in zip(nums1, nums2)]# 将异或结果转换为字符
char_result = [chr(num) for num in result]print("异或结果(字符):", ''.join(char_result))

得到flag的第八位到第十五位

3.变种的base64解密

进入base64_encode函数

_BYTE *__fastcall base64_encode(__int64 a1, unsigned __int64 a2, __int64 a3)
{int v3; // eaxint v4; // eaxint v5; // eaxint v6; // eaxint v7; // eaxint v8; // eax_BYTE *result; // raxunsigned __int64 v10; // [rsp+8h] [rbp-30h]unsigned int v11; // [rsp+20h] [rbp-18h]int v12; // [rsp+28h] [rbp-10h]int v13; // [rsp+2Ch] [rbp-Ch]int v14; // [rsp+30h] [rbp-8h]int v15; // [rsp+34h] [rbp-4h]v10 = a2;v15 = 0;v14 = 0;while ( v15 < a2 ){v3 = v15++;v13 = *(unsigned __int8 *)(v3 + a1);if ( v15 >= a2 ){v5 = 0;}else{v4 = v15++;v5 = *(unsigned __int8 *)(v4 + a1);}v12 = v5;if ( v15 >= a2 ){v7 = 0;}else{v6 = v15++;v7 = *(unsigned __int8 *)(v6 + a1);}v11 = (v12 << 8) + (v13 << 16) + v7;*(_BYTE *)(a3 + v14) = base64_table[(v11 >> 18) & 0x3F];*(_BYTE *)(a3 + v14 + 1) = base64_table[(v11 >> 12) & 0x3F];*(_BYTE *)(a3 + v14 + 2) = base64_table[(v11 >> 6) & 0x3F];v8 = v14 + 3;v14 += 4;*(_BYTE *)(a3 + v8) = base64_table[v11 & 0x3F];}while ( v10 % 3 ){*(_BYTE *)(--v14 + a3) = 61;++v10;}result = (_BYTE *)(v14 + a3);*result = 0;return result;
}

解密过程就是对字符串BYOzAjWyAVA进行变种的base64解密,新的base64编码表是DEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/

但是这里有个小坑,新的base64编码表少了个C。我们手动给它加上去就好了,所以真正的编码表是CDEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/

解密脚本

import base64# 自定义Base64编码表
base64_chars = 'CDEFGHIJKLMNOPQRSTUVWXYZABabcdefghijklmnopqrstuvwxyz0123456789+/'# 待解码的Base64编码字符串
encoded_str = 'BYOzAjWyAVA'# 添加正确的填充字符 "=",使长度变为4的倍数
while len(encoded_str) % 4 != 0:encoded_str += '='# 使用自定义编码表解码
decoded_bytes = base64.b64decode(encoded_str.translate(str.maketrans(base64_chars, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')))# 解码成字符串
decoded_text = decoded_bytes.decode('utf-8')print("Decoded string:", decoded_text)

flag的第三个八位也得到了

4.AES加密

简单介绍一下AES算法

AES(Advanced Encryption Standard)是一种对称加密算法,广泛用于加密和解密数据。AES算法有三种密钥长度:128位、192位和256位。它将明文(plaintext)转换为密文(ciphertext),并将密文转换回明文。

AES的基本步骤包括:

  1. SubBytes(字节替代):将每个字节替换为S盒中对应的值。
  2. ShiftRows(行移位):对每一行进行循环移位操作。
  3. MixColumns(列混淆):对每一列进行固定的矩阵乘法。
  4. AddRoundKey(轮密钥加):将轮密钥与状态矩阵进行按位异或操作。

这些步骤在加密和解密过程中稍有不同,但遵循类似的原理。

AES加密流程:

  1. 密钥扩展:生成轮密钥。
  2. 初始轮密钥加:将明文与初始轮密钥进行异或操作。
  3. 多轮加密:重复固定数量的轮次,每轮包括SubBytes、ShiftRows、MixColumns和AddRoundKey操作。
  4. 最终轮:省略MixColumns,仅执行SubBytes、ShiftRows和AddRoundKey操作。
  5. 输出密文:最后一轮操作后得到的密文即为加密结果。

AES解密流程:

  1. 密钥扩展:生成轮密钥。
  2. 初始轮密钥加:将密文与最后一轮轮密钥进行异或操作。
  3. 多轮解密:逆序执行每轮的逆操作。
  4. 最终轮:省略MixColumns,仅执行逆SubBytes、逆ShiftRows和AddRoundKey操作。
  5. 输出明文:最后一轮操作后得到的明文即为解密结果。

这里的AES加密的密钥是AesMasterAesMast,明文是V4数组。

解密过程是将字符串密钥 "AesMasterAesMast" 编码为字节序列,作为AES解密所需的密钥。然后使用 ECB 模式初始化了一个AES解密器。最后使用 Cryptodome.Util.Padding 模块中的 unpad 函数去除填充,将解密后的数据恢复到原始状态。

解密脚本

from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import unpad# 提供的数据 v4
v4 = bytes([0xF6, 0xAB, 0x47, 0xBE, 0x71, 0xE4, 0x01, 0xDC, 0x03, 0x30, 0x9F, 0xF1, 0x43, 0xF1, 0xD3, 0x66])# 使用"AesMasterAesMast"作为密钥
key = "AesMasterAesMast".encode()# 初始化AES解密器
cipher = AES.new(key, AES.MODE_ECB)# 解密数据
decrypted_data = cipher.decrypt(v4)# 去除填充
unpadded_data = unpad(decrypted_data, AES.block_size)# 输出解密后的数据
print("Decrypted data:", unpadded_data)

得到flag的最后部分

5.总结

将上面的四个部分拼接一下就得到flag了

wdflag{0170b39c5ed24c63ec3b52a6724ba7d5}

由于我写脚本能力的不熟练,所以只能将代码拆开一部分一部分的解密。但凡加密过程复杂点,我写脚本能耗好久。这次比赛的逆向题更是深有体会,只能努力提升自己写脚本的能力。


http://www.mrgr.cn/news/62941.html

相关文章:

  • 【AI日记】24.10.31 学习LangChain和寻找AI研究报告(比如麦肯锡)
  • python99乘法表和判断版本号大小
  • Efficient Adaptive Matching for Real-Time City Express Delivery
  • 代码随想录day15 二叉树(3)
  • PFC前端电路 -- EMI电路
  • 字符串处理
  • 量化交易backtrader实践(三)_指标与策略篇(6)_股票软件指标参考A
  • C++集合运算函数总结-
  • DCS系统
  • LVGL盒子模型的概念
  • 五、鸿蒙开发-组件状态管理
  • OpenCSG携手书生·浦语:InternLM2.5-20B-Chat 正式上线,共建AI未来新生态
  • 哪里能找到海量短视频素材和制作教程?
  • 高效记录编程笔记
  • Spring IOC
  • 使用UDP实现发送和接收
  • 数据结构,问题 C: 后缀表达式
  • 《别了,浔川社团官方;你好,浔川社团官方联合会》
  • 很抽象但是好用的方法打败Vue框架第一天-Vue项目构建原神前端界面(Vue+js+html+css+jquery)
  • 搭建WIN32的开发环境
  • 高并发设计模式之ForkJoin模式
  • 客户的奇葩要求—在CAN网络的基础上加入了CAN_FD的节点
  • Redis(持续更新ing。。。)
  • 贪心算法习题其二【力扣】【算法学习day.18】
  • Rust 力扣 - 1343. 大小为 K 且平均值大于等于阈值的子数组数目
  • 博图V19的DB块,批量导入组态王