能力值:
( LV6,RANK:90 )
|
-
-
2 楼
若需要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;
}
|
能力值:
( LV6,RANK:90 )
|
-
-
3 楼
注册码的生成
将那个超长函数(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
写的有点乱.
好不容易把算法给理解了.
|
能力值:
(RANK:520 )
|
-
-
4 楼
结果提交时间 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
对于只判断等与不等的结点,两个字符互换可以得倒新的注册码
但您的注册机不包含上面的情况.
如有疑问请跟贴说明,感谢参与!
|
|
|