加密解密技术之输入数据 输入函数表(附图)

日期: 2010-01-27 来源:TechTarget中国

  几个月前,我首次遇到了程序因被加壳而带来的问题。我碰上了Advanced Registry Tracer 1.0a (Aspack 108.3的分三次压缩) 。幸好,在网上已经能找到对待这类问题的文章,特别还有一个很棒的工具: Procdump (G-Rom, Lorian & Stone )。 麻烦的是,除了把程序脱壳并获得它完全能运行的执行文件前, 将无法得到一份带有输入函数的反汇编代码。这对自身来说并不怎么的,可是让反汇编数据读起来没有这么清晰。

  例如,你将得到以下的代码:

:0040343A FF15F0634000 Cal dword ptr [004063F0]

  而不是:

*Reference To: SHELL32.ShellExecuteA, Ord :006Ch
|
:0040343A FF15F0634000 Cal dword ptr [004063F0]

  ( 这样毕竟是比较清楚的解释了这个CALL的行为 )


  我就因此产生了在WDAM里获取这些输入函数显示的念头。自此以后,我开始大量收集PE格式文件的资料, 特别是关于输入函数的。这段经历给我留下了一些笔记和一篇所谓开了卷却没有完成的文章…

  最近,在读了一篇关于Advanced Registry Tracer 1.1b的解文后,我怀疑那是aspack的一个新版,   抱着想测试一下我第一次使用的方法的念头,

  我从抽屉底取出了以前的笔记,重读后,忽然让我感觉到特别的简短。 因而我决定对它们填满一点,并利用这个机会再写一篇输入函数的文章.

  我没有雄心重新写一篇完整的输入函数的文章,我没有这个功力. 我只是将我以前读过的一些专家的论文以及我明白的部分作个总结.
我不排除本文中会包含一些推理性错误。

  所有我在这里的总结, 是我在阅读一篇很经典的文章后的成果, 这就是“ Peering Inside the PE : a tour of the win32 Portable Executable File Format ” ,作者是Matt Pietrek, “ Windows Internals ”的作者, 他在曾为 Nu-Mega Technologies Inc.工作 ( 现在还是? )

  要找此文,只需到微软的官方网站上进行搜索。

  PE 格式文件的简单介绍

  一个可执行文件的物理结构在硬盘上和跟它在内存中的很相似,它一经WINDOW的 装载器装载,不需要执行很繁琐的手续, 便能以硬盘里的文件在内存里建立进程.对于WNDOWS的装载器,所有的代码, 数据, 资源, 输入,输出函数等…将被一个挨着一个的连续存储在内存的一个块里.
PE Header 给WINDOWS装载器提供必要的信息,让它知道在某处可找到程序的某部分(section 节),在内存的哪里存储,和如何将这些散件组装起来,构成一个可执行文件.

  Matt Pietrek 以建房子为例子作了个比喻:PE格式文件就象一套集装件的房子, 所有的部分都预先制造好了,只要将它们互相连接,安装起来就可以了.

  我们在这不是要上一堂PE格式文件和PE 文件头(header)的课, (要是为了这个,建议阅读上面列出 Matt Pietrek 的有关文章)。在这,我们选取详细的解释PE文件其中的一个section(节) : idata 节。一般来说, 在这我们可以遇到输入函数 (我们的讨论中心)。为了对输入函数表进行演示,我们选取了 NOTEPAD.EXE。

  注 : 为了避免混乱, 所有的十进制数据将表示为 (dec), 剩余别的将用十六位表示.

  对输入表数据和输入函数的研究

  以下为用Wdam 反编出来 NOTEPAD.EXE 的代码:

Number of Imported Modules = 6 (dec)
Import Module 001: SHELL32.dll
Import Module 002: KERNEL32.dll
Import Module 003: USER32.dll
Import Module 004: GDI32.dll
Import Module 005: comdlg32.dll
Import Module 006: ADVAPI32.dll
+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++
Import Module 001: SHELL32.dll
Addr:7FD47579 hint(006C) Name: ShellExecuteA
Addr:7FD034A7 hint(000F) Name: DragAcceptFiles
=============


  以下是符合在DLL里被调用函数的一串代码的例子
* Reference To: SHELL32.ShellExecuteA, Ord:006Ch
|:0040343A FF15F0634000 Call dword ptr [004063F0]
:
=============
* Reference To: comdlg32.ChooseFontA, Ord:0002h
|
:0040166E E817380000 Call 00404E8A
:00401673 85C0 test eax, eax
: —-
* Reference To: comdlg32.ChooseFontA, Ord:0002h
|
:00404E8A FF2504654000 Jmp dword ptr [00406504]


  借助Procdump (感谢G-Rom Lorian & Stone !)对Notepad.exe 的 PE header 进行观察.

  Procdump 是个用来观察PE header最好不过的工具, 所以不敢独占! (还有我觉得,为了感谢它的创作者,我们更应该频繁的使用它)
那么, 打开Procdump, 点激 “ PE Editor ” 和打开我们的目标文件 notepad.exe.

  以下是正常情况下Procdump应该显示的:

加密解密技术之输入数据 输入函数表1

  这里最让我们感兴趣的是.idata节,因为是在这凝聚了所有输入函数的信息.

  我们发现这里 virtual offset (在内存里,idata节开始处) 跟raw offset (在硬盘里的实际地址)是一致的. 更好, 这为我们后面的工作省了不少事.

  .idata 中有用的数据占的大小是被 virtual size : 0DE8表示 (也就是,在输入数据中,有0DE8 字节的数据)。节的真正的大小(raw size) 是 1000. 节是从 06000 延展到 06FFF。因此, 借助一个文件编制器,我们可以看到:

  在offset 6000: 节的第一个字节
  在offset 6DE8: 最后一个有用的字节
  在offset 6FFF: 节的最后一个字节

  现在让我们来看看PE directory里的一些信息:

加密解密技术之输入数据 输入函数表2

  输入表: (或image Import descriptor)

  我们有输入表的 RVA (virtual offset): 6000

  输入表(Import descriptor)的大小是8C字节。 也就是说,在608C结束所有被输入的DLL的信息.(这些DLL和信息将指向这些DLL的函数)

  输入地址表:

  输入地址表从62E0开始 : 也就是说在这里, 我们将找到每个DLL的函数的调用地址,直到62E0+0240 = 00006520,有0240个字节地址, 0240/04 = 0090字节,也就是十位数144。 这让我们对输入函数的数目有个主意,(一串DLL函数的地址结尾由dword null组成, 那么有少于144个(dec)函数被输入)。

  现在让我们用十六位编辑器来观察一下idata节段:

  注意:

  您不一定总会找到一个命名为“.idata”的节段。有时,输入函数在其他部分节段,例如.rdata,混合在别的数据之间。为了给你一个主意,让我们来看一下Filemon.exe或Regmon.exe的 PE header…


  观察NOTEPAD.EXE输入表的开头: (在内存里,这个表从? image base + rva idata ? 开始,即 00406000)

加密解密技术之输入数据 输入函数表3

  Image Import Descriptor 的格式 (请读Matt Pietrek的 ? peering inside the PE ? !)。在Image Import Descriptor里, 一个DLL及其相应的函数由5个 Dword构成, (就是 20 (dec) 伏特 = 0014 字节)

  Dword 1 -特征(hint name array)
  这个dword是指向指针表的第一个元素的指针.
  这个表的每个指针指向hint name函数,跟着一个函数名.

  例子:(表的开头)

加密解密技术之输入数据 输入函数表4

  在0000657A, 我们有一个hint name (006C)和函数的名字ShellExecuteA.下一个函数位于0006568,即DragAcceptFiles。 (这个表是从底部往上读的)

  Dword 2 – TimeDateStamp

  表明什么时候文件被建立.(DLL?)

  Dword 3 – ForwarderChain

  让其转向另一DLL。 (没有提供例子,例子比较难发现“dixit Matt Pietrek”),实际上,我们总能看见FF FF FF FF. (这构成一个容易辨认的视觉符号...就在指针指向DLL的名字前)

  Dword 4 – DLL 的名字

  这个dword是指向DLL名字的指针 (null terminated ascii string)

  例子:(表的开头)

加密解密技术之输入数据 输入函数表5

  在0000658A,我们能看见DLL的名字 (SHELL32.dll)

  我们往上看一下,能看见与它相关函数的名字,这个表应该从底部向上读。


  Dword 5 -输入地址表

  这个dword是指向地址表第一个元素的指针。这个地址表与指针指向hint name (函数名)同时平行有效。

  例如: (表的开头)

-hint names表的第1个元素指向ShellExecuteA函数 (参看dword 1 – characteristics)
-地址表的第1个元素包含ShellExecuteA函数的物理地址= 7FD47579


  例子:(表的开头)

加密解密技术之输入数据 输入函数表6

  注:这个表通常被WINDOWS的PE loader 在装载(或运行?)执行文件时覆盖。的确, WINDOWS的PE loader 得重新调整 每个函数的地址,假如函数的地址在一个新的DLL出去时被改过了的。每个函数的地址是借助GetProcAddress函数(hModule,lpProcname) (包含函数的DLL 句柄, 长指针指向函数名)得来.

  以下的简化图表为了全面总结一下:


  .IDATA节:输入数据表

加密解密技术之输入数据 输入函数表7

  现在,我们在Softice或Hexworks下来整体观察一下Microsoft类型的输入表,看看的每个部份在视觉上是怎样辨认的.

加密解密技术之输入数据 输入函数表8

  主要视觉参照符号由在蓝色或红色的框构成。

  例如:为了快速的检查在hint name array 和 输入地址表里的数据有没有明显的反常现象,只要看看在第二个竖栏里的数据(红色的框里)


  怎么样,您能跟的上吗? 我尽量试着解释的清楚一点.

  好了,请放心,最难的已经过去了,现在我们换看另一种组织比较简单的输入表.直到现在我们所见的,是那些符合使用微软的一些工具编写的,连接的程序.用DELPHI 或 Borland公司的其他工具编写的程序跟这个不同.以下是 Matt Pietrek 在 ? Peering Inside the PE ?里说的:

  “为了您,Borland的用户,与上述的描述有轻微的出入。 一个由TLINK32产生的PE文件缺少了一个表. 在这样的一个执行文件里,在IMAGE_IMPORT_DESCRIPTOR里的领域特征(aka the hint-name array)是00。所以,在所有PE文件中,只有指向第一领域的表是被保证存在的(the Import Address Table)。 “


  所以,不止有一个指针表:输入地址表。这类型的输入表可以在用Delphi编写的程序里观察到 : 例如Restorator 2.5 (一个资源编辑器)
但我们还是一起来观察一下ASPCAK2000的输入表(原来的,当它还没有被Aspack加壳前)。请跟我来:

  观察ASPACK2000.EXE的输入表开头(在内存里,表是从 imagebase+rva idata开始)。

加密解密技术之输入数据 输入函数表9

  就是啦,只有Dword 4和5的每个输入包含数据! 这样简化了我们的阅读…

  Dword 4 – DLL 的名字总是指针指向DLL的名字 (null terminated ascii string)


  例子:(表的开头)

加密解密技术之输入数据 输入函数表10

  在0004669C我们有DLL的函数名(kernel32.dll).我们发现跟着它的后面有些与它相应的函数.这次这个表从上往下读.


  Dword 5 -输入地址表

  指针指向指针表的第一个元素,也就是指向与这个DLL相关的函数.

  在我们的例子中:

表里的第一元素指向DeleteCriticalSection 函数
表里的第二元素指向LeaveCriticalSection函数

  最后的指针指向函数的结尾(DLL函数名的结尾)是由双词00表示 (0000 0000)


  例如: (表的开头)

加密解密技术之输入数据 输入函数表11

  在000466AA,我们有hint name (0000) ,跟在后面有函数DeleteCriticalSection.下个函数是000466C2,即LeaveCriticalSection。表是从上向下读。


  通常,输入地址表本该包含被调用函数的地址,现在用来指向每个DLL函数名.

  在执行文件时, WINDOWS的装载器将这些数值换成调换这些函数的地址.
(您可以用以下的方法来检查一下:运行程序,然后转到SoftIce下去看看这些指针的变化)

  最后一个简化小图整体总结一下:

加密解密技术之输入数据 输入函数表12

  好了,最后让我们在SOFTICE或HEXWORKS里,视觉辨认一下Borland类型的程序的输入表的每个部分 :

加密解密技术之输入数据 输入函数表13

  还跟得上吗?虽然这个对输入表的快速流览让人感到有些乏味(我们这里只讲述了这个大主题中的一小部份),但是在某种情况下,吸收这些基础是被证明有用的.

  特别是当您遇到一写加了壳的程序,您不能靠反编译来获得一串输入表数据,输入函数。为了了解更多,请不要犹豫的在这方面多收集专家的资料.我这里只是总结了一些我学习后记住了,或感觉弄明白了的东西…

  好了,现在我们知道如何对付微软或Borland类型的输入表…我们来点实际操作吧…

  实践的目标程序是: Aspack 2000.exe

  Aspack是一个执行程序的压缩壳,详情请参看它的网站:http:// www.aspack.com

 Aspack2000.exe本身就是用Aspack 来加壳的!上一个版本的Aspack( 108.3)已经包含了了某些烦人的特征:

  Aspack对允许对一个程序进行多层压缩加壳,在有些情况下,procdump的自动脚本将对它无能为力, 因而,必须采用全手动DUMP的方法.Advanced Registry Tracer 1.0a就是分三次压缩的.在脱壳后,无法获得清晰的输入函数表.(部分的输入表将被Aspack的装载器损坏)。

  Aspack 2000的版本的特征与以上的版本基本一致,只是增多了对SOFTICE的检验和对PE LOADER被修改的检验功能.

  目标: 获取Aspack 2000在Wdasm下带有清晰的函数表的脱壳版.

  工具: SoftIce (谢谢Numega! ), Procdump (谢谢G-Rom, Lorian & Stone ! ! ), FrogsICE (谢谢Frog s_Print!! ), Hexworks30 (谢谢… 噢… BpSoft !)

  方法: 我将试着找出一种比较通用的,操作起来比较简单的方法 (尽可能也适应别的壳的?)….由您来裁定吧.

  我将介绍分为4个步骤:

-手动DUMP出输入函数表,在它还是”干净”的时候 (SoftIce + procdump或者IceDump)

-手动在程序执行前DUMP出它的脱壳程序 (SoftIce + procdump)

-把DUMP出的输入表插入脱壳后的程序里(hexworks30)

-在directory Import table里,将入口处(entry point)及地址升级 (procdump)


  埋头苦干前的准备工作:

  1 – Anti-SoftIce

  为了安心工作,首先要干掉Aspack对SICE的侦查功能:有几个方法,和一个优秀的工具“FrogsIce” (谢谢Frog’s print ).

  在求知欲和测试另一种方法的好奇心驱使下,我在WINICE.EXE文件里, 用十六位编辑器把“SICE”的字符串替改成了“SoCE”,然后重新启动电脑.呵呵, 这样足够让Aspack在内存里检查不出SoftIce。我向你尽力推荐使用FrogsICE .(再次感谢Frog s_Print!)

  收集Aspack的 PE Header 和Directory Import 的信息。在Procdump里,点击PE Editor 并且打开Aspack2000.exe,以取得有用的信息. (这里用重写及红色表示) :

加密解密技术之输入数据 输入函数表14

  第一在输入表中引起我们注意的:这里,输入表的RVA与IDATA节里的Virtual Offset 不一致.( 00066D1C 代替了 00046000).它指向.ASP节里面.(一个为了aspack装载器必须的节?)

  执行方法:

  根据Aspack的装载者器必须在某个时候, 将它自己压缩的数据解压,并且将idata节重建为原来的样子的原则,它得必须写那些字节在它原来的位置!

  也就是说,从Virtual Offset 46000 (就是 400000 + 46000 = 446000)

  幸运的话,特别一个BPM 446000 W 我们将被通知idata节的恢复。

  凭着研究过Aspack 108.3壳的经验, (要是原则至今没有改变),我知道它将读取那些被压缩的数据,将它们解压在缓冲内存里,然后将解压后的区域复制到它原来的地方.(即446000).这个,有多少层压缩,它就重复多少次.剩下的,我们就可以观察每次截止时在446000区域的内容,直到它干净为止.(经过以上的练习,我们现在就象小孩子玩游戏一样简单了.)每次截停代表一层压缩.

  在几秒钟内,我们就可以知道多少层压缩被用在这个程序上.

  步骤一 : 手动DUMP出输入表,当这个表还是“干净”时.

  我们要放个bpm在ds:00446000的地址,在装载器开始解压数据前,我们要在softIce下设置一个断点, 同时乘机下个bpm, 以下是具体的步骤: (读起来长,但实际操作起来很简单!)

  CRTL+D转到Sice下:

  BPX getprocaddress或BPX getversionexa (在这里,bpx getprocaddress就足够了)


  X或F5为了回到WINDOWS, 和执行Aspack2000.exe
  POP!截住了!

  F12来到Aspack代码领空.

  我们用BD来取消bpx,然后 BPM ds :446000 W

(我们可来个D 446000来检测.idata节没有被动过,只有些 ????)
X或F5,为了让Aspack的装载器继续工作
POP! 在idata节的446000处,有一个写入被截停

  我们处于这段代码:
 
Break due to BPMB #017F:00446000 W DR3
0177:00C0268F F3A5 REPZ MOVSD <– 这
0177:00C02691 89C1 MOV ECX,EAX
0177:00C02693 83E103 AND ECX,03
0177:00C02696 F3A4 REPZ MOVSB <– 复制剩下的区域
0177:00C02698 5F POP EDI
0177:00C02699 5E POP ESI
0177:00C0269A C3 RET


  我们继续用F10追踪,直到为了复制所有的字节到idata节的第2个movsb执行时..


  迅速的看一眼数据窗口,我们能看到有点象样的一个image import descriptor .


  我们还是让窗口下滚,来流览一下输入表直到函数名的结尾,我们训练有素的眼睛用几秒钟告诉我们一切顺利.

  在idata节只有一层压缩, (108.3版本只也有一层)。 然而它令人惊讶的是,它的创作者本来预备了几层压缩的可能性,却只用了一层!

  现在,我们来DUMP内存的446000到448000 (2000个字节的Virtual Size)

  要是您使用IceDump,可以跳到第二步(手动DUMP程序),要是您借助Procdump,要先用以下步骤“冻结” Aspack:

  A EIP 从此处开始让程序循环在同一指示0177:00C02698 jmp eip 然后X或F5

  然后借助Procdump,在现行程序列里,选取aspack,点击鼠标右键,从446000开始,DUMP 2000个字节.保存为“ImpData_Aspk.dmp” (举例). 你不忘记 KILL TASK Aspack.

  (存盘的文件符合我们在这篇文章里用的例子,Borland类型的输入表细节和视觉辨认的图表)

  该转到第二步了.

  第二步 : 手动DUMP出被解压程序,在它被执行前.当然,为了这样做,要弄清aspack在哪里完成它的工作,且把任务交给被解压的程序,我不会详细解释这个过程,因为在写这篇文章时, 已经能找到一些关于Aspack2000的文章.

  我将快速介绍我在这种情况下的一种特殊的方法,一种“视觉”技术(我得承认这种方法有点“野性”):


  我们重启动Aspack2000.exe,在“bpm 446000 W”依然有效的情况下,我们将获得一个对idata节的写入的截断,这是我们的出发点。我们用F10快速跟踪,无须去弄懂被执行的代码,只是数着按的次数,和观察代码所构成的图像,直到Aspack启动为止。

  (相对来说很快,因为剩下没有多少要被解压的节)重新运行Aspack,截取,快速按F10 N次,跟踪到最后一个调用程序的CALL.

  一旦发现这个CALL,( 对我是 0177:00C1151F )

0177:00C1151F E874F9FFFF CALL 00C10E98 <– 启动 Aspack2000
0177:00C11524 5F POP EDI
0177:00C11525 5E POP ESI
0177:00C11526 5B POP EBX
0177:00C11527 59 POP ECX
0177:00C11528 59 POP ECX
0177:00C11529 5D POP EBP
0177:00C1152A C20400 RET 0004
il suffit de tracer avec F8 pour arriver ici :
0177:00C10E98 89C4 MOV ESP,EAX
0177:00C10E9A 89D0 MOV EAX,EDX
0177:00C10E9C 8B1D6C66C100 MOV EBX,[00C1666C]
0177:00C10EA2 89041C MOV [EBX+ESP],EAX
0177:00C10EA5 61 POPAD <– 恢复 registres
0177:00C10EA6 50 PUSH EAX <– push entry point
0177:00C10EA7 C3 RET <– call entry point


  我不再详细讲,这已经见过的了.
? 89 04 1C 61 50 C3 ?字串可被看做Aspack 2000的签名.

  再之,为了快速的找到这个地址,您只要执行‘s 0 L ffffffff 89,04,1C,61,50,C3’’, 在idata节开头第一个因BPM W的截断.这个搜寻能指出这些代码的所在处,现在剩下的就是在最后的RET放一个BPX,为了手动DUMP出程序.
当然,您会注意到这个技术包含一个很大的瑕疵: 它只是在代码上快的“飞行”,因而我们没有学到什么…

  让我们回归主题:

  让程序运行到RET,记下与程序入口处的相符的registre EAX (我的是0044295C)

  象上次一样:
A EIP 从这开始修改成循环在同一指令里.
0177:00C10EA7 jmp eip
用‘BD*’来消除所有的断点.
然后X 或 F5


  最后使用Procdump (总是它),选择aspack的运行程序,点击鼠标右键来个DUMP FULL.


  注意:

  在DUMP前,我建议您修改以下选择:

– recompute object (yes)
– optimize (no) 为了取得raw offset = virtual offset (后来的就比较容易)
– rebuild Import table 或 don’t rebuild import table ?这个选项不是太重要,反正会被我们DUMP出的文件覆盖.

  将DUMP FULL 存盘为:Aspack2000_upk.exe,然后kill dask.

  我们可以做第三步了.

  第三步:将我们DUMP出的输入表插入已脱壳的程序中.


  我们有一个脱壳后的执行程序,但它的IDATA节还没被修复好.

  现在您对输入表比较了解一点了,您可以用Hexworks打开执行文件,您会发现其中的不妥之处...是的,一眼看上去,这个表好像没什么不对,但只要我们细看,真的不妥.
输入表里有些地址与别的不同, 有些指针不是指向函数的名字,而是指向00C3xxxx (即在我们的区域之外)。

  这些是关于USER32.DLL和KERNEL32.DLL的函数.

  如果您选择rebuid import table的选项,这些指针其中一些将是正确的.
要是您想知道,是谁,什么时候,怎么样做出来的,只要在通入IDATA的BREAK之后,来个BPR 446000 447FFF W然后重新执行,等待那个关键的BREAK,再继续跟踪,就会明白所发生的情况.

在Hexworks30 :

-打开DUMP出的“ImpData_Aspk.dmp”文件,及脱壳后的“Aspack2000_upk.exe”文件

-来个Edit /goto 46000,为了将您带到idata节的的第1个字节。

-选择那个块,大小= 2000字节(十六进制),然后删除.

-在“ImpData_Aspk.dmp”文件里重复同一步骤,选择2000个字节的块,然后“复制”

-激活“Aspack2000_upk.exe”的窗口,然后“粘贴”。


  现在我们有一个脱壳后的Aspack2000的程序,并且它具有一个干净的输入表,就象它原来的一样.剩下的一个手续就是把PE header 和 PE directory的值修改.


  第四步: 将入口处及 directory Import table的地址修改升级.


  用Procdump :

・ 更新被解压后程序的入口处
我的是 : 0044295C – 00400000 = 0004295C (在 eax 里显示的值- image base)
・ 修改 .CODE 节的属性为 ? E0…..20 ? 以便在 Wdasm下得到可编译代码.
・ 修改 Directory Import Table 里 的值,为了指向image import descriptor 的开头= 46000
・ 修改 size = 012C (为得到它的值,只要看看 dump出的文件,和辨认出image import descriptor的结尾.)

  如果您在途中没有出错,您现在不仅有一个DUMP出的程序,而且反编译后,它的输入表是正确的,这个程序能运行.
对SoftIce的监测不再存在,因为这个被Aspack装载器收拾了…

  现在,您修改好这个程序的BUG,您可以支付一个豪华的享受:也就是再用回Aspack来把脱壳后的程序重新加壳!
好了,我希望这篇文章能为大家搞清输入表带来帮助.

  向那些将他们的知识,经验,技术,及工具贡献于破解的人们致谢。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。