1-6位字符为啥没弄好退订了漫游了一直不对

课程名称:
考题类型:
查看权限:
考试题目:若一数据库表,要求其学号字段的输入格式为:总长度为6字符,首字符为字母,2、3、4位只能是数字,第5位是“-”线,第6位是数字。则输入掩码为: ?
考题内容:网络远程教育期末考试【数据库程序设计】模拟试题若一数据库表,要求其学号字段的输入格式为:总长度为6字符,首字符为字母,2、3、4位只能是数字,第5位是“-”线,第6位是数字。则输入掩码为:考题选项:*99999X999-99999-9X000-0
正确答案:
热门单选题
更多模拟试题Java 如何取身份证的后6位数字 如果最后一位是字母则略过字母取后六位数字 - ITeye问答
Java 如何取身份证的后6位数字 如果最后一位是字母则略过字母取后六位数字
采纳的答案
public class IDTest{
public static void main(String[] args) {
String id = "15443X";
System.out.println("Hello World!"+new IDTest().getId(id));
public String getId(String id){
Pattern p = Pattern.compile("[0-9]+[X|x]{1}");
Matcher m = p.matcher(id);
boolean b = m.matches();
id = id.substring(id.length()-7,id.length()-1);
id = id.substring(id.length()-6);
String id = "26032a";
String lastWord = id.substring(id.length()-1);
String reg = "[a-zA-Z]";
if(lastWord.matches(reg)){
String s = id.substring(id.length()-7, id.length()-1);
System.out.println("略过字母:"+s);
System.out.println(id.substring(id.length()-6));
Pattern pattern = Pattern.compile("(\\d{6})[a-zA-Z]?$");
Matcher matcher = pattern.matcher("140025A");
while(matcher.find()){
System.out.println(matcher.group(1));
这个还是去百度提问比较好,
已解决问题
未解决问题CSAPP第二次实验 bomb二进制炸弹的破解
一个类似于的初级实验。用到的gdb的指令并不多,只是基础的使用和内存查看的指令。考的大多是汇编代码的熟练程度和分析能力。不过有几个函数长的让人吐血。本着不轻易爆炸的原则,只好慢慢调。
1. 反汇编bomb
用objdump直接反汇编出汇编代码。
objdump -d ./bomb & bomb.s
可以看到以phase开始的八个函数,其中有1-6 6个必过关卡,还有一个defused是检测是否触发了进入secret的函数,而secert就是隐藏的boss了。按照顺序来吧。
2. phase_1
第一个函数的代码很简单,看到strings_not_equal()函数的调用就能大概知道参数应该是一个字符串。此外可以看到两个push将参数入栈,是为strings_not_equal()准备的。根据函数名,可以知道这个函数是在比较两个字符串是否相等,所以push的很有可能就是一个答案字符串所在地址(如果是程序自带的变量包括字符串等都会在.rodata部分,所以压栈时会直接压入对应地址),另一个来自标准输入的字符串地址。
图1 phase_1部分语句
那么接下来就可以进入gdb,加载bomb,在phase_1处设置断点并运行,任意输入一个字符串:
图2 设置断点并进行测试
图3 检查入栈的参数
很明显可以看到eax内容为来自标准输入的参数的地址,而直接入栈的地址很有可能就是答案。直接kill掉并重新加载bomb,在0x8048b3a处设置断点,由图4所示代码可以看出如果eax为0则通过。运行并输入测试字符串:
图4 phase_1检测部分代码
图5 测试字符串运行结果
如图 $eax==0 , 所以第一个关卡的答案就是 &Public speaking is very easy.& 了。
3. phase_2
观察phase_2,可以看到如下片段:
图6 phase_2部分代码
入栈eax和edx可以看出是两个地址,而read_six_numbers可以看出这个关卡的答案是6个数字。所以就用1 2 3 4 5 6 来进行测试,并read_six_number()函数运行前后对参数进行追踪和对比:
图7 进行phase_2测试
图8 read_six_number()函数运行前
图8 read_six_number()函数运行后
对比可以看到输入的6个数字参数被存在以0xffffd0e0开始的24个字节中。接下来有如下代码:
图9 phase_2的第一个炸弹点
可以看到-18($ebp)是第一个数字的地址,而判断语句就是判断第一个数字是不是1,不是则爆炸。幸运的是测试的数字第一个数字是1,所以可以继续运行:
图10 运行到0x8048b73
图11 对phase_2核心代码的初步解释
如图11所示,由于ebp的值为0xffffd0f8,把输入的6个数字看作数组num[6],则可以将所示代码总结为以下C代码:
图12 phase_2的等价形式
根据图10 和11推断出第一个数字一定是1,根据循环算出后面的数字分别是1*2,2*3,6*4,24*5,120*6,即1 2 6 24 120 720。按照推断出的答案进行测试,在bomb_explode函数处设置断点,如果错误就可以直接Kill重新运行而不会爆炸:
图13 测试phase_2
可以看到并未触发断点,则结果正确。
4. phase_3
首先当然还是先观察phase_3的汇编代码,看是不是调用了有关输入的参数的函数:
图14 phase_3参数的读取部分
首先,将三个地址参数入栈,其中的数据大小为32位,4位,32位,则中间一个参数为单个字符型。在sscanf函数调用后检查$eax,因为sscanf在参数匹配成功后会将匹配成功的参数的个数放入eax中返回,所以检查eax是否大于2,即至少应匹配三个参数才能过第一个爆炸点。
图15 有关其余两个参数的调用
从图15可以看出第一和第三个参数全部都与一个立即数做比较,所以可以推测这两个32位的参数不是指针,而是数字。且可以看出第一个参数如果大于7会跳转绝对寻址到bomb。所以可以得出第三个炸弹的答案格式是 小于8的整数,一个字符,一个数字。此外由于sscanf需要一个格式串来作为匹配,所以通过查看入栈的立即数地址可以得到格式串,即参数的格式:
图16 查找sscanf()的参数串
此外从整体看phase_3可以看出有9个分段,每个分段都类似于一下片段:
图17 phase_3重复片段
且都由一处语句控制跳转内存:
图18 控制跳转语句
控制语句通过将第一个参数的值放入eax中,通过第一个值控制跳转,进一步控制第三个参数与哪个数字比较。如果第三个参数匹配失败就会跳到末尾的explode_bomb()中。所以可以看出是一个switch语句。整理后可以得到以下结构:
图19 phase_3等价的switch语句
所以可以算出第三个关卡共有8个答案,即从后三行中对应每一列为一个答案。任选一个答案,在explode_bomb处设下断点进行测试:
图20 测试phase_3的答案
未触发断点,即成功通过。提示已经过了一半啦。
5. phase_4
观察phase_4的汇编代码首部,也调用了sscanf函数。由汇编代码可以看出参数是一个4字节的参数,通过调出sscanf的格式串可以看出是一个整数:
图21 phase_4中的参数调用
图22 sscanf的格式串
图23 对参数的判断
此外由图23可以看出参数(存放在 -0x4($ebp)的内存中 )需要大于0。而对$eax的判断是为了查看是否成功匹配到一个整数。( $eax是默认sscanf()函数返回值的存储位置,sscanf()的返回值是匹配成功的参数个数 ) 。接下来可以看到将整数入栈后进入func4函数中:
图24 参数入栈并进入func4()中
接下来就转战func4函数,可以看出它是一个递归函数。对于递归函数首先要找到特殊出口:
图25 特殊出口
图26 phase_4对func4()返回值的判断
可以看到当$ebx也就是输入的参数小于1时直接返回1。观察phase_4函数的部分( 图26 )可以看出返回值应该等于55(0x37)。所以还是要研究一下递归部分。根据以下代码可以看到递归部分有两层,且都要进行:
图27 func4的递归部分
不过代码较短又只涉及到输入的参数,所以可以直接看出等价以下C代码:
图28 模拟func4的递归代码
经过计算,想要返回值为55,则i应该为9。测试一下结果的正确性( 还是要在explode_bomb()处设置断点,否则错误就会bomb,然后就会扣分啦。。) :
图29 phase_6测试结果
因为没有触发explode_bomb断点,所以phase_4就这样被KO啦。
6. phase_5
根据上面四关总结出的套路,首先还是观察phase_5首部:
图30 phase_5首部
由入栈参数可以看出是一个4字节变量,因为调用了string_length,所以推断是一个字符串的地址。而$eax应该是string_length的返回值,因为phase_5并未给$eax赋值。根据判断语句可以得出参数应该是一个长度为6的字符串。接下来是第一个循环:
图31 phase_5循环体
首先还是要用gdb看一下所涉及到的参数都有什么信息,在explode_bomb() 和 phase_5() 处设置断点,用字符串&abcdef& 来测试一下:
图32 phase_5第一个循环体的参数及内存观察
如图,在mov $0x804b220, %esi 之后进入循环,而在立即数地址参数中存放着一个字符串,在循环中的参数$ebx则是输入的字符串参数。由于循环过程中没有explode_bomb的入口,不怕直接被炸掉,所以先不探究循环过程,继续运行,看一下什么时候会进入explode_bomb()函数:
图33 在进入strings_not_equal()后的参数变化
可以看到strings_not_equal() 函数,此时已经跳出循环。这个函数在第一个关卡已经出现过,作用是判断两个参数字符串是否相等,检查两个参数,其中0x804980b中存放的应该是不会变的标准串,而$eax存放地址中存放的串是循环后得出的串,很明显不对。所以kill掉。由于图32看到了第一个循环前准备的参数,所以直接来分析汇编代码:
图34 分析phase_5的循环代码
如图,在循环中,取输入串的每个字符的ascii码转换成二进制的低四位,拓展成32位整数后作为偏移量在模式串中取对应位置的字符,存放在0xffffd0e0中。当最后的字符串为&giants&时即可。根据计算,opukma符合此条件。同事可以看出答案不止一个,只要符合就可。接下来用计算出来的字符串进行测试:
图35 phase_5测试
可以看出并没有触发explode_bomb断点,即搞定啦。
7. phase_6
接下来问题来了,这么长的phase_6,什么套路都要崩溃了。。因为比较长,所以先总结一下:参数读取,一个双层循环,三个单层循环,且炸弹入口只出现在双层循环前的参数准备和最后一个循环中。分了这几部分后就不会有无法入手的感觉了。接下来就来挑战一下吧:
首先是读取参数:
图36 phase_6读取参数部分
可以看到给read_six_numbers的是两个参数,根据mov和lea指令可以看出$edx是一个四字节数值,$eax是一个地址,而读入的应该是6个数字,所以用1 2 3 4 5 6进行测试如下:
图37 测试phase_6并查看参数变化
可以看到$eax由地址变成了数字6,所以应该是在read_six_numbers时被当作参数返回的值。可以看到原来$eax保存的地址的内容已经变成了输入的6个数字。继续观察接下来的汇编代码,就到了双层循环部分,即如下图所示代码段:
图38 双层循环部分代码
根据图37观察到的内存等信息,再结合判断条件和调用方式等顺序可以做出等效C代码如下图,其中一层解释更像源代码,二层更加简单粗暴加直接:
图39 双层循环的递进分析
可以看出这段循环的作用就是规范输入的6个数字:最大为6各不相等。又因为图中所表示的比较为无符号比较,所以这6个数字也不能有0。综上即1-6。数字是确定的,所以唯一做评判标准的应该就是顺序了。观察接下来的一部分汇编代码并用gdb观察变量和内存的变化:
图40 下一个循环前的准备
图41 准备阶段的相关内存的分析
可以看到$eax $ecx 和 0xffffd0bc 处的内容被更改了。接下来进入下一个循环:
图42 第一个单循环的代码
可以看到涉及到的最小的内存是($ebp-0x3c),由于多为内存变化,根据汇编代码无法看出内存变化,所以用gdb查看一下循环前后的该处内存变化:
图43 相关内存的变化
可以发现在0xffffd0c8 & 0xffffd0dc的24个内存发生了变化。而0xffffd0e0 & 0xffffd0f4是输入的6个数字所在的内存。根据变化结果和汇编代码,通过计算可以得到如下总结:
图44 第一个单层循环解析
根据对整个单层循环的单步调试,对过程中所操作的内存的信息进行查看:
图45 46 相关内存的查询
根据以上信息,可以大概总结出如下内存和寻址的模式:
图47 寻址方式总结和内存变化
这个循环基本就搞清楚了,接下来是下一个单层循环,同样由于多为内存操作,只能先用gdb单步运行来查看内存的变化:
图48 49 循环中内寄存器和内存的变化
经过观察发现此次循环过程的内存与上一个循环中被改变的内存有关,经过整理后可以发现如下内存变化:
图50 第三次循环执行完毕相关内存变化
可以看到这次循环是根据上一次循环更改的相关内存进行第二次的修改,间接与输入的6个数字有关。接下来是phase_6的最后一个循环:
图51 phase_6最后一个循环
炸弹现在才出现,可以看出来是内存间的访问和比较,根据图47 和图50可以得到下面的流程模拟图:
图52 最后一个循环的运行模拟和参数推算
可以看到这个循环是在测试根据输入的6个数字排好序的地址中存放的数字,输入的6个数字应该使 0x804b230& 0x804b26c 这6个地址中的数字按照降序排列,而输入的6个数字是在图47所示的循环过程中控制6个地址在 0xffffd0c8 & 0xffffd0dc 中的顺序 进而通过图50所示过程控制6个地址存放在以0x804b开始的地址。所以正确输入顺序的推算应是
4 2 6 3 1 5 。如下图所示:
图53 推算正确结果
接下来就要测试一下推断出的结果了,如下图把phase_6的所有explode_bomb()的入口语句设置断点,并在每个循环阶段设置断点:
图54 设置断点并输入推算答案测试
图55 第二个循环阶段完成
如上图,第一阶段未触发explode_bomb()函数,二阶段后检查内存发现在0xffffd0c8 -- 0xffffd0dc段的地址排列正像推算的一样。
图57 第三阶段运行后检测其他相关内存
第三阶段后,根据图57和58可以得出下图所示的图示:
图58 内存图示和比较顺序推算
最后运行后显示成功拆除炸弹并退出程序:
图59 提示成功拆除炸弹并退出
8. phase_defused()
在研究phase_1 - phase_6时发现,在汇编代码中每个关卡通过后都会进入phase_defused()中,且在此函数中还有一个secret_phase() 函数的入口。所以来分析一下phase_defused()函数:
图60 phase_defused()入口语句
首先还是要观察一下0x804b480这里存的是什么。所以在phase_defused()函数入口加断点运行一遍:
图61 观察0x804b480的变化
可以看到随着关卡的通过,0x804b480存储的值在不断增1,到第六个关卡时为6,但并未进入secret_phase(),所以单步运行看一下哪里出了问题:
图62 异常跳过secret_phase()入口
可以看到是因为$eax的值不对导致跳过入口,由于$eax作为sscanf()函数的返回值,所以推算需要匹配两个部分,但在sscanf()运行过程中并未手动输入新的字符串且sscanf()的参数不一定来自标准输入,所以需要查看之前入栈的参数来推算sscanf()的参数有哪些。
图63 查找sscanf()的参数
可以看到模式串是数字+字符串,而收到的匹配串是一个数字9,由于并未手动输入新串,所以排除是程序自带的字符串,所以观察6个关卡的答案,发现第四关的答案是9,而且第四个关卡的参数串是%d,所以有多余的字符串也不会影响匹配的个数,所以推测需要改变第四个答案。在第四关时多输入任意一个字符串:
图64 测试任意字符串
图65 通过参数匹配测试
图66 再次异常跳转
可以看到在输入任意字符串后,在参数匹配个数部分已经成功,但在单步执行到strings_not_equal()时由于返回的参数$eax不为0,所以再次异常跳转,所以观察入栈的两个参数,发现一个字符串是标准输入的字符串,另一个是绝对地址存放的字符串,所以推定应该在第四关输入的字符串就是该处地址显示的字符串,即 &9 austinpowers&。用推算的答案进行测试:
图67 测试推算的答案
图68成功进入secret_phase()入口
可以看到已经成功运行到了secret_phase()入口处。
9. secret_phase()
.首先观察入口部分的代码:
图69 入口部分代码
可以看到有两次调用函数,第一次是read_line(),从而可以推断出此关卡应该是一个字符串作为参数。用gdb单步调试观察第二个调用函数的参数:
图70 第二个调用的函数参数
可见是刚才输入的字符串,继续运行:
图71发现错误
由于在调用第二个函数后$eax已经发生改变,所以$eax的值应该是该函数的返回值,由 cmp语句可知返回值应该为0x3e8+1,为1001。再观察第二个函数的解析符号,为&__strtol_internal@plt&,所以推测应该为 strtol()函数。strtol()函数的参数原型为long int strtol(const char *nptr,char **endptr,int base) ,作用是将一个字符串转换成一个长整数,又因为参数 0xa 被入栈,所以推测这个函数是将输入的字符串转换成十进制长整数赋给$eax作为返回值,且jbe 8048f14 表明 1000&=$eax-1&=0 ,所以初步推定输入的字符串应该是1-1001的任意一个数字。
以数字1作为字符串进行测试:
图72 以 1 做参数进行测试
图73成功通过并进入fun7()
可以看到已经成功通过,并运行到fun7()函数入口,对参数进行分析发现是输入的数字和0x24。由于除了参数匹配的检测fun7()中没有其他的爆炸带你,所以先直接完成fun7()函数回到secert_phase()函数,发现fun7()返回的值未通过测试:
图74 fun7()函数返回值错误
观察fun7()的汇编代码:
图75 一种完成fun7()的方式
由图75可看到如果传入的参数$edx为0,则直接完成函数并返回$eax,此时返回值$eax为0xffffffff = -1 ,gdb测试观察$eax和$edx的值:
图76 查看fun7()参数
可以看到$edx的值是传入的地址,所以首次进入时不会发生edx=0的情况。所以继续观察fun7()其他代码发现又是一个双层递归,但属于分支情况,分析可得如下图所示C模式:
图77fun7()的三分支模式
根据三分支模式在分支处设置断点并运行测试:
图78 设置断点并测试
图79 根据三分支模式寻找递归返回点
如图,由于fun7()是三分支模式,除相等时直接返回0外,只有在传入地址参数为0时才会返回-1。所以查找所有可以递归的地址点,直到某个地址点的左右分支均为0则为结束点。由上图可知该递归模式是四层二叉树递归模式,则有如下的二叉树形态:
图80 内存的二叉树形态
由于secret_phase()判断返回值应为7,所以根据三分支的返回值公式,有且仅有7 = ((0*2+1)*2+1)*2+1。所以应该为 $eax & 0x24 且$eax&0x6b 且 $eax==0x3e9,则输入的数字应该为0x3e9,即1001。strtol()函数在转换时会舍弃无法转换的部分,所以1001后可接第一个字符不为0-9的其他字符串。
根据推算的结果输入字符串进行测试:
图81 测试secret_phase()
由图81可以看到并未触发secret_phase()和fun7()内的explode_bomb()入口,即破解成功。
从破解过程来看,需要至少要 &还可以& 的水平的汇编代码能力,还要不怕麻烦的对许多地址进行递归的查询,很多时候对于 &查询哪个地址可以看到需要的东西& 的问题只有在大致的范围上不断寻找和计算才能准确找到能完美表现变化的地址。所以还是需要很大的耐心的。由于不需要大量的指令,只要懂得gdb的基本使用和查看内存的指令并且耐心调试就可以,所以这篇文章并没有大量的代码段,一切都可以在亲自实践中搞定。base64的编码都
char是一个基本数据类型。它可以表示一个byte大小的数字,即8位,而Base64使用基于6位的编码。所以就是12x
8/6 = 16;而20 x 8/6 = 20 x 4/3 = 24 + 2.666 ,多余的需要用
====补齐到4位,所以是28。
转码过程的例子:
内存1个字符占8位
转前: s 1
先转成ascii:对应 115 49 51
6个一组(4组) 011100110011000100110011
然后才有后面的
然后计算机是8位8位的存数 6不够,自动就补两个高位0了
科学计算器输入 00011100 00110011 00000100 00110011
得到 28 51
查对下照表 c
总之,3个char型字符转换为4个Base64编码的字符,少了要补齐再转换。因此20个转换为21 × 4/3
关于base64的解释详见百度百科
ASCII编码每个字符8bit都是有效编码,base64中每个只有6bit是有效编码。3*8=4*6,所以每3个ASCII编码的字符对应4个base64编码的字符。不够3个按3个算。
(12/3)*4=16;
((20+1)/3)*4=28
Base64表示法指的是:用
64个可打印字符来表示二进制数据的表示方法,64是2的6次方,所以64个打印字符每个字符可以用6位二进制来表示。本题中对应的char字符数组有12个,每个字符的ASCII编码对应为8位二进制表示,即共12*8=96位二进制,若用Base64表示法,则考虑6位为一个打印字符,所以96/6=16个打印字符。同理字符数组里有20个字符,20*8/6=26多4个,最高位补上两位即可,至少需要27个打印字符,但是选项中最接近的是28,所以选择D
3*8=4*6,所以每3个ASCII编码的字符对应4个base64编码的字符。不够3个按3个算。
(12/3)*4=16;
((20+1)/3)*4=28
Base64编码,简言之,就是把原来的8bit字符先进行6bit划分,再对每个划分的6bit进行高位补0.
eg:“s13”字符串的2进制code:
6bit划分:
对每个6bit高位补0:
00011100|00
11 0011|00
0001 00|00
查ascii表,对应字符串为:&czEz&
即原来3个char的数组经Base64编码后变为了4个char.
题中第二个空答案的选项存疑。。
原来数组所占位数:20*8 = 160bit
划分为6bit,共有组数:160/6 = 26……4
即可划分为27组,其中26组位数为6,1组位数为4,对每组高位补0,结果应该是27组?
只要记住,转换后的Base64编码的字符个数必须是4的倍数即可做对这种题。。(为什么是4的倍数?因为转换以3-&4为基础,)
有人问为什么补到28,说一下原因。
Base64编码要求把3个8位字节转化为4个6位的字节,也就是说:
3个char型字符会转换为4个
Base64编码的字符。转化时如果不够3个
char型字符会补齐到3个,
编码的结果要求字符数量为4的整数倍,所以补到28
Base64的编码长度至少比原来长三分之一
根据base64的编码规则:
①把3个字符变成4个字符。
②每76个字符加一个换行符。
③最后的结束符也要处理。
那么,12/3*4=16;20/3*4=28(除不尽,凑齐4)
base64 是6位一个字符,char是8位一个字符,12*8/6=16
20*8/6=26.667,补足4位为28
看了下Base64原理
我来简单说一下:
它是把3个8bit转换为4个6bit的(就是所谓的 3 * 8bit -&4 * 6bit
,然后对6bit前面填充0形成4个8bit(这些都不管 我也不太懂= =)
来看这道题:
12个char对应12*8bit
按照3:4的比例
先算一下 12 / 3正好整除 对应就是 4 * 4 = 16 那么20呢?
20/3 = 6(余2)
6 对应 6*4 = 24
那么2怎么办?
补全0,形成一个3,这不就是3 对应4
24 + 4 = 28
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。
如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='
为毛我一直觉得答案是16,30唉
3个char型字符转换为4个
Base64编码的字符
8比特表示一个字符, 12个字符分成4组, 每组3个. 每组共有24比特二进制, 然后每组24比特除以6分成4组, 高位用0补齐,
这样12个字符共有16个char了. 同理可得数组长度为20时需要28个字符.
简单记忆:
base64加密的结果会比原长度多至少三分之一。
使用Base64表示法时,原字符串中每3个字符一组,使用Base64表示法时,每6个bit位表示一位Base64字符。如果要编码的二进制数据中字符个数不是3的倍数,最后会剩下1个或2个字节怎么办?Base64用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉。
所以在题目中,当char数组长度是12时,每个字符占1个byte,8个bit位,至少需要 12 * 8 / 6 = 16
个Base64字符;当char数组长度为20时,20不是3的倍数,需要在编码的末尾加上一个
'=',进行填充,即将原字符数组的长度变为21,那么至少需要 21 * 8 / 6 = 28个Base64字符。
参考链接:
http://www.liaoxuefeng.com/wiki/095c955c1e6d8bbfac/339f4bbda5c01fc479cbea98b0
Base64是网络上最常见的用于传输8Bit
的编码方式之一,首先将要转换的字符转成ASCII码,再化成二进制,再每六位分成一组,由于计算机是8位的存储,所以最高位补0.最后根据Base64编码表查找对应的字符
这道题你会答吗?花几分钟告诉大家答案吧!
单链表必须从第一个...
扫描二维码,关注牛客网
下载牛客APP,随时随地刷题
京ICP备号-4
扫一扫,把题目装进口袋

我要回帖

更多关于 煮完的鸡蛋怎么弄好拨 的文章

 

随机推荐