一道ctf中的逆向题

iOS逆向juan很多人不会关注这个的啦,毕竟做了又没人给钱23333

开黑吗我玩源氏

大神不来解一发题目。。娱乐一下么。。

:pensive:唉。。看来真是这样子,本以为会出现各种骚气的逆向思路,可这都两天了,,还是没人来玩。
真是现实的向金钱看齐==

话说把这题做为入群题目之一,会不会有人来玩啊:pensive:
本来是想在论坛发一系列iOS相关的ctf题,可现在看来没啥槽点

简单看了一下,校验逻辑在[ViewController checkClicked:]里,用LLDB跟一下应该就出来了

跟这题没啥本质区别吧?

这个太明显了,他说的是算法看不懂

[ViewController checkClicked:]这个大家都能看出来,这题考的是解读逻辑校验算法,并不是简单的输出个passed就算通过,而是要根据校验算法推出当用户名为ctfuser时,serial的值应该为什么。
如果推出的Serial值是正确的话,把ctfuser和相应的Serial值填进文本框后,屏幕是会向选手显示passed,表示推出的Serial是正确的。
然后选手再把Serial值提交上去。

1 个赞

Serial并没有被硬编码进去,赛后据第一的战队透漏说Serial值有无数个。他们用了不到一小时就拿下了:pensive:

检验算法就在那里面,F5一下看看

这是我比赛那天的f5结果,,最后没读懂这个算法

--------分割线-----------


void -[ViewController checkClicked:](void * self, void * _cmd, void * arg2) {
    r7 = sp + 0xc;
    asm{ vst1.64    {d8, d9, d10, d11}, [r4:0x80]! };
    asm{ vst1.64    {d12, d13, d14, d15}, [r4:0x80] };
    sp = (sp - 0x40 & !0xf) - 0xa0;
    r5 = self;
    var_AC = ___stack_chk_guard;
    var_1C = *___stack_chk_guard;
    var_7C = [arg2 retain];
    r4 = r5->_started;
    _Unwind_SjLj_Register();
    if (r4 != 0x0) {
        [r5 appendlog:"already checking...\n"];
    }
    else {
        
        r5->_started = 0x1;
        var_B0 = *0x5990;
        var_B4 = @selector(appendlog:);
        var_A8 = r5;
        [r5 appendlog:("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics" | 0x0) + 0x31a6];
        r0 = objc_loadWeak(*0x5994 + var_A8);
        var_A0 = @selector(text);
        r0 = [r0 text];
        r7 = r7;
        var_78 = [r0 retain];
        CFStringGetCString(var_78, sp + 0x2c, 0x9, 0x600);
        r0 = CFStringGetLength(var_78);
        
        r2 = 0x0;
        do {
            r0 = *(r2 + sp + 0x2c);
            0x6 << 0x10 | sub_3bfe(r0);
            r2 = r2 + 0x1;
            asm{ vadd.f64   d8, d16, d8 };
        } while (r2 < 0x9);
        
        
        r0 = objc_loadWeak(*0x5998 + var_A8);
        r0 = objc_msgSend(r0, var_A0);
        r7 = r7;
        var_74 = [r0 retain];
        CFStringGetCString(var_74, sp + 0x7c, 0x11, 0x600);
        
        
        r2 = 0x0;
        r1 = 0x0;
        do {
            var_A0 = r1;
            var_9C = r2;
            r0 = *(r2 + sp + 0x7c);
            if ((r2 & 0x2) == 0x0) {
                asm{ uxtb       r0, r0 };
                var_A4 = sub_3d44(r0);
                r0 = *(0x1 + var_9C + sp + 0x7c);
                r0 = sub_3d44(r0);
                r2 = var_9C;
                r0 = r0 + var_A4;
            }
            else {
                asm{ uxtb       r0, r0 };
                var_A4 = sub_3d44(r0);
                r0 = *(0x1 + var_9C + sp + 0x7c);
                r0 = sub_3d44(r0);
                r2 = var_9C;
                r0 = var_A4 - r0;
            }
            *(r2 + sp + 0x7c) = r0;
            asm{ uxtb       r0, r0 };
            r0 = sub_3bf4(r0);
            r2 = var_9C;
            r1 = *((SAR(r2, 0x1)) + sp + 0x20);
            if ((r0 ^ r1) <= 0xf) {
                r1 = var_A0 + 0x18e8e;
            }
            else {
                r1 = var_A0 + (r1 - *(r2 + sp + 0x7c) & 0xf);
            }
            r2 = r2 + 0x2;
        } while (r2 < 0x10);
        if (r1 == 0xae5e9) {
            [var_A8 appendboldlog:"passed.\n"];
        }
        //
        else {
            if (r1 == 0xc7470) {
                objc_msgSend(var_A8, var_B4);
            }
        }
        *(var_A8 + var_B0) = 0x0;
        [var_74 release];
        [var_78 release];
    }
    [var_7C release];
    _Unwind_SjLj_Unregister();
    if (*var_AC == var_1C) {
        r4 = sp + 0xa0;
    }
    if (CPU_FLAGS & E) {
        asm{ vld1.64    {d8, d9, d10, d11}, [r4:0x80]! };
    }
    if (CPU_FLAGS & E) {
        asm{ vld1.64    {d12, d13, d14, d15}, [r4:0x80] };
    }
    if (CPU_FLAGS & E) {
        r4 = r7 - 0x18;
    }
    if (CPU_FLAGS & E) {
        sp = r4;
    }
    if (CPU_FLAGS & E) {
        return;
    }
    __stack_chk_fail();
    return;
}

@NavilleZhang @xiaossv

你们看我给出的那个链接了么?

我当然知道要继续逆向;阿里那题也有个算法,两者本质是一样的。这一题的算法在:

不要看伪代码,要么静态直接看汇编,要么动态一步一步跟,算法就出来了。于我来说只是重复劳动而已,就不做这一题了

哦哦,从伪代码来说确实是相同题目:+1:

你那个算法也是无数解么? 感觉好恐怖啊。
那题我动态一步步跟的,循环了一遍,没明白算法,觉得好累,最后放弃了。。

是的我昨天看到这个代码了

膜大神……

细节当然不一样,但思路和题目类型几乎是完全一样的

好吧,看来没人做,我在这里分享下解题思路,供感兴趣的人参考一下:
(以下解题思路来自 time-keeper ),题目要求提交两种Serial值
图不太清晰(其实直接没法看:worried:),但主要是思路 ,所以将就吧。

---------------分割线-------------------
主要的函数位置在 [ViewController checkClicked:]
检查函数将用户名为"ctfuser"进行复杂的变换

[图1]

由于是固定变换,调试搞出 ‘transformed_username="\x00\x00\x00\x00\x00\xA8\x97\x40’

[图2]

后面的运算是将十六进制的序列号2字节分组相加或相减,按位翻转后,分别与对应上述变换结果异或,根据结果进行不同方式求和

[图3]
注意到求和过程主要有两个分支, +102030+x(0<x<0xF)
而两个目标hash值

816240 = 102030*8
714217 = 102030*7 + 7

此时可知该题应有多解,现在构造一组可行解:

对于求得第一种 hash 的情况,只要让序列号分组后每组数字加减结果的位反转 与 对应变 换后的用户名高 4 位一致,即可得到异或结果<=0xF

前 5 组直接使用 ”00”,因为 0+0=0-0=0,后面对于 0xA8、0x97、0x40,位翻转后得 0x15、0xE9、 0x02,
所以这三组所对应序列号 hex 加减后结果的低 4 位应分别为 5、9、2,那么直接就用 509020 吧,序列号为 0000000000509020

对于第二种 hash 结果,需要使上述异或过程的其中一个得到 0xX7(其中 X>0),此处选择 0x97 下手,使用任意 **X0(X!=9)**都能达到效果,那么选择 00,序列号为 0000000000500020。 在软件中验证通过,一个正常 pass,一个粗体 pass

2 个赞

思路清晰.

论坛里面都是逆向大牛。。。你有啥问题直接发帖问啊。。