Duelist's Crackme #3

这是在《Crack2007》,分类“矩阵方式”下的一个CM,帖子地址如下
http://bbs.pediy.com/showthread.php?threadid=30368
因为一开始就想错了方向(其实也不算想错了,是往难的方法想了,竟然想到了遍历二叉树之类的方法,结果难的方法也没写得出算法来只好作罢了),已经拖了很多天了,只好在国外发CM的网站搜了搜 果然找到了solution,然后就搞明白了于是有了这篇日志

算法很简单的,先拖入OD,找字符串定位到按钮事件代码的地址,然后拉到IDA分析(终于在分析CM算法的时候感到此神器的伟大了)


在开始的地方下断点,运行几次大概分析出以下流程:
注册方法:

程序设有18个多选框,要选中指定的几个就算注册成功
程序内部把这些多选框编号为以下数组(不按顺序的)
intCheckBoxs[18]={0x16,0x49,0x5E,0x15,0x27,0x26,0x21,0x25,0x1D,0x59,0x53,0x37,0x31,0x48,0x5D,0x0C,0x61,0x52};
 
注册算法:从上面的编号一个一个试
如果unchecked则试下个
如果checked则:
i++
Result=Result+(CheckBoxs[i-1]*CheckBoxs[i]*i)
18个全部试验完之后,如果Result=0xF35466*0x4D则正确。

我自己想的方法 :(可以不看)
生成一个二叉树,每个结点有i个子节点,共i+1层(第一层是头节点,没意义)。节点的数据放入Checkboxs的索引值。
遍历二叉树就可以得出每种情况,但是实际上我们并不一定需要i个单位长度的组合(因为有for循环,子节点数可能不同),或许我们需要10个数字的组合,这就要把后面的7层给剪掉,那现在还能不能保证这些在17个数字里面的“9数字”组合涵盖了全部情况?
经过实验证明是可以保证的。遍历二叉树,每次遍历到叶节点的时候就算出该次选择的n个checkboxs元素对应的Result值,对比是否等于0xF35466*0x4D,等于则成功

正确做法(python写的,for循环没有括号扩住循环体,得靠缩进识别):
先看看代码然后听我稍微解释一下吧,程序有18个多选框,每个多选框有两种选择 checked和unchecked
所以会有2^18(即
262144  )种情况
先设一个大循环使得a=1到262144,然后试探它的每一位,如果是1的话(假设1是checked)就将当前table[j]和table[j-1]参与运算
第八行的 
0x328FE就是0xF35466*0x4D
当somme=0xF35466*0x4D 时,i为正确答案(转换为二进制,1代表checked,0代表unchecked),但是程序的多选框和数组table并不是按照顺序排列的,所以需要用资源查看器查看一下多选框对应的序号并将code数组中存放的注册码转换为与多选框排列对应的注册码
 
for i in range(1, 262144):
    somme = 0
    a = i
    for j in range(1, 19):
        if (a & 1):
            somme = somme + (j * table[j] * table[j-1])
        a = a >> 1
        if (somme == 0x328FE):
            if (i & 1):
                code[3] = '1'
            i = i >> 1
            if (i & 1):
                code[1] = '1'
            i = i >> 1
            if (i & 1):
                code[2] = '1'
            i = i >> 1
            if (i & 1):
                code[9] = '1'
            i = i >> 1
            if (i & 1):
                code[16] = '1'
            i = i >> 1
            if (i & 1):
                code[5] = '1'
            i = i >> 1
            if (i & 1):
                code[6] = '1'
            i = i >> 1
            if (i & 1):
                code[4] = '1'
            i = i >> 1
            if (i & 1):
                code[17] = '1'
            i = i >> 1
            if (i & 1):
                code[7] = '1'
            i = i >> 1
            if (i & 1):
                code[8] = '1'
            i = i >> 1
            if (i & 1):
                code[10] = '1'
            i = i >> 1
            if (i & 1):
                code[11] = '1'
            i = i >> 1
            if (i & 1):
                code[12] = '1'
            i = i >> 1
            if (i & 1):
                code[13] = '1'
            i = i >> 1
            if (i & 1):
                code[14] = '1'
            i = i >> 1
            if (i & 1):
                code[0] = '1'
            i = i >> 1
            if (i & 1):
                code[15] = '1'
            i = i >> 1
 
            print(code)
 
            sortir = 1
            break
 
    if sortir:
        break

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值