首页
社区
课程
招聘
[原创]答题 [第一阶段◇第二题]看雪论坛.腾讯公司2008软件安全技术竞赛
2008-10-6 09:17 2414

[原创]答题 [第一阶段◇第二题]看雪论坛.腾讯公司2008软件安全技术竞赛

2008-10-6 09:17
2414
注册码 原理 类似于12球找不同的方法
通用Key
静态花招 位置g+1必须等于h
动态花招 验证代码自校验以防止加F2断点CC
动态生成提示对话框且提示字符串进行了加密

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (3)
雪    币: 105
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
pcasa 2 2008-10-6 21:54
2
0
若需要Key有差异,可以尾加上一些数字(0~3) ,也可以是空格符等(ASCII小于数字3的字符)
Key的总长度不高于100个字符
由于最开始的53个字符是一致的,所以没有进行随机数的Key,这样应该不会有扣分吧
最后附上我以前写一个程序
12个球经三次比较就可能找出不同的那一个
//12球3次称出坏球的算法

#include <iostream>

using namespace ::std;

class CBall {
public:
  CBall()
  {
    memset(balls, 0, sizeof(balls));
  }
  // 1 左侧重 0 相等 -1 右侧重 
  // 参数以位来区分  bit0~bit11  
  int Check(int left, int right) const
  {
    int l=0;
    int ln=0;
    int r=0;
    int rn=0;
    for(int i=0; i<12; i++)
    {
      if(left&1<<i)
      {
        ln++;
        l+=balls[i];
      }
      else if(right&1<<i)
      {
        rn++;
        r+=balls[i];
      }
    }
    if(ln<rn)
      return -1;
    if(ln>rn)
      return 1;
    if(l<r)
      return -1;
    if(l>r)
      return 1;
    return 0;
  } 
  
  int findBug()
  {
    // 1234 5678 ABCD
    int a[12];
    int tt;
    int tt1;
    for(int i=0; i<12; i++)
      a[i]=1<<i;
    tt=Check(a[0]|a[1]|a[2]|a[3], a[4]|a[5]|a[6]|a[7]);
    if(tt==0)
    {
      // ABCD
      tt=Check(a[8]|a[9]|a[10], a[0]|a[1]|a[2]);
      if(tt==0)
      {
        // D 
        tt=Check(a[11], a[0]);
        return tt*12;
      }
      else
      {
        // ABC
        tt1=Check(a[8], a[9]);
        if(tt1==0)
        {
          // C 
          return tt*11;
        }
        else
        {
          if((tt>0 && tt1>0)
          || (tt<0 && tt1<0))
          {
            // A
            return tt*9;
          }
          else
          {
            // B
            return tt*10;
          }
        }
      }
    }
    else
    {
      // 1234 5678
      tt1=Check(a[0]|a[1]|a[4], a[2]|a[3]|a[5]);
      if(tt1==0)
      {
        // 78
        tt1=Check(a[7], a[0]);
        if(tt1==0)
        {
          // 8
          return -tt*8;
        }
        else
        {
          // 7
          return -tt*7;
        }
      }
      else
      {
        if((tt1>0 && tt>0)
        || (tt1<0 && tt<0))
        {
          tt1=Check(a[0], a[1]);
          if(tt1==0)
          {
            // 6
            return -tt*6;
          }
          else
          {
            if((tt1>0 && tt>0)
            || (tt1<0 && tt<0))
            {
              // 1 
              return tt*1;
            }
            else
            {
              // 2
              return tt*2;
            }
          }
        }
        else
        {
          tt1=Check(a[2], a[3]);
          if(tt1==0)
          {
            // 5
            return -tt*5;
          }
          else
          {
            if((tt1>0 && tt>0)
            || (tt1<0 && tt<0))
            {
              // 3 
              return tt*3;
            }
            else
            {
              // 4
              return tt*4;
            }
          }
        }
      
      }
    }
    return 0;
  }

  int balls[12]; 
}; 

int main()
{
  CBall ball;
  
  for(int j=-1; j<=1; j++)
  {
    for(int i=0; i<12; i++)
    {
      if(j==0) continue;
      ball.balls[i]=j;
      cout<<i+1<<" "<<j<<" "<<ball.findBug()<<endl;
      ball.balls[i]=0;
    }
  }
  system("pause");
  return 0;
}
雪    币: 105
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
pcasa 2 2008-10-6 22:34
3
0
注册码的生成
  将那个超长函数(sub_401087)按照上面的流程,在保持输出与输入的对应关系不变的情况下,手动构造了一个且是通用的,

1 用户名为12个字节 检查用户名的字符是否全为'a'-'y'且不能有重复的字符
2 计算其索引到一个数组
3 注册码长度至少为53个字符 检查注册码的字符<='3'
4 将其数字字符转为整形数字
  最长不超过100个字符否则会溢出,不知这算不算一个Bug?不信你用150个0去试试
5 调用sub_401087进行注册码变换
  sub_401087()的原理与称球问题差不多,
   在void sub_401087(int key[100], char out[24], int name[12])中
会将name中的排序做两组类似上面的找坏球的算法(共计24次)且每一个状态都是要判定的,将判定的结果保存在out中并返回
   其中有一处有比较很特殊00402D03,其结果是某一个状态下g后必须是h
  这应该算是静态花招
6 检查变换后的两组字符串索引顺序与名字索引顺序一致
7 通过后就会弹出OK了

跳过反调试保护, 修改下面两处补丁后可在OD下F2断点
补丁1
004039D2      F2:AE         repne   scas byte ptr es:[edi]
==>
004039D2      90            nop
004039D3      90            nop
补丁2
004039F8   .^\0F85 AAFEFFFF jnz     004038A8
==>
004039F8      90            nop
004039F9      90            nop
004039FA      90            nop
004039FB      90            nop
004039FC      90            nop
004039FD      90            nop

写的有点乱.
好不容易把算法给理解了.
雪    币: 7209
活跃值: (2630)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
netwind 13 2008-10-7 20:32
4
0
结果提交时间 21 小时 17 分钟
结果提交时间长度 = 1277 分钟
结果提交次数 = 1
结果提交作为注册码
得分 = [(2880 - 1277)/2880]^1/8 x 0.5 x 100 - (1 -1 ) x 5 = 46.47

"若需要Key有差异,可以尾加上一些数字(0~3) ,也可以是空格符等(ASCII小于数字3的字符)"
注册码可以有多组,例如:
301 20 21 2022111212313120221322001101020102010200200102
看这个注册码,把20 和21 换个位置就又组新的了
301 21 20 2022111212313120221322001101020102010200200102

对于只判断等与不等的结点,两个字符互换可以得倒新的注册码
但您的注册机不包含上面的情况.
如有疑问请跟贴说明,感谢参与!
游客
登录 | 注册 方可回帖
返回