【逆向工程】生成能够用dnSpy调试的mono-2.0-bdwgc.dll(一)

最近想要逆向一个Unity游戏,游戏使用的Unity版本是2020.3.17
无奈dnSpy官方仓库提供的版本直到2019.2.1,想要2020的dll只能自己生成,踩了非常多的坑,特地记录一下

首先进入dnSpy-Unity-mono官方仓库,然后跟着它的README一步步走。

第一步

Pull in the latest Unity mono.dll source code (either git pull if you have it or git clone https://github.com/Unity-Technologies/mono.git)
Get this repo and make sure master and dnSpy branches are at the latest commit (git pull in both branches)

首先要创建一个新的本地仓库,用来存放Unity Mono的官方代码
git clone https://github.com/Unity-Technologies/mono
然后还要再创建一个本地仓库,用来存放dnSpy-Unity-mono的仓库,注意master分支和dnSpy两个分支都要拉,这就是第一个坑,为什么后面会细说

第二步

Compile umpatcher in this repo (you need VS2019 or later and .NET Core SDK 3.0 or later installed)

找到umpatcher.sln,直接生成就行。建议用VS2019以上的版本,如果需要.NET SDK,可以网上找找怎么安装,这个还是比较简单的。

第三步

Download the correct Unity editor version
Either install the Unity editor or extract the necessary .dlls with extractmono.bat

去下载一个对应版本的Unity Editor,比如我就需要下载一个Unity Editor2020.3.17
也可以使用它提供的extractmono.bat。我用的是第一种,后面那种没试过。
不过这一步的目的是为了获取时间戳,其实有更简单的方法,等下在第四步讲

第四步

If using extractmono.bat
.\extractmono.bat C:\Users\Unfou\Downloads C:\Users\Unfou\Desktop\mono both
Otherwise, if installing Unity editor:
umpatcher --timestamp “C:\path\to\the\correct\version\mono.dll”

具体的方法很长,建议看原文。核心目的就是获取游戏使用的mono.dll的生成时间戳,等下会用。
它提供了两种方法,一是下载7z,然后用仓库里的extractmono.bat;二是下载对应的Unity Editor,然后找到安装目录中的dll,用umpatcher去看时间戳
但其实有更简单的方法,既然你想用dnSpy断点调试这个游戏,那你一定装了dnSpy,用dnSpy打开游戏原本的mono.dll就可以看到时间戳了:
在这里插入图片描述
也就是说Unity2020.3.17版本mono-2.0-bdwgc.dll的时间戳就是(2021/7/13 20:18:06)

第五步

Check out the correct version branch in the Unity mono repo, eg. if it’s v5.4.3, the branch is called unity-5.4. Branches ending in -mbe use .NET 4.x assemblies.
Use git branch -a to see all remote branches
git checkout unity-5.4 (or whatever version you need)
git pull (make sure it has the latest stuff)
gitk to start a UI
Find the closest merge by comparing the merge date with the timestamp reported by umpatcher above
Remember the commit hash, you’ll need it later

这一步核心目的是通过时间戳找到对应的原版Mono分支
查找官方Mono的所有分支,并切到你想要的分支,比如我就需要
git checkout unity-2020.3-mbe
然后打开gitUI(当然你如果足够有耐心也可以用命令行找,git log就行)找到对应时间戳的版本,记下它的commit hash比如说2020.3.17的就是 72dda61cafa8e84fd78c01eab954e9690cd8d3cb

第六步

Run umpatcher again to patch the code and commit it to the dnSpy-Unity-mono repo
umpatcher 5.4.3 aa8a6e7afc2f4fe63921df4fe8a18cfd0a441d19 “C:\path\to\Unity-mono” “C:\path\to\dnSpy-Unity-mono”

现在你知道了2020.3.17对应的mono的commit hash,你可以把分支回滚到那个版本,你就获得了mono-2.0-bdwgc.dll的源代码,只要再改一改就可以让游戏对你的调试敞开大门,仿佛马上就能大功告成了

BUT,接下来是一串大坑

首先你运行上面的命令,umpatcher {unity version} {commit hash} {mono path} {dnSpy-mono path},然后你就会得到一个报错

Git submodule update external/bdwgc failed with error code 1

第六步(一)

为什么呢?可以看看umpatcher中的源码

public void SubmoduleUpdate(string path) {
	int result = Exec.Run(repoPath, gitPath, $"submodule update {path}");
	if (result != 0)
		ThrowError($"Git submodule update {path} failed with error code {result}");
}

然后到Unity Mono仓库中跑一下git submodule这个命令,可以发现原本的submodule配置的下载路径是git://,但是自从2021年开始git官方就不使用git://而使用https://了。修复的办法也很简单,在Unity Mono仓库下输入
git config --global url.“https://”.insteadOf git://
就可以了

然后你继续运行 umpatcher {unity version} {commit hash} {mono path} {dnSpy-mono path},又会得到一个报错

File ‘\dnSpy-Unity-mono\dnSpy-Unity-mono-v2020.x-V40.sln’ doesn’t exist

第六步(二)

这个报错信息比较直白,很明确的跟你说了缺少dnSpy-Unity-mono-v2020.x-V40.sln,因为作者只维护到2019版本,自然没有后面的sln文件。至于修复也很简单,拷贝一个dnSpy-Unity-mono-v2019.x-V40.sln,改一下文件名,然后编辑一下,把里面没用的配置删干净,删成这样就行了:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32630.194
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dnSpyFiles", "dnSpyFiles", "{BCDFE47C-A4D8-4F5C-BCED-4AEBDC711E34}"
	ProjectSection(SolutionItems) = preProject
		dnSpyFiles\dnSpy.c = dnSpyFiles\dnSpy.c
	EndProjectSection
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {6F2773ED-F031-4BBF-BE69-53D43FA453CC}
	EndGlobalSection
EndGlobal

但非常坑的是,这时候你再运行umpatcher,还是会报错

Directory unity-mono-2020.3.17-mbe already exists

第六步(三)

我们再看一下umpatcher的源码:

public void Patch() {
	if (Directory.Exists(dnSpyVersionPath))
		throw new ProgramException($"Directory {dnSpyVersionPath} already exists");
	CopyOriginalUnityFiles();
	UpdateReadMe();
	MergeMasterIntoDnSpy();
	PatchOriginalFiles();
}

之前脚本已经生成了unity-mono-2020.3.17-mbe目录,因此会报错,但是简单的删除文件夹也是不行的。在sln报错之前,umpatcher已经做了好几步操作,包括

1)回滚原版Mono仓库的代码到commit hash对应分支
2)更新原版Mono仓库的子模块
3)dnSpy-Mono仓库切换到master分支,拷贝原版Mono仓库的部分代码并提交
4)更新master分支的ReadMe文件并提交
5)切换到dnSpy分支并合并master分支的代码

可以看到它会切换分支,这就是之前为什么要把两个分支都拉到最新的原因。
这些操作里面,345都需要回滚,如果修改Patch函数,把PatchOriginalFiles前面都注释掉,可以只回滚5。

回滚完分支以后,别忘了重新建一下dnSpy-Unity-mono-v2019.x-V40.sln并commit,因为umpatcher会检查git clean,如果分支不干净会报错。

回滚代码以后再运行umpatcher以后依旧会报错,别怕,这是最后一个了

Line is … but expected line is …

第六步(四)

看一下报错的位置:

void Patch_mono_mini_debugger_agent_c()
{
	...
	{
		int index = textFilePatcher.GetIndexesOfLine(line => line.Text.Contains("case CMD_THREAD_GET_FRAME_INFO: {")).Single();
		index = textFilePatcher.GetIndexOfLine(line => line.Text.Contains("tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);"), index);
		Verify(lines[index + 1].Text, "\t\tmono_loader_unlock ();");
		Verify(lines[index + 2].Text, "\t\tg_assert (tls);");
		lines[index + 2] = lines[index + 2].Replace("\t\tif (!tls)");
		textFilePatcher.Insert(index + 3, "\t\t\treturn ERR_INVALID_ARGUMENT;");
	}
}

也就说Mono中有一行代码与作者的预期不符了,是哪一行呢?

	case CMD_THREAD_GET_FRAME_INFO: {
		...
		mono_loader_lock ();
		tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
		mono_loader_unlock ();
		if (tls == NULL)	// g_assert (tls);
			return ERR_UNLOADED;
	}

看来 if (tls == NULL) 这行在mono之前的版本应该是 g_assert (tls);,后来被官方修改了
因此只要把umpatcher中这一块整个删掉就行了

最后再运行 umpatcher {unity version} {commit hash} {mono path} {dnSpy-mono path},终于弹出了

Patch Unity files (unity-mono-2020.3.17-mbe)

这个时候unity-mono-2020.3.17-mbe工程就算生成完毕了

第七步

最后一步就是用新的工程生成可以dubug的mono-2.0-bdwgc.dll

dnSpy-Unity-mono-vZZZZ.x-V40.sln (Unity with .NET 4.x assemblies), where ZZZZ is the major version number, eg. 2017, 2018, …
Use configuration Release
Use platform x86 or x64

一般来说,这一步会让你重定向工程,不重定向的话下载它需要的Windows SDK 和 MSVC工具集也可以,随个人爱好,然后生成选项选Release,x86或x64看游戏是几位的,直接生成libmono-dynamic就行,生成出来的mono-2.0-bdwgc.dll会在dnSpy-Mono仓库的builds目录下

接下来,用这个mono-2.0-bdwgc.dll替换掉游戏原本的dll就可以了

然后,你运行游戏就会发现

游戏Crash了!!!

没错,接下来还有一串坑,且听下回分解
【逆向工程】生成能够用dnSpy调试的mono-2.0-bdwgc.dll(二)

本文链接:
dnSpy-Unity-mono官方仓库
mono官方仓库
我的个人仓库

### 回答1: spine-unity-3.8.99是Spine软件针对Unity引擎开发的一个版本。Spine是一款功能强大的2D骨骼动画编辑器,能够帮助开发者创建流畅、逼真的2D角色动画。而Unity引擎则是一款广泛应用于游戏开发的跨平台开发工具。 spine-unity-3.8.99的发布主要是为了提供更好的兼容性和功能性。这个版本可能修复了一些之前版本中存在的问题,改进了软件的稳定性和性能表现。同时,针对Unity引擎的特性和功能,spine-unity-3.8.99也可能做了一些适配和优化,以便更好地集成和使用Spine动画。 此外,spine-unity-3.8.99可能还增加了一些新的特性和工具,以提供更多的选项和灵活性,方便开发者根据自己的需求定制和优化动画效果。这样,开发者可以更加方便地在Unity引擎中使用Spine来制作高质量、流畅的2D角色动画,为游戏添加更多的细节和魅力。 总的来说,spine-unity-3.8.99的发布是为了进一步提升Spine在Unity引擎中的使用体验,使开发者能够更加方便地创建出更加生动、精美的2D角色动画,并为游戏提供更多的互动性和视觉效果。 ### 回答2: spine-unity-3.8.99是Spine软件的一个版本。Spine是一款用于创建2D骨骼动画的软件,它允许用户通过设置骨骼结构和绘制动画关键帧来制作复杂的角色动画。 spine-unity-3.8.99是Spine软件的Unity插件版本。Unity是一种强大的跨平台游戏引擎,它支持2D和3D游戏的开发,并且有广泛的用户和社区支持。通过将Spine插件集成到Unity中,开发者可以使用Spine的骨骼动画功能来制作和控制游戏中的角色动画。 spine-unity-3.8.99可能是Spine和Unity之间的一个特定版本兼容性的标识。由于Spine和Unity都在不断发展和升级,为了确保Spine插件与Unity引擎的版本相匹配,Spine团队会发布适用于不同Unity版本的Spine插件版本。这样,使用Spine插件在开发过程中可以避免一些潜在的兼容性问题。 总结来说,spine-unity-3.8.99是Spine软件的Unity插件版本,提供了Spine骨骼动画的功能和控制,并且在特定的版次中与Unity引擎兼容。 ### 回答3: spine-unity-3.8.99是一个用于Unity引擎的插件,用于支持Spine骨骼动画。Spine是一个2D骨骼动画编辑器,它允许开发者创建复杂的动态角色动画。 spine-unity-3.8.99提供了Unity引擎与Spine的无缝集成,使开发人员可以在Unity中直接使用Spine创建的骨骼动画。这个插件包含了一系列用于呈现、控制和优化动画的组件和功能。 使用spine-unity-3.8.99,开发者可以在Unity中轻松导入Spine动画文件,并通过Unity的编辑器界面进行编辑和调整。插件提供了一组工具,帮助用户在运行时控制动画的播放、循环、混合、绑定事件和触发动画等。同时,它还提供了优化功能,以保证动画在运行时的性能和效果。 spine-unity-3.8.99还支持与Unity其他功能的无缝集成,如粒子效果、物理引擎、碰撞检测等。这使得开发人员可以创建更加丰富多样的动画效果,并在游戏中实现更高的互动性和流畅度。 总之,spine-unity-3.8.99是一个强大的插件,为开发者提供了在Unity中使用Spine骨骼动画的便利。通过其丰富的组件和功能,开发人员可以更好地实现游戏中的复杂动画效果,提高游戏的视觉吸引力和用户体验。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值