currwin 发表于 2014-10-23 09:27

【吾爱破解2014CrackMe大赛】【第二组】

本帖最后由 L4Nce 于 2014-10-24 22:39 编辑

      直接说结论,我认为这个cm是不可能被正常的方法keygen的。因为代码中有几个地方写得不严谨,或许这是作者的有意为之,如果真的是这样的话只能说我实在是太菜了。
       这个cm让我想起了我以前玩的一个游戏,打个比方,就是排列9*9的灯泡矩阵,并且通过Name与Key控制灯泡的明灭。如果假设刚开始时灯泡是灭的,那么到最后,如果所有灯泡都是灭的话,就成功了。
      问题就出在这里,让我慢慢说明:
首先是初始化灯泡:
每个灯泡的结构如下
struct light {
    DWORD statuc;   //灯泡的明灭状态
    DWORD LineFirst;    //灯泡是否处于第一行
    DWORD LineLast;    //灯泡是否处于最后一行
    DWORD ListFirst;    //灯泡是否处于第一列
    DWORD ListLast;    //灯泡是否处于最后一列
}
      接下来是初始化了,原程序使用了复杂的数据来混淆视线,弄懂了定义就可以了。
#define true 0xFEFEFEFE
#define false 0xEFEFEFEF                  //判断灯泡行列的两个常数
#define off    0xFFEEFFEE
#define on    0xEEFFEEFF                   //判断灯泡状态的两个常数
PS: off ^ 0x11111111 = on.       on ^ 0x11111111 = off。 所以,下面的??异或0x11111111实际上是在转换灯泡的状态。
   先初始化9*9的灯泡阵列,注意,这里是第一个问题:
代码大致如下:
_DWORD *__usercall sub_401EB0<eax>(_DWORD *result<eax>)
{
signed int iLine; // edx@1 初始化棋盘
signed int iList; // ecx@2

iLine = 0; // 9行
do
{
iList = 0; // 9列 1*5 的DWORD
do
{
*result = 0xFFEEFFEEu; // 主元素
if ( !iLine )
{
result = 0xFEFEFEFEu; // 第0行
LABEL_5:
result = 0xEFEFEFEFu;
goto LABEL_6;
}
result = 0xEFEFEFEFu; // 非0行
if ( iLine != 9 )
goto LABEL_5;
result = 0xFEFEFEFEu; // 第9行,不存在?
LABEL_6:
if ( !iList ) // 第0列
{
result = 0xFEFEFEFEu;
LABEL_8:
result = 0xEFEFEFEFu;
goto LABEL_9;
}
result = 0xEFEFEFEFu; // 非0列
if ( iList != 9 )
goto LABEL_8;
result = 0xFEFEFEFEu; // 第9列。。。不存在?
LABEL_9:
++iList;
result += 5;
}
while ( iList < 9 );
++iLine;
}
while ( iLine < 9 );
return result;
      不清楚?再弄一下:
iLine = 0;
do {
if(iLine == 9)
....//设置灯泡为最后一行
} while(iLine < 9)
      你一定是在逗我,这样写的话,无论如何,最后一行的数据是无法被设定的,同理,最后一列也是没有被设置的。也就是说,这灯泡阵列的最后一行,最后一列,能不用就尽量不用,否则不知道会出现什么结果。。。

      然后是根据名字设置灯泡,这个挺好懂的:
do
      {
      NameA = (szName >> 4) & 0xF;       // 对Name进行拆分,然后
      NameB = szName & 0xF;            // NameA%9行   nameB%9列
      if ( (unsigned int)NameA > 9 )
          NameA %= 9u;
      if ( (unsigned int)NameB > 9 )
          NameB %= 9u;
      ++v13;
      v40 = NameA;
      v41 = NameB;
      (&chess) = (_DWORD *)0xEEFFEEFF;// 初始化有被名字指向的部分
      }
      while ( v13 < v12 );                      // 使用名字对棋盘进行初始化
       拆分每一个Name字符为左右两部分,分别指出了需要修改的灯泡的行与列,然后设置其状态为 on。

       自然的,下面就是需要我们去利用Key,把灯泡全弄为off就好了。然后这里又是一个问题。
       前面的处理是一样的,拆分每一个key,然后指出需要修改的灯泡的行数与列数。接着,修改它四周的灯泡。
       修改的代码如下:
v20 = 5 * v19;                        // 20 = 4*5
      if ( (&chess1) != (_DWORD *)0xFEFEFEFE )// 检查棋盘分配,是否不为第0行
          (&chess) = (_DWORD *)((unsigned int)(&chess) ^ 0x11111111);// 非0行,把上一行的数据 ^ 11111111
      if ( (&chess2) != (_DWORD *)0xFEFEFEFE )// 检查是否不为最后一行(9)?会出现?XXXX
          (&chess45) = (_DWORD *)((unsigned int)(&chess) ^ 0x11111111);// 当前行(+9) = 上一行 ^ 11111111
      if ( (&chess3) != (_DWORD *)0xFEFEFEFE )// 检查是否不为第0列
          *(int *)((char *)&v38 + v20 * 4) = (unsigned int)(&chess) ^ 0x11111111;// 前一个数据 = 当前数据 ^ 11111111
      if ( (&chess4) != (_DWORD *)0xFEFEFEFE )// 检查是否不为第9列,XXXX
          (&chess5) = (_DWORD *)((unsigned int)(&chess) ^ 0x11111111);// 后一个数据 = 上一行^ 11111111
       注释得有点乱,举个例子:
       如果灯泡是属于正则内点中,那么可以表示为:
1 2 3                                  ? off ?
4 5 6   对应的状态为:      ??   ?
7 8 9                                 ??   ?
      然后这段的作用就是,选中了灯泡5,于是对灯泡2,4,6,8的状态进行修改。
       再具体一点就是使用灯泡2的状态来设置灯泡2,4,6,8的状态,最终结果为:
?on ?
off ? off
?off ?
       你可能认为我写错了,但是我的确是没有写错。这里4,6,8本身的状态被无条件忽视了,然后2的状态复制给了它们,然后2再改变自己的状态。于是,无论选中哪一个灯泡,都一定会在这灯泡隔壁设置两种状态,所以,通过这种正常的思路是不可能弄出正确的key的。更别提最后一行最后一列的状态都是没有正常设置的了。
       并且,这里的判断也不严谨,因为这里都是利用上一行的数据来修改四周的数据的,所以,如果是位于第一行的话,就会造成数据溢出的状况。

       然后,第3点就是对Key循环的地方有问题:
      就结论来说,它循环的次数为 iKeyLen ^ 4.
      对, 你没有看错,就连循环次数也是这种奇怪的情况。

      于是,如果这真的是作者有意设置的话,那么只能用这种方法来完成keygen了。
      把Name与key的变换都弄掉。具体来说就是:

Name: (空)
Key:   任意4位字符

       OK,就是这么多了,最后附上一个爆破的,这样至少也应该能够得到一点分吧

currwin 发表于 2014-10-23 12:50

标题弄错了,应该是第二组的

ximo 发表于 2014-10-24 17:55

最后成绩:80*2=160分
评委评价:利用bug,顺利kg,攻击有效。
谢谢参与,请继续加油。

ximo 发表于 2014-10-24 17:56

此cm得确存在逻辑bug,楼主顺利找到了bug,并且在此情况下,依然找到了通解,要赞一下。

a070458 发表于 2014-10-24 23:52

{:1_936:}因为最后一个想来想去没办法设置
我还傻乎乎去解方程,去穷举 {:1_906:}

currwin 发表于 2014-10-25 09:05

ximo 发表于 2014-10-24 17:56
此cm得确存在逻辑bug,楼主顺利找到了bug,并且在此情况下,依然找到了通解,要赞一下。

      谢谢评委,O(∩_∩)O哈哈~,瞬间找回自信了

currwin 发表于 2014-10-25 09:07

a070458 发表于 2014-10-24 23:52
因为最后一个想来想去没办法设置
我还傻乎乎去解方程,去穷举

cm是人写出来的,出现逻辑上的错误也是非常正常的。就像你看那些教科书一样,不可能全是正确的,正确率有%75以上就应该庆祝了

Avenshy 发表于 2014-10-25 11:50

看到排行榜默默地进来....你那么会找bug你家里人知道吗……{:1_931:}

Bigtang 发表于 2014-10-30 20:56

膜拜了。yd的思维。这个游戏叫 点灯游戏

bess 发表于 2014-11-3 00:06

真的很厉害   觉得自己差好远
页: [1] 2
查看完整版本: 【吾爱破解2014CrackMe大赛】【第二组】