8 个字节的数据通过空方法写入文件
8 bytes of data being written to file by an empty method
我一直在研究驻留在 dll 中的游戏的保存代码,并发现了一些有趣的东西。
我正在使用带 Reflexil 的 ILSpy 来读取和更改 dll 的代码。
好的,我有以下代码片段(如 ILSpy 所示):
stream.Write(this.V.Count); //this is signed 4-byte integer, it equals 1 in this case (10 00 00 00)
using (List<StatModifier>.Enumerator enumerator = this.V.GetEnumerator())
{
while (enumerator.MoveNext())
{
StatModifier current = enumerator.Current;
current.Write(stream);
}
}
在此之前有一些代码写入同一个 BinaryWriter,但我稍后会谈到它,因为它与此事无关。
current.Write(stream);
是对这个方法的调用:
public virtual void Write(BinaryWriter stream)
{
}
这是一个空方法(我使用 Reflexil 删除了它的内容)。只有 IL 代码是这个命令(如 ILSpy 中所示):
Offset OpCode Operand
>0 0 ret
接下来 运行 的代码(在方法调用之后)被 ret 命令缩短,因此它不会向二进制文件写入任何其他内容。然后游戏代码正确关闭文件 (stream.Close();
)。这与问题无关,但我知道你会问。如果有人要求我可以添加前后代码,但我不明白这样做的意义。
我测试的方式:
- 我用干净的游戏代码创建了一个保存文件,所以我可以加载它。
- 我复制到另一个文件夹了。
- 我修改了代码来测试它。
- 我把原来的复制回去了
- 我已经进入和退出游戏(执行此代码 - 将游戏保存到文件的代码)。
- 我用十六进制编辑器检查了文件。
- 重复 3-6。
这会加载保存文件,进入游戏,然后在退出时使用更改后的代码覆盖它。我知道这部分代码保存了游戏的哪一部分,而且我知道在我短暂的进入和退出会话期间它保持不变。这样,除了保存代码外,一切都保持不变。
当我使用此代码启动游戏并使其成为 运行 时,它会创建此二进制文件。该代码已经更改,因此大部分通常保存的数据已被删除,因此更容易查找更改:
74 74 70 00 18 05 00 00 00 9A 99 19 3F 00 00 00
00 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 80
3F 01 01 00 00 00 9A 99 19 3F 9A 99 19 3F
二进制文件的第一部分是由我在开始时省略的代码编写的,因为它跨越了几个 类 和方法调用,但我认为它与这里没有任何关系。这是重要的部分:
01 00 00 00 9A 99 19 3F 9A 99 19 3F
这是最后 12 个字节。前四个表示从第一个代码片段 (this.V.Count
) 开始的带符号的 4 字节整数。
最后八个是神秘的。我不知道他们来自哪里。于是又玩了一会儿。我将第一个片段更改为:
stream.Write(this.V.Count); //this is signed 4-byte integer, it equals 1 in this case (10 00 00 00)
using (List<StatModifier>.Enumerator enumerator = this.V.GetEnumerator())
{
while (enumerator.MoveNext())
{
StatModifier current = enumerator.Current;
}
}
如您所见,current.Write(stream)
不再被调用。
当我再次运行游戏时,我得到了这个输出:
7C 74 70 00 18 05 00 00 00 9A 99 19 3F 00 00 00
00 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 80
3F 01 01 00 00 00
你有没有发现遗漏了什么?第一个 运行 的最后 8 个字节不见了。唯一的变化是删除了空方法调用。
我第一次注意到这一点是在查看一个完整的保存文件并试图跟踪其在源代码中的创建时。我只是找不到那些 8 字节的来源,所以我最终更改了代码,删除了这个和那个以查看我遗漏了什么。事实证明我并没有真正遗漏任何东西。所以这也发生在完全干净的代码中。
如果有人真的感兴趣,我可以告诉他们这是关于哪个游戏,并向他们发送相关文件,以便他们自己尝试。
那么,有人知道这些字节的来源吗?这怎么可能?
编辑因不清楚而投票关闭的人:
我问的到底是在哪个宇宙中不清楚?
函数是虚函数,其实运行的实现是在StatModifier派生的子class里,你看错了class
我一直在研究驻留在 dll 中的游戏的保存代码,并发现了一些有趣的东西。
我正在使用带 Reflexil 的 ILSpy 来读取和更改 dll 的代码。
好的,我有以下代码片段(如 ILSpy 所示):
stream.Write(this.V.Count); //this is signed 4-byte integer, it equals 1 in this case (10 00 00 00)
using (List<StatModifier>.Enumerator enumerator = this.V.GetEnumerator())
{
while (enumerator.MoveNext())
{
StatModifier current = enumerator.Current;
current.Write(stream);
}
}
在此之前有一些代码写入同一个 BinaryWriter,但我稍后会谈到它,因为它与此事无关。
current.Write(stream);
是对这个方法的调用:
public virtual void Write(BinaryWriter stream)
{
}
这是一个空方法(我使用 Reflexil 删除了它的内容)。只有 IL 代码是这个命令(如 ILSpy 中所示):
Offset OpCode Operand
>0 0 ret
接下来 运行 的代码(在方法调用之后)被 ret 命令缩短,因此它不会向二进制文件写入任何其他内容。然后游戏代码正确关闭文件 (stream.Close();
)。这与问题无关,但我知道你会问。如果有人要求我可以添加前后代码,但我不明白这样做的意义。
我测试的方式:
- 我用干净的游戏代码创建了一个保存文件,所以我可以加载它。
- 我复制到另一个文件夹了。
- 我修改了代码来测试它。
- 我把原来的复制回去了
- 我已经进入和退出游戏(执行此代码 - 将游戏保存到文件的代码)。
- 我用十六进制编辑器检查了文件。
- 重复 3-6。
这会加载保存文件,进入游戏,然后在退出时使用更改后的代码覆盖它。我知道这部分代码保存了游戏的哪一部分,而且我知道在我短暂的进入和退出会话期间它保持不变。这样,除了保存代码外,一切都保持不变。
当我使用此代码启动游戏并使其成为 运行 时,它会创建此二进制文件。该代码已经更改,因此大部分通常保存的数据已被删除,因此更容易查找更改:
74 74 70 00 18 05 00 00 00 9A 99 19 3F 00 00 00
00 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 80
3F 01 01 00 00 00 9A 99 19 3F 9A 99 19 3F
二进制文件的第一部分是由我在开始时省略的代码编写的,因为它跨越了几个 类 和方法调用,但我认为它与这里没有任何关系。这是重要的部分:
01 00 00 00 9A 99 19 3F 9A 99 19 3F
这是最后 12 个字节。前四个表示从第一个代码片段 (this.V.Count
) 开始的带符号的 4 字节整数。
最后八个是神秘的。我不知道他们来自哪里。于是又玩了一会儿。我将第一个片段更改为:
stream.Write(this.V.Count); //this is signed 4-byte integer, it equals 1 in this case (10 00 00 00)
using (List<StatModifier>.Enumerator enumerator = this.V.GetEnumerator())
{
while (enumerator.MoveNext())
{
StatModifier current = enumerator.Current;
}
}
如您所见,current.Write(stream)
不再被调用。
当我再次运行游戏时,我得到了这个输出:
7C 74 70 00 18 05 00 00 00 9A 99 19 3F 00 00 00
00 00 00 00 00 00 00 80 3F 00 00 80 3F 00 00 80
3F 01 01 00 00 00
你有没有发现遗漏了什么?第一个 运行 的最后 8 个字节不见了。唯一的变化是删除了空方法调用。
我第一次注意到这一点是在查看一个完整的保存文件并试图跟踪其在源代码中的创建时。我只是找不到那些 8 字节的来源,所以我最终更改了代码,删除了这个和那个以查看我遗漏了什么。事实证明我并没有真正遗漏任何东西。所以这也发生在完全干净的代码中。
如果有人真的感兴趣,我可以告诉他们这是关于哪个游戏,并向他们发送相关文件,以便他们自己尝试。
那么,有人知道这些字节的来源吗?这怎么可能?
编辑因不清楚而投票关闭的人: 我问的到底是在哪个宇宙中不清楚?
函数是虚函数,其实运行的实现是在StatModifier派生的子class里,你看错了class