2024年5月

longlongcall

首先挂在linux下,IDA远程调试运行,发现Hack,退出了,搜字符串,找到后找x-ref
2024-05-30T11:25:11.png
发现有两处,如下两张图,分别把这两处的上一层函数跳转改成强制的(不走hacker,过反调试)
2024-05-30T11:25:21.png
2024-05-30T11:25:31.png

然后重新打开运行发现就正常了,然后跟着走,来到了scanf("%44s", xx),意味着flag长度是44,接着走,发现他两个两个读取你输入的flag,然后加起来的值再分别和他俩进行异或以加密flag,最后再对flag进行对比,拿到里面加密后的flag后,可以通过暴力枚举来写出exp

ans = bytes.fromhex("BBBFB9BEC3CCCEDC9E8F9D9BA78CD795B0ADBDB488AF92D0CFA1A392B7B4C99E94A7AEF0A199C0E3B4B4BFE3")

def decrypt(a, b):
    for i in range(0, 256):
        for j in range(0, 256):
            if a == (i+j)^i and b == (i+j)^j:
                return (i, j)

for i in range(0, len(ans), 2):
    b1, b2 = decrypt(ans[i],ans[i+1])
    print(chr(b1)+chr(b2),end='')
# miniLCTF{just_s1mple_x0r_1n_lon9_l0ng_c@ll!}

补一个之后用z3写的wp

from z3 import *
ans = bytes.fromhex("BBBFB9BEC3CCCEDC9E8F9D9BA78CD795B0ADBDB488AF92D0CFA1A392B7B4C99E94A7AEF0A199C0E3B4B4BFE3")

sol = Solver()

v = [BitVec(f"v{i}", 8) for i in range(44)]
for i in range(0, 44, 2):
    p = (v[i] + v[i+1])
    v[i] = v[i] ^ p
    v[i+1] = v[i+1] ^ p

for i in range(44):
    sol.add(v[i] == ans[i])

print(sol.check())

m = sol.model()
result = [0] * 44

for p in m.decls():
    # print(chr(m[v[i]].as_long()),end='')
    result[int((p.name()[1:]))] = m[p].as_long()

print(list(map(chr, result)))
print("".join(map(chr, result)))

Bigbanana

从switch表中找到,F2 00 00 00这个后面跟着的,
2024-05-30T11:26:35.png
稍微整理一下
2024-05-30T11:26:45.png
再稍微分析一下

F4, 01 立即数加法
F3 两个异或
F2 checkAnswer 后面跟着应该的结果
FE 看是否播放banana
F0 好像是把上一次结果保存
10 getchar并推上栈

F8 push 栈[0]字符
F7 push 栈[1]字符


10 00 00 00 10 00 00 00 F8 00 00 00 F7 00 00 00
F4 00 00 00 4D 69 4E 69  栈[1]字符 ('m')
01 00 00 00 4C 2D 63 74  栈[0]字符 ('i')
F4 00 00 00 00 00 00 00
F3 00 00 00 栈上xor   000000001D2D440F

F2 00 00 00 0F 44 2D 1D  check Answer
FE 00 00 00 66 00 00 00 banana

F0 00 00 00   ' 拿 栈[0]字符 ('i') + 结果 74632DB5

这里f8是74632DB5
10 00 00 00 F8 00 00 00 F4 00 00 00 16 00 00 00
01 00 00 00 21 00 00 00  ' 结果 000000000000008F


F4 00 00 00 14 45 11 00

F3 00 00 00
F2 00 00 00 50 72 74 74 FE 00 00 00
...

exp

flag = "mi"

f4List = [0x16,0x00114514,   
0x21,0x00228A28,   
0x2C,0x0033CF3C,   
0x0B,0x00451450,   
0x16,0x00565964,   
0x21,0x00679E78,   
0x2C,0x0078E38C,   
0x0B,0x008A28A0,   
0x16,0x009B6DB4,   
0x21,0x00ACB2C8,   
0x2C,0x00BDF7DC,   
0x0B,0x00CF3CF0,   
0x16,0x00E08204,   
0x21,0x00F1C718,   
0x2C,0x01030C2C,   
0x0B,0x01145140,   
0x16,0x01259654,   
0x21,0x0136DB68,   
0x2C,0x0148207C,   
0x0B,0x01596590,   
0x16,0x016AAAA4,   
0x21,0x017BEFB8,   
0x2C,0x018D34CC,   
0x0B,0x019E79E0,   
0x16,0x01AFBEF4,   
0x21,0x01C10408,   
0x2C,0x01D2491C,   
0x0B,0x01E38E30,   
0x16,0x01F4D344,   
0x21,0x02061858,   
0x2C,0x02175D6C,   
0x0B,0x0228A280,   
0x16,0x0239E794,   
0x21,0x024B2CA8,   
0x2C,0x025C71BC,   
0x0B,0x026DB6D0,   
0x16,0x027EFBE4,   
0x21,0x029040F8,   
0x2C,0x02A1860C,   
0x0B,0x02B2CB20,   
0x16,0x02C41034,   
0x21,0x02D55548,   
0x2C,0x02E69A5C]

f01List = [0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B]

ans = [0x74747250,0x00228A4D,0x0033CFAA,0x004514CB,0x00565966,0x00679FBC,0x0078E4CC,0x008A2949,0x009B6EC8,0x00ACB3E0,0x00BDF8F6,0x00CF3D22,0x00E082EB,0x00F1C745,0x01030C9C,0x0114518E,0x01259634,0x0136DC9C,0x0148217D,0x015965AE,0x016AABB8,0x017BF02F,0x018D352A,0x019E7AE7,0x01AFBF19,0x01C1043C,0x01D249A4,0x01E38E3E,0x01F4D3B0,0x02061853,0x02175E76,0x0228A241,0x0239E866,0x024B2D81,0x025C72F0,0x026DB738,0x027EFCFC,0x029041F1,0x02A186E7,0x02B2CBE3,0x02C4105D,0x02D55595,0x02E69A7B]

# 第一轮(因为读取了两个字符所以不好处理,直接拿第一轮结果)
ll = 0x74632DB5
for i in range(43):
        succeed = False
        for c in range(0,256):
                aa = c
                temp_ll = ll + f4List[i*2] + f4List[i*2+1]
                aa += f01List[i]
                if aa ^ temp_ll == ans[i]:
                        ll = aa
                        flag += chr(c)
                        print(i,flag)
                        succeed  = True
                        break
        if not succeed:
                print("err",i)
                
                
        
'''
0 min
1 mini
2 miniL
3 miniLc
4 miniLct
5 miniLctf
6 miniLctf{
7 miniLctf{b
8 miniLctf{bi
9 miniLctf{big
10 miniLctf{bigb
11 miniLctf{bigb4
12 miniLctf{bigb4n
13 miniLctf{bigb4na
14 miniLctf{bigb4nan
15 miniLctf{bigb4nan4
16 miniLctf{bigb4nan4_
17 miniLctf{bigb4nan4_i
18 miniLctf{bigb4nan4_i5
19 miniLctf{bigb4nan4_i5_
20 miniLctf{bigb4nan4_i5_v
21 miniLctf{bigb4nan4_i5_v3
22 miniLctf{bigb4nan4_i5_v3r
23 miniLctf{bigb4nan4_i5_v3ry
24 miniLctf{bigb4nan4_i5_v3ry_
25 miniLctf{bigb4nan4_i5_v3ry_i
26 miniLctf{bigb4nan4_i5_v3ry_in
27 miniLctf{bigb4nan4_i5_v3ry_int
28 miniLctf{bigb4nan4_i5_v3ry_int3
29 miniLctf{bigb4nan4_i5_v3ry_int3r
30 miniLctf{bigb4nan4_i5_v3ry_int3r5
31 miniLctf{bigb4nan4_i5_v3ry_int3r5t
32 miniLctf{bigb4nan4_i5_v3ry_int3r5t1
33 miniLctf{bigb4nan4_i5_v3ry_int3r5t1n
34 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng
35 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_
36 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r
37 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1
38 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1g
39 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1gh
40 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1ght
41 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1ght?
42 miniLctf{bigb4nan4_i5_v3ry_int3r5t1ng_r1ght?}

补一个之后用z3写的exp

from z3 import *
flag = "mi"


f4List = [0x16,0x00114514,   
0x21,0x00228A28,   
0x2C,0x0033CF3C,   
0x0B,0x00451450,   
0x16,0x00565964,   
0x21,0x00679E78,   
0x2C,0x0078E38C,   
0x0B,0x008A28A0,   
0x16,0x009B6DB4,   
0x21,0x00ACB2C8,   
0x2C,0x00BDF7DC,   
0x0B,0x00CF3CF0,   
0x16,0x00E08204,   
0x21,0x00F1C718,   
0x2C,0x01030C2C,   
0x0B,0x01145140,   
0x16,0x01259654,   
0x21,0x0136DB68,   
0x2C,0x0148207C,   
0x0B,0x01596590,   
0x16,0x016AAAA4,   
0x21,0x017BEFB8,   
0x2C,0x018D34CC,   
0x0B,0x019E79E0,   
0x16,0x01AFBEF4,   
0x21,0x01C10408,   
0x2C,0x01D2491C,   
0x0B,0x01E38E30,   
0x16,0x01F4D344,   
0x21,0x02061858,   
0x2C,0x02175D6C,   
0x0B,0x0228A280,   
0x16,0x0239E794,   
0x21,0x024B2CA8,   
0x2C,0x025C71BC,   
0x0B,0x026DB6D0,   
0x16,0x027EFBE4,   
0x21,0x029040F8,   
0x2C,0x02A1860C,   
0x0B,0x02B2CB20,   
0x16,0x02C41034,   
0x21,0x02D55548,   
0x2C,0x02E69A5C]

f01List = [0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B,0x16,0x21,0x2C,0x0B]

ans = [0x74747250,0x00228A4D,0x0033CFAA,0x004514CB,0x00565966,0x00679FBC,0x0078E4CC,0x008A2949,0x009B6EC8,0x00ACB3E0,0x00BDF8F6,0x00CF3D22,0x00E082EB,0x00F1C745,0x01030C9C,0x0114518E,0x01259634,0x0136DC9C,0x0148217D,0x015965AE,0x016AABB8,0x017BF02F,0x018D352A,0x019E7AE7,0x01AFBF19,0x01C1043C,0x01D249A4,0x01E38E3E,0x01F4D3B0,0x02061853,0x02175E76,0x0228A241,0x0239E866,0x024B2D81,0x025C72F0,0x026DB738,0x027EFCFC,0x029041F1,0x02A186E7,0x02B2CBE3,0x02C4105D,0x02D55595,0x02E69A7B]

# 第一轮(因为读取了两个字符所以不好处理,直接拿第一轮结果)


s = Solver()

x = [BitVec(f"x{i}", 8) for i in range(43)]
ll = 0x74632DB5
for i in range(43):
        succeed = False
        aa = x[i]
        temp_ll = ll + f4List[i*2] + f4List[i*2+1]
        aa += f01List[i]
        s.add(aa ^ temp_ll == ans[i])
        ll = aa
        s.add(x[i] < 0x7f)
        s.add(x[i] > 0x20)

print(s.check())
m = s.model()

result = [0] * 43
for p in m:    
    result[int(p.name()[1:])] = m[p].as_long()

print("".join(map(chr, result)))

RustedRobot

首先拿到app,把libmyrust.so分离出来,拖入IDA64进行分析(我还用了IDARust Demangler插件来辅助我进行分析)。
首先花了一下午给Xiaomi13刷了KernelSU,学了个Frida,如下是Hook的Frida脚本,有时候正常hook,有时候hook不上(目前不知道什么原因)

function main(){
    Java.perform(function() {
    var CryptoClass = Java.use("com.doctor3.androidrusttest.CryptoClass");
        console.log("Hooked CryptoClass\n");
    CryptoClass.encrypt.overload('[Ljava.lang.String;').implementation = function(strArr) {
        var str = strArr[0];
        var str2 = strArr[1];
        console.log("Encrypt method called with parameters: " + str + ", " + str2 + "\n");
        // 调用原始方法
        this.encrypt(strArr);
    };
});
}
setImmediate(main);

随后IDA里面分析so,发现它创建了一个数组(长度2), 也就是对应Java代码里面的函数参数,然后在函数末尾进行了Java static method invoke。

    public static void encrypt(String[] strArr) {
        int i = 0;
        String str = strArr[0];
        String str2 = strArr[1];
        byte[] bArr = {49, -93, 51, -59, 24, -5, -59, 60, -45, -32, -55, -54, -89, 67, 42, -94, 47, 110, 72, 13, 31, 55, 55, 34, 127, 65, -120, 13, -109, -92, -71, -97};
        byte[] bytes = str.getBytes();
        byte[] bytes2 = str2.getBytes();
        SecretKeySpec secretKeySpec = new SecretKeySpec(bytes, AES);
        try {
            Cipher cipher = Cipher.getInstance(AES);
            cipher.init(1, secretKeySpec);
            byte[] doFinal = cipher.doFinal(bytes2);
            while (i < 32) {
                i = (bArr[i] == doFinal[i] && doFinal.length == 32) ? i + 1 : 0;
                Toast.makeText(context, "Wrong", 1).show();
                return;
            }
            Toast.makeText(context, "Right", 1).show();
        } catch (Exception e) {
            Toast.makeText(context, "Wrong", 1).show();
            e.printStackTrace();
        }
    }

然后,使用Frida进行Hook,我们得知,第一个元素恒为定值,而第二个元素随着输入而改变(我不断更改miniLCTF{xxx}中的值,发现当miniLCTF{3}的时候,第二个字符是2,而且继续更改也之影响第二个字符,我就猜想这个字符很可能被反转了)。随后在CyberChef,先解密掉bArr,获取被混淆后的真正flag,我们得到

Encrypt method called with parameters: btdfA2jeeljf.1bp, ~2|GUDMjojn
flag,但是混淆后
~u1c1s`E4UTVS|GUDMjojn

随后就进行字符串反转,而后减一得到flag
于是我们可以得到exp:
https://gchq.github.io/CyberChef/#recipe=AES_Decrypt(%7B'option':'UTF8','string':'btdfA2jeeljf.1bp'%7D,%7B'option':'Hex','string':''%7D,'ECB/NoPadding','Hex','Raw',%7B'option':'Hex','string':''%7D,%7B'option':'Hex','string':''%7D)Remove_whitespace(true,true,true,true,true,false)Reverse('Character')ADD(%7B'option':'Decimal','string':'-1'%7D)&input=MzEgYTMgMzMgYzUgMTggZmIgYzUgM2MgZDMgZTAgYzkgY2EgYTcgNDMgMmEgYTIgMmYgNmUgNDggMGQgMWYgMzcgMzcgMjIgN2YgNDEgODggMGQgOTMgYTQgYjkgOWY&oeol=NEL

OLLessVM

00007FF6C5E8A4 | 8D041F            | lea eax,qword ptr ds:[rdi+rbx]                                |
00007FF6C5E8A4 | 48:63D3           | movsxd rdx,ebx                                                |
00007FF6C5E8A4 | 48:63C8           | movsxd rcx,eax                                                |
00007FF6C5E8A4 | 8A440D F7         | mov al,byte ptr ss:[rbp+rcx-9]                                |
00007FF6C5E8A4 | 320432            | xor al,byte ptr ds:[rdx+rsi]                                  |
00007FF6C5E8A4 | 32C3              | xor al,bl                                                     |
00007FF6C5E8A4 | 42:880432         | mov byte ptr ds:[rdx+r14],al                                  |

x64dbg打开,找到,输入一个东西下硬件断点找到关键点,拿到xor表,main函数的ans表和bl(counter)即可写出wp:

xort = bytes.fromhex("9199417B79814BCBA9EC2E02CB94E526910BA60F2881A160D1525FC47AAD4FFFE299D57A286EC037F570E6460707A2F54B393A97328EB0E7BBE8C7D2B7087B628ED06FBF369F0000A0F4A55946024602")


ans = bytes.fromhex("FCF12D1131C7198ADABC147C98EADB65F729D04348FC8428F92923AC59CD51E0C2B8F7590C4BE610DD59CC6D2B2A8CDA7B0808A406BB86D083D1FDE98B35455D514CD172F6B8E69EE2B72D7525712B4B864587A1C947C55A165E1AD1179D186E3FD275E9E35156C206046D1A50657DFDA912")

for i in range(len(ans)):
    print(chr(i^xort[i]^ans[i]),end='')
# miniLCTF{Y0u_s0Lv3d_th3_0bfs?}

OLLessVM_RENVEGE

发现使用ReadConsoleW来读取控制台

BOOL WINAPI ReadConsole(__in HANDLE hConsoleInput,__out LPVOID lpBuffer,__in DWORD nNumberOfCharsToRead,__out LPDWORD lpNumberOfCharsRead,__in_opt LPVOID pInputControl);
#include <iostream>
#include <vector>
#include <Windows.h>

uint8_t x0r[16] = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80 };
int main()
{
        const char* f = "miniLCTF{1141414141414111111111}";
        char* flag = (char*)malloc(33);
        memcpy_s(flag, 33, f, strlen(f));
        if (!flag)
        {
                return -1;
        }

        for (size_t i = 0; i < 32; i++)
        {
                flag[i] ^= x0r[i % 16];
        }

        auto inn = (DWORD*)flag;
        auto xnn = (DWORD*)x0r;
        
        std::cout << std::hex;
        DWORD offset = 0xEEB7B2B6;
        DWORD keyOffset = 0xBADECADA;
        DWORD sum = 0x2EB7B2B6;
        uint32_t key = 0xBADECADA;
        for (int k = 0; k < 12; k++)
        {
                for (int i = 0; i < 8; i++)
                {
                        DWORD e1 = ((inn[(7 + i) % 8] >> 5) ^ (inn[(1 + i) % 8] << 2));
                        DWORD e2 = ((inn[(1+ i) % 8] >> 3) ^ (inn[(7 + i) % 8] << 4));
                        //cout << e1 << endl << e2 << endl;
                        /*
                        0x1fbe03fe
                        0xc7df907b
                        */
                        DWORD p = e1 - ~e2 - 1;
                        //std::cout << "sum=0x" << sum << std::endl;
                        DWORD e3 = xnn[(sum ^ i) & 3] ^ inn[(7 + i) % 8];
                        DWORD p2 = inn[(1 + i) % 8] ^ key;
                        //cout << p << endl << e3 << endl << p2 << endl;

                        DWORD p3 = p2 - ~e3 - 1;
                        DWORD e4 = p3 ^ p;
                        //cout << p3 << endl << e4 << endl;
                        DWORD p4 = inn[(i) % 8] - ~e4 - 1;
                        //std::cout << "i=" << i << "|" << p4 << std::endl; // p4 is ANS
                        inn[i] = p4;
                        //std::cout << "-------------\n";
                }
                //std::cout << "k=" << k << "----------------------------------------------------\n";

                key += keyOffset;
                sum = sum + offset + !(k % 2);
        }
        char* result = (char*)malloc(33);
        if (!result) return -1;
        for (size_t i = 0; i < 32; i++)
        {
                result[31 - i] = flag[i] ^ x0r[(31 - i) % 16] ^ 0x18;
        }
        if (*(DWORD*)result != 0xc293a546)
        {
                std::cout << "errrr";
        }
        char ans[] = {0x4b ,0xa0 ,0x0c ,0xff ,0xab ,0x0a ,0x13 ,0xb0,0x32 ,0x91 ,0x6d ,0x87 ,0x8b ,0xab ,0xf5 ,0xa5,0xdc ,0x77 ,0xd4 ,0x95 ,0xb9 ,0x02 ,0xa6 ,0xac,0xe4 ,0x74 ,0x2c ,0x6b ,0xeb ,0xe1 ,0x5e ,0x25};
        return 0;
}

注意到(sum ^ i) & 3,立马想到了TEA加密算法,再看一下这个结构,完全不像??
不过e1, e2好像key中的l和r,所以想办法得搞成TEA,也方便写解密脚本

注意到程序中p2 - ~e3 - 1这种模式,加密过程中出现了三次,所以想办法看看能不能化简。
这种模式立即让我想到了VMProtect 3.5,虚拟化后的加法过程,随即我翻阅了去年组会中我写的blog:
https://组织内部神秘博客地址/d/955-redi-er-ci-zu-hui-idapythonji-chu-appcallshi-yong/9

2024-05-30T11:29:06.png

可以注意到,化简后是

p2 - ~e3 - 1  <====>  p2 + e3

这样就可以化简整个加密函数

uint8_t lkey[16] = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80 };
void encryption(DWORD* inn)
{
        DWORD offset_ = 0xBADECADA;
        DWORD key = 0x2EB7B2B6;
        uint32_t sum_ = 0xBADECADA;
        auto xnn = (DWORD*)lkey;
        for (int k = 0; k < 12; k++)
        {
                for (int i = 0; i < 8; i++)
                {
                        DWORD l = ((inn[(7 + i) % 8] >> 5) ^ (inn[(1 + i) % 8] << 2));
                        DWORD r = ((inn[(1 + i) % 8] >> 3) ^ (inn[(7 + i) % 8] << 4));
                        DWORD p4 = inn[(i) % 8] + (((inn[(1 + i) % 8] ^ sum_) + (xnn[(key ^ i) & 3] ^ inn[(7 + i) % 8])) ^ (l + r));
                        inn[i] = p4;
                }
                sum_ += offset_;
                key += 0xEEB7B2B6 + !(k % 2);
        }
}

xnn是lkey, lkey是xor(key)表,至此我们需要写解密函数,我的处理方法是把key和sum先算12次,得到最后结果,然后反着来用,按照TEA的方法来逆向。

void decryption(DWORD* inn)
{
        DWORD offset_ = 0xBADECADA;
        DWORD key = 0x2EB7B2B6;
        uint32_t sum_ = 0xBADECADA;
        auto xnn = (DWORD*)lkey;

        for (int k = 0; k < 12; k++)
        {
                sum_ += offset_;
                key += 0xEEB7B2B6 + !(k % 2);
        }

        for (int k = 11; k >= 0; k--)
        {
                sum_ -= offset_;
                key -= 0xEEB7B2B6 + !(k % 2);
                for (int i = 7; i >= 0; i--)
                {
                        DWORD l = ((inn[(7 + i) % 8] >> 5) ^ (inn[(1 + i) % 8] << 2));
                        DWORD r = ((inn[(1 + i) % 8] >> 3) ^ (inn[(7 + i) % 8] << 4));
                        inn[i] -= (((inn[(1 + i) % 8] ^ sum_) + (xnn[(key ^ i) & 3] ^ inn[(7 + i) % 8])) ^ (l + r));
                }
        }
}

至此,给出完整exp:

#include <iostream>
#include <vector>
#include <Windows.h>

uint8_t lkey[16] = { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80 };

void encryption(DWORD* inn)
{
        DWORD offset_ = 0xBADECADA;
        DWORD key = 0x2EB7B2B6;
        uint32_t sum_ = 0xBADECADA;
        auto xnn = (DWORD*)lkey;


        for (int k = 0; k < 12; k++)
        {
                for (int i = 0; i < 8; i++)
                {
                        DWORD l = ((inn[(7 + i) % 8] >> 5) ^ (inn[(1 + i) % 8] << 2));
                        DWORD r = ((inn[(1 + i) % 8] >> 3) ^ (inn[(7 + i) % 8] << 4));
                        DWORD p4 = inn[(i) % 8] + (((inn[(1 + i) % 8] ^ sum_) + (xnn[(key ^ i) & 3] ^ inn[(7 + i) % 8])) ^ (l + r));
                        inn[i] = p4;
                }
                sum_ += offset_;
                key += 0xEEB7B2B6 + !(k % 2);
        }
}

void decryption(DWORD* inn)
{
        DWORD offset_ = 0xBADECADA;
        DWORD key = 0x2EB7B2B6;
        uint32_t sum_ = 0xBADECADA;
        auto xnn = (DWORD*)lkey;

        for (int k = 0; k < 12; k++)
        {
                sum_ += offset_;
                key += 0xEEB7B2B6 + !(k % 2);
        }

        for (int k = 11; k >= 0; k--)
        {
                sum_ -= offset_;
                key -= 0xEEB7B2B6 + !(k % 2);
                for (int i = 7; i >= 0; i--)
                {
                        DWORD l = ((inn[(7 + i) % 8] >> 5) ^ (inn[(1 + i) % 8] << 2));
                        DWORD r = ((inn[(1 + i) % 8] >> 3) ^ (inn[(7 + i) % 8] << 4));
                        inn[i] -= (((inn[(1 + i) % 8] ^ sum_) + (xnn[(key ^ i) & 3] ^ inn[(7 + i) % 8])) ^ (l + r));
                }
        }
}

int main()
{
        char ans[] = { 0x4b ,0xa0 ,0x0c ,0xff ,0xab ,0x0a ,0x13 ,0xb0,0x32 ,0x91 ,0x6d ,0x87 ,0x8b ,0xab ,0xf5 ,0xa5,0xdc ,0x77 ,0xd4 ,0x95 ,0xb9 ,0x02 ,0xa6 ,0xac,0xe4 ,0x74 ,0x2c ,0x6b ,0xeb ,0xe1 ,0x5e ,0x25 };
        char* result = (char*)malloc(33);
        if (!result) return -1;
        result[32] = 0;
        for (size_t i = 0; i < 32; i++)
        {
                result[i] = ans[31 - i] ^ lkey[(31 - i) % 16] ^ 0x18;
        }
        decryption((DWORD*)result);
        for (size_t i = 0; i < 32; i++)
        {
                result[i] ^= lkey[i % 16];
        }
        std::cout << result;

        return 0;
}

MiniLCTF 2024

真正意义的打了5天的CTF,时间长,事件多,题目有趣。
0x Team
rank list
最后也是真不容易地拿到了总分第一,认识了许多大佬,队友也都很猛,废寝忘食地capture flag,最后一天也是Web手连着K掉了两个难题,挽救了低分(Web差一道就AK了)。
第一次AK所有逆向题目(可能只是因为比赛时间较长吧,我们没有专门的Misc手,我也打了打Misc)
第一次AK所有Misc题目(队友是神,0基础CTF就能AK)

还是得吐槽一下区块链方向,最后一天上了个题让我们人心惶惶,因为大家都没做出来,但是最后也没人解出来,好像是容器有一些问题,或者只是题目比较难吧(

以后的打算:主攻Reverse,学一学Pwn,顺便当个小小运维,其他题和队友齐力解决。

我们队伍(0x)的Writeups(2024/5/9开放围观!):
飞书WP链接