日服3.0.1 国服1.0.0

前言

前面一直讲Assembly-CSharp.dll的修改,这次换个修改方式,从游戏的数据文件入手,事先声明这修改对国服无效,结算的时候会数据错误,如果有兴趣可以继续往下看

国服的那点保护

国服的Assembly-CSharp.dll跟日服不一样,做了一点处理,一开始还想用动态调试把它dump出来,结果用IDA载入后发现那段代码实在是太简单了
首先载入libmono.so,跟DLL载入有关的函数就那几个,直接跳到mono_image_open_from_data_with_name,发现他重写了一个mono_image_open_from_data_with_name_0

int __fastcall mono_image_open_from_data_with_name_0(int a1, signed int a2)
{
  int v2; // r6@2
  int v3; // r10@3
  int v4; // r5@3
  int v5; // r6@4
  int v6; // r5@5
  char v7; // t1@6

  if ( a2 > 256 )
  {
    v2 = *(_DWORD *)(a1 + 32);
    if ( v2 )
    {
      v3 = v2 ^ *(_DWORD *)(a1 + 40);
      v4 = (v2 ^ *(_DWORD *)(a1 + 36)) + v3;
      *(_DWORD *)(a1 + 40) = 0;
      *(_DWORD *)(a1 + 36) = 0;
      *(_DWORD *)(a1 + 32) = 0;
      if ( a2 > v4 )
      {
        v5 = v4 - 2;
        *(_BYTE *)(a1 + v4 - 1) ^= *(_BYTE *)(a1 + v3);
        if ( v3 <= v4 - 2 )
        {
          v6 = a1 + v4;
          do
          {
            v7 = *(_BYTE *)(v6-- - 1);
            --v5;
            *(_BYTE *)(v6 - 1) ^= v7;
          }
          while ( v3 <= v5 );
        }
      }
    }
  }
  return mono_debug_init(a1, a2);
}

依旧是C#代码

byte[] bytes = File.ReadAllBytes(fileName);
if (bytes.Length > 256)
{
	uint v2 = BitConverter.ToUInt32(bytes, 32);
	if (v2 != 0)
	{
		uint v3 = v2 ^ BitConverter.ToUInt32(bytes, 40);
		uint v4 = (v2 ^ BitConverter.ToUInt32(bytes, 36)) + v3;
		for (int i = 32; i < 44; i++)
		{
			bytes[i] = 0;
		}
		if (bytes.Length > v4)
		{
			int v5 = (int)v4 - 2;
			bytes[v4 - 1] ^= bytes[v3];
			if (v3 <= v4 - 2)
			{
				int v6 = (int)v4;
				do
				{
					byte v7 = bytes[v6-- - 1];
					--v5;
					bytes[v6 - 1] ^= v7;
				}
				while (v3 <= v5);
			}
		}
		File.WriteAllBytes(fileName, bytes);
	}
}

直接丢进Managed文件夹下跑,就能把Assembly-CSharp.dll和Assembly-CSharp-firstpass.dll解密出来了

Reflector也会坑爹

日服的Assembly-CSharp.dll对变量名做了一些处理,虽然直接上de4dot就行,但是int_0,int_1什么的看上去还是有点蛋疼。不过国服的Assembly-CSharp.dll解密之后什么混淆也没加,而且经过研究后发现日服国服加密的密钥和算法都一样,所以直接从国服的Assembly-CSharp.dll里取出AES和AES2这两个类,然后就有一个蛋疼的情况。。。
用.NET Reflector 8.5.0.179反编译AES时,里面的3个SCRAMBLE_KEY都是错误的。。。第一次尝试解密CSV的时候被坑了一下,然后发现那3个SCRAMBLE_KEY应该都是长度为21的字节数组,但是Reflector却反编译成了长度为24的数组。至于为什么我也不知道,后来用ILSpy测试倒是能够正确反编译。所以用Reflector提取后需要把3个SCRAMBLE_KEY后面的3个0都删掉

解密与修改

解密就很简单了,直接调用AES的Decode函数就行,解密后文件是Unity3D的AssetBundle文件,直接上disunity就能拿到CSV文件,CSV文件还有可能再被加一层密(国服的enemy.csv),需要再调用AES2的DecryptRJ256函数。
至于CSV就根据喜好修改就行,重点就是如何打包回去,这里讲下手动打包的办法,用到的软件还是disunity。
首先了解一下Unity3D的AssetBundle的结构
AssetBundle->AssetFile->File (CSV)
disunity本身只提供了从AssetFile打包回AssetBundle的功能,所以需要修改AssetFile,先用bundle-extract命令从AssetBundle里拿到AssetFile,一般是一个”CAB”开头的文件,然后用修改后的CSV文件替换AssetFile里的内容,以及修改一些头信息,就能打包回去了,这里以国服的enemy.csv讲一个例子(虽然并不能用
用16进制编辑器打开”CAB”开头的文件
QQ截图20150908023416
QQ截图20150908023624
QQ截图20150908023734

1是大端模式的文件总大小,2小端模式的object大小,用2减去1得到0x1060就是object开始的地方,如图2,其中3是CSV文件的大小,4开始一直到后面就是CSV文件的内容了,5是用来对齐的数据
具体修改就是替换4里面的内容,然后修改3,也即是CSV的大小,然后用CSV的大小除以8根据余数修改5,规律如下
余数          1 2 3 4 5 6 7 0
补0的个数 7 6 5 4 7 6 5 4
修改完3,4,5以后,看下现在”CAB”文件的大小,然后修改1,注意是大端模式,然后把1的值减去前面算的0x1060,修改2的值。至此就修改完毕了。
最后使用disunity的bundle-inject命令打包回AssetBundle,替换手机里的文件就行了

42 条评论

  1. 虽然也结合其它文章一起仔细“看”了,但还是完全看不懂。。这个门槛好高啊 :shock:

  2. 你好,對於程式什麼的我也只是初心而已…遇到了一點的問題希望dalao能夠解答一下
    1:如果我沒理解錯誤的話1那8個位的16進制指的就是本文件以BYTE為單位的csv文件總大小吧?而2就是以最終文件總大小減去1060.hex吧?但是我依然沒能理解到底3該咋改…求高手指點

    2:補0的意思是否把0加上去令最終01-0F都塞到以8為倍數呢?

    感謝

  3. 完全不懂解密反编译之类的萌新第一次尝试_(:зゝ∠)_
    理了下大概的顺序
    1.用VS把 您提供的代码编译出exe 在managed下运行 解出Assembly-CSharp.dll和Assembly-CSharp-firstpass.dll
    2.用ILSpy打开解压后的这两个dll 取出AES和AES2两个类 对assets/bin/data 下的csv文件调用AES的Decode函数解密,解密后文件是Unity3D的AssetBundle文件。 这一步问题是比较大的 因为我现在手头没vs 还在下 。现在用ILSpy打开不了这两个dll 提示Specified argument was out of the range of valid values. 应该是未进行第一步的原因。之后取出类 对哪里的文件调用Decode解密都是不会做的点….
    3.用disunity对AssetBundle文件进行操作。得到enemy enemy_ai_order等五个文件 这点是一个基友和我说的 他拿到的就是这五个文件的excel 此时就是卡牌和副本的数据了…csv转excel我倒是会(x( 0难度好不好!)
    不知道操作顺序是不是这样的orz 等vs弄好了试试_(:зゝ∠)_ 希望大神

  4. 大神看看我那里出错了,一​​路都成功就是打包失败
    我解enemy_party.csv这个文件,用bundle-extract解出CAB-Container-enemy_party.csv,然后什么都没改用bundle-inject打包这个文件,disunity出现[info] CAB-Container-enemy_party,但没有出现打包回去的文件 :cry:

  5. 你好,非常感谢你的分享。就是我在反编译以后可以看到里面的AES2类和相关的函数了,但是在用这些函数解密csv的时候解出来的csv特别不正常。因为我是对官方给的数据包里面的csv文件跑的AES2里面的decode方法,不知道这样和你文中提到的先解密拿到csv再解密csv有没有什么不同。因为才开始玩这些东西,希望可以和大神多交流交流,多学习学习,谢谢啦~

  6. 大神求教
    用ilspy打开Assembly-CSharp.dll后,Class AES里面的变数和函数名字都变乱码了

  7. 大神能否看一下乖离语音那个acb和awb要怎么解。。贴吧有人说基本提取不能 是真的么

    1. 对 是criware什么的。我研究了一下之后 吧acb和awb解开了。。得到了hca文件。。不过用一个hca播放器播放出来刺耳的杂音(经测试这个播放器可以播放其他的awb解出来的hca或者bin文件,可以播放的话 就可以转换成wav或者mp3了),所以应该是加密了,。然后我看到dll里有CriHcaDecoder这个名字的类的,不过c#学的不是很深= =用不来这dll导入的类 不晓得这个是不是解密的

    2. 看了下这类返回AudioClip类型,很有可能是解码类。这类调用so里的函数,你要用的话可以用mono照着写个安卓程序调用,或者逆向出so里的函数

  8. ……解了card.csv和skill.csv 只看到了技能效果,实际数据却不在这里面……
    技能上是一个{1}的参数,然而不知道参数存在哪个文件里_(:з」∠)_……求解怎么看具体数据

  9. 博主的背景竟然跟我之前桌面壁纸一样呢。。搜索csv解密 搜到这里,自己本来就是学软件的。就在折腾这个,但是想问一下博主 载入so文件是怎么个载入法?

    1. 先要谢谢博主~已经解密成功啦。一切问题都和博主说的一样,R工具会多的几个0也是。不过我这边的dll倒是不用解密,直接用R工具或者ILSpy打开就能看到完整的代码,拿出来就能用。

  10. :shock: 感谢,刚被你拯救过的第一次尝试解包的咸鱼,C#都不会用,我愧对我的专业,愧对我的学校 :cry:

  11. 博主,推荐个游戏给你
    御姬之翼
    也是UNITY3D的游戏,不过是香港制作,目前有港服台服DMM服3个服务器。并且开放了网页版和手机版数据通用。
    游戏模式是MA那种。
    已开服2年,目前貌似只有我一个人在做修改和辅助,很累啊。
    有时间和兴趣的话,期待一起讨论这个游戏。我在百度御姬之翼吧ID叫kensougo

  12. 请问一下…
    路径”files\patch1_Character_Assets\enemy\ems_001\camera”下的文件是没有加密的…
    用disunity解不出东西…用记事本打开是UnityRaw开头的
    知道这些是什么文件吗?解不出来强迫症要犯了…
    谢谢!

    1. UnityRaw开头的是未压缩的AssetBundle文件
      disunity只能提取打包在AssetBundle(AssetFile)里的
      AudioClip (.mp3)
      Font (.ttf)
      Mesh
      TextAsset (.txt)
      Shader
      Texture2D
      Cubemap
      SubstanceArchive
      MovieTexture
      这9种文件
      你那个文件夹下的,比如cm_0010_entry这个文件,里面打包的是AnimationClip,MonoScript,AssetBundle这3种类型的文件
      disunity都不支持,所以提取不出来

  13. 非常感谢大触的教程! :wink:

    虽然第一次用C#但还是解出来了
    这下子可以整理更多数据了!(强迫症的我 :mrgreen:

欢迎留言

8 + 5 =