吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8390|回复: 38
收起左侧

[.NET逆向] aspose.words for .net 21.4,虚拟化后的修改

  [复制链接]
qands 发表于 2021-4-3 22:38
其实分析不难,改IL指令搞的我心力憔悴,清明出去玩都惦记着.
(求助:dnspy有没有编辑方法时显示IL指令的功能啊....)
等下要麻将,先发结果和几个参数,过会儿再写分析过程.

虚拟化代码存在在一个乱码的资源文件里,像这样.
image.png

进入虚拟化那个乱码的字符串".Ounr+YPC1" ,指向这个资源的某个位置,从而读出一些字节.
[C++] 纯文本查看 复制代码
	\u000F\u2004\u200B\u2008.\u0005\u2005\u200B\u2008().\u0003(\u000F\u2004\u200B\u2008.\u0008\u2005\u200B\u2008(), ".Ounr+YPC1", u);


读出来的bytearr 经过解密 得到解密的bytearr,每4字节组合,得到一个操作指令.这些指令(应该,95%)是源程序的IL指令.暂时称它为指令数组.
指令数组在执行过程中看的到.像这样.解密过程我没看,这个过程也虚拟化了.
image.png

这些操作指令的意义是写死在程序里的.是个字典,对应相应的操作.执行过程中也可以看得到

指令数组中的指令在字典中查询并执行的代码在这里
[C#] 纯文本查看 复制代码
	private void \u0005\u2000()
	{
		this.\u000E\u2002 = this.\u000E\u2001;
		int key = this.\u0008\u2004.\u0003\u2000();
		this.\u000E\u2001 += 4U;
		\u0002\u2007.\u0002\u2000 u0002_u;
		global::\u0002\u2007.\u0005.TryGetValue(key, out u0002_u);
		u0002_u.\u0003(this, this.\u0002(this.\u0008\u2004, u0002_u.\u0002));
	}


每次运行后的结果,保存在这里
image.png
比如比较注册的时间的过程,你会在结果集中看到
取出存取注册信息的那个类.
取出注册码过期时间.
执行call得到datetime.now
执行call比较时间大小
返回结果(0或1)
判断是否跳转
...
在这个程序块最后下断,可以很清晰的看到这个过程.按一次F5做一行事情.

当前运行到了IL指令数组的哪个位置,保存在这里
image.png

当要跳转的时候 \u000F\u2003的值变成新位置 并在这个程序块返回的程序块中进行判断.这个值不跳转的时候为null
[Asm] 纯文本查看 复制代码
	private void \u0006(bool \u0002)
	{
		uint u000F_u = this.\u000F\u2002;
		for (;;)
		{
			try
			{
				while (!this.\u0005\u2002)
				{
					if (this.\u000F\u2003 != null)
					{
						this.\u000E\u2001 = this.\u000F\u2003.Value;
						this.\u0002((long)((ulong)this.\u000E\u2001));
						this.\u000F\u2003 = null;
					}
					else if (this.\u000E\u2001 >= u000F_u)
					{
						break;
					}
					this.\u0005\u2000();
				}
			}
			catch (object u)
			{
				this.\u0002(u, 0U);
				if (\u0002)
				{
					continue;
				}
				this.\u0006(true);
			}
			break;
		}
	}

好了.现在总结下
1.根据指令数组的长度的不同,你基本可以判断出它在执行哪个虚拟化的程序块.
2.指令数组长度/4就是源程序IL指令的数量,大致可以判断出被虚拟方法的代码长度.如果长度相差太大,直接跳出虚拟化的循环就可以了.不用老点F5
3.我们可以修改\u000F\u2003的值跳转到虚拟方法的任何位置.

根据上2篇文章的经验,判断是否注册的代码很简单,大概长这样
[C#] 纯文本查看 复制代码
        if (\u000F\u2008\u2004\u2001.\u000F != null && \u000F\u2008\u2004\u2001.\u000F.\u000E != (\u0002\u2009\u2004\u2001)0 && !(\u000F\u2008\u2004\u2001.\u000F.\u0006 < DateTime.Now) && \u0008\u2002\u2005.\u0003() != 4096)
        {
            return (\u0002\u2009\u2004\u2001)1;
        }
        return (\u0002\u2009\u2004\u2001)0;


最终调试结果是,这段判断注册与否的代码被虚拟化后的长度是0x0000013E(它加了很多干扰代码,把指令搞长了)
return 1 那里对应的数组位置是0x88,在虚拟化的跳转处下断,长度是0x13e时第一次跳转发生在数组位置0x6c.
我在这里注入了断代码,当\u000F\u2003==0x6c时,修改成0x88.
然后就成功了.

免费评分

参与人数 8吾爱币 +8 热心值 +8 收起 理由
努力加载中 + 1 + 1 热心回复!
swhyy + 1 + 1 我很赞同!
azcolf + 1 + 1 热心回复!
抱薪风雪雾 + 1 + 1 谢谢@Thanks!
大白痴先生 + 1 + 1 用心讨论,共获提升!
为之奈何? + 1 + 1 我很赞同!
夜泉 + 1 + 1 热心回复!
joneqm + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

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

pjy612 发表于 2023-2-2 11:40
本帖最后由 pjy612 于 2023-2-2 12:14 编辑
dplxin 发表于 2023-2-2 11:05
嗯。。  老哥分享下  aspose    rsahook的方法学习一下`..`

rsa 是不是只hook 一处就够了

这个是动态hook 因为它里面的 RSA验签是 自己实现的。所以每个库都要针对性筛选关键点然后 hook。

它的验签逻辑是 通过公钥解析 sign 能得到 原始报文的 hash,然后对入参报文进行 hash 。
两个 hash 循环比较 验证。

本来还有办法就是Hook Base64直接Patch它验证用的公钥。
但是 它里面还有个 黑名单 会走相同的验签解析逻辑。
所以 根本判断不出来 它在验证什么。

所以理论上要处理的就是 从旧版本里面 把它 验签解析sign的代码抽出来。
然后 对自己 伪造的 license 生成 sign 和 对应成功的 hash。
然后 Hook 验签逻辑,发现被验证的 sign 是我们生成的时候 返回 对应的 hash。
[C#] 纯文本查看 复制代码
private static void Postfix_VerifyData(byte[] __0, ref byte[] __result, MethodInfo __originalMethod)
{
    if (StackInAspose())
    {
        if (__result.Length != 127)
        {
            if (RSA_SIGN.SequenceEqual(__0))
            {
                __result = RSA_Hash.ToArray();
            }
        }
    }
}
pjy612 发表于 2023-1-10 16:36
夜泉 发表于 2021-4-3 22:58
关注,第一时间开始看~

最终弄下来
最稳定的还是找个过期的授权模板,然后把 Sign 给 伪造掉 强制返回对应的hash...

其次就是 Hook 系统函数
XmlElement 的 InnerText getter  
XmlReader 的 ReadString
判断 当前是读取 SubscriptionExpiry 的时候 给个 2099
然后就是
String 的 IndexOf,有些DLL会重查一下 日期是不是在文件里,所以 这里判断下 如果是 2099啥的 就给他返回个存在。


其他的 比如 Hook Convert.FromBase64String 去替换 RSA的公钥
由于没有上下文会让它自己的黑名单校验出错导致失败。

.NET 的 Hook 感觉还是 HarmonyLib 最好用...
基本那些商用的DLL都能用 HarmonyLib 在不改代码时动态Hook 约等于 运行时构建Aop...
而且能拿到调用链的上下文
夜泉 发表于 2021-4-3 22:58
本帖最后由 夜泉 于 2021-4-4 02:54 编辑

关注,第一时间开始看~


(求助:dnspy有没有编辑方法时显示IL指令的功能啊....)

我都是开另一个程序,每次想要什么IL指令都写上重新编译,然后ildasm查看的。。。


对了,为啥不直接修改IL代码然后还原回去?在这里注入,每执行一条IL指令,都要判断一下,感觉也太那啥了吧?
对哦,这个只有解密没有加密,,,通过解密还原加密也太累了

我选择用 过期授权文件。。。

xingkongtianyu 发表于 2021-4-4 08:31
谢谢分享,向大神学习了!
wfcaicai 发表于 2021-4-4 10:27
谢谢分享
 楼主| qands 发表于 2021-4-4 13:11
夜泉 发表于 2021-4-3 22:58
关注,第一时间开始看~

image.png

这么改的,在这里下断,程序一共也没到这里几次,不影响效率.
而且就算在每次执行都判断次,也不影响效率.这个虚拟机已经把代码搞这样了,还怕效率低?


要还原它以前的代码也是可以的,直接从指令数组得到所有指令,然后对照着字典翻译,然后再把得到的IL指令写到虚化前的方法里.就是这个工作量.....


anye521 发表于 2021-4-4 15:07
感谢&#128591;分享
swhyy 发表于 2021-4-4 17:51
支持楼主原创,楼主厉害
oah1021 发表于 2021-4-5 16:19
感谢大佬的分享
小夫哥 发表于 2021-4-5 16:25
看不懂.要多多学习了....
benny856694 发表于 2021-4-5 20:14
感谢大佬分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-15 15:46

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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