0%

最近也在慢慢开始接触一些macOS/iOS安全,首先一个难题就是环境搭建。现在的情况是我有一台mac pro 13 2020和一个iphone8,分别记录一下vmware安装macOS虚拟机和iOS越狱降级这两个在调试macOS/iOS内核之前必须做的准备工作。

vmware安装macOS虚拟机

目前主要有两种方式搭建macOS虚拟机:
1.在macOS物理机上能够使用vmware fusion/virtualbox或者vagrant搭建macOS虚拟机,说起来倒是很简单:用vmware fusion应该不会有什么坑,用virtualbox也有人把要踩的坑总结好了:Run macOS 10.15 Catalina (and other versions) in VirtualBox on macOS。用vagrant参考偏执的iOS逆向研究员:收集全版本的macOS iOS+越狱+内核调试这篇文章即可。比较麻烦的是如果用vmware fusion/virtualbox的话sb苹果是不提供完整系统镜像的,得自己找;用vagrant的话又因为大家都知道的原因你得有一个很稳的梯子下那十几个G的镜像文件。
2.在linux/windows物理机上因为版权的原因默认是没有合法的手段让你装macOS虚拟机的,最最最常见的方法就是用unlocker patch掉vmware workstation pro然后安装macOS,当然镜像还是得自己找。推荐使用这个branch的unlocker:https://github.com/BDisp/unlocker/releases,当前最新的版本是3.0.3。这个branch的unlocker据我测试应该是能直接用不会有什么坑。不过这里还是要注意一个问题,unlocker中的gettools.exe会去下载com.vmware.fusion.zip.tar并且下载速度很慢,我们可以先去把这个包下好,下载的地址是到http://softwareupdate.vmware.com/cds/vmw-desktop/fusion找你用的vmware workstation pro对应的版本即可。更改gettool.py的代码,把下载com.vmware.fusion.zip.tar的代码注释掉,用pyinstaller重新打包一个gettools.exe。以管理员权限运行win-install.cmd,在time.sleep(20)的时候把下载好的com.vmware.fusion.zip.tar拷贝进tools目录即可。

接下来就可以安装macOS了,这里我用的镜像是网上找的一个10.10.2的,如果提示你”没有足够的空间来进行安装”按照网上的方法抹掉vmware的硬盘即可:OS X Base System 上没有足够的空间来进行安装。除此之外我没有遇到任何问题。

最后就是安装VMware Tools了,gettools.exe已经下载好了darwin.iso和darwinPre15.iso,我的vmware workstation pro是15.5.1版的,应该用darwinPre15.iso。

关闭虚拟机,编辑虚拟机,设置CD/DVD,使用ISO映像为darwinPre15.iso。开启虚拟机之后会看到桌面的VMware Tools,直接安装就OK了。

很多时候如果你发现github上某个工具因为已经没有维护而不能使用的时候一个小技巧就是去看看issue或者pull request里面有没有人还在继续维护。本来最先搜到的是https://github.com/theJaxon/unlocker,因为没有维护了所以遇到一点问题,在pull request里面找到了另外有人维护的https://github.com/BDisp/unlocker。去年也是,升级了vmware workstation pro之后https://github.com/sysprogs/VirtualKD也没法用了,在issue里面找到了另外有人维护的https://github.com/4d61726b/VirtualKD-Redux。想学习MachO文件格式,https://github.com/gdbinit/MachOView早已无人维护,在issue里面找到了另外有人维护的https://github.com/mythkiven/MachOView……感谢这些编写维护开源软件的大神,不然这些问题真是让人够头疼的。

iOS越狱降级

首先肯定大家都明白越狱是个什么意思,就和你研究android安全肯定需要有一台root过的手机一样,我们也需要一台越狱的iPhone。不过越狱有四种。

完美越狱(Tethered Jailbreak)
不完美越狱(Untethered Jailbreak)
半完美越狱(Semi-tethered Jailbreak)
半不完美越狱(Semi-untethered Jailbreak)

我画了个图,你一看就明白了。tether是拴绳拴链的意思,tethered就是需要数据线连电脑,untethered就是不需要数据线连电脑。

如果你不知道你的iPhone能不能越狱,你可以到这个网站上查:https://canijailbreak.com/

一看之后你就会发现这几年出的越狱都是半不完美越狱,因为现在苹果的保护措施越来越完善,完美越狱有当然是有,但是能值很多钱,人家不会公开。这几年越狱界最大的新闻就是被称为史诗级漏洞的checkm8了,因为这个漏洞存在于BootROM中,无法通过软件更新的方式修复,所以理论上来讲只要你的iPhone在受影响的设备范围内,不管你怎么升级系统都能用这个漏洞越狱。我们直接去https://checkra.in/下载越狱程序按照上面的说明来就可以了。越狱之后该在Cydia里面装什么等等网上都有很多文章了,这里就不再说了。

接下来说说怎么降级。降级不是你想降就能降的,iOS设备上的固件恢复需要配合Apple服务器进行校验,Apple停止公开验证某个固件版本时,iOS设备就不能从高版本恢复到停止验证的版本。iOS在更新设备固件的过程中会将设备的ECID等信息以及一个一次使用的nonce发送给Apple服务器,服务器在校验通过后会返回校验结果,结果使用非对称算法加密,在没有私钥的情况下无法解密也无法伪造。但是我们可以将校验结果保存下来,之后Apple不再提供此版本校验的时候重放校验过程,实现iOS降级到不提供验证的版本。

说了一大堆可能有点晕了,我们来实际操作一下。现在Apple只会验证最新的iOS 14.0.1版本,我的iPhone8是iOS 13,因为我以前没有保存校验结果,所以理论上现在我没有任何办法将我的iPhone8降级到一个更低的版本。但是现在我可以保存14.0.1的校验结果,假设说以后我的iPhone8升级到了iOS 14.0.2,理论上我就可以通过这个保存的校验结果降级到14.0.1。

首先checkra1n越狱之后我们添加repo:halo-michale.github.io/repo/,安装插件Generator Auto Setter,默认会写入Generator值为一串0x1把nonce固定,这样也方便我们以后降级。然后我们打开爱思助手查ECID:

点击查看设备详情查硬件模型:

然后到https://tsssaver.1conan.com/把这些信息填进去点击submit,就可以下载shsh2文件了。在将来的某个时候如果想降级到这个版本我们可以使用futurerestore,在设备进入kDFU/pwnDFU模式之后用像这样的命令完成降级:

./futurerestore -t xxx.shsh2 –latest-sep –latest-baseband xxxx.ipsw

更新的iPhone和iOS操作似乎还有些不一样,以后如果需要的话再补充。

不过这还没完,苹果还有一个SEP机制(Secure Enclave Processor,安全区域处理器),如果降级的iOS系统与当前的SEP不兼容,那么降级会被禁止。iOS13范围内SEP都是兼容的,那么你只要备份过对应版本的shsh2文件,就可以在iOS13范围内降级。但是网上我看说如果你升级到iOS14,即使有iOS13的shsh2文件就会因为SEP不兼容无法降级。

所以iOS的越狱降级这些还真的挺头疼的……

最后再扯下如何入门macOS/iOS安全,经过一段时间的探索我有如下想法:

1.学http://www.newosxbook.com/index.php上的三本书,建议海淘。国内那些写macOS/iOS的书我翻了几本得出的结论是都不用买。当然就这么看肯定是非常枯燥的,所以我建议有时间就翻翻,一次也不用看太多。

2.学习各种出现的macOS/iOS漏洞,主要是project zero的。

目前我也是积极在整理这些历史漏洞:https://github.com/houjingyi233/macOS-iOS-exploit-writeup

3.从推特或者关注的大牛那里获取一些他们的研究成果然后学习。

如果遇到其它环境方面的问题我也会继续在这篇文章里面更新,2020年争取也写一些macOS/iOS漏洞研究方面的文章!

Speaking of dll hijacking, many people may think it is very useless. However, I noticed researchers disclosured some special dll hijacking scenarios that can lead to LPE and even RCE. Some times ago, I accidentally discovered vulnerability in dll loading mechanism in cisco webex teams that can lead to LPE, and as far as I know, no one has ever mentioned this kind of dll hijacking scenario before.

Cisco Webex Teams Client for Windows DLL Hijacking Vulnerability

I found cisco webex teams was installed to “C:\Users\username\AppData\Local\CiscoSpark” and I decided to take a look at current_log.txt。

It seems that several dlls were not loaded successfully the first time. This is very strange, CiscoCollabHost.exe wants to load these dlls from “dependencies”, error code 126 means “The specified module could not be found”, but “dependencies” and CiscoCollabHost.exe are in the same directory, and in “dependencies” these dlls exist. So something must be wrong…

Until I found the corresponding code in spark-windows-media.dll in IDA, and it took some time before I realized what was going on.

In AddDllDirectory documentation says that the parameter should be “An absolute path to the directory to add to the search path”. However, Microsoft did not say you cannot use relative path, nor did they say what would happen if you use it. What’s even more interesting is that if you use a relative path like L”\\dependencies” like here, in fact windows will treat it as “C:\dependencies”!

We can write code like:

1
2
3
4
5
6
7
8
9
10
PCWSTR pcwstr = L"\\dependencies";

if(!AddDllDirectory(pcwstr))
{
std::cout << "failed!\n";
}

LoadLibraryExW(L"test.dll", 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

std::cout << "Hello World!\n";

Compile poc.exe, then put poc.exe into C:\example\poc.exe, if C:\dependencies\test.dll and C:\example\dependencies\test.dll both exist, poc.exe will load C:\dependencies\test.dll.

So it is very simple to exploit this vulnerability here, just put wmeclient.dll into C:\dependencies\wmeclient.dll. After the victim opens cisco webex teams and successfully logs in, this wmeclient.dll will be loaded and executed by cisco webex teams. Directly writing PE files to C:\ requires administrator rights, but creating a directory in C:\ and then writing PE files to that directory does not require administrator rights.

Consider another situation where the exe and the dll are not in the same path. If C:\abc\def\poc.exe wants to load C:\abc\lib\test.dll, can we write code like LoadLibraryW(L”.. \\lib\\test.dll”)? This will also lead to vulnerability, because windows will treat “..\\lib\\test.dll” directly as “C:\lib\test.dll”. I found such code in another renowned manufacturer’s product. I reported this to them and I am still waiting for reply. I will add more details 90 days after my report or a security bulletin available.

Not only the path related to load dll handled in this way by windows, functions like CreateProcess may also cause vulnerability if given a relative path. Because some products have both windows and linux versions, developers may mix the code of these two platforms. For example, if you write code like this:

1
2
3
4
5
6
7
8
9
TCHAR szCmdLine[] = {TEXT("\\bin\\whoami")};
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;

CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

Windows will add C:\ and .exe, which means put whoami.exe into C:\bin\whoami.exe and it will be executed. I found codes similar to this in cisco DCNM. They told me that this problem only exists on server 2019 and server 2019 is not an environment supported by DCNM by default, so no CVE for this:

https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvv65124

I also reported my findings to MSRC, but MSRC said this is the default behavior. I am not surprised, if the default behavior is to let developers write vulnerable code, that’s fine.

I am sharing my discovery because I haven’t seen anyone mention these and similar vulnerabilities may exist in other products. At the same time, I want to remind developers should make sure that all your dlls are loaded correctly. I want to thank cisco PSIRT although they do not have a bug bounty program but I am still willing to report vulnerability to them. They are very professional and will give you feedback at every stage(received-confirmed-coordinate disclosure time-final public disclosure).

timeline:

2020-06-30: vulnerability found and reported to cisco PSIRT

2020-07-01: cisco PSIRT assigned PSIRT-0447917012

2020-07-10: cisco PSIRT was not able to reproduce this, more details provided

2020-07-15: cisco PSIRT confirmed this vulnerability

2020-08-05: cisco PSIRT informed that the vulnerability will be fixed in the new version released on August 27, and security bulletin will be released on September 2

2020-08-19: cisco PSIRT hoped to postpone the release of security bulletin to October 7 to ensure that all users can upgrade to the unaffected version before public disclosure

2020-10-07: cisco PSIRT released security bulletin

先给大家看看时间线吧(漏洞已经被修复):
2020-01-06:发现爱奇艺客户端某个需要用户发生交互的场景可以导致远程代码执行,报告到爱奇艺SRC
2020-01-08:发现报告被关闭,留言反馈
2020-01-09:发送邮件到[email protected]
2020-01-09:爱奇艺SRC负责人表示审核人员看错了,让我重复提交一次
2020-01-10:重新提交了漏洞
2020-02-21:通过QQ向爱奇艺SRC运营反馈这个漏洞不应该被评为中危应该是高危,对方表示会讨论
2020-03-06:再次通过QQ向爱奇艺SRC运营询问,对方表示还没有上班
2020-04-01:再次通过QQ向爱奇艺SRC运营询问,对方表示这周之内答复
2020-04-03:和爱奇艺SRC运营讨论交流,对他们的工作提出了批评和质疑,对方补发了金币和奖励

我不能理解的事情有这么几个:
1.市值上百亿美元的美股上市公司审核漏洞为何如此随意?一个能影响爱奇艺windows客户端至少几百万用户的高危漏洞能被审核人员看错直接忽略?我在漏洞下面留言没有回应,直到我发邮件询问。爱奇艺SRC的运营流程和审核人员工作的专业和态度为什么有这么严重的问题?

2.为什么我联系爱奇艺SRC运营详细说明了我认为为什么应该评高危而不是中危之后,仍然一直不给我答复,期间我不得不两次询问?

3.我和爱奇艺SRC运营沟通的过程中一直保持文明礼貌,克制自己的情绪,爱奇艺SRC运营为什么给我发送了一个微笑的表情?

4.为什么不给我道歉?是不是爱奇艺SRC觉得白帽子好欺负还是爱奇艺SRC觉得自己很牛逼不需要道歉又或者是爱奇艺SRC觉得自己什么也没有做错?

我那天在朋友圈吐槽完了之后觉得还没有发泄够,于是给[email protected]发了邮件,问了他们这几个问题,同时我也问他们爱奇艺SRC存在的意义是什么?是觉得其它公司有所以我们也要有糊弄一下就行给老板做一下样子还是真的觉得安全问题很重要?

因为我不想再理这群人,所以我邮件里面说请你们不要回复我。之后爱奇艺SRC负责人在之前拉的群里说可以给我补偿一张爱奇艺年卡激活码,当然仍然没有道歉。我不想理他,他加我QQ好友我也没通过,因为我作为一名安全研究人员已经被这家SRC侮辱到体无完肤,我很担心他对我继续进行侮辱。

我虽然穷但是我不是为了钱,我只是想讲道理。开始认定中危给了我100个积分,死皮烂脸扯了这么久补发了我100个积分,按照爱奇艺SRC上的规定相当于能换300块+300块的京东卡,我特么还真的不在乎。不是说嫌钱少,甲方做安全可能资源是有限的,钱少不是不可以理解,但是该高危为什么要评中危?我也明确承认是需要用户交互的,无意夸大漏洞危害,无交互就应该是“严重”而不是“高危”了。

前段时间一篇文章有人吐槽微博一个漏洞在微博SRC换了一条毛巾。不管是低廉的奖励,不公正的漏洞定级甚至是对安全研究人员言语上的不尊重等等种种侮辱行为我都不是第一个遭遇的,也不会是最后一个,那为什么会出这种事情?

我觉得是跟大环境有关。project zero经常因为90天内厂商没有修复漏洞就披露细节,还有前两年像sandboxescaper这样windows的0day一个接着一个发的。国内你要是敢这么玩轻则被约谈喝茶,重则涉及到的厂商直接起诉你。所以国外厂商普遍也更重视SRC建设,白帽子劳动成果能得到尊重,因为你把人家惹到了直接发0day所有人都会看你笑话。而国内厂商料定白帽子不敢披露漏洞,于是就对白帽子进行各种侮辱。

看起来好像对白帽子披露漏洞不加限制更加危险,实际上是好处大于坏处的。真正像sandboxescaper这样一心搞破坏的人几乎可以忽略不计(看他推现在也好像是被微软招安了),绝大部分白帽子厂商给了足够的金钱和尊重都不想搞出什么事情。为什么规则应该倾向白帽子还有一个原因是白帽子面对厂商是弱势群体。国内厂商之间各种报团,很多SRC漏洞评价标准都是一起制定的,经常各种开会扯淡拉关系,而白帽子之间很难形成一个类似于工会的组织维护白帽子的权益。不爽了也就只能发个帖子吐吐槽,不然还敢怎么样呢?

这几年网络安全这一行好像还挺火,一直有新人干这行,虽然时不时有白帽子和SRC扯起来但是大大小小的SRC也不愁没有人来报洞。但是国内白帽子这样的生存环境一直持续五年十年之后呢?

更新:不知道为什么爱奇艺SRC的负责人在我写这篇博客的当天就看到了然后来找我了。我不想再说这件事情了,到此为止。

关于如何给linux内核提交代码这个问题其实有官方的非常详细的文档,网上也有很多文章。但是这些文档要么就是太长读不下去要么就是缺乏关键步骤。因为给linux内核提交代码不是在github上pull一个request就完事了,你想想代码那么多,大家天天去pull request人家Linus Torvalds也看不过来。linux内核每个模块的代码是有不同的人负责的,我们想要提交代码需要把patch通过邮件发给对应的维护者。我第一次看如何给linux内核提交代码的官方文档的时候看了下文章长度几乎都想放弃提交了。今天刚好看到一个觉得可以提交的点,所以做一下记录,希望我写的步骤尽量简洁。

首先安装几个必要的软件:sudo apt-get install esmtp mutt vim git

vim和git就不用说了,esmtp是mstp的拓展,mutt是linux下收发邮件的程序。

在home目录下创建下面几个配置文件。

.muttrc

1
2
3
4
5
set sendmail="/usr/bin/esmtp"
set envelope_from=yes
set from="Your Name <[email protected]>"
set use_from=yes
set edit_headers=yes

.esmtprc

设置文件权限:

1
2
chmod g-rwx ~/.esmtprc
chmod o-rwx ~/.esmtprc

文件内容如下:

1
2
3
4
5
identity "[email protected]"
hostname smtp.gmail.com:587
username "[email protected]"
password "ThisIsNotARealPassWord"
starttls required

.gitconfig

文件内容如下:

1
2
3
[user]
name = Your Name
email = [email protected]

如果你用的是gmail,在“设置”->“转发和 POP/IMAP”中勾选“启用 IMAP”并保存更改。

需要注意的是这些配置文件中应该用相同的邮箱和姓名,姓名最好填自己的真实姓名,不要填一个奇奇怪怪的。然后我们把内核代码clone下来。

1
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

备份原来的文件,修改,生成patch。

1
2
3
4
5
6
7
8
SRCTREE= linux
MYFILE= drivers/net/mydriver.c

cd $SRCTREE
cp $MYFILE $MYFILE.orig
vi $MYFILE # make your change
cd ..
diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch

git status命令查看改变了哪些文件。

git diff命令查看具体修改的内容。

git add命令将要提交的文件的信息添加到索引库中。如果再运行git diff命令就看不到之前修改的文件了。运行git status命令可以看到提示信息由Changes not staged for commit变成了Changes to be committed,文件名也由红色变成了绿色。

如果此时想放弃这次修改,可以使用git reset <file>移除已经添加到索引库中的改变。使用git commit -s -v命令提交我们的修改,此时会添加Signed-off-by:这一行。然后我们需要写清楚为什么要这么改。第一行写上”更改的子模块”+”: “+”简要描述修改的内容”。然后接下来再详细描述。

使用git show HEAD命令查看我们的commit。使用git format-patch -o /tmp/ HEAD^生成patch。

检查下有无格式错误。

看看应该发邮件给谁。

前两个maintainer是收件人,需要抄送给open list。我们最好先给自己发一封邮件再次确认一切无误。

好了,现在可以发邮件了。之后就是等待给我们回复,可能会接受我们的commit,可能会拒绝我们的commit,可能会要求我们再修改,这都很正常。接受我们的commit之后还需要等一段时间才会被加入内核代码。到时候你会还收到邮件。比如我的commit是6月19日被接受的,7月2日被加到4.14/4.19/5.1-stable tree中。

如果你用的不是gmail或者不想用mutt一些步骤可能会不太一样。建议参考下面两份官方文档。

1.FirstKernelPatch

2.Submitting patches: the essential guide to getting your code into the kernel

今年一直在强迫自己有空多看点书,会慢慢分享一些读后感。

《Malware Data Science》这本书读之前我的期望比较高,虽然我没打算深入做这个方向,但是现在太多关于病毒分析的书了,写来写去都是那些东西,有这么一本从数据科学的角度讲病毒分析的书感觉很难得。但是大致读完之后,还是有点失望。满分100分只能打个60分,个人觉得属于读不读都可以的那种。

这本书一共有12章,第1章是介绍,第2章是静态分析,第3章是动态分析,可以直接跳过。下面重点说第4章到第12章。

第4章:教你怎么画图来识别攻击活动。书上举的两个例子一是把相同CC的样本连在一起,二是把含有相同图片的样本连在一起,分别用的APT1和木马样本。大概效果像下面这样。

大家都懂的,想看的话就别指望国内出翻译版了。

这种系统首先就是大名鼎鼎的virustotal的VTgraph了,virustotal官方还出了个virustotal的教程:https://storage.googleapis.com/vt-gtm-wp-media/virustotal-for-investigators.pdf

国内这样的系统还有腾讯的安图,前几天它们一篇文章中判断今年几个影响恶劣的病毒团伙背后是同一个犯罪组织:https://mp.weixin.qq.com/s/tmNYp1WHtUxYRE3aRQNUeA

当然还有360网络研究院大数据关联平台和360威胁情报中心(现更名为奇安信威胁情报中心)威胁分析平台:https://ti.360.net/blog/articles/apt-c-27-(goldmouse):-suspected-target-attack-against-the-middle-east-with-winrar-exploit/

还有微步在线等平台,就不一一列举了。

第5章:共享代码识别,这个其实是很有用的一个功能。比如为什么说VPNFilter与BlackEnergy有关,因为它们都用了相同的方式去修改RC4算法进行加密,如果在分析的时候有这样一个共享代码识别的系统,样本扔进去就跑出来识别出共享了BlackEnergy的代码,能省很多精力和时间。这样的系统目前intezer有一个。

这个是免费的,花钱可以有更多高级功能。

书上说了有这么几个方法识别二进制文件共享代码:汇编指令,字符串,IAT表,动态API调用。我估计intezer大概主要也就是汇编指令和字符串。最后基于字符串做了一个简单的命令行查询系统。

还有一个开源的IDA插件Kam1n0,是2015年IDA插件大赛的第二名:https://github.com/McGill-DMaS/Kam1n0-Community

第6章:扯了一些机器学习的概念。介绍了机器学习的步骤,特征空间和决策边界概念,模型的过拟合和欠拟合问题,和几个机器学习的算法:逻辑回归,KNN,决策树和随机森林。

第7章:扯了一些机器学习的评价指标。TP、TN、FP、FN,ROC,Precision,TPR,FPR等等。懂机器学习的话,这两章可以直接跳过。

第8章:先用是否被加密和压缩这两个指标作为特征,决策树作为算法写了一个判定恶意文件和正常文件的很简单的示例代码。然后实现了一个更接近实际用的,提取字符串作为特征,随机森林作为算法。

第9章:可视化,教你怎么画一些比较高大上的图,随便截了几张。

第10章:扯了一些深度学习的概念。神经网络原理是什么,怎么训练神经网络,最后介绍了几种神经网络:前向神经网络,卷积神经网络,自编码神经网络,生成对抗网络,循环神经网络和残差网络。懂的话也可以直接跳过。

第11章:用神经网络检测恶意HTML页面。

第12章:怎么成为一个数据科学家,随便扯扯。

数据科学用于病毒分析当然能做很多有趣的事情。但是打60分的原因是觉得翻翻还是可以,例子都太简单了,机器学习/深度学习这种玄学类的东西,举那么简单的例子基本等于没有举,真正用于实践会遇到很多问题。

其实我是买了书的,但是纸质看起来不太方便,又找了好久才找到pdf,想看看这本书又找不到pdf的话:aG91amluZ3lpMTU5。

大二的时候开始写博客,现在觉得还是应该有一个自己的网站,希望能自己总结知识的同时帮助别人学习:)

所有在本网站和第三方平台发表的文章未经许可,请勿转载