Arduino+Avr libc制作Badusb原理及示例讲解

2019-12-04来源: eefocus关键字:Arduino  Avr  libc制作  Badusb原理

一、 前言

2014年美国黑帽大会上研究人员JakobLell和Karsten Nohl展示了badusb的攻击方法后,国内与badusb相关的文章虽然有了一些,但是大部分人把相关文章都阅读后还是会有种“不明觉厉”的感觉,badusb仍有一层朦胧的面纱。经过一段时间的学习和研究后,笔者希望通过自己的一些心得体会可以帮助其他人更清晰地认识badusb,也希望这篇文章能够起到一定的启发。这篇文章主要分为五个部分——知识扫盲部分、badusb固件编写部分、badusb配置界面部分、技术展望部分和总结部分。

二、硬件准备

本文使用的硬件是Arduino Leonardo开发板,但是不难将Leonardo开发板替换为其它Arduino开发板。


三、知识扫盲

1. 虽然USB协议有一定的漏洞,但是不是任何USB设备都能制作badusb的。制作badusb有两个核心,一个是能够为USB设备编写相应的固件,另一个是能够将编写的固件烧录到USB设备中。要编写相应的固件就需要掌握USB设备中微控制器(或者说芯片)的指令规范文档(如果Intel不提供开发文档,那么除了Intel自己没有人能为Intel处理器编写程序);而要将固件烧录到USB设备中,要么使用相应的硬件编程器,要么就需要USB设备本身已经存在的bootloader来辅助进行烧录工作(bootloader是USB设备厂商在生产时就放在USB设备中的,网上某些优盘的优盘量产工具也是从厂商流出的,而不是第三方编写的)。要同时满足两个核心条件还是比较难的,即便是JakobLell和Karsten Nohl公布的badusb利用代码也是针对满足一定条件的优盘,因为流出的优盘量产工具有限(既然有优盘量产工具,可以推测相应的优盘中肯定有bootloader或者类似bootloader的固件存在,那么通过逆向优盘量产工具就可以掌握PC端软件和特定优盘的通信方式,进而实现自己的烧录工具)。

2. Arduino 和 teensy这类开发板之所以容易制作badusb,是因为它们采用的微控制器官方有详细的说明文档。最常用的是atmel公司的微控制器,atmel官网提供了各种开发文档和开发相关的库等。

3. Atmel厂商的微控制器整合了SRAM, FLASH和EEPROM。SRAM就好比电脑的内存,不用关心;FLASH高地址存放的是bootloader,低地址则存放用户烧录的固件,芯片加电时直接执行用户的固件,但是芯片复位时会先执行bootloader(这一点是烧录的关键),再执行用户的固件;EEPROM则主要用来存放数据,用户可以随意修改EEPROM中的数据,固件也可以从EEPROM里读取数据(本文的固件示例和PC端程序都利用了这一特性)。

4. Avr libc是一个开源项目,针对atmel厂商的各种微控制器开发C语言库、编译器、烧录工具等一系列辅助工具,还有针对Windows平台的WinAvr项目。Arduino ide的核心其实也是avr libc。

5. Arduino的开发板有相应的bootloader(在FLASH高地址)可以和avr libc项目中的avrdude.exe软件通信,实现固件的烧写和读取动作。在Arduino开发板复位时,会加载bootloader,这时候就可以利用avrdude.exe和bootloader通信。复位操作可以通过开发板上的复位按钮,或者编程实现软复位操作(如果开发板支持的话)。

6. Intel hex 是一种用于编程器的特殊的文件格式,正是因为这种格式,使得我们可以自由控制数据的存储地址。Intel hex的文件格式解析可以自行网上搜索。


四、知识获取途径

1. USB知识获取

如果只是为了简单了解USB设备为什么可以模拟键盘、鼠标等其它设备,网上有许多博客是关于USB规范详解的,也可以简单地看《USB开发大全》和《USB应用开发实例详解》前面关于USB通用协议部分,如果不是对硬件感兴趣没必要深究。

2. Arduino、Avr libc知识获取

这两样其实都是开源的,所以只要有足够的精力和实力,看源代码深入了解相关知识是没问题的。但是如果只是想体验一下制作badusb,可以只看一下Arduino的官方文档和avrdude.exe的相关文档,看这些文档时也没必要深究每个细节,能一定程度上“照葫芦画瓢”就可以了。


五、Badusb固件编写

这里给的固件示例在执行时会从EEPROM中指定的地址读取数据,根据读取的数据和制定的规则发送相应的按键响应给PC主机。


#include"Keyboard.h"


#include"EEPROM.h"


 


intmodifier_key = -1;      //modifier_key不为-1说明Win键、Ctrl键或者Shift键按下,这个示例特指Win键


intkeycode;                //存放要发送的按键代码


unsignedint delay_time = 0;    //固件执行下条指令时延迟的时间


unsignedint address  = 0;  //从EEPROM读取数据的地址,这里要和EEPROM存放数据的地址一致


charnum_char[10] = {0};        //某个数字的字符串形式,这个数字用于delay()的参数,也就是作为睡眠的时间


int num= 0;


intindex = 0;


 


//change this to match your platform:


voidsetup() {


  // make pin 2 an input and turn on the


  // pullup resistor so it goes high unless


  // connected to ground:


  pinMode(2, INPUT_PULLUP);


  Keyboard.begin();


  delay(1000);                  //等待一段时间,让USB设备和PC主机通信完成初始化工作


  while((keycode = EEPROM.read(address++))!= 0){//循环从EEPROM中读取数据直到读到数值0(不是数字0),这个值是在向EEPROM中写入数据时在末尾添加的。


    if (keycode == '$') {            //如果从EEPROM中读到的数值等于'$'的ASCII码


      modifier_key = 131;            //将modifier_key的值设为Win键的键值,这个值会和后续的按键组合后发送给PC主机


      continue;


    }


/* 将两个'&'字符之间的数字作为后续一个按键发送后睡眠的时间,这里之所以要有这个控制值是因为种种因素都会影响按键按下到某个窗口弹出的时间,如果在窗口未弹出就发送了某个按键,这个按键就失效了,后续的按键组合起来也不完整了。比如在按下Win+R键后,还没等运行对话框弹出,固件就发送了"cmd"按键,那么这次启动cmd肯定就失败了。 */


    if (keycode == '&') {           


      while ((keycode = EEPROM.read(address++))!= '&') {


        num_char[index++] = keycode;


      }


      sscanf(num_char, "%d",&num);


      delay_time = num;          //将EEPROM中读取的数据转换为数值后保存到delay_time,控制下次发送按键后睡眠时间


      memset(num_char, 0, sizeof(num_char));//清空num_char为下次转换做准备


      continue;


    }


    if (keycode == ';') {    //如果从EEPROM中读取的数值等于';'的ASCII码,将发送一个回车键的按键码


      keycode = 176;     //176等于回车键的按键码


    }


     Write(keycode);     //实际发送按键的动作


  };


}


//


voidloop() {


  // do nothing:


  while (true);


}


 


voidWrite(int code)


{


  if (modifier_key != -1) {     //在这个例子中,modifier_key不等于-1就等于Win键的按键码


    Keyboard.press(modifier_key);    //按下Win键,不放


    Keyboard.press(code);            //按下另一个按键,不放


    Keyboard.releaseAll();       //同时放开Win键和另一个按键,发送Win+某个按键给PC主机


    modifier_key = -1;


    delay(delay_time);           //这个时间要么等于0,要么等于两个'&'字符之间指定的值


  } else {


    Keyboard.write(code);            //否则直接按下某个按键并放开


    delay(delay_time);           //这个时间要么等于0,要么等于两个'&'字符之间指定的值


  }


  delay_time = 0;


}


这里针对这个固件给几个例子帮助理解:


1.从EEPROM中依次读取到’$'、’r'($r)表示badusb会按下Win+R键。


2.从EEPROM中依次读取到’$'、’r'、’;'($r;)表示badusb会按下Win+R,然后按回车键。


3.从EEPROM中依次读取到’&’、’5′、’0′、’0′、’&’、’$'、’r'、’;'(&500&$r;)表示badusb会按下Win+R键,然后等待500毫秒(保证运行对话框弹出),再按下回车键。


4.从EEPROM中依次读取到(&500&$rpowershell&400&;Get-Date;)表示badusb先按下Win+R键,等待500毫秒后输入powershell,按回车键后等待400毫秒,再输入Get-Date,最后按下回车键。


六、Badusb配置界面

所谓的Badusb配置界面,就是avrdude.exe的UI界面精简版,再额外提供了控制Badusb执行的动作的功能(本质就是修改了EEPROM特定地址的数据,因为固件是根据EEPROM中的数据执行动作的)。

图1 PC程序界面


这个程序主要就是avrdude.exe的UI界面,只有executable处和address处是为了自定义Badusb动作设计的。partno的选项和programmer的选项是解析选定的avrdude.conf得到的,所以不选择avrdude.conf的话partno和programmer的下拉框将为空;端口号是通过注册表获取到的。


当点击upload按钮

[1] [2]
关键字:Arduino  Avr  libc制作  Badusb原理 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic481961.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:LED 驱动控制专用电路 TM1628 AVR 测试程序源代码
下一篇:轻松玩转LCD12864-基于AVR单片机的LCD12864串行显示

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

使用USBASP给Arduino烧写bootloader教程
arduino板由于操作不发导致固件损坏,或者想更新固件怎么办?今天给大家介绍一下如何使用UsbAsp烧写bootloader.个人认为,此种方法比使用TinyIsp要方便并且成本更低。 首先确保手上有一个USBASP下载器,某宝上一搜一大堆,下面以TSROBOT的兼容型UNO板,分别介绍mega16u2的固件和mega328p的固件烧写。______________________________________________________________________ 下载器的驱动安装:将USBasp 插入电脑usb 接口后,系统提示找到硬件,按下列图示安装。<ignore_js_op>选择“从列
发表于 2019-12-11
使用USBASP给Arduino烧写bootloader教程
使用eclipse Arduino IDE开发 AVR程序
小白写程序都是用eclipse的,所以学习Arduino时自然就想用eclipse,因为俺懒,这样省事。网上找了些帖子看看,感觉开发环境都比较麻烦,这样不符合俺这种懒人的风格,所以我弄了个简单点的。第一步:下载各种东西1、JDK,这个去oracle官网下就好了(其实百度下载更快)http://download.oracle.com/otn-pub/java/jdk/8u20-b26/jdk-8u20-windows-x64.exe。2、eclipseArduinoIDE,http://eclipse.baeyens.it/download.php3、arduino-1.5.6-r2http://www.arduino.cc/en
发表于 2019-12-06
使用eclipse Arduino IDE开发 AVR程序
AVR开发 Arduino方法(附二) 故障排除:烧录引导程序
在“内存子系统”一章中我们曾提到,Arduino UNO R3开发板上的ATMega328P有0.5KB的Flash空间用于引导程序;因为有引导程序的支持,Arduino可以使用串口上传程序而无需编程器。一般地,按下Arduino UNO R3开发板上的复位按键,13引脚上的LED快速的闪烁3下,代表引导程序正常启动。如果出现上传程序没有响应或复位时LED没有闪烁,排除硬件故障后,可以考虑重新烧录引导程序。(1) 使用USBasp编程器烧录引导程序Arduino IDE支持的编程器有AVRISP mkII,USBtinyISP和USBasp等,这里以USBasp
发表于 2019-12-06
AVR开发 Arduino方法(附二) 故障排除:烧录引导程序
AVR开发 Arduino方法(七) 嵌入式操作系统FreeRTOS
FreeRTOS可以提供任务管理,队列管理,中断管理,资源管理和内存管理等功能,由于占用资源少,它可以运行在Arduino UNO R3开发板上。你可以在https://github.com/greiman/FreeRTOS-Arduino上下载到它,将下载到的FreeRTOS-Arduino-master.zip解压,并将/FreeRTOS-Arduino-master/libraries文件夹下的内容全部复制到Arduino IDE安装目录下的libraries文件夹里就可以使用了。下面是它提供的frBlink示例: 1 // frBlink.ino 2 #include
发表于 2019-12-06
AVR开发 Arduino方法(六) 内存子系统
Arduino UNO R3主处理器ATMega328P的芯片内部拥有3种存储器:数据存储器,程序存储器和电可擦写可编程存储器;它们各自有不同的用途。1.数据存储器数据存储器是一块2KB大小的静态随机存储器(SRAM)。其中一部分空间分配给了通用寄存器和I/O寄存器,其余部分一般用于存储全局变量,堆栈数据和支持动态内存分配。它的存取速度快,但掉电后数据会丢失。2.程序存储器程序存储器是一块32KB大小的闪存(Flash),其中0.5KB用于引导程序。它可以多次擦写,掉电后数据不会丢失,一般用于存储程序。3.电可擦可编程只读存储器电可擦写可编程只读存储器(EEPROM)是一块1KB大小的独立数
发表于 2019-12-06
AVR开发 Arduino方法(五) 模数转换子系统
模数转换子系统用于将传感器采集的模拟信号转换为数字信号。Arduino UNO R3主处理器ATMega328P的模数转换子系统采用逐次逼近的方式完成模数转换。使用Arduino库函数进行模数转换十分简单,下面的示例可以将A0引脚上的模拟信号转换为数字信号,并将转换结果打印到串口0上:  1 // ReadAnalogVoltage.ino 2 void setup() { 3   Serial.begin(9600); 4 } 5  6 void loop() { 7   int
发表于 2019-12-06
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved