深度分析 (dnspy破解某收费.net软件) 注册机篇(RSA非对称加密精髓)

查看 153|回复 9
作者:gksj   
前言
本文作为本栏目下原贴   "关于 dnspy破解某收费.net软件注册码的探讨" 的深入研究帖子
原帖地址:
https://www.52pojie.cn/thread-1612175-1-1.html
本帖目的与价值
1.介绍基于.NET的C#窗口程序启动逻辑架构
2.dnspy软件关于IL代码的编辑(对于直接修改代码报错或者有软件大小自效验的程序适用)
3.借鉴学习软件作者的验证程序逻辑
4.借鉴软件作者程序代码中对注册表,表格,加密解密算法代码的学习
关于这个软件分析共分两个章节(爆破与注册机)
本篇内容是注册机篇
爆破篇地址  https://www.52pojie.cn/thread-1614580-1-1.html
注册机篇地址 https://www.52pojie.cn/thread-1614583-1-1.html
概览
注册界面验证逻辑架构:
注册按钮事件中判定逻辑明细btn_active_Click


a.png (57.67 KB, 下载次数: 0)
下载附件
2022-4-1 01:33 上传

将注册码文本框中内容赋值到内部定义变量text
将text内容传递给注册算法的方法SecurityUtil.Verify,并读取返回值(true/false)
        false
                弹窗(注册码错误);返回
        true
                弹窗(激活成功)→初始化注册表(建立注册表类)→将text文本写入注册表license键值→弹出重启对话框→
                点击确认按钮→软件重启
注册算法逻辑架构Verify


aa.png (71.38 KB, 下载次数: 0)
下载附件
2022-4-1 01:33 上传

`bool flag = rsacryptoServiceProvider.VerifyData(Encoding.UTF8.GetBytes(string.Format("[{0}][{1}][{2}]", networkAdpaterID, SecurityUtil.Encrypt(SecurityUtil.passwd), array[1])), "SHA", signature);`
     将注册码用分隔符拆分成数组→获取网络配置信息→导入RSA公钥→将注册码拆分数组第一部分从BASE64还原成字节→效验签名返回值
     效验签名方式:[网络信息][加密后的设定密码][拆分后的注册码第二部分],SHA比较,注册码第一部分字节
     效验成功返回true,失败返回false
客户端申请注册码的内容分析btn_client_Click


b.png (22.68 KB, 下载次数: 0)
下载附件
2022-4-1 01:37 上传

调用生成公钥和私钥方法:保存私钥文件,保存公钥文件


bb.png (38.62 KB, 下载次数: 0)
下载附件
2022-4-1 01:37 上传

获取注册信息:读取私钥文件;网络配置信息;加密后的设定密码


bbb.png (34.54 KB, 下载次数: 0)
下载附件
2022-4-1 01:37 上传

获取第一个可用网卡的MAC地址,并去空格&减号替换成冒号


bbbb.png (64.18 KB, 下载次数: 0)
下载附件
2022-4-1 01:38 上传

归纳整理:
1.申请信息是由2个分号分割的三部分组成:私钥&MAC&加密信息
2.注册码信息是由1个分号分割的两部分组成:私钥签名&拆分注册码第二部分
3.签名前数据是由三部分组成:[MAC][加密信息][注册码第二部分]
是不是很绕?没错,这也是为什么我花了一天的时间研究注册码算法的原因
需要解决以下问题:
对于以前没有接触过RSA的人来说,以下问题需要解决:
rsacryptoServiceProvider.VerifyData三部分 第一部分很容易知道是未处理的源码,第二部分是加密方式,第三部分什么呢?
经过微软MSDN查找到一个链接
https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.rsacryptoserviceprovider.verifydata?redirectedfrom=MSDN&view=net-6.0
参数
buffer
Byte[]
已签名的数据。
halg
Object
用于创建数据哈希值的哈希算法的名称。
signature
Byte[]
要验证的签名数据。
返回
Boolean
如果签名有效,则为 true;否则为 false。
原来是签名,那什么是签名呢?经过好久的搜索又看到了另一个文章
https://blog.csdn.net/e295166319/article/details/52734608
用RSACryptoServiceProvider签名验签
           byte[] messagebytes = Encoding.UTF8.GetBytes("luo罗");
           RSACryptoServiceProvider oRSA = new RSACryptoServiceProvider();
           string privatekey = oRSA.ToXmlString(true);
           string publickey = oRSA.ToXmlString(false);
            //私钥签名
            RSACryptoServiceProvider oRSA3 = new RSACryptoServiceProvider();
            oRSA3.FromXmlString(privatekey);
            byte[] AOutput = oRSA3.SignData(messagebytes, "SHA1");
            //公钥验证
            RSACryptoServiceProvider oRSA4 = new RSACryptoServiceProvider();
            oRSA4.FromXmlString(publickey);
            bool bVerify = oRSA4.VerifyData(messagebytes, "SHA1", AOutput);
研究了半天终于明白了,原来:
已经签名的数据就是没有经过希哈之前的原数据

那希哈的算法就很明显了:
1.导入私钥数据
2.把需要签名的数据转换成字节数组
3.用SignData方法对字节数组进行希哈运算,并返回希哈值
4.希哈值就是要验证的签名数据
那注册码的格式就是:
从注册信息里面提取第二部分数据作为希哈签名的第一部分
从注册信息里面提取第三部分作为希哈签名的第二部分
希哈签名的第三部分作为注册码的第二部分额外添加
所以:注册码分号分割的第二部分信息是自定义的,可以自己填写
所以注册码的生成代码就是这样:
string RegCode = MsgText.Text;  //将客户端注册信息内容复制一份放到RegCode变量中
string[] CodeStr = RegCode.Split(new string[] { ";" }, StringSplitOptions.None);  //将RegCode数据用分号拆分成数组
string PrivateKey = CodeStr[0];            //私钥数据
string MacAddr = CodeStr[1];               //网卡MAC地址
string CheckBase64Password = CodeStr[2];   //软件作者联系方式加密后的秘钥
//自定义的加密信息,猜测可能是作者预留的申请人信息,也可能是授权过期日期(原软件代码里面没有使用这个数据(只在验证秘钥的时候用了)
string FreeCodeText = FreeText.Text;       //自定义加密信息,只在注册码验证的时候用了
//组合私钥签名需要的数据
string PrivateKeyCode = string.Format("[{0}][{1}][{2}]", MacAddr, CheckBase64Password, FreeCodeText);
//将需要私钥签名的字符串转换成字节数组(因为RSA只能处理byte类型)
byte[] PrivateKeyByte = Encoding.UTF8.GetBytes(PrivateKeyCode); //UTF8编码方式,这个在校验签名的时候用的是UTF8,所以要对应
//
RSACryptoServiceProvider RsaOrder = new RSACryptoServiceProvider();//调用(实例化)RSA签名方法
RsaOrder.FromXmlString(PrivateKey); //读取并写入私钥数据
byte[] SignKeyByte = RsaOrder.SignData(PrivateKeyByte, "SHA"); //生成签名数据
string SignKeyText = Convert.ToBase64String(SignKeyByte);//转换签名数据(因为注册时用了FromBase64String还原方法)
string RegKeyText = string.Concat(SignKeyText, ";", FreeCodeText);//组合用于注册的秘钥数据
KeyText.Text = RegKeyText; //将组合后用于注册的秘钥数据写入软件的注册码文本框中
看到了吗,自始至终原软件内都没有把注册码数据放在内存里面进行比较,而且还有自定义验证信息
所以通过下断点去获取注册码的方式已经被作者封的死死的,对于破解小白来说根本就没有通过断点大法截取秘钥的可能性.
不过通过三天的时间,我弄懂了RSA公钥私钥非对称加密的方法和一些概念,至少以后自己想用RSA去做注册码,会挡住大部分新手
在编写注册机的过程中,我也用到了这个软件里面的一些东西,比如:
注册表的读写(注册码直接写入注册表,无需开启软件)
正则表达式判断注册信息格式是不是正确
调用VB的数据输入框来输入数据
Format格式化数据
DES的加密与解密
内部外调数据的处理
回报
我把我写的注册机的源代码项目文件分享出来,也是给.net逆向的水友们一个学习C#编程开始的范例模板和学习动力
启动验证界面


c.png (12.52 KB, 下载次数: 0)
下载附件
2022-4-1 01:44 上传

注册机主界面


cc.png (62.6 KB, 下载次数: 0)
下载附件
2022-4-1 01:44 上传

生成的注册码进行注册


ccc.png (38.6 KB, 下载次数: 0)
下载附件
2022-4-1 01:45 上传

1.注册机启动时是需要密码的,这个密码需要大家去破解了,哈哈哈,也算是给水友们出的一个题目,共同进步嘛
2.注册机没有加密或者混淆处理过,dnspy打开就行了,密码就写在软件的源代码里面哦
3.注册机的启动密码位置和我以前发过的帖子的分析过程有高相似度,找到了对你以后.net逆向也是提升
4.注册机中应用了很多关于FORM事件的东西,这对大家以后分析大型软件时很有帮助
5.注册机源代码我做了非常详细的注释(注释基本上都快和代码一样多了),新手阅读起来很容易理解
6.注册机就作为交流学习,切勿外传用于商业用途.
7.注册机禁止爆破以后外发,保护本篇文章分析的软件作者利益不受损害.
8.注册机源代码的解压密码和注册机启动密码一样哦!
总结
通过这个软件的代码分析,这个软件中使用的代码可以作为C#软件代码开发初学者的经典程序
软件代码干净整洁,变量使用规整精炼
所调用插件的入口函数清晰,程序架构清晰.
几个问题留在这里,是我在测试中发现的,你们来分析一下
1.为什么将试用期改为10年之后软件直接提示已到期?
2.为什么虚拟机和实体机转换后注册秘钥失效?
3.未经过希哈运算的完整数据格是什么样的?
4.是否在调试的时候可以获取到真正的注册码?
5.32位和64位系统注册表的读取位置是否一样?
6.这个软件在验证方面有哪些不足?
7.以你对这个软件验证授权的方式有什么更改的建议?
原版软件,注册机,注册机CSharp源代码文件下载地址:
http://2950800.ysepan.com/
文件夹访问下载密码:52pojie

注册码, 注册机

orangemeow   


wtujoxk 发表于 2022-4-2 13:33
看下面的回复楼层!

看了一下,意义不大。仅256位的RSA加密确实有可能被优化的因式分解算法破解,但本质上与暴力破解无异。目前常用的RSA加密位数则是2048位或4096位,是理论上不可能破解的。
附:我试着破解你那个程序的公钥得到的私钥,大概在一分钟以内就可以产生一组解,但这本质上仍然是暴力破解,密钥长度的增加会使这样的尝试完全没有意义。
-----BEGIN RSA PRIVATE KEY-----
MIGrAgEAAiEAtBsC69X4FZb7G2yl9aEhrGA7FZPyGszXXJ87GAWo0ysCAwEAAQIgTTp/6CyZ8ngJ
ONs/1rG/Q/fWNmtaA5jn1mgIHgO44xECEQDu1RDy5ZzBdFht9TyVrX8/AhEAwQ1E8oWRyS7OVlgv
d2zdFQIRAI+ROitTTRaEhEf/giwNFKoCECo0m30iHJwiwGALvRp82UsCEQDIG39R0bEjcBXtdYvP
V9sY
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIGqAgEAAiEAtBsC69X4FZb7G2yl9aEhrGA7FZPyGszXXJ87GAWo0ysCAwEAAQIgTTp/6CyZ8ngJ
ONs/1rG/Q/fWNmtaA5jn1mgIHgO44xECEQDBDUTyhZHJLs5WWC93bN0VAhEA7tUQ8uWcwXRYbfU8
la1/PwIQKjSbfSIcnCLAYAu9GnzZSwIRAI+ROitTTRaEhEf/giwNFKoCEB9NSoBQndOwGzFkTYBe
RMw=
-----END RSA PRIVATE KEY-----
gksj
OP
  


orangemeow 发表于 2022-4-1 20:19
无法理解,这个程序利用RSA的算法让人摸不到头脑。
是这样的,RSA的正确使用方法是这样:软件开发者私藏 ...

确实是这样的,这个软件存在太多疑点了和疑问
1.软件没有没有进行任何混淆或者加密.
2.软件代码有很多方法根本就没有被调用过
3.软件验证授权放在了FORM的LOAD事件里面,这样如果是动态调试很快就能追到验证为.
4.私钥作为客户端注册信息直接生成并保存在本地
5.使用第一个ENABLE的MAC地址,一旦这个MAC对应的网卡不是内网SQL数据库服务器通信的网卡,被禁用掉了那么这个注册码也就失效了.
6.软件验证授权只在启动时进行了验证,验证位置过于集中.
7.删除注册表键值就可以无限期试用,那注册就变得没有意义
8.如果有人用HOOK方式直接禁用掉了LOAD事件,那么注册验证将毫无意义.
请叫我老龚   

@Hmily 你看这个帖子的排版可以吗?有什么好的建议吗?谢谢!
不知道外链是否合规
gksj
OP
  


gksj 发表于 2022-4-1 17:00
@Hmily 你看这个帖子的排版可以吗?有什么好的建议吗?谢谢!
不知道外链是否合规

目前看挺好的,外链这个你就需要好好检查一下了,内容不能出现违规,比如强调的侵权成品和联系方式不要出现。
gksj
OP
  

文本附件下载地址
https://gksj.lanzouq.com/b036ufzza
密码:e6ji
yespan连接以后可能失效
wwb66668   

感谢楼主的分享
orangemeow   

无法理解,这个程序利用RSA的算法让人摸不到头脑。
是这样的,RSA的正确使用方法是这样:软件开发者私藏一个密钥(私钥),客户端保存一份密钥(公钥),客户只要把一些必要的信息提供给开发者,开发者用私钥签名后返还给客户,客户端使用公钥对签名串进行校验即可。这个过程的坚固性是数学和密码学所确保的,无论如何也不可能在不破解程序(或修改客户端自带的公钥)的情况下制作注册机。
我已经有点忘掉了.net的语法,但源代码里似乎看到了生成私钥这个语句,也就是客户端当场生成密钥对,这是我难以理解的。我觉得楼主你可能恰好遇到了一个使用RSA算法的错误案例,说实话,如果真的有人能在不修改主程序的情况下制作真正的RSA算法的注册机,那世界网络安全的基石就被打破了。
glorymusic   

学习了,RSA的非对称加密,安全性还是很高的啊。再仔细琢磨琢磨。
wuaipipixia888   

鄙人小白一枚 特来楼主这里学习受教
您需要登录后才可以回帖 登录 | 立即注册

返回顶部