`
yidongkaifa
  • 浏览: 4066006 次
文章分类
社区版块
存档分类
最新评论

破解 bytescout Barcode SDK (2.2.0.343)

 
阅读更多

声明:本文纯粹出于学习目的,如果用于商业目的造成法律责任后果自负。


bytescout 的收费条码SDK库很不错,需要购买License,但毕竟是用.Net语言写的,如何保证license不失效呢?这周末不加班,没事儿就试着破解一下,着实还费点儿劲,时间加到一起估计得有10个小时以上了,比以前破解致得E6文档管理系统、Visual SVN花的时间多多了,而且这次并没有彻底破解,只是时间问题,就不纠结到这儿了,学习的目的已经达到。


首先下载SDK包

http://bytescout.com/download/trial/barcodesdk.html

安装完之后在安装目录里会有.Net 1.0~4.0的各个版本编译好的二进制程序库,另外还有两个程序作为演示。其中一个在BarCodeGenerator目录里,另一个就在安装目录的根目录。

第一招:还是按照老套路,请出Reflector,打开Bytescout.BarCode.dll,结果没那么好,程序集使用混淆器进行了混淆,所有变量和函数名都进行了重命名,要命的是都使用了非可见字符, 而且导出的时候reflector总是抛出异常,反编译失败。 然后,又找到ILSpy (http://wiki.sharpdevelop.net/ILSpy.ashx),虽然速度慢点儿,但可以反编译的代码多了些,却仍然不能反编译出可编译的代码。一开始尝试通过使用ILSpy分析出的函数、变量的引用关系,加上代码把几个关键的类还原出来,但那些变量都是非可见字符,整出来还是要花些时间的。

第二招:那就再试ildasm反编译成IL代码,看能不能在Visual Studio中进行调试,这样速度会快很多,因为只要从Barcode类的构造函数跟踪进去就可以了,构造函数有两个参数一个就是license的账号,另一个是密钥。程序集都使用了SuppressIldasm:

[assembly: SuppressIldasm]

,直接用ildasm直接反编译还不行,需要一个技巧(http://murphy.globalpatrol.net/2011/06/how-to-get-around-protected-module-cannot-disassemble/),使用UltraEdit打开程序集,在二进制下搜索ASCII串”SuppressIldasmAttribute“,然后把相应的二进制数据都填成0,再用ildasm反编译即可。可以在visual studio里直接用GUI打开,也可以在命令行

ildasmBytescout.BarCode.dll /UTF8 /out:Bytescout.BarCode.il

然后修改代码后再重新编译:

ilasmBytescout.BarCode.il /DLL

我先试了一下重新编译后是否还可以运行,但是再重新编译后的程序集有问题,总是加载不成功,也不知道是不是还需要其它的文件,使用代码保护后要处理密钥的问题,暂时先放一下。

第三招: 想起来安装的时候运行那个BarCodeGenerator生成的条码图中是没有演示版本里面的那个讨厌的版本号的,那就是说肯定有个地方是保存了密钥,或者有其它方法解决的,于是从BarCodeGenerator.exe下手。从ILSpy反编译的C#代码和ILDASM反编译的IL代码可以看出启动时的那个窗口燎是MainForm2,那就是说mainframe2中肯定有一个Barcode对象或BarcodeControl对象,而每一个Barcode对象都有两个属性RegistrationName和RegistrationKey,这两个license的账号,得到Barcode对象后就可以通过这两个属性得到license。

本来想在IL中加入弹出对话框或在控制台输出license的代码,但编译后的IL总是无法运行。


又想到反射,因为发现MainForm2是public,那就是说可以再写一个程序,然后创建一个MainForm2的对象,然后就可以访问里面的Barcode对象或BarcodeControl对象直接获取密钥。分析ILSpy反编译的MainForm2的一个私有方法,该方法没有任何参数,正是从窗口中获取各项设置,然后生成一个条码,其返回值正是生成的条码,只要能通过反射获得这个方法,然后调用这个方法生成一个Barcode对象问题就解决了。代码如下:

class Program
	{
		static void Main(string[] args)
		{
			Form display = new Form();
			display.Width = 300;
			display.Height = 100;
			display.FormBorderStyle = FormBorderStyle.FixedDialog;

			Label lbl = new Label();
			lbl.AutoSize = true;
			lbl.Text = "用户名:";
			display.Controls.Add(lbl);

			TextBox txtUser = new TextBox();
			txtUser.Width = display.Width - lbl.Width - 40;
			display.Controls.Add(txtUser);
			lbl.Location = new Point(10, 10);
			txtUser.Location = new Point(lbl.Right + 10, lbl.Top);

			Label lblKey = new Label();
			lblKey.Text = "序列号:";
			display.Controls.Add(lblKey);
			lblKey.AutoSize = true;

			TextBox txtKey = new TextBox();
			txtKey.Width = display.Width - lblKey.Width - 40;
			display.Controls.Add(txtKey);

			lblKey.Location = new Point(10, lbl.Bottom + 10);
			txtKey.Location = new Point(lblKey.Right + 10, lblKey.Top);

			try {
				Bytescout.BarCode.MainForm2 form = new Bytescout.BarCode.MainForm2();  // 创建一个窗体对象
				form.ShowDialog();
				form.FormClosing += new FormClosingEventHandler(form_FormClosing);
			

				Type formType = form.GetType();
				MethodInfo[] methods = formType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance); // 获取所有方法
				MethodInfo getCode = null;
				foreach (var m in methods) {// 找出生成Barcode对象的方法
					if (m.ReturnType.FullName == "Bytescout.BarCode.Barcode") { 
						getCode = m;
						break;
					}
				}
				if (getCode != null) {
					// 调用方法生成Barcode对象
					Bytescout.BarCode.Barcode code = (Bytescout.BarCode.Barcode)getCode.Invoke(form, null);
					txtUser.Text = code.RegistrationName;
					txtKey.Text = code.RegistrationKey;
				} else {
					MessageBox.Show("FAILED!");
				}
				display.ShowDialog();
			} catch (Exception ex) {
				MessageBox.Show(ex.Message);
			}
		}


		static void form_FormClosing(object sender, FormClosingEventArgs e)
		{
			Bytescout.BarCode.MainForm2 form = sender as Bytescout.BarCode.MainForm2;
			e.Cancel = true;
			form.Hide();
		}
	}

当然,编译的时候要添加对BarCodeGenerator.exe和Bytescout.BarCode.dll的引用。

bytescout还是花了很大力气在软件保护上的,但还是有漏洞,不仅仅是软件开发过程中的问题,.Net本身也有安全漏洞,先说说软件开发过程中的问题:

1) MainForm2本来只是作为程序中的主窗体用的,没有必要使用public,可以用internal,这样我上面就不能直接创建对象了,当然通过反射也是可以的,这个不是根本问题;

2) RegistrationName和RegistrationKey两个属性完全可以定义为只写的,把get方法去掉,我这儿的方法就不好使了。那样我话就得直接从管理密钥的加密算法相关类中直接获取了,那些类都不是public,而且名称不可见,还得使用反射进行摸索,摸到那个函数再调用(其实就是从静态的HashTable中获取数据)。

3)最严重的其实是那个示例程序不该一起发布到程序包里,或者别把某个license加进去,.Net很不安全。


再说说.Net的问题:

1) SupressIldasm太容易就被破解掉了,实际上应该就是一个标志位,而且是字符串,如果是个二进制的数也会好些;

2) 反射这东西安全性太差了,既然是private却仍然可以调用,安全何在?如果Type.GetMethods( )方法不能获取私有方法这招就不好使了,当然反射本身也就会有很多限制。


.Net、Java有很多优点,当然也有很多缺点,方便了自己也方便了破解,话又说回来,无论是用哪种语言写的程序总会被破解的,只是难度大小问题,破解也只是成本问题,得要看成本划不划算。想想windows的加密机制的演进,最有效的仍然是网络授权,通过实时的检查来进行限制,但软件并不是都需要联网的,通过网络授权的限制太大,USB硬件密钥对于非网络版的软件可能会更安全,这种方案银行也在用。但USB硬件密钥理论上也不是100%有效,只是破解难度较大而已,因为硬件与软件中间还有一层驱动,从驱动层进行破解,仍然是限制不住的。


如何保护自己的软件,还需要多思!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics