某系列文档转换库 注册码逆向分析
本帖最后由 pjy612 于 2023-3-14 00:26 编辑### 前情提要
因为某个老项目 的 HTML to PDF 组件,有问题了需要修。
然后网上找了下解决方案,结果大部分是收费的。最终用的还是MIT的。
但是也有不少虽然不能用在项目里,但是可以拿来练手的。
### 受害者 来源
https://stackoverflow.com/questions/564650/convert-html-to-pdf-in-net
列表中 **UERGIE1ldGFtb3JwaG9zaXMgLk5ldA==** 所在系列 其中一员 ** RG9jdW1lbnQgLk5ldA== **
虽然它不是 pdf 的,但是里面逻辑全面一点,其他库 核心逻辑 和算法一致
### 正篇开始
先上demo代码。
```C#
// NOTICE: Place this line firstly, before creating of the DocumentCore object.
DocumentCore.Serial = "1234567890";
// Let's create a new document by activated version.
DocumentCore dc = new DocumentCore();
dc.Content.End.Insert("Hello World!", new CharacterFormat() { FontName = "Verdana", Size = 65.5f, FontColor = Color.Orange });
// Save a document to a file in DOCX format.
string filePath = @"Result.docx";
dc.Save(filePath);
```
首先 扔到 dnspy 里面看看情况,发现有自定义混淆。
为了方便后续分析 找到字符串相关的 混淆的Token 用 de4dot 预先处理一下。
然后 license 的关键词是 Serial,查下引用
校验逻辑围绕 Load 和 Save,看着没啥暗桩。
那就直奔主题。
可以看到 校验完 license 之后 跟着的就是水印逻辑。
那么 只要 返回值 不在 switch 逻辑中 也就是 **Enum14** 不是 1-3 就不会有水印。
# b( ̄▽ ̄)d 找到了 我们在这里爆破就可以收工啦!!!#
开个玩笑,用Nuget的包 因为不少都有关联,不推荐去爆破它...还是逆向算法吧...
那么我们继续往里面看 Class121.smethod_1 的逻辑。
有两个函数 Class121.smethod_3 和 Class121.smethod_0
Class121.smethod_3 返回类型 **Enum13**
Class121.smethod_0 返回类型 **Enum14**
然后 Class121.smethod_0 里面又调用了 Class121.smethod_3
那么 重点应该在 Class121.smethod_0 里面
那么 license 的 核心逻辑 就是 Class121.smethod_3
额外校验在 Class121.smethod_0
其中 Class121.smethod_2(out text, out text2, out text3);
可以看到是根据 当前程序集 获取 一些 用于验证的项。
然后根据逻辑分析
```C#
if (@enum <= (Class121.Enum13)2332)
{
if (@enum == (Class121.Enum13)2329 || @enum == (Class121.Enum13)2332)
{
if (text != "Document .Net")
{
return (Class121.Enum14)3;
}
goto IL_105;
}
}
```
**RG9jdW1lbnQgLk5ldA==** 对应的 **Enum13** 应该为 2329 或 2332
结合 上图 Class121.smethod_3 的内容
那么也就是 我们用的 license 必须满足 下面的条件
```
enum = (Class121.Enum13)((string_0 * '\a' + string_0 * '\r' / (string_0 * '\v' + '\u0001') + string_0 * '_' + string_0 * 'X' + string_0 * 'T' + string_0 * 'E' + string_0 * ',' + string_0 * 'W' + string_0 * '\u0015' + string_0 * 'W') / (string_0 * 'U' - string_0 * 'Y' + string_0 * '-' - string_0 * 'U' - string_0 * '8' + string_0 * '\u0081' - string_0 * 'K' + string_0 * '^' - string_0 * 'X' + string_0 * 'n' - string_0 * 'N'));
// enum == 2329 ||enum == 2332
```
再继续看
里面没有时间限制 但是有版本限制,结合开头部分的代码。
**Enum14** 为 0 则 无水印
好耶!可以在开头爆破了!(bushi...
```
if (major <= num)
{
enum2 = (Class121.Enum14)0;
}
return enum2;
```
也就是我们的 license 的 第一位 要大于等于 当前程序集 的 **Version.Major**
然后 如果想长期使用并且能更新的话 第一位最好是 **9**
结论,我们要弄出一个 长度11 (多了没啥用)并且首位是9的字符串。
然后满足上面的等式就行!
那么问题来怎么做呢?
对不起。。。我不会。。。我没看懂。。。我没想出来。。。
我偷懒去问了chatgpt,然后 它 顾左右而言他。。。
最后 穷举吧...(实在太丢人了,穷举的代码就不发了...期待算法大佬逆向下看看这玩意到底怎么算的....)
然后 我们就算出了个结果 **OTAwMDIzOTM3OTg=** !
然后 放到 Demo 代码中跑一下! ok 没水印了!完美(穷举)收工!
### 附录
该产品系列其他库对应 code
|产品|code|
| -------------|--------------------|
|UERGIFZpc2lvbiAuTmV0 |847 |
|VXNlT2ZmaWNlIC5OZXQ= |2131 |
|RXhjZWwgdG8gUERGIC5OZXQ= |2118 |
|RG9jdW1lbnQgLk5ldA== |2329 2332 |
|UlRGIHRvIEhUTUwgLk5ldA== |2129 |
|SFRNTCB0byBSVEYgLk5ldA== |3031 |
|UERGIE1ldGFtb3JwaG9zaXMgLk5ldA==|5128 |
|UERGIEZvY3VzIC5OZXQ= |3026 3027 3029 3028|
calc count= 10000000000
key count = 71097
seconds = 30
last key = 99999979588
优化一下算法,30秒可以算完所有key,共71097个。 solly 发表于 2023-3-17 16:06
calc count= 10000000000
key count = 71097
seconds = 30
我本来是拿ascii字符去算的然后进位和回退好麻烦...
等实现完了才想到 纯数字就行....🤣
那样算起来就简单了...
一个for或者多线程分段算一下汇个总,但实际还是穷举.... {:301_1004:}
虽然结尾有些拉跨...
但是 确实没想到 它该怎么正向生成的,咱就倒着穷举了。。。 学习,这个需要再次处理,不过没水印也行,反正我是截图,ps收拾水印。 哈哈哈哈, 我的想法第一时间也是穷举。压根不想考虑怎么逆向。
第一位9 后面10位 疯狂+1,然后 把那段验证扔进去,做好判断,跳出。
搞定! 学习了,感谢分享 谢谢提供和分享 谢谢提供和分享
学习了,感谢分享
学习了,感谢分享 谢谢分享
页:
[1]
2