逆向工程生成能够用dnSpy调试的mono-2.0-bdwgc.dll

Posted m_Ficus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆向工程生成能够用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官方仓库
我的个人仓库

dnSpy - 一款 .NET 程序逆向工具

项目地址https://github.com/0xd4d/dnSpy

项目作者:0xd4d

dnSpy 是一款针对 .NET 程序的逆向工程工具。该项目包含了反编译器,调试器和汇编编辑器等功能组件,而且可以通过自己编写扩展插件的形式轻松实现扩展。该项目使用 dnlib读取和写入程序集,以便处理有混淆代码的程序(比如恶意程序)而不会崩溃。

已发布工具的下载地址:

最新发布:https://github.com/0xd4d/dnSpy/releases

或者通过源码构建该项目,参考 Wiki

特性展示

Edit any method, property or event in C# or Visual Basic

Edit any type (class), method, property, event, field

Add, remove, rename any type (class), method, property, event, field

Edit, add, remove .NET resources and save them to disk

The IL editor allows editing method bodies at the IL level: IL instructions, locals, exception handlers

Debug any .NET assembly, no source code required

Raw contents of locals (eg. decrypted byte arrays) can be saved to disk

Optimizations for smaller screens

Multiple tabs and tab groups

Search assemblies

Assembly analyzer

Highlighted references, keywords, use Tab, Shift+Tab, Ctrl+Shift+Up, Ctrl+Shift+Down to select next or previous reference or Alt+Up/Down for next definition

Structure visualizer adds colorized vertical guide lines between braces; loops, try/catch and conditional blocks are shown in different colors

Structure visualizer is very useful when you're in a method like this:

Go to: Entry Point, Module Initializer, MD Token, MD Table Row

Syntax highlighted tooltips with XML doc comments when hovering over a type (class), method, property, event, field

Background images can be shown in the text editor

Same image with left margin and top margin set to 75%

Export to project decompiles all selected assemblies and creates a Visual Studio solution

Command line decompiler, supports Windows, Linux, Mac

Scripting with C# REPL, control the debugger and other extensions with C#

Hex editor

Metadata editor, click on a token or press Ctrl+Shift+D

该项目的翻译相关

如果你想要帮助翻译 dnSPY 成其它语言,请点击此处

Wiki

具体命令和编译相关的内容请参考 Wiki 。

以上是关于逆向工程生成能够用dnSpy调试的mono-2.0-bdwgc.dll的主要内容,如果未能解决你的问题,请参考以下文章

dnSpy 如何调试附加进程

dnspy怎么全选导出

dnSpy调试IIS(w3wp进程)

支持 dotnet 6 的 dnSpy 神器版本

dnspy程序集资源管理器不见了

Aspose最新版22.8教程