ebCTF(问鼎杯)题库逆向——dice game 笔记

附件:提取码:lv68

拖入 OD 后查找字符串,直接找到主函数,这点感觉难度不大。试着通过 OD 在要跳转的地方改 flag 值来改变跳转,跳到 goodboy,输出的 flag 竟然是乱码,一脸懵逼,后来瞎搞倒是做出来了(做法一)。(最后通过方法二搞懂了原因)

整个程序大致的流程倒是很清晰:通过随机数来模拟掷骰子,然后让你掷处 3,1,3,3,7 ,只要掷得都对就能得到 flag

做法一:

可以看到,这个掷骰子的方式是通过 rand() 函数,然后将结果存储在 eax 中并赋值到 [ebp-0x5c] 中,之后将 [ebp-0x5c] 中的值与1,2,3,4,5,6,进行比较,相等就执行后面的代码,不相等就跳转到下一个比较的地方

rand函数后面对 eax 做了一堆处理,但eax在处理之后是跟1,2,3,4,5,6比较,所以我们可以直接对eax进行赋值。因此直接修改汇编代码多的地方用 nop 填充

后面几次同理,改成1,3,3

但是在最后一次掷 7 的时候我没有找到 rand() 函数,也没有找到对 eax 处理的地方,但是我们从后面的比较中也可以看到进行比较的数仍然是 [ebp-0x5c],所以我们可以把看起来是对 [ebp-0x5c] 进行修改的几处代码进行修改

然后保存修改,运行修改后的软件,得到 flag

但是为什么我强制跳转会出现乱码呢?现在在方法二中解释原因

做法二:

在 IDA PRO x86 中打开

找到主函数,来看看伪C代码:

这些都跟我之前总结的一样,来看看输出flag的地方

这个 flag 就是 v88 字串,看看它在之前做了什么修改

可以看到,程序在开始定义了两个字串

之后对这两个字串进行了3次按位与或

第一次与或的值v90的值为16,之后没有对v90进行处理

但是第二次与或的值v89却做了很多处理,其它的处理都是直接乘除加减,唯独这5个处理非常有意思

一开始很不理解这个 if 语句,我关注到 if 表达式中的两个变量都是用 time(0) 得到的,上网搜索

C 库函数 time_t time(time_t *seconds) 返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。

这个 time(0) 返回的是一个系统时间!这是一个“反调试”的代码,因为如果你手动去调整跳转,算上F8中间的一些代码,加起来会超过2秒,v89就会莫名其妙被 *2!所以后面异或的时候会出现乱码,怪不得后来我保存到可执行文件后就能输出正确 flag 了。

知道了 flag 的生成原理,那就照搬写出 .c 文件:

#include<stdio.h>
#include<string.h>

int main()
{
    int v89=6;
    char v88[]={19,33,56,21,61,51,87,71,45,39,106,115,68,5,38,89,92,121,23,68,69,119,26,117,73,125,5,74,120,116,106,112,66,2,113,5,15,34,8,'\0'};
    char v91[]={2,55,15,53,15,60,21,7,60,48,42,48,85,18,55,21,30,53,1,81,'\0'};
    v89*=2;
    //v89*=2;
    v89+=4;
    //v89*=2;
    v89*=3;
    //v89*=2;
    v89+=2;
    //v89*=2;
    v89 *= 2;
    //v89*=2;
    int v90=16;
    for(int i=0;;++i)
    {
        if(i>=strlen(v91))
            break;
        v91[i]^=v90;
    }
    for(int i=0;;++i)
    {
        if(i>=strlen(v91))
            break;
        v91[i]^=v89;
    }
    int i =0;
    for(int j=0;;++j)
    {
        if(j>=strlen(v88))
            break;
        v88[j]^=v91[i];
        ++i;
        if(i>=strlen(v91))
            i=0;
    }
    printf("%s",v88);
}

数组中的值是我直接把原来字符串中的值转换成十进制ASCII码输进去的(0x..是十六进制值,我也转成十进制了)

运行得到flag

总结

这是我第一次遇到能输出 flag 但乱码的情况,综合两个软件发现了其中的奥秘,涨姿势了

ps:这两天花了挺多时间在做另一道题,太坑了,到现在都没做出来。网上一查竟然要“走迷宫”的算法,崩溃了。所以先做做别的吧,毕竟那道题怎么输出地图我都不会。最近打算看看《IDA PRO权威指南》,然后学学 python。重点是期末了,又没空了,这两天又回CS:GO坑了XD。所以,啥事都乱了

说点什么

avatar

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

  Subscribe  
提醒