吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8763|回复: 66
收起左侧

[.NET逆向] 用Mod的思路去给第三方库打补丁

[复制链接]
pjy612 发表于 2023-1-18 11:43
本帖最后由 pjy612 于 2023-2-1 20:05 编辑

一般去使用一些第三方库的时候,如果想去水印很多的时候都是硬编码反编译DLL。
这样一旦更新什么的就要重新操作一遍,费时费力。
如果是反射和注入的话,又不一定能很好的定位静态对象。
那么有没有类似Aop的Hook 能帮忙我们对运行中的库动态打补丁和加Hook呢?

还真有。。。HarmonyLib 和 HarmonyX
一般这两个常用的是 基于 BepInEx 给 Unity 游戏做Mod。但我们也能把他用在.Net应用上。

下面就拿一个 有水印的 office 文档处理的库 做个示范演示一下。
111.png
坛子里有大佬发过对应的逻辑,都是基于过期的license处理。这里不过多的说明

但是 license 都是有 RSA 验签的。
那我们能不能不改动整个 license,但是 在 dll 读取 过期时间的时候 我们去hook它呢?
license 的格式是 XML的 所以肯定会用到 XML相关的读取函数。那么我们对它进行Hook。

222.png
Hook  XmlElement 属性的 InnerText 的 Getter 函数,如果 当前是在读取  SubscriptionExpiry 我们直接将 返回值 "20200827" 修改成 "20991231"。

这样不影响 校验部分对整个 xml 做 校验。但是单独变更了 过期时间。

同理 有的DLL 是用的 XmlReader 的 ReadString ,我们也处理一下。
333.png

那么问题来了,有些DLL 在 读取完时间之后 还会又重新验证下 这个内容是否是真的在 xml 里面。
444.png
我们也Hook 一下,如果检查的时候我们自己修改的新过期时间,就给改成一个 大于 -1 的就行。


然后问题来了,那个 StackInAspose 函数是什么?
因为我们Hook 的都是 底层函数,虽然加了一些前置判断 为了避免影响到其他 逻辑,判断一下调用堆栈。
555.png
只 Hook 对 SetLicense 之下的调用链做处理。

然后 既然是针对 系统函数的Hook ,那么我们 对这种仅一次授权验证的 需要在Patch完后及时释放掉。
所以 Patch类用 using 包裹比较好。
666.png

最后 使用上就是
777.png
new 对象的时候 激活 Harmony 的 Patch。
析构时 解除 Patch。

测试结果
888.png

水印都成去除。

总结,
使用 HarmonyLib 的好处就是,不用每次针对性 修改DLL,也不需要处理 DLL之前的强命名关联等。全部在运行时中打补丁。
当然 补丁前 该怎么Hook 的分析还是要的。

PS:
用好了这个大杀器 对一些 RSA 验签也可以无脑 return true. 可以单独只逆向算法,不用去想公钥私钥的问题了。


PS2:
cell 库 里面有个 随机数控制的 暗桩 所以需要 针对性静态Patch一下(见回复)
其他库不清楚什么时候也会实装类似的校验。

免费评分

参与人数 9威望 +1 吾爱币 +28 热心值 +7 收起 理由
coffee0818 + 1 谢谢@Thanks!
frozleaf + 1 + 1 我很赞同!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
chyuyuguo2004 + 1 + 1 我很赞同!
decai + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 谢谢@Thanks!
光之优雅 + 1 + 1 用心讨论,共获提升!
1MajorTom1 + 1 热心回复!
sdieedu + 2 鼓励转贴优秀软件安全工具和文档!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| pjy612 发表于 2023-2-1 17:56
本帖最后由 pjy612 于 2023-2-10 15:47 编辑
dplxin 发表于 2023-2-1 14:08
那就这个帖子回复,
我这边还有个今天能用的 license  你可以试一下

Cell 里面有个随机数暗桩  = =。 看了下 没虚拟化 有三处调用,保存 或者 用了图表 可能 概率性触发。
其他的库里面还没看到。。。
c1.png

c2.png

c3.png

AsposeLicensePatch 里面针对 Cell 加个静态Patch吧。。。

RSA Patch 的话 控制 日期 小于 20600101 即可。

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private static Harmony staticHarmony;
static AsposeLicensePatch()
{
    staticHarmony = new Harmony($"{nameof(AsposeLicensePatch)}_Static");
}
static MethodBase _cellCheckMethod = null;
public static bool PatchCell(Type cell)
{
    if (_cellCheckMethod != null && staticHarmony.GetPatchedMethods().Contains(_cellCheckMethod)) return true;
    Type[] types = AccessTools.GetTypesFromAssembly(cell.Assembly);
    Type[] array = types.Where(t =>
    {
        if (t.IsSealed && t.IsClass)
        {
            List<ConstructorInfo> constructors = AccessTools.GetDeclaredConstructors(t, false);
            if (constructors.Count == 1)
            {
                ConstructorInfo constructorInfo = constructors.First();
                ParameterInfo[] parameterInfos = constructorInfo.GetParameters();
                if (parameterInfos.Length == 2)
                {
                    if (parameterInfos[0].ParameterType == typeof(string) && parameterInfos[1].ParameterType == t)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }).ToArray();
    if (array.Length == 1)
    {
        _cellCheckMethod = AccessTools.FirstMethod(array[0], m => m.ReturnType == typeof(bool));
        staticHarmony.Patch(_cellCheckMethod, new HarmonyMethod(typeof(AsposeLicensePatch), nameof(ForceBoolFalse)));
    }
    return _cellCheckMethod != null && staticHarmony.GetPatchedMethods().Contains(_cellCheckMethod);
}
static bool ForceBoolFalse()
{
    return false;
}
/*
using (new AsposeLicensePatch())
{
   new Aspose.Cells.License().SetLicense(new MemoryStream(buffer));
}
//接在 using 处理之后 静态处理
AsposeLicensePatch.PatchCell(typeof(Aspose.Cells.License));
*/

析构函数的代码 最好也改改 主要是 this.Dispose
[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
~AsposeLicensePatch()
{
    this.Dispose(false);
}
private bool _isDisposed = false;
protected virtual void Dispose(bool disposing)
{
    if (!this._isDisposed)
    {
        if (disposing)
        {
            harmony?.UnpatchSelf();
        }
        this._isDisposed = true;
    }
}
 
public void Dispose()
{
    this.Dispose(true);
    System.GC.SuppressFinalize(this);
}


 楼主| pjy612 发表于 2023-8-23 11:01
本帖最后由 pjy612 于 2023-8-23 11:24 编辑

最新版的 Words 23.8 里面取值部分有些变动。可以额外Patch个地方处理。
再其他的 就请自行研究了。@dplxin
[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
[HarmonyPatch(typeof(XmlCharacterData), "Data", MethodType.Getter)]
[HarmonyPostfix]
private static void Postfix_XmlText_Data_Getter(XmlCharacterData __instance, ref string __result, MethodInfo __originalMethod)
{
        if (StackInAspose())
        {
                var stacks = new StackTrace().GetFrames();
                if (stacks.Any(s => s.GetMethod().Name.StartsWith("get_OuterXml")))
                {
                        return;
                }
                var parentNod = __instance.ParentNode;
                if (parentNod == null) return;
                if (parentNod.Name == "SubscriptionExpiry" || parentNod.Name == "LicenseExpiry")
                {
                        __result = NEW_EXP;
                }
        }
}

        
peikesmart 发表于 2023-11-9 20:07
感谢,我用net 6.0和Aspose.PDF最新版本23.10打上补丁了。
下面是代码。
[C#] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
internal class AsposeLicensePatch : IDisposable {
    private Harmony harmony;
    private const String NEW_EXP = "20591231";
 
    public AsposeLicensePatch()
    {
        harmony = Harmony.CreateAndPatchAll(this.GetType(), nameof(AsposeLicensePatch));
    }
 
    static Boolean StackInAspose()
    {
        var stacktrace = new StackTrace();
        var stackFrames = stacktrace.GetFrames();
 
        if (stackFrames == null) return false;
        var isAsposeLicense = stackFrames.Any(r => r.HasMethod() && r.GetMethod().Name == "SetLicense" && r.GetMethod().DeclaringType != null && (r.GetMethod().Module.ScopeName.StartsWith("Aspose.") || r.GetMethod().Module.ScopeName.StartsWith("GroupDocs.")));
 
        return isAsposeLicense;
    }
 
    ~AsposeLicensePatch()
    {
        this.Dispose(false);
    }
 
    private bool _isDisposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!this._isDisposed)
        {
            if (disposing)
            {
                harmony?.UnpatchSelf();
            }
            this._isDisposed = true;
        }
    }
 
    public void Dispose()
    {
        this.Dispose(true);
        System.GC.SuppressFinalize(this);
    }
 
    // https://www.52pojie.cn/thread-1737340-1-1.html
    [HarmonyPatch(typeof(XmlElement), "InnerText", MethodType.Getter)]
    [HarmonyPostfix]
    private static void Postfix_XmlElement_InnerText_Getter(XmlElement __instance, ref String __result, MethodInfo __originalMethod)
    {
        if (StackInAspose())
        {
            if (__instance.Name == "SubscriptionExpiry")
            {
                __result = NEW_EXP;
            }
        }
    }
 
    [HarmonyPatch(typeof(XmlReader), "ReadString")]
    [HarmonyPostfix]
    private static void Postfix_XmlReader_ReadString(XmlReader __instance, ref String __result, MethodInfo __originalMethod)
    {
        if (StackInAspose())
        {
            if (__instance.LocalName == "SubscriptionExpiry")
            {
                __result = NEW_EXP;
            }
        }
    }
 
    [HarmonyPatch(typeof(String), "IndexOf", new Type[] { typeof(String) })]
    [HarmonyPostfix]
    static void PostFix_String_IndexOf(String __instance, String value, ref Int32 __result, MethodInfo __originalMethod)
    {
        if (StackInAspose())
        {
            if (__result != -1) return;
            if (value == NEW_EXP)
            {
                __result = 0;
            }
        }
    }
 
    [HarmonyPatch(typeof(XmlCharacterData), "Data", MethodType.Getter)]
    [HarmonyPostfix]
    private static void Postfix_XmlText_Data_Getter(XmlCharacterData __instance, ref string __result, MethodInfo __originalMethod)
    {
        if (StackInAspose())
        {
            var stacks = new StackTrace().GetFrames();
            if (stacks.Any(s => s.GetMethod().Name.StartsWith("get_OuterXml")))
            {
                return;
            }
            var parentNod = __instance.ParentNode;
            if (parentNod == null) return;
            if (parentNod.Name == "SubscriptionExpiry" || parentNod.Name == "LicenseExpiry")
            {
                __result = NEW_EXP;
            }
        }
    }
}

[C#] 纯文本查看 复制代码
1
2
3
4
5
6
7
using (new AsposeLicensePatch())
{
    new Aspose.Pdf.License().SetLicense(new MemoryStream(Convert.FromBase64String("License")));
 
    var document = new Document("用户手册_V1.0.pdf");
    document.Save("output.docx", Aspose.Pdf.SaveFormat.DocX);
}
sdieedu 发表于 2023-1-18 20:09
虽然没有看懂 我觉得依然牛
 楼主| pjy612 发表于 2023-1-18 20:20
本帖最后由 pjy612 于 2023-1-18 20:21 编辑
sdieedu 发表于 2023-1-18 20:09
虽然没有看懂 我觉得依然牛


这种教程 算是 头一次写。。。
主要算是介绍一个 可以动态Hook .NET 的库...

毕竟在写应用的时候,那些第三方库 过于依赖nuget 不适合去反编译破解。

当然 破解过程部分 先去坛子里看看 其他大佬 破解 Aspose 的 帖子 再看可能 更明白一点。。。
Blanke 发表于 2023-1-19 10:11
思路不错
代码可以分享下吗
yaoguen 发表于 2023-1-19 14:45
能分享一下代码吗?,谢谢
q705031 发表于 2023-1-26 13:03
虽然没有看懂 我觉得依然牛
billpeace 发表于 2023-1-31 14:48
谢谢分享
dplxin 发表于 2023-2-1 14:07
那就这个帖子回复,
我这边还有个今天能用的 license  你可以试一下
<?xml version="1.0"?>
<License>
  <Data>
    <LicensedTo>CPS</LicensedTo>
    <EmailTo>stefan.stachow@cps.gov.uk</EmailTo>
    <LicenseType>Site OEM</LicenseType>
    <LicenseNote>Up To 10 Developers And Unlimited Deployment Locations</LicenseNote>
    <OrderID>220725095952</OrderID>
    <UserID>938906</UserID>
    <OEM>This is a redistributable license</OEM>
    <Products>
      <Product>Aspose.Total for .NET</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SerialNumber>28d85812-77fc-4bf1-b0fc-7e0c0be64bac</SerialNumber>
    <SubscriptionExpiry>20240109</SubscriptionExpiry>
    <LicenseExpiry>20230209</LicenseExpiry>
    <ExpiryNote>This is a temporary license for non-commercial use only and it will expire on 2023-02-09</ExpiryNote>
    <LicenseVersion>3.0</LicenseVersion>
    <LicenseInstructions>https://purchase.aspose.com/policies/use-license</LicenseInstructions>
  </Data>
  <Signature>gi1yLX1CrlX6JvrPEbJSDMS0dmykurCZTLs7Z7uwe+hncRWFNLNQYgdmDLFwVAhJC85JicsWR+Qr+uncyoerCVtnmjF62RczD4KOOcIvSEMU7AotrA6EXa6M98mYu/GRLqa3gDQmU8s6SBhuKfhFQtNZ79oyf+uxIHWW+XE+YcE=</Signature>
</License>
dplxin 发表于 2023-2-1 14:08
那就这个帖子回复,
我这边还有个今天能用的 license  你可以试一下
<?xml version="1.0"?>
<License>
  <Data>
    <LicensedTo>CPS</LicensedTo>
    <EmailTo>stefan.stachow@cps.gov.uk</EmailTo>
    <LicenseType>Site OEM</LicenseType>
    <LicenseNote>Up To 10 Developers And Unlimited Deployment Locations</LicenseNote>
    <OrderID>220725095952</OrderID>
    <UserID>938906</UserID>
    <OEM>This is a redistributable license</OEM>
    <Products>
      <Product>Aspose.Total for .NET</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SerialNumber>28d85812-77fc-4bf1-b0fc-7e0c0be64bac</SerialNumber>
    <SubscriptionExpiry>20240109</SubscriptionExpiry>
    <LicenseExpiry>20230209</LicenseExpiry>
    <ExpiryNote>This is a temporary license for non-commercial use only and it will expire on 2023-02-09</ExpiryNote>
    <LicenseVersion>3.0</LicenseVersion>
    <LicenseInstructions>https://purchase.aspose.com/policies/use-license</LicenseInstructions>
  </Data>
  <Signature>gi1yLX1CrlX6JvrPEbJSDMS0dmykurCZTLs7Z7uwe+hncRWFNLNQYgdmDLFwVAhJC85JicsWR+Qr+uncyoerCVtnmjF62RczD4KOOcIvSEMU7AotrA6EXa6M98mYu/GRLqa3gDQmU8s6SBhuKfhFQtNZ79oyf+uxIHWW+XE+YcE=</Signature>
</License>
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-13 03:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表