【计算机系统基础bomb lab】CSAPP实验:Bomb Lab

  • CSAPP 实验:Bomb Lab
    • 实验内容简述
    • 实验环境
    • 实验过程:phase 1
      • phase 1 调试过程
    • 实验过程:phase 2
      • phase 2 调试过程
    • 实验过程:phase 3
      • phase 3 调试过程
    • 实验过程:phase 4
      • phase 4 调试过程
    • 实验过程:phase 5
      • phase 5 调试过程
    • 实验过程:phase 6
    • 一些其他收获

CSAPP 实验:Bomb Lab

实验内容简述

  • 作为实验目标的二进制炸弹 “Bomb Lab” Linux可执行程序包含了多个阶段(或关卡),在每个阶段程序要求输入一-个特定字符串,如果输入满足程序代码所定义的要求,该阶段的炸弹就被拆除了,否则程序输出 “炸弹爆炸BOOM!!!” 的提示并转到下一阶段再次等待对应的输入-实验的目标是设法得出解除尽可能多阶段的字符串。
  • 为完成二进制炸弹拆除任务,需要通过反汇编并分析可执行炸弹文件程序的机器代码或使用 gdb 调试器跟踪机器代码的执行,从中理解关键机器指令的行为和作用,进而设法推断拆除炸弹所需的目标字符串。

实验环境

64 位 linux 操作系统

实验过程:phase 1

  • 将可执行文件bomb 反汇编

    objdump -d bomb > bomb.asm
    
  • 查看源代码

    可以了解到 phase_1 是调用函数名

  • bomb.asm 里搜索 phase_1,阅读源码含义

phase 1 调试过程

  • 使用 gdb 调试,将断点设置在 phase_1 ,即 0x400ee0。运行后随便输入后查看 0x402400 的内容

    (gdb) b *0x400ee0
    Breakpoint 1 at 0x400ee0
    (gdb) r
    Starting program: /mnt/d/OneDrive/csapp/bomb/bomb
    Welcome to my fiendish little bomb. You have 6 phases with
    which to blow yourself up. Have a nice day!
    dsasd Breakpoint 1, 0x0000000000400ee0 in phase_1 ()
    (gdb) i r rip
    rip            0x400ee0            0x400ee0 <phase_1>
    (gdb) si
    0x0000000000400ee4 in phase_1 ()
    (gdb) si
    0x0000000000400ee9 in phase_1 ()
    (gdb) x/s 0x402400
    0x402400:       "Border relations with Canada have never been better."
    

  • 可以从上面了解到字符串的答案就是: Border relations with Canada have never been better.

实验过程:phase 2

  • 查看 phase 2 汇编代码

    0000000000400efc <phase_2>:400efc:    55                      push   %rbp400efd:  53                      push   %rbx400efe:  48 83 ec 28             sub    $0x28,%rsp400f02:    48 89 e6                mov    %rsp,%rsi----------------------分割线----------------------------------------;上面是函数的初始化400f05:  e8 52 05 00 00          callq  40145c <read_six_numbers>;读取六个数字400f0a:    83 3c 24 01             cmpl   $0x1,(%rsp);拿第一个数字与 1 进行比较400f0e:    74 20                   je     400f30 <phase_2+0x34>;如果相等就跳转到 400f30400f10:  e8 25 05 00 00          callq  40143a <explode_bomb>;否则,爆炸400f15:  eb 19                   jmp    400f30 <phase_2+0x34>400f17:  8b 43 fc                mov    -0x4(%rbx),%eax ;将第一个数字赋给 eax400f1a: 01 c0                   add    %eax,%eax;将第一个数字*2400f1c:    39 03                   cmp    %eax,(%rbx);将当前数字(eax) 与后一个数字 (rbx) 比较400f1e:    74 05                   je     400f25 <phase_2+0x29>;如果相等,就跳转到400f25400f20:   e8 15 05 00 00          callq  40143a <explode_bomb>;否则爆炸400f25:  48 83 c3 04             add    $0x4,%rbx;循环迭代条件400f29:  48 39 eb                cmp    %rbp,%rbx;rbp 是栈底,也就是数组最后一个元素,作为循环判断的最后一个条件400f2c: 75 e9                   jne    400f17 <phase_2+0x1b>;如果没遍历到最后一个数字,就跳转到循环内400f17400f2e:    eb 0c                   jmp    400f3c <phase_2+0x40>;循环结束,跳转到最后函数结束后的处理400f3c400f30:  48 8d 5c 24 04          lea    0x4(%rsp),%rbx ;将第二个数赋值给 rbx400f35:  48 8d 6c 24 18          lea    0x18(%rsp),%rbp ;设置栈底,就是最后一个数字(0x18 == 24,输入的是6个数,所以是最后一个数)400f3a:   eb db                   jmp    400f17 <phase_2+0x1b>;跳到 400f17 进入循环开始的地方----------------------分割线----------------------------------------;之后都是函数结束后的处理400f3c:    48 83 c4 28             add    $0x28,%rsp400f40:    5b                      pop    %rbx400f41:  5d                      pop    %rbp400f42:  c3                      retq
    

phase 2 调试过程

  • 设置断点

    (gdb) b phase_2
    Breakpoint 1 at 0x400efc
    
  • 运行并输入phase 1 的答案与 phase 2 推测出的答案

  • 一直单步汇编运行,执行到 400f0a: cmpl $0x1,(%rsp); 此步说明第一个数字必须为1

  • 比较第一个数字是否为 1

    (gdb) x/wd $rsp
    0x7ffffffedd70: 1
    

    可以看到,rsp 的值为1 ,就是我们输入的第一个值:1

    由此,通过 je 400f30 可知,两数相等,故跳转到 400f30

  • 通过单步汇编调试,查看rsp 的值

    (gdb) si
    0x0000000000400f30 in phase_2 ()
    (gdb) si
    0x0000000000400f35 in phase_2 ()
    

    由此可以得出,rbx 此时存放的是第二个数字 2rbp 作为栈底,是最后一个数字的结尾,存放的是 4199473 这个数字。

  • 继续单步汇编调试,进入循环400f17

    此时执行完 400f17:mov -0x4(%rbx),%eax eax` 的值为 1。如下图

    继续单步调试,执行到 add %eax,%eax ,对 eax进行 乘 2 的操作。 此时 eax 为2 ,与我们输入的第二个数( rbx 存放) 相等

  • 继续单步汇编调试,跳转到 400f25:add $0x4,%rbx

    执行完 add $0x4,%rbx ,则选择了数组的下一个数字,判断循环是否是否结束。

  • 之后一直执行到结束。

  • 所以答案为:1 2 4 8 16 32

实验过程:phase 3

  • 查看 phase_3 汇编代码:
0000000000400f43 <phase_3>:400f43: 48 83 ec 18             sub    $0x18,%rsp400f47:    48 8d 4c 24 0c          lea    0xc(%rsp),%rcx ;第二个参数400f4c: 48 8d 54 24 08          lea    0x8(%rsp),%rdx ;第一个参数400f51: be cf 25 40 00          mov    $0x4025cf,%esi ;系统自带字符串"%d %d",2个参数400f56:  b8 00 00 00 00          mov    $0x0,%eax;----------------------------------------------------------------400f5b:    e8 90 fc ff ff          callq  400bf0 <__isoc99_sscanf@plt>400f60:   83 f8 01                cmp    $0x1,%eax ;eax 与 1 比较。返回的是输入的参数个数400f63: 7f 05                   jg     400f6a <phase_3+0x27> ;如果大于 1,跳转400f6a400f65:  e8 d0 04 00 00          callq  40143a <explode_bomb>400f6a:   83 7c 24 08 07          cmpl   $0x7,0x8(%rsp) ;比较 7 与 第一个参数大小400f6f:    77 3c                   ja     400fad <phase_3+0x6a> ;如果第一个参数大于7,爆炸400f71:    8b 44 24 08             mov    0x8(%rsp),%eax ;把第一个参数赋给 eax400f75:  ff 24 c5 70 24 40 00    jmpq   *0x402470(,%rax,8) ;跳转到 rax*8 + *0x402470400f7c:    b8 cf 00 00 00          mov    $0xcf,%eax400f81:    eb 3b                   jmp    400fbe <phase_3+0x7b>400f83:  b8 c3 02 00 00          mov    $0x2c3,%eax400f88:   eb 34                   jmp    400fbe <phase_3+0x7b>400f8a:  b8 00 01 00 00          mov    $0x100,%eax400f8f:   eb 2d                   jmp    400fbe <phase_3+0x7b>400f91:  b8 85 01 00 00          mov    $0x185,%eax400f96:   eb 26                   jmp    400fbe <phase_3+0x7b>400f98:  b8 ce 00 00 00          mov    $0xce,%eax400f9d:    eb 1f                   jmp    400fbe <phase_3+0x7b>400f9f:  b8 aa 02 00 00          mov    $0x2aa,%eax400fa4:   eb 18                   jmp    400fbe <phase_3+0x7b>400fa6:  b8 47 01 00 00          mov    $0x147,%eax400fab:   eb 11                   jmp    400fbe <phase_3+0x7b>400fad:  e8 88 04 00 00          callq  40143a <explode_bomb>400fb2:   b8 00 00 00 00          mov    $0x0,%eax400fb7: eb 05                   jmp    400fbe <phase_3+0x7b>400fb9:  b8 37 01 00 00          mov    $0x137,%eax ;eax 为311(十进制)400fbe:  3b 44 24 0c             cmp    0xc(%rsp),%eax ;比较第二个参数与 eax400fc2:  74 05                   je     400fc9 <phase_3+0x86>;如果成功,拆弹成功400fc4: e8 71 04 00 00          callq  40143a <explode_bomb>;----------------------------------------------------------------400fc9:  48 83 c4 18             add    $0x18,%rsp400fcd:    c3                      retq

分析:

我这个都是自己调试出来看到参数的,最开始第一个参数与第二个参数理解有误。结果最开始输入的竟然是第二个参数

首先看到了调用函数是 __isoc99_sscanf 可以从中得知,返回的 eax 为输入格式的个数,而最开始 0x4025cf 的字符串就是 %d %d,可以了解到参数个数为 2 。

之后让第一个参数与 7 比较,可以猜到第一个参数是一个选择做一个选择,选择是下面7个跳转(类似于 switch)。

最后可以在 400f75:jmpq *0x402470(,%rax,8) 观测,程序的跳转地址情况。

phase 3 调试过程

  • 设置断点并运行

    此时的 ans.txt如下:

    Border relations with Canada have never been better.
    1 2 4 8 16 32
    1 311

  • 单步汇编调试,直到执行完 400f5b:callq 400bf0 <__isoc99_sscanf@plt>

  • 单步汇编调试,执行到 400f75:jmpq *0x402470(,%rax,8),观察对应 0x402470 开始的 8 个单元对应的值。

    rax 保存的是第一个参数的值,我们输入的是 1,所以计算机结果是 0x402470 + 1 * 80x402478 单元对应的值 0x400fb9

  • 单步汇编调试,验证进入的单元。

  • 要使第一个第二个参数与 0x137相等,即十进制 311,最后拆除炸弹。

实验过程:phase 4

0000000000400fce <func4>:400fce:   48 83 ec 08             sub    $0x8,%rsp400fd2: 89 d0                   mov    %edx,%eax ;eax = 14 (phase_4 输入的第三个参数)400fd4:   29 f0                   sub    %esi,%eax ;eax = 14 - 0 = 14 (第二个参数减去第三个参数)400fd6: 89 c1                   mov    %eax,%ecx ;ecx = 14400fd8:  c1 e9 1f                shr    $0x1f,%ecx;逻辑右移31 位,ecx 为0400fdb:    01 c8                   add    %ecx,%eax ;eax = 14400fdd:  d1 f8                   sar    %eax ;算术右移1位,即÷2  eax = 7400fdf: 8d 0c 30                lea    (%rax,%rsi,1),%ecx ;ecx = 7400fe2:  39 f9                   cmp    %edi,%ecx ;比较第一传入参数与 ecx = 7400fe4: 7e 0c                   jle    400ff2 <func4+0x24> ;如果小于等于7,跳转400ff2400fe6:   8d 51 ff                lea    -0x1(%rcx),%edx ;400fe9: e8 e0 ff ff ff          callq  400fce <func4>400fee:  01 c0                   add    %eax,%eax400ff0: eb 15                   jmp    401007 <func4+0x39>400ff2:    b8 00 00 00 00          mov    $0x0,%eax ;eax = 0400ff7:   39 f9                   cmp    %edi,%ecx ;比较 7 与第一个传入参数的大小400ff9:   7d 0c                   jge    401007 <func4+0x39>;如果第一个传入参数的大小大于等于7就正常返回400ffb: 8d 71 01                lea    0x1(%rcx),%esi400ffe:    e8 cb ff ff ff          callq  400fce <func4>401003:  8d 44 00 01             lea    0x1(%rax,%rax,1),%eax401007: 48 83 c4 08             add    $0x8,%rsp40100b: c3                      retq    000000000040100c <phase_4>:40100c:    48 83 ec 18             sub    $0x18,%rsp401010:    48 8d 4c 24 0c          lea    0xc(%rsp),%rcx;第二个参数401015:  48 8d 54 24 08          lea    0x8(%rsp),%rdx;第一个参数40101a:  be cf 25 40 00          mov    $0x4025cf,%esi;"%d %d"40101f:  b8 00 00 00 00          mov    $0x0,%eax;------------------------------------------------------------------------------------------401024:  e8 c7 fb ff ff          callq  400bf0 <__isoc99_sscanf@plt>401029:   83 f8 02                cmp    $0x2,%eax;输入的参数个数是不是两个40102c:    75 07                   jne    401035 <phase_4+0x29>;不是,爆炸40102e: 83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp);将第一个参数和 0xe 比较401033: 76 05                   jbe    40103a <phase_4+0x2e>;如果小于等于,就继续401035:    e8 00 04 00 00          callq  40143a <explode_bomb>;否则爆炸40103a:  ba 0e 00 00 00          mov    $0xe,%edx;调用函数第三个传入的实参,1440103f:  be 00 00 00 00          mov    $0x0,%esi;调用函数第二个传入实参,0401044:    8b 7c 24 08             mov    0x8(%rsp),%edi;调用函数第一个传入实参,也是输入的第一个参数401048:  e8 81 ff ff ff          callq  400fce <func4>40104d:  85 c0                   test   %eax,%eax ;递归返回值为040104f:    75 07                   jne    401058 <phase_4+0x4c>;否则爆炸401051: 83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp) ;经过func4 递归后,输入的第二个参数应为0 401056:   74 05                   je     40105d <phase_4+0x51>;第二个参数不为0就爆炸401058:  e8 dd 03 00 00          callq  40143a <explode_bomb>;------------------------------------------------------------------------------------------40105d:    48 83 c4 18             add    $0x18,%rsp401061:    c3                      retq

分析:

首先从callq 400bf0 <__isoc99_sscanf@plt> 可以知道又是调用sscanf,上面的内容就是输入的参数。 401010:lea 0xc(%rsp),%rcx401015:lea 0x8(%rsp),%rdx 可以得知,这是传入的第二个和第一个参数,传入的是两个参数。

之后从 40103a:mov $0xe,%edx 可以得知,接下来这三行都是传递实参,为调用 func4 做准备。 func4 被调用的过程可以分析出第一个数字小于等于7,之后完成以后回到 phase_4401051:cmpl $0x0,0xc(%rsp) 可以得知第二个参数为 0。故测试以下 7 0

phase 4 调试过程

  • 设置断点,并运行至 phase_4

    此时的 ans.txt如下:

    Border relations with Canada have never been better.
    1 2 4 8 16 32
    1 311
    7 0

  • 执行到调用 func4 的位置,中间确认输入参数

  • 重点是 func4 的实现,这个过程需要的确定各个寄存器的值是否符合预期

  • 最后拆弹成功

实验过程:phase 5

0000000000401062 <phase_5>:401062: 53                      push   %rbx401063:  48 83 ec 20             sub    $0x20,%rsp401067:    48 89 fb                mov    %rdi,%rbx ;第一个参数 -> rbx40106a:    64 48 8b 04 25 28 00    mov    %fs:0x28,%rax ;接下来4行汇编是栈哨兵的检查(栈的保护机制,在编译时加上 -fno-stack-protector 就会被取消)401071:   00 00 401073:   48 89 44 24 18          mov    %rax,0x18(%rsp) ;将哨兵的值赋值到栈里401078:   31 c0                   xor    %eax,%eax ;如果 eax 不为0,则说明栈被破坏;---------------------------------------------------------------------------------40107a:    e8 9c 02 00 00          callq  40131b <string_length> ;判断字符串长度40107f: 83 f8 06                cmp    $0x6,%eax ;字符串长度必须为6401082:  74 4e                   je     4010d2 <phase_5+0x70>401084:  e8 b1 03 00 00          callq  40143a <explode_bomb>401089:   eb 47                   jmp    4010d2 <phase_5+0x70>40108b:  0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx ;ecx = Mem[rbx + rax(0) * 1] 此时ecx 指向字符串第一个字符a40108f:   88 0c 24                mov    %cl,(%rsp) ;取字符串的低8位值入栈401092:   48 8b 14 24             mov    (%rsp),%rdx ;输入字符串作为值(具体的ascii),之后在一长串字符串将输入字符串的值作为偏移量401096: 83 e2 0f                and    $0xf,%edx ;与1111 取与运算后作为偏移量,也就是取低4位401099:   0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx ;edx = 'a' 0x4024b0 = "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?";分别取第10位 f(I:74->0100 1001), 第 16 位 l(O:79->0100 1111), 第 15 位 y(N:78->0100 1110),第 6 位 e(E:69->0100 0101),第 7 位 r(F:70->0100 0110),第 8 位 s(G:71->0100 0111)4010a0:   88 54 04 10             mov    %dl,0x10(%rsp,%rax,1) ;rax = 04010a4:   48 83 c0 01             add    $0x1,%rax ;rax = 14010a8:   48 83 f8 06             cmp    $0x6,%rax ;循环终止的判断条件4010ac:  75 dd                   jne    40108b <phase_5+0x29>4010ae:  c6 44 24 16 00          movb   $0x0,0x16(%rsp)4010b3:   be 5e 24 40 00          mov    $0x40245e,%esi ;第二个传入参数 0x40245e = "flyers"4010b8:    48 8d 7c 24 10          lea    0x10(%rsp),%rdi ;第一个传入参数,rdi 0x10(%rsp)是保存的我们输入的地址,上面的操作就是将每个字符串赋值到0x10(%rsp)起始的地址单元里面4010bd:  e8 76 02 00 00          callq  401338 <strings_not_equal> ;要使得二者相等4010c2: 85 c0                   test   %eax,%eax4010c4: 74 13                   je     4010d9 <phase_5+0x77> ;相等就结束4010c6:   e8 6f 03 00 00          callq  40143a <explode_bomb>4010cb:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)4010d0:  eb 07                   jmp    4010d9 <phase_5+0x77>4010d2:  b8 00 00 00 00          mov    $0x0,%eax ;初始化 eax 为0 4010d7:    eb b2                   jmp    40108b <phase_5+0x29>;---------------------------------------------------------------------------------4010d9:    48 8b 44 24 18          mov    0x18(%rsp),%rax4010de:   64 48 33 04 25 28 00    xor    %fs:0x28,%rax4010e5: 00 00 4010e7:   74 05                   je     4010ee <phase_5+0x8c>4010e9:  e8 42 fa ff ff          callq  400b30 <__stack_chk_fail@plt>4010ee:  48 83 c4 20             add    $0x20,%rsp4010f2:    5b                      pop    %rbx4010f3:  c3                      retq

分析:

首先能够判断是要输入 6 个字符串,然后随便输入6个字符进行调试,建议使用规律不同的字符串,这样能够知道传递的参数位置。我使用的是 abcdef

接着当代码运行到 40108b:movzbl (%rbx,%rax,1),%ecx 以后,表示程序进入到循环体内,最后退出的条件是 rax == 6 ,而 rax 的初始值为 0, 这个意思就是遍历完我们输入的字符串,循环体内的意思是取我们输入字符的值的低四位的值,我们输入的是字符,也就是该字符对应 ascii 码的低四位。然后利用这个值作为一个索引,去 0x4024b0 这个长的字符串中寻找 flyers 对应的下标,注意我注释里面添加说明的是第几位,但是具体下标要-1操作。

当代码运行到 4010b3:mov $0x40245e,%esi 的时候,可以看到这个就是在传递参数了,作为第二个实参,是系统赋予的,要将这个字符串flyers0x10(%rsp) 的值(也就是上面提及到的低四位ascii码作为索引取出来的字符)进行比较,必须要二者相等。

综上,得出更新的ans.txt

Border relations with Canada have never been better.
1 2 4 8 16 32
1 311
7 0
IONEFG

phase 5 调试过程

  • 设置断点在 phase_5 并运行

  • 运行到进入循环体 40108b:movzbl (%rbx,%rax,1),%ecx

    可以看到movzbl (%rbx,%rax,1),%ecx,注意 rbx 最开始就用存储输入的字符串,此时rax作为循环体初始变量 为 0。

  • 执行到 401096 以后,完成了取第一个值的低四位的目的,此时再查看取到值是否为 I 的低四位 ascii 码的值 9

    可以看到值为 9,证明计算没错,之后可以直接运行 n,直到结束。

  • 运行 n,直接验证是否正确

实验过程:phase 6

实在是太长了,暂时放弃

【计算机系统基础bomb lab】CSAPP实验:Bomb Lab相关推荐

  1. 计算机系统基础:时序逻辑电路实验

    一.实验目的 1.掌握集成触发器的逻辑功能及其应用 2.了解移位控制的功能及其工作原理 二.实验设备与器材 1.+5V直流电源 2.连续脉冲源 3.单次脉冲源 4.逻辑电平开关 5.逻辑电平显示器 6 ...

  2. 计算机系统基础实验:认识logisim软件、门电路逻辑功能测试(仿真)

    通过logisim对逻辑电路进行分析 文章目录 目录 文章目录 前言 一.使用工具 二.实验过程 1.门电路绘制 2.真值表 总结 前言 计算机系统基础也开了实验课,实验内容是利用logisim软件进 ...

  3. CSAPP实验记录(二)Bomb Lab

    CSAPP实验记录(二)Bomb Lab 二进制炸弹是由一系列阶段组成的程序.每个阶段都要求你在 stdin 上键入一个特定的字符串.如果你输入了正确的字符串,那么这个阶段就被拆除,炸弹进入下一个阶段 ...

  4. CSAPP实验二:二进制炸弹(Bomb Lab)

    本系列文章为中国科学技术大学计算机专业学科基础课<计算机系统>布置的实验,上课所用教材和内容为黑书CSAPP,当时花费很大精力和弯路,现来总结下各个实验,本文章为第二个实验--二进制炸弹( ...

  5. CSAPP实验之Bomb Lab详解

    前言 Bomb Lab来自<深入理解计算机系统>(CSAPP)一书的第三章"程序的机器级表示"的配套实验,该实验的目的是通过反汇编可执行程序,来反推出程序执行内容,进而 ...

  6. CSAPP实验二——bomb lab实验

    CSAPP实验二-- bomb lab实验 实验前准备 第一部分(phase_1) 第二部分(phase_2) 第三部分(phase_3) 第四部分(phase_4) 第五部分(phase_5) 第六 ...

  7. 深入理解计算机系统(CSAPP)含lab详解 完结

    文章目录 深入理解计算机操作系统-第一章 1.1 信息就是位 + 上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1 ...

  8. csapp实验摘选 I Data Lab ——小小菜下士的第一篇博客

    csapp实验摘选 I Data Lab --小小菜下士的第一篇博客 注:这是我的第一篇博客,试图在通往程序猿的路上踏出坚实的一步. --小小菜下士 实验来自: [读厚 CSAPP]I Data La ...

  9. CSAPP Lab5实验记录 ---- Shell Lab(实验分析 + 完整代码)

    文章目录 Lab 总结博客链接 前引 Lab5 Shell Lab 1.获取相关Lab材料 2.Overview(总览) 3.Explore(实现前的摸索) 4.函数实现 + 实现代码分析 1.eva ...

最新文章

  1. 图解 Kafka,一目了然!
  2. 【Linux 驱动】第九章 与硬件通信
  3. 训练深度学习网络时候,出现Nan是什么原因,怎么才能避免?——我自己是因为data有nan的坏数据,clear下解决...
  4. Web.config 灵活配置
  5. 有勇气的牛排---微信小程序
  6. php 关于文件的一些封装好的函数
  7. 《BeagleBone开发指南》——1.7 小结
  8. python的运行环境_python-运行环境配置-1
  9. 清华CrossWOZ,助你徒手搭建任务导向对话系统
  10. linux把标准输出赋值给变量遇到的问题
  11. Vue 实现点击复制功能概述
  12. 在创投界有个公开的秘密
  13. 解决debian (Friendly ARM 嵌入式板)的sudo等一部分命令无法TAB补全
  14. Spring MVC拦截器配置以及统一登陆校验实现
  15. 如何清理驱动人生的新闻弹窗
  16. [转载]INNO SETUP注册DLL文件
  17. 网页加速器1.0.5.6 免费版
  18. android studio导入as项目,Android Studio(AS)--导入项目
  19. 《惢客创业日记》2018.11.23(周五) 郭鑫年,你是不是死了?
  20. C++ : Boost : Rational 有理数类

热门文章

  1. 【QML】MouseArea
  2. Linux物理服务器迁移到vmware虚拟化
  3. 华为桌面云解决方案兼容性列表
  4. 特斯拉,被破解了。。
  5. H265码流分析(一)
  6. 几十行代码写完数独APP
  7. VS2019下生成静态库并调用
  8. threejs 的思维导图
  9. android布局界面点击事件在控件间的传递路径
  10. web安全测试之appscan – “X-XSS-Protection”头缺失或不安全 - 猿码设计师