吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 1815|回复: 17

[原创逆向图文] 【重磅】Aspose全家桶永久去限制全攻略(支持.NET 4x/6/8)

[复制链接]
壹佰 发表于 2024-4-2 13:19 | 显示全部楼层 |阅读模式

Aspose.Total全家桶包含我们日常经常要用到的Aspose.Cells/Aspose.Words/Aspose.Slides/Aspose.PDF/...等一系列库文件。
我们通过Visual Studio 2022中NuGet安装最新版到本地试用时,基本都有水印限制。


今天我们就用.Net HOOK技术来去掉所有限制,体验全功能的强大魅力。


首先,讲解下实现思路。先从网上去找一个过期的License(我找到一个20200827过期的License),调用SetLicense方法来设置这个License。
这个时候库会去判断这个License是否过期,然后我们就可以通过Hook技术拦截它的这个判断,让它永久返回不过期,从而达到预期结果。


说起来简单,实现起来真的太难了。目前有很多开源库,都实现了.net4.8及以下版本Framework的Hook技术,比如Harmony/HarmonyX等等。
但是.net6/7/8却一个都没有,在这方面研究的人太少,也没什么成果出来。当然也可能是我没发现,有知道的评论区告诉我。


没办法,只有自己去摸索了。在加班加点辛苦了快两年,终于让我整理出一个支持所有.net 4x/6/8的Hook技术库,我把它命名为Crane MethodHook。
这个Hook库的实现原理太复杂,有时间我专门开贴详细介绍。今天主要介绍一下使用它来破解Aspose全家桶。


我们先建个控制台应用(框架选择.Net 4x/6/8都是可以的),使用NuGet安装一下这个Crane.MethodHook库,最新版是我今天刚发布的V1.0.6版。


然后我们设置一下License,不同的Aspose库设置方法不一样,但是基本都是new Aspose.<product>.License().SetLicense()方法。
设置License之前我们还必须进行方法Hook绑定,注意顺序先hook再设置License。


其中有三个重要的方法:MethodBase.Invoke(),string.Compare,XmlElement.get_InnerText
我们分别对这三个方法进行Hook,先建立这三个方法的新版本:


[C#] 纯文本查看 复制代码
public static object NewMethodInvoke(MethodBase method, object obj, object[] parameters)
{
    if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "ParseExact" && parameters.Length > 0 && parameters[0].ToString().Contains("0827"))
    {
        var ret = DateTime.ParseExact(DATE_CHANGED_TO, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
        ShowLog(method, ret, obj, parameters, true);
        return ret;
    }
    else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "ParseExact" && parameters.Length > 0 && System.Text.RegularExpressions.Regex.Match(parameters[0].ToString(), @"^\d{4}\.\d{2}\.\d{2}$").Success)
    {
        var ret = DateTime.ParseExact("20200501", "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture);
        ShowLog(method, ret, obj, parameters, true);
        return ret;
    }
    else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.DeclaringType != null && method.DeclaringType.Name == "String" && method.Name == "Compare")
    {
        if (parameters.Length == 2)
        {
            if (parameters[0].ToString() == "20200827")
            {
                var ret = 1;
                ShowLog(method, ret, obj, parameters, true);
                return ret;
            }
            else if (parameters[1].ToString() == "20200827")
            {
                var ret = -1;
                ShowLog(method, ret, obj, parameters, true);
                return ret;
            }
        }
    }
    else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "op_GreaterThan" && parameters.Length == 2 && parameters[1] is DateTime && ((DateTime)parameters[1]).ToString("MMdd") == "0827")
    {
        ShowLog(method, false, obj, parameters, true);
        return false;
    }
    else if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && method.Name == "Split" && System.Text.RegularExpressions.Regex.Match(obj.ToString(), @"^\d{4}\.\d{2}\.\d{2}$").Success
         && obj != null && obj.ToString().Substring(0, 4) == DateTime.Now.Year.ToString())
    {
        var ret = new string[] { "2019", "08", "27" };
        ShowLog(method, ret, obj, parameters, true);
        return ret;
    }

    var hook = MethodHookManager.Instance.GetHook(System.Reflection.MethodBase.GetCurrentMethod());
    var result = hook.InvokeOriginal<object>(method, obj, parameters?.ToArray());
    ShowLog(method, result, obj, parameters);
    return result;

}

public static int NewCompare(string s1, string s2)
{
	if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && s2 == "20200827")
	{
		Utils.LogWriteLine($"HOOK SUCCESS: From {Assembly.GetCallingAssembly().GetName().Name} String.Compare({s1},{s2}) return -1;", ConsoleColor.Green);
		return -1;
	}
	else
	{
		var hook = MethodHookManager.Instance.GetHook(MethodBase.GetCurrentMethod());
		var ret = hook.InvokeOriginal<int>(null, s1, s2);
		Utils.LogWriteLine($"NOT Aspose Call: From {Assembly.GetCallingAssembly().GetName().Name} String.Compare({s1},{s2}) return {ret};", ConsoleColor.DarkRed);
		return ret;
	}
}

private static readonly string DATE_CHANGED_TO = (DateTime.Today.Year + 1).ToString() + "0827";

public static string NewInnerText(XmlElement element)
{
	if (Assembly.GetCallingAssembly() != null && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.") && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.Words") == false && Assembly.GetCallingAssembly().FullName.StartsWith("Aspose.Hook") == false && element.Name == "SubscriptionExpiry")
	{
		Utils.LogWriteLine($"HOOK SUCCESS: From {Assembly.GetCallingAssembly().GetName().Name} XmlElement.InnerText ({element.Name},{element.InnerXml}) return {DATE_CHANGED_TO};", ConsoleColor.Green);
		return DATE_CHANGED_TO;
	}
	else
	{
		var hook = MethodHookManager.Instance.GetHook(System.Reflection.MethodBase.GetCurrentMethod());
		return hook.InvokeOriginal<string>(element);
	}
}


然后执行Hook绑定,这很简单,先调用AddHook方法。

[C#] 纯文本查看 复制代码
Crane.MethodHook.MethodHookManager.Instance.AddHook(new MethodHook(
                        typeof(MethodBase).GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(object), typeof(object[]) }, null),
                        typeof(NewHookMethods).GetMethod(nameof(NewHookMethods.NewMethodInvoke), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(MethodBase), typeof(object), typeof(object[]) }, null)
                    ));

Crane.MethodHook.MethodHookManager.Instance.AddHook(new MethodHook(
                        typeof(string).GetMethod("Compare", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(string) }, null),
                        typeof(NewHookMethods).GetMethod(nameof(NewHookMethods.NewCompare), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(string) }, null)
                    ));


注意一下XmlElement.get_InnerText方法在.net4x和.net6/8下的获取稍有不同:

[C#] 纯文本查看 复制代码
#if NET40
                    Hook = new MethodHook(
                        typeof(XmlElement).GetProperty("InnerText", BindingFlags.Public | BindingFlags.Instance).GetGetMethod(true),
                        typeof(NewHookMethods).GetMethod(nameof(NewHookMethods.NewInnerText), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(XmlElement) }, null)
                    ),
#else
                    Hook = new MethodHook(
                        typeof(XmlElement).GetProperty("InnerText", BindingFlags.Public | BindingFlags.Instance).GetMethod,
                        typeof(NewHookMethods).GetMethod(nameof(NewHookMethods.NewInnerText), BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(XmlElement) }, null)
                    ),    
#endif


然后启用Hook即可。

[C#] 纯文本查看 复制代码
Crane.MethodHook.MethodHookManager.Instance.StartHook();


那么现在Hook也设置好了,License也设置了,下面就来测试下成果。
顺便提一句,设置License如果明确知道目标应用要用到哪个Aspose产品,可以直接调用对应产品的SetLicense方法。
而我更喜欢用反射遍历的方式去查找当前应用引用了哪些Aspose产品,然后动态去调用其SetLicense方法,并且已经封装到库中,方便调用,也没有依赖。

我们分别测试Aspose.Cells/Aspose.Words/Aspose.Slides/Aspose.PDF这几款常用产品,检验一下是否达成预期。

fakename.png

fakename.png

通过日志,可以清晰的看到每款产品在SetLicense过程中都有哪些关键方法调用,有助于我们把握其中值得推敲和改善的关键点。
通过测试我们看到每款产品都能全功能完美使用,目标达成。

fakename.png

fakename.png

fakename.png

fakename.png

fakename.png

测试发现,不止是Aspose最新版,就是其历史所有老版本,同样的代码都是能支持的。

这就是Method Hook技术的强大魅力,不用修改库文件,就能改变其功能。值得珍藏。

好了,思路、过程、工具、关键点、结果、总结都有了。你不妨一试,有疑问评论区告诉我。我会给你解惑所有。
同时希望大家都能重视.Net Hook技术,把它应用到未来所有的挑战中。
也欢迎大家和我一起交流技术,共同进步。

评分

参与人数 11HB +14 THX +8 收起 理由
松岛枫 + 1 + 1
布鲁斯李 + 2 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
身心自在 + 1
花盗睡鼠 + 2 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
汇编基础 + 1
消逝的过去 + 1
白丁老师 + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
jyjjf + 1 + 1
美好映像 + 2 + 1
chinamsu + 2 + 1 [吾爱汇编论坛52HB.COM]-吃水不忘打井人,给个评分懂感恩!
CrackLy + 1 + 1 感谢分享

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
CrackLy 发表于 2024-4-2 17:45 | 显示全部楼层

用深思或者DNG之类的hook了jit的,是否可以用这种方式hook
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
学编程的闹钟 发表于 2024-4-2 18:06 | 显示全部楼层

Aspose是什么软件哦
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
lies 发表于 2024-4-2 18:07 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
学编程的闹钟 发表于 2024-4-2 21:10 | 显示全部楼层

CrackLy 发表于 2024-4-2 17:45
用深思或者DNG之类的hook了jit的,是否可以用这种方式hook

应该是可以的
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 壹佰 发表于 2024-4-2 21:26 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
学编程的闹钟 发表于 2024-4-2 21:29 | 显示全部楼层


OK,谢谢楼主
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
jyjjf 发表于 2024-4-3 12:41 | 显示全部楼层


好多文档处理类工具都是用这个开发的,简单点就是调用DLL开发,然后套个界面
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
学编程的闹钟 发表于 2024-4-3 13:48 | 显示全部楼层

jyjjf 发表于 2024-4-3 12:41
好多文档处理类工具都是用这个开发的,简单点就是调用DLL开发,然后套个界面 ...

就是xls文档吗
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
pizazzboy 发表于 2024-4-3 15:54 | 显示全部楼层

谢谢大佬的分享。
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层
8层
9层
10层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

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