浙江财经大学
信息管理与工程学院

C#软件破解实战(一)–注册机

本文由 Ocrosoft 于 2016-04-26 22:19:15 发表

重装了MYSQL,之前写的全没了……

———————————————————————————————————————————

这次的实战破解软件是用C#编写的,出品公司为”海贝益友“,是一款计算机二级Office自我测评软件.

———————————————————————————————————————————

1.先用Reflector打开程序文件.

1

2.很简单地找到了注册码段,软件没有进行混淆,所以加密的代码全部都暴露出来了.

2

3.分析代码,发现验证过程是这样的:

    3.1.一开始,有机器码(s1);

    3.2.然后用户输入了一个注册码(s2);

    3.3.接下来,程序从注册码取第1,3,5,7,9…位,从机器码取第2,4,6,8,10…位,放到相应的位置组合成一个新的字符串(s3);

    3.4.取s3的第1,2位,将这两位的字符ASCII码相加,对36取余得到一个数(num1),在上方的数组(字典)中找到num1位置的对应的字符(注意:数组的下表是从0开始的,如果num1等于1,则是第二个字符),将这个字符保存到新字符串(s4)的第2位;

    3.5.取s3的第2,3位,重复上一步,保存到s4的第3位……取s3的第19,20位,重复上一步,保存到s4的第20位;

    3.6.将s2的第1位保存到s4的第一位;

    3.7.对比s2和s4,如果全部一样,就注册成功;

4.既然知道了是如何验证的,那么考虑要如何推出注册码.

    4.1.倒推出注册码貌似是不可能的,而且注册码应该不唯一.

    4.2.那就来暴力:枚举出所有的可能性,然后取验证是否正确.

    4.2.1.但是,如果直接枚举20位注册码,最坏的情况是20!,351928天…

    4.2.2.所以考虑一位一位来,先随机取第1位,然后枚举第2位,在字典中查出第2位,得出s4的第2位,和注册码第2位对比,如果相同,继续枚举第3位,不同则继续枚举第2位或第1位.

    4.2.3.具体的实现方法,就是DFS.(算法总算有用了…)

5.开写.(为保护开发者权益,不公开所有代码,仅放出DFS代码供研究)

void dfs(int pos)
{
    for(int i=0; i<36; i++)
    {
        if(flag)return;
        PrivatePWD[pos]=chArray[i];
        if(pos%2!=0)
        {
            chArray2[pos]=UserPublicPWD[pos];
            if(chArray[(chArray2[pos-1]+chArray2[pos])%36]==PrivatePWD[pos])
            {
                if(pos==23)
                {
                    for(int i=0; i<24; i++)
                    {
                        printf("%c",PrivatePWD[i]);
                    }
                    printf("\n");
                    flag=true;
                    return;
                }
                else
                    dfs(pos+1);
            }
        }
        else
        {
            chArray2[pos]=PrivatePWD[pos];
            dfs(pos+1);
        }
    }
}

6.注册成功

3

PS:其实更加简单的方法是—–爆破!这个程序的爆破比写注册机简单多了.

但是由于有了注册机,下次的爆破将更换更为复杂的程序(写不出注册机).

PS:程序更新后,只是更换了字典.

提醒开发者:C#最好进行混淆,把验证写得复杂,最好把验证机制放到服务端.

重写:(这样好看多了)

#include <set>
#include <map>
#include <list>
#include <cmath>
#include <stack>
#include <queue>
#include <ctime>
#include <string>
#include <cstdio>
#include <vector>
#include <cctype>
#include <climits>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
#define ms(a) memset(a,0,sizeof(a))
typedef long long ll;
const int INF = INT_MAX;
const int MAXN = 1000 + 10;
using namespace std;
bool flag = 0;
char chArray[]
{
	'L', 'U', '3', 'A', 'R', '4', 'K', '5', 'F', '6', 'M', '7', 'Y', '8', 'W', '9',
		'B', 'D', 'E', 'H', 'I', 'N', 'P', 'Q', 'S', 'T', 'V', 'X', 'Z', 'J', '0', 'O',
		'G', '1', 'C', '2'
};
char PrivatePWD[30] = { '0' };
char UserPublicPWD[30];
int main()
{
	srand(time(0));
	while (cin >> UserPublicPWD)
	{
		for (int i = 0; i < 24; i++)
		{
			if (!(i % 2))PrivatePWD[i] = chArray[rand() % 36];//加上随机数生成的比较好看
			else PrivatePWD[i] = chArray[(PrivatePWD[i - 1] + UserPublicPWD[i]) % 36];
		}
		cout << PrivatePWD << endl;
	}
	return 0;
}

欢迎分享与转载,请保留链接与出处。Ocrosoft » C#软件破解实战(一)–注册机

点赞 (0)or拍砖 (0)

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    机器码QIPIBB7W3G2MQE1X0QGFG0OH 求大神破解啊

    安情缘5个月前 (08-16)回复