本帖最后由 尼桑 于 2020-2-15 09:51 编辑
此为新人教程,大佬请飘走,实在要看就别喷
(看不懂也评个分呗,情人节快乐!)
下一篇帖子:https://www.52pojie.cn/thread-1105080-1-1.html
0x00 前言
最近在Stexx上发现了一个好玩的游戏,但我这种手残党实在是玩不下去,于是就准备修改一下。看了一看它的游戏目录,明显就是Unity写的游戏(不知道Unity的自行百度)
Unity的游戏代码其实并不在软件里面,而是在 xxxxxxUnity游戏/xxx_data/Managed/Assembly-CSharp.dll和Assembly-CSharp-firstpass.dll里面
但是Assembly-CSharp-firstpass.dll基本不用,所以就只修改Assembly-CSharp.dll就可以了
0x01 工具
游戏 X 1
DnSpy 6.0.1 X 1
0x02 DnSpy简单介绍
DnSpy是一款.net程序反编译工具,可以对net程序进行反编译,还有替代库文档的功能,如果遇到了代码丢失或者损坏的情况,可以直接恢复。(摘自百度)
我说它是神器完全不为过,因为它可以反编译.NET代码,而且可以修改,这对我们这种不懂IL指令的小白来说是一个巨大的福利!
(唯一有点不好的地方就是它比较吃内存,要占500~800MB内存,但即使这样,利还是远远大于弊的)
DnSpy可以通过爱盘下载,不大,就20多MB
链接:https://down.52pojie.cn/Tools/NET/dnSpy.zip
0x03 修改过程
0x0301 飞行
打开DnSpy,把游戏的Assembly-CSharp.dll拖进DnSpy(有的要用x64位的,有的要用x32位(x86位)的,具体看情况)
大概是这样:
右面会加载一大堆Unity的模块
点击Assembly-CSharp.dll
我们想让他飞行,我的思路是:把跳跃的代码修改一下,让它可以多段跳,就相当于飞行了。(就是无限地在空中跳)
既然是跳跃,就肯定要找关于跳跃的东西
(下面的内容需要面向对象级别的编程或是C#编程基础)
点击搜索,搜索“jump”方法
出来很多结果
其中有两个方法名是JumpAnimation(直译就是跳跃动画,但我感觉应该是跳跃动作)
先去第一个看看:
[C#] 纯文本查看 复制代码 private Vector3 JumpAnimation()
{
float lift = 1f;
return this.ApplyTorsoPose(1f, 1f, 0f, lift);
}
这个方法是TorsoMuscles类的方法 (机翻:躯干肌肉)
太短了,肯定不是
而且跳跃是用腿,不是用躯干
再去下一个:
[C#] 纯文本查看 复制代码 private void JumpAnimation(Vector3 torsoFeedback)
{
this.ragdoll.partHips.rigidbody.SafeAddForce(torsoFeedback, ForceMode.Force);
if (this.human.jump)
{
float num = 0.75f;
int num2 = 2;
float num3 = Mathf.Sqrt(2f * num / Physics.gravity.magnitude);
float num4 = Mathf.Clamp(this.human.groundManager.groudSpeed.y, 0f, 100f);
num4 = Mathf.Pow(num4, 1.2f);
num3 += num4 / Physics.gravity.magnitude;
float num5 = num3 * this.human.weight;
float num6 = this.human.controls.unsmoothedWalkSpeed * ((float)num2 + num4 / 2f) * this.human.mass;
Vector3 momentum = this.human.momentum;
float num7 = Vector3.Dot(this.human.controls.walkDirection.normalized, momentum);
if (num7 < 0f)
{
num7 = 0f;
}
this.upImpulse = num5 - momentum.y;
if (this.upImpulse < 0f)
{
this.upImpulse = 0f;
}
this.forwardImpulse = num6 - num7;
if (this.forwardImpulse < 0f)
{
this.forwardImpulse = 0f;
}
this.framesToApplyJumpImpulse = 1;
if (this.human.onGround || Time.time - this.human.GetComponent<Ball>().timeSinceLastNonzeroImpulse < 0.2f) //这是判断人是否在地面上,以及延时是否够
{
this.upImpulse /= (float)this.framesToApplyJumpImpulse; //if块里面的应该就是执行跳跃的代码了
this.forwardImpulse /= (float)this.framesToApplyJumpImpulse;
this.ApplyJumpImpulses();
this.framesToApplyJumpImpulse--;
}
this.human.skipLimiting = true;
this.human.jump = false;
}
else
{
if (this.framesToApplyJumpImpulse-- > 0)
{
this.ApplyJumpImpulses();
}
int num8 = 3;
int num9 = 500;
float num10 = this.human.controls.unsmoothedWalkSpeed * (float)num8 * this.human.mass;
Vector3 momentum2 = this.human.momentum;
float num11 = Vector3.Dot(this.human.controls.walkDirection.normalized, momentum2);
float num12 = num10 - num11;
float d = Mathf.Clamp(num12 / Time.fixedDeltaTime, 0f, (float)num9);
this.ragdoll.partChest.rigidbody.SafeAddForce(d * this.human.controls.walkDirection.normalized, ForceMode.Force);
}
}
这个应该是了
它是LegMuscles类的一个方法 (机翻:腿部肌肉)
可以看出有一个if判断人是否在地上,以及跳跃延迟是否够
我们把它改成if(true)试试
右键---编辑类
开游戏试一下,不行。
为什么?因为这个JumpAnimation方法不是只要跳跃键按下就执行的,所以,我们要找其他思路
human.onGround有点可疑,因为游戏肯定会先判断玩家是否在地面上才会执行JumpAnimation这个方法
它是Human类里面的一个字段
我们在Human类搜索一下human.onGround
搜到了一个赋值操作
[C#] 纯文本查看 复制代码 this.onGround = (this.groundDelay <= 0f && this.groundManager.onGround);
在FixedUpdate()方法里面
把它后面的 (this.groundDelay <= 0f && this.groundManager.onGround);改成true试试
再开游戏,这次成功了:
{你们应该知道这是什么游戏了)
直接飞到终点,很过瘾
0x0302 修改力量,重量,重力等属性
先搜索力量
搜索Force字段名:
出来了好多结果。。。
先点maxPushForce吧
这是HandMuscles类的字段 (机翻:手部肌肉)
所以有很多可以改的力量的参数
右键---修改类 就可以了
0x0303 设置飞行开关
这个游戏自带一个控制台
按“·”打开(ESC下面的按键)
那我们就搜索Command这个类
结果没有有用的结果
突然想起来这个游戏的控制台也可以叫作弊码输入
搜索CheatCode试试
搜到了
果然,就是控制台的代码
在Start()方法里面有很多命令的注册
我们也写一个
[C#] 纯文本查看 复制代码 Shell.RegisterCommand("fly",new Action(this.fly),null);
添加fly方法:
[C#] 纯文本查看 复制代码 private void fly()
{
//暂时留空
}
先留空,之后写
我们先再去到Human这个类
添加fly字段
[C#] 纯文本查看 复制代码 public static bool fly; //注意必须是public static
在前面的onGround赋值操作中,改一下代码:
[C#] 纯文本查看 复制代码 this.onGround = (fly ? true : (this.groundDelay <= 0f && this.groundManager.onGround));
现在可以补全CheatCode.fly()方法了
[C#] 纯文本查看 复制代码 private void fly()
{
Human.fly = ! Human.fly;
if (Human.fly)
{
Shell.Print("fly mode on");
}
else
{
Shell.Print("fly mode off");
}
}
在游戏内打开控制台,输入fly就可以开关飞行模式(不是你手机上的那个飞行模式....)
0x0304 修改跳跃高度
既然是跳跃高度,那就要回到LegMuscles类的JumpAnimation方法
再贴上代码:
[C#] 纯文本查看 复制代码 private void JumpAnimation(Vector3 torsoFeedback)
{
this.ragdoll.partHips.rigidbody.SafeAddForce(torsoFeedback, ForceMode.Force);
if (this.human.jump)
{
float num = 0.75f;
int num2 = 2;
float num3 = Mathf.Sqrt(2f * num / Physics.gravity.magnitude);
float num4 = Mathf.Clamp(this.human.groundManager.groudSpeed.y, 0f, 100f);
num4 = Mathf.Pow(num4, 1.2f);
num3 += num4 / Physics.gravity.magnitude;
float num5 = num3 * this.human.weight;
float num6 = this.human.controls.unsmoothedWalkSpeed * ((float)num2 + num4 / 2f) * this.human.mass;
Vector3 momentum = this.human.momentum;
float num7 = Vector3.Dot(this.human.controls.walkDirection.normalized, momentum);
if (num7 < 0f)
{
num7 = 0f;
}
this.upImpulse = num5 - momentum.y;
if (this.upImpulse < 0f)
{
this.upImpulse = 0f;
}
this.forwardImpulse = num6 - num7;
if (this.forwardImpulse < 0f)
{
this.forwardImpulse = 0f;
}
this.framesToApplyJumpImpulse = 1;
if (this.human.onGround || Time.time - this.human.GetComponent<Ball>().timeSinceLastNonzeroImpulse < 0.2f) //这是判断人是否在地面上,以及延时是否够
{
this.upImpulse /= (float)this.framesToApplyJumpImpulse; //if块里面的应该就是执行跳跃的代码了
this.forwardImpulse /= (float)this.framesToApplyJumpImpulse;
this.ApplyJumpImpulses();
this.framesToApplyJumpImpulse--;
}
this.human.skipLimiting = true;
this.human.jump = false;
}
else
{
if (this.framesToApplyJumpImpulse-- > 0)
{
this.ApplyJumpImpulses();
}
int num8 = 3;
int num9 = 500;
float num10 = this.human.controls.unsmoothedWalkSpeed * (float)num8 * this.human.mass;
Vector3 momentum2 = this.human.momentum;
float num11 = Vector3.Dot(this.human.controls.walkDirection.normalized, momentum2);
float num12 = num10 - num11;
float d = Mathf.Clamp(num12 / Time.fixedDeltaTime, 0f, (float)num9);
this.ragdoll.partChest.rigidbody.SafeAddForce(d * this.human.controls.walkDirection.normalized, ForceMode.Force);
}
}
经过简单的分析,可以看出ApplyJumpImpulses()这个方法就是执行跳跃的具体方法
再贴上它的代码:
[C#] 纯文本查看 复制代码 private void ApplyJumpImpulses()
{
float d = 1f;
for (int i = 0; i < this.human.groundManager.groundObjects.Count; i++)
{
if (this.human.grabManager.IsGrabbed(this.human.groundManager.groundObjects[i]))
{
d = 0.75f;
}
}
Vector3 a = Vector3.up * this.upImpulse * d;
Vector3 a2 = this.human.controls.walkDirection.normalized * this.forwardImpulse * d;
this.ragdoll.partHead.rigidbody.SafeAddForce(a * 0.1f + a2 * 0.1f, ForceMode.Impulse);
this.ragdoll.partChest.rigidbody.SafeAddForce(a * 0.1f + a2 * 0.1f, ForceMode.Impulse);
this.ragdoll.partWaist.rigidbody.SafeAddForce(a * 0.1f + a2 * 0.1f, ForceMode.Impulse);
this.ragdoll.partHips.rigidbody.SafeAddForce(a * 0.1f + a2 * 0.1f, ForceMode.Impulse);
this.ragdoll.partBall.rigidbody.SafeAddForce(a * 0.1f + a2 * 0.1f, ForceMode.Impulse);
this.ragdoll.partLeftThigh.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partRightThigh.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partLeftLeg.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partRightLeg.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partLeftFoot.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partRightFoot.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partLeftArm.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partRightArm.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partLeftForearm.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.ragdoll.partRightForearm.rigidbody.SafeAddForce(a * 0.05f + a2 * 0.05f, ForceMode.Impulse);
this.human.groundManager.DistributeForce(-a / Time.fixedDeltaTime, this.ragdoll.partBall.rigidbody.position);
}
d这个变量很可疑,我们把它改成100f试试
再进游戏
结果跳一下直接上天了
所以只要修改d就行了,这里不再详细说了
0x0305 保存
点击DnSpy左上角文件---保存模块就行了
0x04 DnSpy的一些坑
1.占内存太大了。。。。 2.有的时候加入一个int i = 0;都会报错,还需要导入模块才行 3.自动补全不太好用,有时候你明明在另一个类里定义了public static int i = 0;,但在另一个类里 "一个类.i = 1" 会报错,要保存模块才行 4.代码分析有点奇怪,应该是编译器的问题,比如说写 "if(a == b){}" DnSpy反编译出来是"a == b;" 虽然是这样,但这都是小问题,我还是强烈推荐小白下载!
0x05 小结
.NET程序修改破解小白首推DnSpy,IL指令大佬就用其他工具吧
用DnSpy修改破解只要会一点Java或者C#就能比较轻松地修改破解
(Java和C#基本一样,但也有不同的地方) 用DnSpy破解修改主要思路就是: 找关键方法或者字符串,静态分析,注册码这一类的可以动态分析 然后就用DnSpy的修改类或者是修改方法功能修改代码 但前提是dll没被加壳 加壳就麻烦了 0x06 最后 我这个其实修改的不全,只修改了一部分,还有很多可以修改的地方,大家有兴趣可以自己修改 最后给那些找不到Assembly-CSharp.dll或不想下载游戏的人奉上Assembly-CSharp.dll原版 解压密码:www.52pojie.cn 声明:您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。 |