来自 <http://www.jybase.net/ruanjianpojie/20120311795_5.html>

时间:2012-03-11 21:59来源:未知 整理:寂涯网络 点击:9678次

最近为了支持下汉化游戏,加入了一个汉化组做技术,主要的工作就是解包游戏资源, 提取其中的资源文本交给翻译人员来翻译,因此我就将自己一次分析游戏资源包格式到写出解包程序的过程整理成文,与大家共享。

我们今天的目标是一款名为《夜神任务:同心同灵》的游戏,下载地址: http://www.verycd.com/topics/2854279/。游戏并不大,这样利于我们由浅入深地进行学习。

分析游戏用到的工具有:

1.查壳工具PEiD,同时还要用它来识别程序中使用的压缩算法;

2.调试器OD 1.10;

3.静态反汇编工具IDA;

4.16进制编辑器WinHex

1.最后要用一种编程语言写出自己的解包工具,为了锻炼自己的汇编语言编程能力,开发语言我选择了win32汇编,使用了汇编的IDE--Radasm和汇编的sdk——MASM32 v10。大家只要明白了资源文件的结构,可以选用自己所擅长的编程语言来写解包器。

静态分析

安装完游戏之后,在游戏的根目录我们能看到如图1所示几个文件和目录,从大小和名字来看,可以很容易的确定资源文件是放在DATApc文件夹中。

在Datapc文件夹中有三个比较大的pak文件,这三个文件就是游戏的资源包了,也就是我们要解包的对象。在很多情况下?六<文件文件是可以用winrar、好压或者72解压的, 这类PAK文件用WinHex之类的16进制打开后可以发现开头的两个字母都是“PK”,而且右 键菜单中会有用winrar之类的压缩软件解压的选项。但是这个游戏的资源文件不属于这种类型(是的话就不会有这篇文章了)。我们用WinHex打开三个PAK文件,找一下三个文件 的共同特征,首先会发现文件开头部分格式比较相似,都是以“KCAP”四个字母开头,这 应该是这类文件的一个标志,后面是一个hex值为00 00 00 01的双字,用途未知,从偏移0x20开始到0x1f处都是0,只有0x8偏移处的一个双字有所不同,都在偏移0x20处开始有格式比较相同的数据,如图2。

在这里,我们可以假定前面20h个字节的内容为固定的文件头大小,继续往下看,会发 现三个PAK文件都是些以HEX值为78 9C开头的数据块,这些数据块大多数都是长度不定,并以不定数量个0结尾。到了接近末尾的时候,才出现了一些不一样的数据。这些数据中还包括一些可读字符,看起来应该是文件名,而且每隔0\120字节就是下一个文件名,直到文件结束。文件名的后面是长串的0,应该是填充文件名缓冲区的。在从文件名开头往后0x100

字节处开始出现其他信息,但是目前还不知道这些信息是做什么的,最后的16字节也是全部是0。如图3

根据上面的分析,可以大体的推断这种PAK文件由三部分组成:第一部分从偏移0到 0x1F处是文件头;第二部分是包含了大量以HEX值为78 9C开头的数据块的部分则是保存资源压缩后的数据的部分;最后的部分因该是每一个文件的信息,应该根据这些信息将压缩后 的数据解压。当然这些都是猜测,只有实践后才会知道猜测的是否正确。

通过这些分析,我们可以先简单的定义出表示这些部分的结构体,暂时作用未知的部分 就叫做UnKnown:

文件头部分

HEAD STRUCT

dwFlag DWORD ?

dwUnKnownl DWORD ?

dwUnKnown2 DWORD ?

dwZero DWORD 5 dup(?)

HEAD ENDS

文件信息部分

FILEI0F0 STRUCT

szFileName BYTE  100h dup(?)

dwUnKnownl DWORD ?

dwUnKnown2 DWORD ?

dwUnKnown3 DWORD ?

dwUnKnown4 DWORD ?

dwZero DWORD 4 dup(?)

FILEI0F0 ENDS

好,初步静态分析过程已经完成,但是还有很多地方没搞明白,这就需要我们动态跟踪下游戏程序了。

动态跟踪

跟踪前,先用PEID查一下壳,显示microsoft visual c++,应该没加壳,前面分析道有很多数据块,并且开头都是78 9c,说明文件是被压缩了,我们可以用peid的插件krypto ANALyzer插件看一下程序中都使用了哪些加密或者压缩算法,结果找到了这些算法:

ADLER32 ::00233292 ::00633E92

ADLER32 ::00233446 ::00634046

CRC32 :: 0028CD58 :: 0068E158

CRC32b : :0027DCE8 :0067F0E8

ZLIB deflate [word]  ::0028CC2C : :0068E02C

ADLER32和CRC32应该是用来校验文件的,我们先不管。ZLIB这个是游戏资源包压缩很 常用的压缩算法,而且压缩后的文件开头的标志就是78 90,所以可以确定这个游戏是先用zlib算法将文件压缩,然后放到一个大文件(PAK)中的。

接下来就该od+ida分析文件结构中还没有搞明白的地方。od载入游戏的主程序,先 Ctrl+N查看下游戏都调用了哪些跟文件有关的API,经过一番查找发现调用了 CreateDirectoryA、CreateFileA、ReadFile、SetFilePointer、WriteFile 几个api。先都下上断点, 然后f9,程序断在createFile上,从堆桟上看参数如下:

0012F5A4 0061A407 /CALL to CreateFileA from NyxQuest. 0061A405

0012F5A8 0012F7C8 |FileName = 〃DataPC/DataCommon.pak〃

0012F5AC 80000000 |Access = GENERIC_READ

0012F5B0 00000003 |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE

0012F5B4 0012F5D0 |pSecurity = 0012F5D0

0012F5B8 00000003 |Mode = OPEN_EXISTING

0012F5BC 00000080 |Attributes = NORMAL

0012F5C0 00000000 \hTemplateFile = NULL

Ctrl+F9返回,到ida中看一下这个地方做了些啥,结果发现这个地方很复杂

查看下函数名,发现这里是c的库函数,_tsopen_nolock,既然如此就不在这里浪 费力气了,继续ctrl+F9 N次,并在ida中观察函数的名字,发现程序其实调用的是fopen, 并且还发现下面有fseek、ftell、rewind,但是并没有发现fread,所以继续F9,然后会 在SetFilePointer上中断三次,分别是fseek、ftell、rewind调用的,继续F9,就会中断到ReadFile上,这个就应该是fread调用的了,然后Ctrl+F9返回多次,找到是在004317M 处调用的fread。

分别在fopen、fseek、ftell、rewind、fread上下断点,并把在api上的断点去掉, 重新载入游戏,F9运行。中断到了 fopen上,从参数可以看出是以“rb”的方式打开了 “DataPC/DataCommon.pak”。ctrl+F9,发现返回值是006C6C60h,记下这个值,然后继续 F9,中断到了 fseek,从堆栈看参数是

0012F700 0043170D RETURN to NyxQuest. 0043170D from NyxQuest. 005F5370

0012F704 006C6C60 NyxQuest. 006C6C60

0012F708 00000000

0012F70C 00000002

还原成 C 就是 fseek(0x006C6C60,0, SEEK_END);

可以看出是将DataPC/DataCommon.pak的指针移动到了文件最后。继续F9中断到了 ftell, 参数是:

0012F708 0043171F RETURN to NyxQuest. 0043171F from NyxQuest. 005F5278 0012F70C 006C6C60 NyxQuest. 006C6C60

还原成 C 就是 fteN(0x006C6C60);

这个函数是返回当前文件指针的位置的,ctrl+F9发现返回值是013DD0C0h,用Winhex打开datapc/DataCommon.pak,发现指向的是文件末尾,这里应该就是确定下前面的fseek,是不是把指针设置到了文件的末尾,没有什么用,继续F9,中断到了rewind,参数是:

0012F708 0043173A RETURN to NyxQuest. 0043173A from NyxQuest. 005F5015 0012F70C 006C6C60 NyxQuest. 006C6C60

这个函数又将文件的指针设置回了文件开头(有意思么? ?)。 继续F9,在Fread上断下来了,参数如下:

0012F8F4 004317AF RETURN to NyxQuest. 004317AF from NyxQuest. 005F4FBD

0012F8F8 0012FAA4 ;将读取的东西放到这个缓冲区

0012F8FC 00000001 ;sizeSl,以字节为单位读取的

0012F900 00000020 ;读取的大小为20h字节

0012F904 006C6C60 NyxQuest. 006C6C60 ;读取的是前面fopen打开

的 DataCommon. oak

Ctrl+F9,然后在00的内存窗口看下0012FAA4位置到底读了些什么,结果发现就是我们定义为HEAD结构体的部分。继续F9,又中断到了fseek,参数如下:

0012F8F8 00431828 RETURN to NyxQuest. 00431828 from NyxQuest. 005F5370 0012F8FC 006C6C60 NyxQuest. 006C6C60 0012F900 013D4F60 0012F904 00000000

还原成 C 就是 fseek(0x006C6C60, 0x013D4F60, SEEK_SET);

在winhex里面看看这个0x013d4f60位置是什么,结果发现是第一个文件名的开头。那么这个值是如何来的呢?我们在IDA中逆着向上看,发现这个值有可能从两个地方来,用 OD在0x00430621这个跳转处下断点,重新载入,看一下到底是执行了哪个分支,结果发 5见跳转并没有执行,所以这个值是00430627 . E8 C40A0000 CALL 004310F0这条指令调用的函数的返回值,然后在下面经过多次传递后又乘以12011所得到的。这个函数是有 一个参数,从od中看这个参数是一个指针,指向读取到内存中的pak文件的偏移018处的一个DWORD,也就是head中的第三个dword,而这个函数的作用就是将这个值每个字节从后往前排,并把得到的值返回(感觉好乱啊)。举个例子,比如DataCommon.pak的HEAD中的第三个双字在WinHex中看是00 00 00 73,经过转换之后就是73 00 00 00 (这个转换是 在01 00430627处调用一个函数转换的),在程序中读取后就是73h乘以12011就是801611 而DataExt.pak中的这个位置是00 00 03 D7,转换后就是D7 03 00 00,在程序中读取后 就是3D7h,乘以120h就是451E0ho

继续F9,中断到了fread上,参数如下:

0012F8F4 004317AF RETURN to NyxQuest. 004317AF from NyxQuest. 005F4FBD

0012F8F8 013055D8 ASCII "

0012F8FC 00000001

0012F900 00008160

0012F904 006C6C60 NyxQuest. 006C6C60

可以看出来这里把所有的文件信息部分都读取到了内存。

分析到了这里,我们已经可以不用在分析了,已经完全可以凭猜测加测试搞定。根据分析结 果HEDA结构体可以冲洗定义成这样:

HEAD STRUCT

dwFlag DWORD ?

dwUnKnownl DWORD ?

dwFilelnfoSize DWORD ?

dwZero DWORD 5 dup(?)

HEAD ENDS

再看DataPC.PAK文件的文件信息部分的第一个FILEIOFO结构体,最开始的的100h字节 是文件名,往后的有数据的双字则是重点,它们应该包含文件名所指的这个文件在这个pak包中的大小,偏移等信息,经过试验发现第二个双字经过反转(同上面方法一样)之后(不用乘以120h)是这个文件压缩后的数据的大小,因为zlib解压的时候要求输入解压完的文 件大小,这个大小一般都是在压缩之前保存好的,而正好第一个双字的数值大小经过反转(不乘以120h)后大小比较合适,就假设他是文件的大小。第三个双字反转后则是这个文件pak中的偏移,但是这个偏移没有什么太大用处,因为每个文件之间都是没有空隙的,读取 完了一个直接读取下一个就可以了。由于剩下的部分都是一样的,可以不用在乎。这样我么 可以把FILEIORD重新修改成这样

FILEIOFO STRUCT

szFileName BYTE 100h dup(?)

dwExpFileSize DWORD ?

dwCompFileSize DWORD ?

dwOffset DWORD ?

dwUnKnown DWORD 5 dup(?)

FILEIOFO ENDS

文件数据结构的分析就到这里了,对于完整了解这个pak,还需要很多工作要做,不过对于编写一个解包器,以上的分析就足够了。

编程实现

根据分析所得的这些信息,写一个解包程序就不难了,大体流程如下:

1.读取文件的HEAD,检查HEAD.dwFlag是否为5041434Bh,不是则说明不是我们分析的格式的pak文件,不在往下执行。

2.读取HEAD.dwFilelnfoSize,然后按照前面说的方法计算出文件信息部分的大小。 相关的代码在WM_COMMAND消息处理逻辑中

invoke SendDlgItemMessage, hWin, LST_INF0, LB_RESETCONTENT, 0, 0 invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF. lStructSize, sizeof @stOF push hWin pop @stOF. hwndOwner mov @stOF. lpstrFilter, offset szFilter

mov @stOF. lpstrFile, offset szFileName

mov @stOF. nMaxFile, MAX_PATH

mov @stOF. Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or

0FN_HIDEREAD0NLY

invoke GetOpenFileName, addr @stOF

.if eax

invoke

SendDlgItemMessage, hWin, EDT_PAKPATH, WM_SETTEXT, 0, offset szFileName

invoke CreateFile, offset szFileName, GENERIC_READ, \

FILE_SHARE_DELETE, NULL, OPEN_EXISTING, NULL, NULL

.if eax==-l

invoke MessageBox, hWin, offset 0penError, NULL, MB_0K

invoke ExitProcess, 0

.endif

mov hFile, eax

invoke GetFileSize, eax, NULL

mov dwFileSize, eax

invoke CreateFileMapping, hFile, NULL, PAGE_READONLY, 0, 0, NULL

.if !eax

invoke MessageBox, hWin, offset 0penError, NULL, MB_0K

invoke CloseHandle, hFile

invoke ExitProcess, 0

.endif

mov hFileMap, eax

invoke MapViewOfFile, eax, FILE_MAP_READ, 0,0, 0

.if !eax

invoke MessageBox, hWin, offset OpenError, NULL, MB_OK

invoke CloseHandle, hFileMap

invoke CloseHandle, hFile

invoke ExitProcess, 0

.endif

mov dwBaseAddress, eax

assume eax:ptr HEAD

.if [eax]. dwF1ag!=PACK

invoke MessageBox, hWin, CTXT (〃不支持的 PAK 格式' 0,0,MB_OK

invoke EndDialog, hWin, 0

.endif

mov ebx, [eax]. dwFilelnfoSize

mov byte ptr dwFilelnfoSize[3], bl

mov byte ptr dwFileInfoSize[2], bh

shr ebx, 16

mov byte ptr dwFileInfoSize[l], bl

mov byte ptr dwFilelnfoSize, bh ;pop dwFilelnfoSize assume eax:nothing

mov ebx, dwBaseAddress

add ebx, dwFileSize

mov @dwMaxOffset, ebx

imul eax, dwFilelnfoSize, 120h

sub ebx, eax

mov @dwFilePoint, ebx

assume ebx:ptr FILEINFO .while ebx<@dwMaxOffset invoke

SendDlgItemMessage, hWin, LST_INF0, LB_ADDSTRING, 0, addr [ebx]. szFileName add ebx, sizeof FILEINFO .endw assume ebx:nothing

3.用一个大的循环读取文件的信息,根据信息用zlib的解压函数解压数据,并将数据写到文件中。 y^-

ExportProc proc uses ebx esi edi, lParam

LOCAL @dwMaxOffset, @Buffer[110]:BYTE, @szFileName[MAX_PATH]:BYTE LOCAL @dwNumberOfBytesWritten, @szPath[MAX_PATH]:BYTE LOCAL @szCreatePath[MAX_PATH]:BYTE LOCAL @dwErro, @lpDest, @dwSuccess, @dwFilePoint mov @dwErro, 0 mov @dwSuccess, 0

invoke _BrowseFolder, lParam, addr @szPath .if eax

push dwBaseAddress pop @dwFilePoint add @dwFilePoint, 20h

mov ebx, dwBaseAddress add ebx, dwFileSize

mov @dwMaxOffset, ebx ;设置循环结束的位置 imul eax, dwFilelnfoSize, 120h sub ebx, eax

assume ebx:ptr FILEINFO .while ebx<@dwMaxOffset

invoke wsprintf, addr @szFileName, CTXT(〃%s\%s〃),addr @szPath, addr [ebx]. szFileName ;将文件名追加到路径名后面

invoke Replace, addr @szFileName ;将路径中的

/转换为\

invoke CreateFile, addr

@szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, \

CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ;创建出出文件 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;第一次创建文件失败可能是因为文件夹不存在, 则再创建所需要的文件夹再创建一遍该文件* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * i f i

.if eax==-l

invoke InitOutputPath, addr @szFileName, addr

@szCreatePath

invoke SHCreateDirectoryEx, lParam, addr

@szCreatePath, NULL

invoke CreateFile, addr @szFileName, GENERIC_ffRITE, FILE_SHARE_READ, \

NULL, CREATE_ALffAYS, FILE_ATTRIBUTE_NORMAL, NULL

.if eax==-l

inc @dwErro invoke

SetDlgItemInt, lParam, STC_ERROR, @dwErro, FALSE

jmp CONTINUE .endif .endif

mov hCreateFile, eax ;保存创建的文件的句柄 ;;;;;;;;计算导出后文件(实际文件)的大小 * * • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •

mov eax, [ebx]. dwRealSize

mov byte ptr dwExpFileSize[3], al

mov byte ptr dwExpFileSize[2], ah

shr eax, 16

mov byte ptr dwExpFileSize[l], al mov byte ptr dwExpFileSize, ah

invoke GlobalAlloc, GPTR, dwExpFileSize ;根据要导出 的实际文件大小申请一块内存,提供21化解压函数使用

.if eax

mov @lpDest, eax

;;;;;;;;;;;;;;;;; 计算未解压缩前的数据的大小 * * • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • * * * mov eax, [ebx]. dwFileSize

mov byte ptr dwSrcFileSize[3], al mov byte ptr dwSrcFileSize[2], ah shr eax, 16 mov byte ptr dwSrcFileSize[l], al

mov byte ptr dwSrcFileSize, ah

;;;;;;;;; 调 用 zlib 的 解 压 函 数 解 压 >ur_. 数

^^ • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • * * * *

invoke uncompress, @lpDest, offset

dwExpFileSize, @dwFilePoint, dwSrcFileSize

• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • * * * *

invoke

WriteFile, hCreateFile, @lpDest, dwExpFileSize, \

addr @dwNumberOfBytesWrit ten, NULL

.if eax

inc @dwSuccess

invoke

SetDlgItemInt, lParam, STC_SUCCESS, @dwSuccess, FALSE

jmp CONTINUE

.else

inc @dwErro

invoke

SetDlgItemInt, lParam, STC_ERROR, @dwSuccess, FALSE

.endif

invoke CloseHandle, hCreateFile

invoke GlobalFree, @lpDest

.else

inc @dwErro

invoke

SetDlgItemInt, lParam, STC_ERROR, @dwErro, FALSE

.endif

CONTINUE: mov eax, dwSrcFileSize

add @dwFilePoint, eax

add ebx,sizeof FILEINFO ;指向下一个FILEINFO

.endw

assume ebx:nothing

invoke MessageBox, lParam, CTXT (〃 导出完成! ! 〃),CTXT (〃 完成!

"),MB_OK

.endif

ret

ExportProc endp

限于篇幅就不将其它代码贴出来了。 希望本文能为想自己修改汉化游戏的朋友带来一点帮助,这方面的技术我也是初学,有所疏漏在所难免,希望大家不吝赐教。

一款游戏资源解包工具的开发始末相关推荐

  1. 疫情期间自我修炼, 搞一搞老游戏资源解包

    疫情期间自我修炼, 准备搞一搞老游戏资源解包, 修旧利废,聊以自慰.首先对不住的是大雨资讯的<大富翁>系列,挑了几个感兴趣的解包完毕: 1-3是DOS版,没什么好看. 4太难看,决定从5开 ...

  2. 华为固件解包工具linux,华为固件解包工具

    有些朋友还不知道华为官方SD卡刷机包UPDATA.APP要如何解包?今天小编特意带来这款华为固件解包工具update.app给大家使用,该软件用于解包华为官方SD卡刷机包UPDATA.APP,可将AP ...

  3. 华为固件解包工具linux,华为app固件解包工具

    华为固件解包工具是一款针对华为手机所推出的APP固件解包软件.它的功能十分强大,将华为官方SD卡刷机包UPDATA.APP解包成IMG镜像分区文件,还可以提取recovery.img.system.i ...

  4. 华为固件解包工具linux,华为app固件解包工具下载

    华为固件update.app解包工具是一款专门为用户打造的华为app固件解包工具,可以帮助用户解华为官方sd卡刷机包UPDATA.APP,可以将app固件解包成img镜像文件,也可以对刷机包进行定制等 ...

  5. 安卓pkg解包工具_这个曾改变安卓的男人,要对苹果下手了?

    将「雷科技Lite」收藏为我的小程序,不再错过精彩内容 凡是经历过早期安卓的用户,几乎没有不知道 Root 这个词的. 几年前,大约是 Android 2.x 的时期,那会儿我们能接触到最早的 Roo ...

  6. asar软件包linux,WinAsar下载_WinAsar工具下载(ASAR文件查看打包解包工具)-下载之家...

          WinAsar官方版是一款很实用的对ASAR文件进行管理的工具,WinAsar拥有ASAR文件查看.打包.解包等功能,WinAsar工具官方版还能够对asar文件进行解密加密,软件里面包含 ...

  7. asar软件包linux,ASAR文件查看打包解包工具下载-ASAR文件查看打包解包工具v2018.07.12免费版-ucbug软件站...

    ASAR文件查看打包解包工具是一款能够帮助用户对ASAR文件进行管理的工具,通过ASAR文件查看打包解包工具能够对文件进行查看.打包.解包等功能,有需要的可以下载使用. 功能介绍 electron的a ...

  8. 华为固件解包工具linux,华为解包工具官方下载

    华为官方APP固件解包工具包括:华为官方固件update.app专用解包工具和 system.img解包工具,可解包华为官方SD卡刷机包UPDATA.APP,可将APP固件解包成IMG镜像分区文件,继 ...

  9. 华为固件解包工具linux,华为固件解包工具-官方版-华为固件解包工具update.app官方版-独木成林...

    华为官方固件update.app解包工具,用于解包华为官方SD卡刷机包UPDATA.APP,可将APP固件解包成IMG镜像分区文件,继续解包可对刷机包进行定制,可用本工具提取recovery.img. ...

最新文章

  1. QLocalServer与QLocalSocket进程通讯
  2. 杭电2855 Fibonacci Check-up
  3. 11月上旬息壤网络域名总量呈负增长 份额跌破1%
  4. CORS 跨域-哪些操作不受同源限制
  5. CSS 中文字体的英文名称对照
  6. Linq下有一个非常实用的SelectMany方法,很多人却不会用
  7. Spring,Reactor和ElasticSearch:使用伪造的测试数据进行标记
  8. mpvue 从零开始 女友拉黑了我 5 不在以下request 合法域名列表中,请参考文档
  9. 手机界面常见的的九宫格
  10. 5.过滤器作为模板——寻找沃尔多、不相同的模板匹配_3
  11. Hadoop为什么没有采用RAID?
  12. ASP.NET MVC 5– 使用Wijmo MVC 5模板1分钟创建应用
  13. 25 亿条/秒消息处理!Flink 又双叒叕被 Apache 官方提名
  14. 计算机控制电梯报告总结,电梯控制实验报告电梯控制实验报告.doc
  15. 一些成功又不失趣味的网络营销案例
  16. Vue 九宫格抽奖实现
  17. fastlane php,fastlane 自动化打包不同的target,以及手动传版本号参数
  18. android自定义大转盘,Android 自定义View 抽奖大转盘(1)
  19. keyshot手机渲染教程_keyshot渲染教程
  20. win10计算机属性管理打不开,win10系统此电脑属性打不开怎么办

热门文章

  1. 100盏灯泡的开关问题
  2. 论文阅读-DF-Platter: Multi-Face Heterogeneous Deepfake Dataset(多人脸异构深度伪造数据集)
  3. cephadm安装ceph
  4. 80% 的初创公司缺乏对话式人工智能知识
  5. h5页面生成图片分享到微信js_H5微信自定义分享链接(设置标题+简介+图片)
  6. 用MATLAB计算函数的积分
  7. 派聚七:聊聊淘宝店铺日常运营技巧--聚会回顾
  8. 将LCD屏幕倒过来显示(LCD翻转)
  9. SQL Server函数,你想要的都在这
  10. Camera2预览流程简单附demo