HuaShine2015 发表于 2016-5-26 20:59:32

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

本帖最后由 HuaShine2015 于 2016-5-26 20:58 编辑

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

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

然后加上翅膀配上航弹

配齐主要机组人员

准备起飞


背景:
原理图概述

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

软件流程图

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

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

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

struct CellObject {
char mac0;
char mac1;
char mac2;
char pin;
};

Energy energy;
CellObject cob;
String pin_type = "AT+TYPE0";
String inputString = "";
boolean stringComplete = false;
boolean license = false;
boolean sts = false;
const unsigned long WAIT_TIME1 = 120000;
const unsigned long WAIT_TIME2 = 25000;
const unsigned long WAIT_TIME3 = 200000;
unsigned long connStop = 0;
unsigned long mcuSleep = 0;

CellObject get_Conn() {
CellObject getvaul;
EEPROM.get(0, getvaul);
return getvaul;
}
void set_Conn(CellObject setVar) {
EEPROM.put(0, setVar);
EEPROM.put(512, 1);
}

void clrEEPROM() {
for (int i = 0 ; i < EEPROM.length() ; i++) {
    EEPROM.write(i, 0);
}
}

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

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

void bt_sf_rst() {
Serial.println("AT+RESET\r");
delay(2500);
}
void sleep_bt() {
Serial.println("AT+SLEEP\r");
delay(1000);
}
void wakeup_bt() {
for (int i = 0; i <= 12; i++) {
    Serial.print("WAKEUPBT");
}
Serial.println("\r");
delay(1500);
}

void root_bt() {   //设置蓝牙模块
while (true) {
    digitalWrite(MCULED, !digitalRead(MCULED));
    if (digitalRead(DETECTPIN) == LOW) {
      delay(30);
      if (digitalRead(DETECTPIN) == LOW) {
          break;
      }
    }
    delay(250);
}
digitalWrite(MCULED, HIGH);
wakeup_bt();
//Serial.println("AT+NAMELIFAN320\r");
//delay(600);
Serial.print(pin_type); Serial.println("\r");
delay(500);
cob = get_Conn();
Serial.print("AT+PIN"); Serial.print(cob.pin); Serial.println("\r");
delay(800);
Serial.println("AT+ROLE0\r");
delay(500);
Serial.println("AT+NOTI1\r");
delay(500);
Serial.println("AT+NOTP1\r");
delay(500);
Serial.println("AT+IMME0\r");
delay(500);
Serial.println("AT+PWRM0\r");
delay(1000);
bt_sf_rst();
digitalWrite(MCULED, LOW);
}

void ctrl_login() {                        //控制MCU是否可以休眠
if (digitalRead(DETECTPIN) == LOW) {
    delay(30);
    if (digitalRead(DETECTPIN) == LOW) {
      delay(30);
      if (digitalRead(DETECTPIN) == LOW) {
      sts = false;
      license = false;
      mcu_sleep();
      }
    }
}
}

void ctrl_timeout() {                           //连接超时控制
unsigned long currentMillis = millis();
if (digitalRead(DETECTPIN) == HIGH) {
    delay(30);
    if (digitalRead(DETECTPIN) == HIGH) {
      delay(30);
      if (digitalRead(DETECTPIN) == HIGH) {
      if ( (license == false) && (currentMillis - connStop >= WAIT_TIME2)) {
          connStop = currentMillis;
          Serial.println("timeout1");
          bt_hw_rst();   
      } else if (license == true && (currentMillis - connStop >= WAIT_TIME1) && stringComplete != true && (!Serial.available())) {
          connStop = currentMillis;
          Serial.println("timeout2");
          bt_hw_rst();
      }
      }
    }
}
}

void mcu_sleep() {                                 //MCU休眠代码
unsigned long currentMillis = millis();
if (currentMillis - mcuSleep >= WAIT_TIME3) {
    mcuSleep = currentMillis;
    Serial.println("mcuslp");
    wakeup_bt();
    sleep_bt();
    energy.PowerDown();
}
}

void base_case() {       //业务主体代码
if (stringComplete) {
    if (digitalRead(DETECTPIN) == HIGH) {
      if (inputString.endsWith("close#") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      digitalWrite(LOCKPIN, HIGH);
      delay(1100);
      digitalWrite(LOCKPIN, LOW);
      Serial.println("off");
      } else if (inputString.endsWith("open#") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      digitalWrite(UNLOCKPIN, HIGH);
      delay(1100);
      digitalWrite(UNLOCKPIN, LOW);
      Serial.println("on");
      } else if (inputString.endsWith(";") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      cob = get_Conn();
      String temp = inputString.substring((inputString.indexOf(';') - 6), inputString.indexOf(';'));
      for (int i = 0; i < temp.length(); i++) {
          cob.pin = temp;
      }
      Serial.println(cob.pin);
      set_Conn(cob);
      root_bt();
      } else if (inputString.endsWith("admin#") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      Serial.print("{\"user1\":\"");Serial.print(cob.mac1);Serial.print("\",\"user2\":\"");                        //返回JSON格式
      Serial.print(cob.mac2);Serial.print("\",\"PIN\":\"");Serial.print(cob.pin);Serial.print("\"}");   
      } else if (inputString.endsWith("}") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      cob = get_Conn();
      String temp = inputString.substring((inputString.indexOf('}') - 12), inputString.indexOf('}'));
      for (int i = 0; i < temp.length(); i++) {
          cob.mac1 = temp;
      }
      Serial.println(cob.mac1);
      set_Conn(cob);
   
      } else if (inputString.endsWith("]") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      cob = get_Conn();
      String temp = inputString.substring((inputString.indexOf(']') - 12), inputString.indexOf(']'));
      for (int i = 0; i < temp.length(); i++) {
          cob.mac2 = temp;
      }
      Serial.println(cob.mac2);
      set_Conn(cob);
         
      } else if (inputString.endsWith("skoff#") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      pin_type = "AT+TYPE0";
      Serial.println(pin_type);
      root_bt();
      } else if (inputString.endsWith("skon#") && license == true) {
      connStop = millis();   //
      mcuSleep = millis();   //
      pin_type = "AT+TYPE3";
      Serial.println(pin_type);
      root_bt();
      } else if (license == false) {
      Serial.println("ghost");
      }
    }
    inputString = "";
    stringComplete = false;
}
delay(50);
}

void wakeISR() {                      //唤醒后执行代码
if (energy.WasSleeping()) {
    digitalWrite(MCULED, HIGH);
    Serial.println("mcuwk");
    connStop = millis();
    mcuSleep = millis();
    delay(1000);
    digitalWrite(MCULED, LOW);
} else {
}
}

void setup() {                   //MCU初始化

digitalWrite(HWRSTPIN, LOW);
digitalWrite(DEFAULTPIN, HIGH);
digitalWrite(LOCKPIN, LOW);
digitalWrite(UNLOCKPIN, LOW);

pinMode(HWRSTPIN, OUTPUT);
pinMode(DEFAULTPIN, OUTPUT);
pinMode(DETECTPIN, INPUT_PULLUP);
pinMode(LOCKPIN, OUTPUT);
pinMode(UNLOCKPIN, OUTPUT);
pinMode(MCULED, OUTPUT);

digitalWrite(HWRSTPIN, LOW);
digitalWrite(DEFAULTPIN, HIGH);
digitalWrite(LOCKPIN, LOW);
digitalWrite(UNLOCKPIN, LOW);
digitalWrite(MCULED, LOW);

Serial.begin(9600);
inputString.reserve(200);
if (digitalRead(DEFAULTPIN) == LOW) {
    delay(20);
    if (digitalRead(DEFAULTPIN) == LOW) {
      default_set();
    }
}
if (EEPROM.read(512) != 1) {
    default_set();
}
attachInterrupt(0, wakeISR, RISING);

}

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

base_case();
ctrl_login();
ctrl_timeout();
delay(500);

}

void serialEvent() {    //串口事件响应代码
cob = get_Conn();
char str;
int idx = 0;
boolean mc1 = false;
boolean mc2 = false;
boolean back = true;
while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inputString.indexOf('x') != -1 && idx < 13 && sts == false) {
      str = inChar;
    }
    if (idx >= 13 && sts == false) {
      mc1 = true;
      mc2 = true;
      /*for (int i = 0; i < 12; i++) {      
      Serial.print(cob.mac1);
      Serial.print("-");
      }
      Serial.println();
      for (int i = 0; i < 12; i++) {
      Serial.print(cob.mac2);
      Serial.print("+");
      }
      Serial.println();
      for (int i = 0; i < 6; i++) {
      Serial.print(cob.pin);
      Serial.print("*");
      }*/
      for (int i = 0; i < 12; i++) {
      if (cob.mac1 != str) {
          mc1 = false;
          break;
      }
      }
      for (int i = 0; i < 12; i++) {
      if (cob.mac2 != str) {
          mc2 = false;
          break;
      }
      }
      if (mc1 == true || mc2 == true) {
      license = true;
      sts = true;
      } else if((mc1 == true || mc2 == true)&&(back == true)) {
      Serial.print("login:");
      for (int i = 0; i < 12; i++) {
          Serial.print(str);
      }
      Serial.println();
      back = false;
      }
    }

    if ((inChar == '#') || (inChar == '}')
      || (inChar == ']') || (inChar == ';')) {
      stringComplete = true;
    }
}
}

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

GDHack 发表于 2016-5-26 23:26:46

土豪,我帮你捡肥皂~

PINKWALKMAN 发表于 2016-5-27 08:01:12

土豪,我帮你捡肥皂~

原野动力 发表于 2016-6-3 12:18:20

支持支持支持支持

Hackerpro 发表于 2016-6-19 10:17:18

真乃神人也

geek01 发表于 2016-8-7 00:04:20

灰常实用啊!完事具备只欠汽车了:lol

pepsi68 发表于 2016-8-18 17:55:34

思路决定出路啊!

楼主下次搞个NFC,拍一拍就开门。
页: [1]
查看完整版本: 暴力改造汽车遥控钥匙为手机APP控制