极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 25536|回复: 6

暴力改造汽车遥控钥匙为手机APP控制

[复制链接]
发表于 2016-5-26 20:59:32 | 显示全部楼层 |阅读模式
本帖最后由 HuaShine2015 于 2016-5-26 20:58 编辑

前言:
       免滚码破解,无需拆装,手机APP作为车门遥控钥匙。
屌丝车怎样简单粗暴的实现某V品牌汽车高大上B格,拎包入住步骤如下




主题:
       这是本人代步小破车遥控钥匙原来的样子
(表和我说射频破解MCU加RF模块模拟啥啥的,现在遥控器都滚码433M哦,还双向验证。撇开破解难度不谈,你要是让你老婆知道你折腾半夜就为破解滚码这破玩意,估计得罚洗尿布半年)


然后加上翅膀配上航弹

配齐主要机组人员

准备起飞


背景:
原理图概述

模块特性
使用的TI公司CC254X平台BLE蓝牙模块DX-BT05,内部封装的固件版本较简陋(此模块未过MFi认证的)。 MCU使用pro mini
系统特性

软件流程图

MCU端代码
  1. //2016-5-26 create by Shine.Hua

  2. #include <Enerlib.h>
  3. #include <EEPROM.h>

  4. #define HWRSTPIN 7
  5. #define LOCKPIN 4
  6. #define UNLOCKPIN 5
  7. #define DEFAULTPIN 6
  8. #define DETECTPIN 2
  9. #define MCULED 13

  10. struct CellObject {
  11.   char mac0[13];
  12.   char mac1[13];
  13.   char mac2[13];
  14.   char pin[7];
  15. };

  16. Energy energy;
  17. CellObject cob;
  18. String pin_type = "AT+TYPE0";
  19. String inputString = "";
  20. boolean stringComplete = false;
  21. boolean license = false;
  22. boolean sts = false;
  23. const unsigned long WAIT_TIME1 = 120000;
  24. const unsigned long WAIT_TIME2 = 25000;
  25. const unsigned long WAIT_TIME3 = 200000;
  26. unsigned long connStop = 0;
  27. unsigned long mcuSleep = 0;

  28. CellObject get_Conn() {
  29.   CellObject getvaul;
  30.   EEPROM.get(0, getvaul);
  31.   return getvaul;
  32. }
  33. void set_Conn(CellObject setVar) {
  34.   EEPROM.put(0, setVar);
  35.   EEPROM.put(512, 1);
  36. }

  37. void clrEEPROM() {
  38.   for (int i = 0 ; i < EEPROM.length() ; i++) {
  39.     EEPROM.write(i, 0);
  40.   }
  41. }

  42. void default_set() {                  //MCU烧录后EEPROM均是清空状态,所以此函数功能是保留至少要能保存设置一个可以连接的MAC,能让手机APP连接后再修改
  43.   clrEEPROM();
  44.   delay(1000);
  45.   CellObject defaultVar = {
  46.     "",                               //发现官方EEPROM库函数有bug,创建对象时第一个属性值读写不全。此处创建结构体类时,第一个属性留空
  47.     "008012345678",
  48.     "EA3146CE9FF7",
  49.     "000000"
  50.   };
  51.   pin_type = "AT+TYPE0";
  52.   set_Conn(defaultVar);
  53.   root_bt();
  54. }

  55. void bt_hw_rst() {                         //蓝牙模块连接以后自动切换到透传模式,此时无法接收AT指令
  56.   digitalWrite(HWRSTPIN, HIGH);           //所以此处使用切换蓝牙HW_RST PIN状态来强制断开蓝牙连接恢复到AT指令模式
  57.   delay(1500);
  58.   digitalWrite(HWRSTPIN, LOW);
  59.   delay(3500);
  60.   wakeup_bt();
  61.   sleep_bt();
  62. }

  63. void bt_sf_rst() {
  64.   Serial.println("AT+RESET\r");
  65.   delay(2500);
  66. }
  67. void sleep_bt() {
  68.   Serial.println("AT+SLEEP\r");
  69.   delay(1000);
  70. }
  71. void wakeup_bt() {
  72.   for (int i = 0; i <= 12; i++) {
  73.     Serial.print("WAKEUPBT");
  74.   }
  75.   Serial.println("\r");
  76.   delay(1500);
  77. }

  78. void root_bt() {     //设置蓝牙模块
  79.   while (true) {
  80.     digitalWrite(MCULED, !digitalRead(MCULED));
  81.     if (digitalRead(DETECTPIN) == LOW) {
  82.       delay(30);
  83.       if (digitalRead(DETECTPIN) == LOW) {
  84.           break;
  85.       }
  86.     }
  87.     delay(250);
  88.   }
  89.   digitalWrite(MCULED, HIGH);
  90.   wakeup_bt();
  91.   //Serial.println("AT+NAMELIFAN320\r");
  92.   //delay(600);
  93.   Serial.print(pin_type); Serial.println("\r");
  94.   delay(500);
  95.   cob = get_Conn();
  96.   Serial.print("AT+PIN"); Serial.print(cob.pin); Serial.println("\r");
  97.   delay(800);
  98.   Serial.println("AT+ROLE0\r");
  99.   delay(500);
  100.   Serial.println("AT+NOTI1\r");
  101.   delay(500);
  102.   Serial.println("AT+NOTP1\r");
  103.   delay(500);
  104.   Serial.println("AT+IMME0\r");
  105.   delay(500);
  106.   Serial.println("AT+PWRM0\r");
  107.   delay(1000);
  108.   bt_sf_rst();
  109.   digitalWrite(MCULED, LOW);
  110. }

  111. void ctrl_login() {                          //控制MCU是否可以休眠
  112.   if (digitalRead(DETECTPIN) == LOW) {
  113.     delay(30);
  114.     if (digitalRead(DETECTPIN) == LOW) {
  115.       delay(30);
  116.       if (digitalRead(DETECTPIN) == LOW) {
  117.         sts = false;
  118.         license = false;
  119.         mcu_sleep();
  120.       }
  121.     }
  122.   }
  123. }

  124. void ctrl_timeout() {                             //连接超时控制
  125.   unsigned long currentMillis = millis();
  126.   if (digitalRead(DETECTPIN) == HIGH) {
  127.     delay(30);
  128.     if (digitalRead(DETECTPIN) == HIGH) {
  129.       delay(30);
  130.       if (digitalRead(DETECTPIN) == HIGH) {
  131.         if ( (license == false) && (currentMillis - connStop >= WAIT_TIME2)) {
  132.           connStop = currentMillis;
  133.           Serial.println("timeout1");
  134.           bt_hw_rst();     
  135.         } else if (license == true && (currentMillis - connStop >= WAIT_TIME1) && stringComplete != true && (!Serial.available())) {
  136.           connStop = currentMillis;
  137.           Serial.println("timeout2");
  138.           bt_hw_rst();
  139.         }
  140.       }
  141.     }
  142.   }
  143. }

  144. void mcu_sleep() {                                 //MCU休眠代码
  145.   unsigned long currentMillis = millis();
  146.   if (currentMillis - mcuSleep >= WAIT_TIME3) {
  147.     mcuSleep = currentMillis;
  148.     Serial.println("mcuslp");
  149.     wakeup_bt();
  150.     sleep_bt();
  151.     energy.PowerDown();
  152.   }
  153. }

  154. void base_case() {       //业务主体代码
  155.   if (stringComplete) {
  156.     if (digitalRead(DETECTPIN) == HIGH) {
  157.       if (inputString.endsWith("close#") && license == true) {
  158.         connStop = millis();   //
  159.         mcuSleep = millis();   //
  160.         digitalWrite(LOCKPIN, HIGH);
  161.         delay(1100);
  162.         digitalWrite(LOCKPIN, LOW);
  163.         Serial.println("off");
  164.       } else if (inputString.endsWith("open#") && license == true) {
  165.         connStop = millis();   //
  166.         mcuSleep = millis();   //
  167.         digitalWrite(UNLOCKPIN, HIGH);
  168.         delay(1100);
  169.         digitalWrite(UNLOCKPIN, LOW);
  170.         Serial.println("on");
  171.       } else if (inputString.endsWith(";") && license == true) {
  172.         connStop = millis();   //
  173.         mcuSleep = millis();   //
  174.         cob = get_Conn();
  175.         String temp = inputString.substring((inputString.indexOf(';') - 6), inputString.indexOf(';'));
  176.         for (int i = 0; i < temp.length(); i++) {
  177.           cob.pin[i] = temp[i];
  178.         }
  179.         Serial.println(cob.pin);
  180.         set_Conn(cob);
  181.         root_bt();
  182.       } else if (inputString.endsWith("admin#") && license == true) {
  183.         connStop = millis();   //
  184.         mcuSleep = millis();   //
  185.         Serial.print("{"user1":"");Serial.print(cob.mac1);Serial.print("","user2":"");                          //返回JSON格式
  186.         Serial.print(cob.mac2);Serial.print("","PIN":"");Serial.print(cob.pin);Serial.print(""}");   
  187.       } else if (inputString.endsWith("}") && license == true) {
  188.         connStop = millis();   //
  189.         mcuSleep = millis();   //
  190.         cob = get_Conn();
  191.         String temp = inputString.substring((inputString.indexOf('}') - 12), inputString.indexOf('}'));
  192.         for (int i = 0; i < temp.length(); i++) {
  193.           cob.mac1[i] = temp[i];
  194.         }
  195.         Serial.println(cob.mac1);
  196.         set_Conn(cob);
  197.      
  198.       } else if (inputString.endsWith("]") && license == true) {
  199.         connStop = millis();   //
  200.         mcuSleep = millis();   //
  201.         cob = get_Conn();
  202.         String temp = inputString.substring((inputString.indexOf(']') - 12), inputString.indexOf(']'));
  203.         for (int i = 0; i < temp.length(); i++) {
  204.           cob.mac2[i] = temp[i];
  205.         }
  206.         Serial.println(cob.mac2);
  207.         set_Conn(cob);
  208.          
  209.       } else if (inputString.endsWith("skoff#") && license == true) {
  210.         connStop = millis();   //
  211.         mcuSleep = millis();   //
  212.         pin_type = "AT+TYPE0";
  213.         Serial.println(pin_type);
  214.         root_bt();
  215.       } else if (inputString.endsWith("skon#") && license == true) {
  216.         connStop = millis();   //
  217.         mcuSleep = millis();   //
  218.         pin_type = "AT+TYPE3";
  219.         Serial.println(pin_type);
  220.         root_bt();
  221.       } else if (license == false) {
  222.         Serial.println("ghost");
  223.       }
  224.     }
  225.     inputString = "";
  226.     stringComplete = false;
  227.   }
  228.   delay(50);
  229. }

  230. void wakeISR() {                      //唤醒后执行代码
  231.   if (energy.WasSleeping()) {
  232.     digitalWrite(MCULED, HIGH);
  233.     Serial.println("mcuwk");
  234.     connStop = millis();
  235.     mcuSleep = millis();
  236.     delay(1000);
  237.     digitalWrite(MCULED, LOW);
  238.   } else {
  239.   }
  240. }

  241. void setup() {                   //MCU初始化
  242.   
  243.   digitalWrite(HWRSTPIN, LOW);
  244.   digitalWrite(DEFAULTPIN, HIGH);
  245.   digitalWrite(LOCKPIN, LOW);
  246.   digitalWrite(UNLOCKPIN, LOW);
  247.   
  248.   pinMode(HWRSTPIN, OUTPUT);
  249.   pinMode(DEFAULTPIN, OUTPUT);
  250.   pinMode(DETECTPIN, INPUT_PULLUP);
  251.   pinMode(LOCKPIN, OUTPUT);
  252.   pinMode(UNLOCKPIN, OUTPUT);
  253.   pinMode(MCULED, OUTPUT);

  254.   digitalWrite(HWRSTPIN, LOW);
  255.   digitalWrite(DEFAULTPIN, HIGH);
  256.   digitalWrite(LOCKPIN, LOW);
  257.   digitalWrite(UNLOCKPIN, LOW);
  258.   digitalWrite(MCULED, LOW);

  259.   Serial.begin(9600);
  260.   inputString.reserve(200);
  261.   if (digitalRead(DEFAULTPIN) == LOW) {
  262.     delay(20);
  263.     if (digitalRead(DEFAULTPIN) == LOW) {
  264.         default_set();
  265.     }
  266.   }
  267.   if (EEPROM.read(512) != 1) {
  268.     default_set();
  269.   }
  270.   attachInterrupt(0, wakeISR, RISING);

  271. }

  272. void loop() {        //主循环代码

  273.   base_case();
  274.   ctrl_login();
  275.   ctrl_timeout();
  276.   delay(500);

  277. }

  278. void serialEvent() {    //串口事件响应代码
  279.   cob = get_Conn();
  280.   char str[13];
  281.   int idx = 0;
  282.   boolean mc1 = false;
  283.   boolean mc2 = false;
  284.   boolean back = true;
  285.   while (Serial.available()) {
  286.     char inChar = (char)Serial.read();
  287.     inputString += inChar;
  288.     if (inputString.indexOf('x') != -1 && idx < 13 && sts == false) {
  289.       str[idx++] = inChar;
  290.     }
  291.     if (idx >= 13 && sts == false) {
  292.         mc1 = true;
  293.         mc2 = true;
  294.       /*for (int i = 0; i < 12; i++) {      
  295.         Serial.print(cob.mac1[i]);
  296.         Serial.print("-");
  297.         }
  298.         Serial.println();
  299.         for (int i = 0; i < 12; i++) {
  300.         Serial.print(cob.mac2[i]);
  301.         Serial.print("+");
  302.         }
  303.         Serial.println();
  304.         for (int i = 0; i < 6; i++) {
  305.         Serial.print(cob.pin[i]);
  306.         Serial.print("*");
  307.         }*/
  308.       for (int i = 0; i < 12; i++) {
  309.         if (cob.mac1[i] != str[i + 1]) {
  310.           mc1 = false;
  311.           break;
  312.         }
  313.       }
  314.       for (int i = 0; i < 12; i++) {
  315.         if (cob.mac2[i] != str[i + 1]) {
  316.           mc2 = false;
  317.           break;
  318.         }
  319.       }
  320.       if (mc1 == true || mc2 == true) {
  321.         license = true;
  322.         sts = true;
  323.       } else if((mc1 == true || mc2 == true)&&(back == true)) {
  324.         Serial.print("login:");
  325.         for (int i = 0; i < 12; i++) {
  326.           Serial.print(str[i + 1]);
  327.         }
  328.         Serial.println();
  329.         back = false;
  330.       }
  331.     }

  332.     if ((inChar == '#') || (inChar == '}')
  333.         || (inChar == ']') || (inChar == ';')) {
  334.       stringComplete = true;
  335.     }
  336.   }
  337. }
复制代码

MCU端封装的软件接口明细

手机APP端UI


使用BLE GATT协议通讯,代码见所附下载地址,不详述
附言:
1.如需实践,切记关机后充电,也就是断开输出负载
   其实供电部分可以用MOS管加Attiny控制来实现和手机一样的开机充电
2.此蓝牙模块有几个bug
      --和IOS系统可以正常连接和GATT协议通讯,但应该是未过MFi认证的原因,底层固件无权限取得IOS端设备MAC。
         此时会用一种随机算法虚拟一个MAC地址抛给MCU,这比较讨厌 。
      --此模块固件如设置上电后等待MCU指令模式,MCU给休眠指令后,无法正常休眠。只适合上电自运行模式
3.如不考虑能耗问题,可以使用此蓝牙的主模式,搜索附近指定MAC的RSSI值来判断是否车主接近和离开。
   这样可以实现免操作自动开关门,代码实现不难,有兴趣的可以尝试一下。

本文所有源码下载路径
http://pan.baidu.com/s/1eSJNoHk
厂商参考资料下载路径
http://pan.baidu.com/s/1eSJNoHk

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2016-5-26 23:26:46 | 显示全部楼层
土豪,我帮你捡肥皂~
回复 支持 反对

使用道具 举报

发表于 2016-5-27 08:01:12 | 显示全部楼层
土豪,我帮你捡肥皂~
回复 支持 反对

使用道具 举报

发表于 2016-6-3 12:18:20 | 显示全部楼层
支持支持支持支持
回复 支持 反对

使用道具 举报

发表于 2016-6-19 10:17:18 | 显示全部楼层
真乃神人也
回复 支持 反对

使用道具 举报

发表于 2016-8-7 00:04:20 | 显示全部楼层
灰常实用啊!完事具备只欠汽车了
回复 支持 反对

使用道具 举报

发表于 2016-8-18 17:55:34 | 显示全部楼层
思路决定出路啊!

楼主下次搞个NFC,拍一拍就开门。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 22:26 , Processed in 0.057593 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表