首页
社区
课程
招聘
[原创] 分享一次还原某网游 3D骨骼动画文件为collada过程 --- 长篇
发表于: 2017-9-22 00:28 18838

[原创] 分享一次还原某网游 3D骨骼动画文件为collada过程 --- 长篇

2017-9-22 00:28
18838

写在前面的话: 因为一些兴趣近期对一款网游的资源文件进行的分析提取,历经10天挑灯夜战, 最终成功解开了PKG压缩包, 还原了 骨骼3D文件, 动作3D文件, 重要的是借由逆向,间接学到了不少初级3D数学知识,过程思路为主,代码为辅,将在本文中一一介绍。 (解开了也没钱没用途 写个帖子以防自己忘记)

-

文中用到的主要工具: C32asm,Ollydbg,x64_dbg,WinDbg,IDA Pro,PCHunter,3DMAX

-

参考资料:
百度百科COLLADA介绍
collada快速入门
DAE模型与骨骼动画解析渲染



(可跳过剩下内容直接看下一章节),如果要强行逆向也是可以的,旋转X,Y,Z在转换成所谓的64字节时,观察排列可得知X,Y,Z进行矩阵相乘时有关系可循, 比如X转换64字节后某一个位置固定是0或1,那后一个64字节与X相乘时,某一些位置结果不变, 这样可以固定得到一个原数据, 然后一步一步推算回去,不过脑子代价太大,我个人选择另寻他路,实在不行时再强行逆向算法。 在后期得到正在的算法后,可以知道这里的5次"关键函数"累加正是旋转X,Y,Z,的矩阵信息(3X3) 平移信息4字节, 缩放信息 4字节, 各5个信息组合起来, 而X,Y,Z转换计算可以在后面的算法代码看到。

参考资料:④:【3D计算机图形学】变换矩阵、欧拉角、四元数

参考:⑤ 四元数,欧拉角及姿态矩阵的相互转换

参考:⑥ 矩阵乘法的本质是什么?
参考:⑦理解矩阵乘法

参考:⑧矩阵的加、减、乘、除、求逆运算的实现

参考:⑨为什么matrix(矩阵)不可以相除?

如有转载希望标明出处

百度百科COLLADA介绍
collada快速入门
DAE模型与骨骼动画解析渲染
④:【3D计算机图形学】变换矩阵、欧拉角、四元数
四元数,欧拉角及姿态矩阵的相互转换
矩阵乘法的本质是什么?
理解矩阵乘法
矩阵的加、减、乘、除、求逆运算的实现
为什么matrix(矩阵)不可以相除?

 
游戏文件夹内有许多.pkg为后缀的文件,且文件大小不俗,一般都是存放着压缩过的游戏图片,音乐,建模等数据,过去热门的游戏有各种提取/解压工具, 甚至有的游戏可以用winrar直接打开, 但很不幸,此次的目标两者皆否。
打开C32Asm,16进制选取游戏文件夹内的某pkg文件后可以看到。
一眼能认出的就是 文件名字还有 下面的 被压缩过的数据, 由经验判断, 78 01 极可能是 zip算法的标头, 于是从420偏移处开始选择,一直到结尾空白区域把压缩数据复制出来保存。
选择了 6694 字节进行解压, 解压成功,的确是zip算法, 但是,文本文件各种乱码, 图片文件各种花屏, 却又能看到部分明文, 数据的确是正确的,是什么原因呢?  经过对比以及几次失败的尝试后发现。 我选取的是 6694 个字节, 但回到图1,压缩数据前的那4个字节数值却是 F6190000 反转(变量储存在内存的反转关系不用多说了吧) 后为 000019F6 = 6646,  这多出来的48字节怎么回事呢? 填充字节? 偷字节? 还是其中的某些字节有过处理? 如此的话静态分析就不会有结果了, 到了这里不得不动态调试游戏一探究竟。
由于是TP保护的网游,使用OD附加前需要搞定几处保护,简单讲 path nop掉gamebase.dll的沙盘创建,提前占用R0调试端口,然后运行网游后,使用PCHunter 恢复几处R3HOOK ,调试器能附加后,使用WinDbg附加找到主动抛异常的几个线程记下, 并重新运行游戏继续使用PCHunter搞定几个异常线程,就可以用OD附加了。

通过PCHunter可以发现,游戏运行后打开了所有的PKG文件句柄, 所以我们要对ReadFile以及SetFilePointer下断,返回用户代码进行多次来回运行后, 观察定位了几个关键函数, (由于时间过去10多天就不给出详细的跟踪过程了)
首先,ReadFile 读取都是1016字节一次,读一次后,SetFilePointer就会把偏移+8 然后再读下一段1016字节, 也就是说,每1024个字节会舍弃掉最后8字节,  这样就解释得通了, 为什么前面手动选取到6694个字节, 但数据前的标头却写的6646字节。  6646/1016*8取整=6 6*8刚好就是多出来的字节了。 多出来的这些就是不需要的,读取的时候跳过。测试后能成功解压出正常的数据,这个点算是解决了。

第二个点,文件名对应数据的偏移怎么拿到, 在游戏里找好第一次需要读取PKG包的点,对SetFilePointer下断后,第一次的返回就是临近获得偏移的地方,后发现偏移量每次都是由一个数*0x400后得到的, 而这个数,在文件名的前面28个字节处,代表这个文件名的数据从第几个0x400偏移开始.. 
//定义此结构用于读取包内文件信息
  PkgFileInfo =record
     FileDataGroup:Cardinal;  //数据偏移位于第几组 FileDataGroup*0x400=偏移
     unknow:Cardinal;
     unknow2:Cardinal;
     unknow3:Cardinal;
     unknow4:Cardinal;
     unknow5:Cardinal;
     UnCompfileSize:Cardinal;    //解压后的大小
     FileName:array[0..255] of Char; //文件名
  end;
知道文件名列表的规则,知道了数据读取规则,剩下的就是解压缩了。

写到这里才发现写得敷衍了些, 因为过去时间太久加上本文的重点在后面,解压这里就简单带过吧。搞定PKG文件花了半天时间, 而接下来的9天都是与3D信息文件的战斗...
解开了pkg包内的数据后,有图片,有脚本,有字符串表,都是明文可以直接打开的, 唯独3D数据,skel,anim,col等等 骨骼,蒙皮,动作等文件有过处理,尝试用各种3D软件都无法读取, C32asm打开也看不出什么名堂, 因为我从没接触过3D方面, 不管是游戏还是建模等等方面, 所以一时语塞了。这时候拖关系得到一个重要的信息,这款游戏的3D文件都是通过一个编码器从Collada数据格式转换过来的, 而这个编码器!你猜怎么着,它居然就在我们公司楼下的美术的电脑上, 今晚就潜伏进去偷过来(开玩笑)。
拿到了这个编码器,就有了前进的方向,目前需要进行测试收集信息,那么就离不开所谓的Collada数据格式。
通过搜索得知,collada是一种数据规范,意为让不同的3D软件都能读同一个格式取到相同的信息,各工具间导出导入方便交换3D数据。 一般这样的文件在3DMAX里导出为*.dae文件.
简而言之,目前需要逆向编码器对dae文件的编码过程,从而通过游戏文件逆向还原成dae文件就对了。打开3DMAX, 创建3个简单的骨骼,设置自动关键帧,选择其中一个节点做平移动作和旋转动作,并导出为dae格式,导出时不需要三角算法和单一矩阵。
DAE文件为XML格式,打开后看到
观察得知<library_animations>节点下存储了动画信息,<library_visual_scenes>节点下存储了骨骼信息,目前只关注这两个节点就可以了。由于骨骼文件的数据较少,决定先从简单的开始分析,多次观察统计后不难发现, node 节点包含一块骨骼(点)的信息, 如果有有子骨骼的话,就会在node节点下再包含一个node节点,刚才创建的3个连着的骨骼,其实上就是父子关系, 不过现阶段骨骼里面的各种数值代表什么意思完全不清楚。
对编码器动手之前,还是需要静态分析一下的,尝试用编码器编码刚才导出的Test.Dae文件, 编码器是一个控制台程序,直接运行就退出了,推测是通过参数调用, 载入OD,设置命名行参数为"1111111111111",并单步运行, 直到结束都没在堆栈或寄存器等看到类似11111111的字符,连GetCommandLine都得不到执行, 转换思路搜索字符串来到可疑的地方。
013E99E2  |.  68 A4684701   push converte.014768A4                   ;  collada\
013E99E7  |.  C785 D4FEFFFF>mov [local.75],0xF
013E99F1  |.  C785 D0FEFFFF>mov [local.76],0x0
013E99FB  |.  C685 C0FEFFFF>mov byte ptr ss:[ebp-0x140],0x0
013E9A02  |.  E8 49C0FFFF   call converte.013E5A50
013E9A07  |.  8D85 68FDFFFF lea eax,[local.166]
013E9A0D  |.  50            push eax                                 ; /pFindFileData = 0014FA18
013E9A0E  |.  68 B0684701   push converte.014768B0                   ; |collada\*.dae
013E9A13  |.  C645 FC 02    mov byte ptr ss:[ebp-0x4],0x2            ; |
013E9A17  |.  FF15 10604701 call dword ptr ds:[<&KERNEL32.FindFirstF>; \FindFirstFileA
013E9A1D  |.  8BF8          mov edi,eax
013E9A1F  |.  83FF FF       cmp edi,-0x1
013E9A22  |.  75 2D         jnz short converte.013E9A51
013E9A24  |.  E8 67B10200   call converte.01414B90
013E9A29  |.  8B10          mov edx,dword ptr ds:[eax]
013E9A2B  |.  68 C0684701   push converte.014768C0                   ;  No Collada files found
013E9A30  |.  8BC8          mov ecx,eax
013E9A32  |.  FF52 04       call dword ptr ds:[edx+0x4]
013E9A35  |.  68 E4684701   push converte.014768E4                   ;  \n
013E9A3A  |.  E8 075F0600   call converte.0144F946
013E9A3F  |.  68 C0684701   push converte.014768C0                   ;  No Collada files found
013E9A44  |.  E8 FD5E0600   call converte.0144F946
013E9A49  |.  83C4 08       add esp,0x8
013E9A4C  |.  E9 A9010000   jmp converte.013E9BFA
013E9A51  |>  6A 00         push 0x0                                 ; /pSecurity = NULL
013E9A53  |.  68 D8684701   push converte.014768D8                   ; |Converted
013E9A58  |.  FF15 14604701 call dword ptr ds:[<&KERNEL32.CreateDire>; \CreateDirectoryA
原来编码器会判断有无collada文件夹,有的话才对里面的*.dae文件进行处理, 配置好后运行, 得到 Test.skel 和Test.anim 两个文件, 因为刚才的DAE文件里只有骨骼和动画,刚好就得到这两个文件。
用C32Asm打开Test.skel 可以看到。
通过多次生成不同的骨骼文件静态对比后 可以看到 骨骼名字结束后, 空了4个字节,然后是64个字节的骨骼信息, 然后4个字节表示下方有几个子节点,然后才是下一个骨骼的数据,现在要做的就是理解这64个字节是怎么转换得来的了,由经验得知, 3F800000是 浮点数1.000000 的十六进制数据, Skel文件内多次看到, 那么这64个字节其实是16个浮点数?  回去看一下dae文件,是不是都是浮点数?   难道!!! 所谓的编码器,就是简单的把DAE文件中的浮点数转换成16进制??????


然而!!!  并不是... skel中的浮点数和dae中的肉眼看没有任何关系。进行到这里时,本来让我继续我是拒绝的.又没人给钱.

过了一天,灵光一闪,3DMAX在导出DAE文件时,collada选项那里,有一个三角算法和一个单一矩阵可供选择,于是,导出单一矩阵后,可以看到Testjuzheng.dae内,bone001骨骼信息node节点那里有了的变化
<node name="Bone001" id="Bone001" sid="Bone001" type="JOINT">
<matrix sid="matrix">
0.679118 -0.734029 -0.000000 9.930389 0.000000 0.000000 1.000000 0.000000 -0.734029 -0.679118 0.000000 -8.927395 0.000000 0.000000 0.000000 1.000000
</matrix>
在看编码后的Testjuzheng.skel
这 16 个浮点数!!! 刚好对应到了 Skel文件的 Bone001下的16个浮点数, 虽然16个数排列顺序不一样, 但这是一个重大突破。 像饿了好几天的求生者发现食物一样,我立马去验证Bone002的数据………………  很遗憾, 对不上...... 这感觉就像女神和你的告白下一秒说是愚人节一样, 但无风不起浪, 第一个数据完全相同这一点足以给我动力继续下去了。到了这一步, 不得不开始动态调试, 分析Bone002的浮点数据到了骨骼文件怎么就变了。

用OD载入编码器,搜索字符串"ibrary_visual_scenes",来到调用函数,下方紧接着就是 "node" 的字符串,从node 下方进入处理过程后,单步跟踪,定位到了骨骼节点小数字符串转换成 16 进制的过程,下面不远就是 这64个字节进行转换的位置了, 由于太简单就不上图了, 直接上关键的算法。
由于OD不支持查看XMM寄存器的数值,这里改用x64_dbg调试
这个函数,就是Bone002摇身一变成为Skel文件里数据的关键,函数一共三个参数,一个为上一个节点(Bone001)的 16个浮点数, 一个为本次节点(Bone002 dae中)的16个浮点数, 还有一个为输出地址, 那么搞定这个算法骨骼就可以通过Skel文件还原成DAE文件中的数值了, 通过跟踪理解, 尝试做了这样一张图
IDA Pro中的伪代码为:
讲真,IDA的伪代码我并看不懂。口头描述代码如下
float a[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; //DAE中的排序
float b[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};

a={1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16};
b={1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16};  //转换成编码器内存中的排序 
a和b 进入函数过程的话.a为上一个节点信息, b为本次
用第二次循环举例
将 本次节点(b)信息的 第二组 2 6 10 14 传给寄存器XMM0 并进行洗牌操作后,各寄存器状态如下
XMM0  2  2  2  2
XMM1  6  6  6  6
XMM2 10 10 10 10
XMM3 14 14 14 14

xmm4-xmm7的数据为:
XMM4 13  9  5  1    //这里是 上个节点a的所有数据 
XMM5 14 10  6  2
XMM6 15 11  7  3
XMM7 16 12  8  4

然后和 XMM0-XMM3 和 XMM4-XMM7 分别相乘后数据如下:

XMM0  26  18  10  2
XMM1  84  60  36  12
XMM2 150 110  70  30
XMM3 224 168 112  56

ADD  484 356 228  100 (累加操作)

这其中的一次循环 484 356 228 100 就是保存到skel中的数据了。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 2
支持
分享
最新回复 (43)
雪    币: 155
活跃值: (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
还未编缉完么
2017-9-22 06:55
0
雪    币: 3279
活跃值: (1997)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
文章好长,虽然看不懂,但是觉得作者能写这么长的文章再加截图,作者应该很有耐性。
2017-9-22 07:48
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
4
sadanlasi 还未编缉完么
一晚上终于编完了老哥
2017-9-22 08:00
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
5
chixiaojie 文章好长,虽然看不懂,但是觉得作者能写这么长的文章再加截图,作者应该很有耐性。
这些东西以后自己不会用到怕忘记了,就写详细点哈哈。
2017-9-22 08:01
0
雪    币: 768
活跃值: (535)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
6
玩3D,全是些矩阵运算,看着就晕,楼主好牛
2017-9-22 08:56
0
雪    币: 66
活跃值: (2760)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
厉害啊      边逆边学
2017-9-22 09:02
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
FishSeeWater 玩3D,全是些矩阵运算,看着就晕,楼主好牛
我也是一知半解,靠抄代码过日子的
2017-9-22 09:29
0
雪    币: 1534
活跃值: (312)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
楼主好厉害,学习了
2017-9-22 12:40
0
雪    币: 5676
活跃值: (1303)
能力值: ( LV17,RANK:1185 )
在线值:
发帖
回帖
粉丝
10
666
2017-9-22 15:18
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
不错!
2017-9-22 19:51
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
12
终于修复完不少错别字,  定下标题了... 
其实中间遇到的问题还可以讲很多东西,全写完太长了,就写了关键的地方。
2017-9-22 20:17
0
雪    币: 940
活跃值: (1058)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
13
很厉害,    重在坚持啊
2017-9-22 20:23
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
14
一直用Model  Ripper,没研究过文件的路过了
2017-9-23 04:13
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
15






cvcvxk



一直用Model Ripper,没研究过文件的路过了


哟,修仙的V大 
其实我也一直知道有HOOK  DX接口来提取游戏模型的工具,  但提取动作的好像没有找到,可惜这次的目标恰恰就是动作信息。。
突然一想HOOK能截取到模型,应该也能针对模型的骨骼点做HOOK截取动作吧,要是过几天有人告诉我真有截动作的那我就悲剧了。
2017-9-23 05:14
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
16






noNumber









cvcvxk



一直用Model Ripper,没研究过文件的路过了


哟,修仙的V大&nbsp; 其实我也一直知道有H ...

好像真的能。
我一般都是用老外的工具:
http://cgig.ru/en/
http://www.gildor.org/


2017-9-23 06:19
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
17






cvcvxk









noNumber









cvcvxk



一直用Model Ripper,没研究过文件 ...

看到你的消息吓死我了...  虽然这么说不好..  好像不能截到动画

Ninja  Ripper我试用了,只能截到模型和图片,      主页有一篇文章提取到的游戏动画是游戏压缩包内解出来的,差点吓尿...
第二个网站好像是虚幻引擎专用,不过也没看到动画相关....
还是谢谢了。
2017-9-23 09:38
0
雪    币: 272
活跃值: (3258)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
群主详细讲解下怎么过保护把。。要不然过不了保护进行不下去!!!。。
2017-9-23 09:45
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
19
gtict 群主详细讲解下怎么过保护把。。要不然过不了保护进行不下去!!!。。
我这款游戏冷门游戏,TP保护版本比较低,网上搜得到的相关方法并且有效的。
2017-9-23 09:48
0
雪    币: 7024
活跃值: (4237)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
感谢分享,  学习了,佩服楼主的耐心
2017-9-23 10:26
0
雪    币: 1
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
顶,  要消化完不容易啊。
2017-9-23 13:04
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
22






noNumber









cvcvxk









noNumber









cv ...

我是能,不是说ninja可以,第二个那个UE引擎专怼,我超喜欢。ninjia出来的model有bones的基本型,没有动作而已,自己拿着bones做动作就行了(
我司武术指导用动作采集器生成bones动作)

不过截动作出来,需要先确定模型,然后把动作过程复制出来,然后还原成可以看的文件。
2017-9-23 17:54
0
雪    币: 308
活跃值: (230)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
23
cvcvxk noNumber cvcvxk no ...
我主要是害怕,自己像愣头青一样逆逆逆,  结果早就有现成的工具可以把动作提取出来就悲剧了。
2017-9-23 18:45
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
能力很高,技术很强!老大给个机会让我给你提鞋
2017-9-23 22:20
0
雪    币: 12628
活跃值: (3127)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
3d  矩阵  od  ida都懂,但我就逆向不出来,
2017-9-24 07:53
0
游客
登录 | 注册 方可回帖
返回
//