三洋空调IR包中的逆向工程4位校验和(?)

逆向工程 二元分析 解密 协议
2021-07-04 05:10:05

我是三洋空调的逆向工程IR协议。AC 在每次按键时发送遥控器的整个当前状态。发送的数据长 67 位,最后 4 位似乎是某种错误检查。

我想通了大部分事情,但我找不到错误检查是如何完成的。Temp + 模式是其中的一部分,但我找不到解决整个难题的方法。还有关于什么col的任何建议。16 可能(我在概述中缺少功能吗?)会很棒。

以下是示例值:

 1  2  3 4 5   6   7   8   9  10 11 12      13      14    15  16        17          18
100 1 00 0 0 1011 00 1111 000 1   1  0 00001010010 0000 00000 0 000100000000000000 1010 ->
100 1 00 0 0 1011 00 1111 000 1   1  1 00001010010 0000 00000 0 000100000000000000 1010 ->
100 1 00 1 0 0000 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 1010
100 1 00 1 0 1000 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0110
100 1 00 1 0 0100 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 1110
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 00 0 0 0011 00 1111 000 1   1  0 00001010010 0000 00000 0 000100000000000000 0010 ->
100 1 00 0 0 0011 00 1111 000 1   1  0 00001010010 0000 00000 0 000100000000000000 0010 ->
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 0100 00000 1 000100000000000000 0100
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 1100 00000 1 000100000000000000 0100
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 0010 00000 1 000100000000000000 0100
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 1010 00000 1 000100000000000000 0100
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 0110 00000 1 000100000000000000 0100
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1000 00000 1 000100000000000000 0100
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1101 00000 1 000100000000000000 0100
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1001 00000 1 000100000000000000 0100
100 1 00 0 0 1011 00 0000 000 1   1  0 00001010010 0000 00000 1 000100000000000000 0100
100 1 10 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 01 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 11 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 1 000100000000000000 0100
100 1 00 0 0 0011 00 0000 000 0   1  0 00001010010 0000 00000 0 000100000000000000 1000
100 1 00 0 0 0011 00 0000 000 1   1  0 00001010010 0000 00000 0 000100000000000000 1000
000 1 10 0 0 1001 00 0000 000 1   1  0 00001010010 0000 00000 0 000100000000000000 1011
100 1 00 0 0 0011 00 0000 000 1   1  0 00001010010 0000 00000 0 000100000000000000 1000
010 1 10 0 0 0100 00 0000 000 1   1  0 00001010010 0000 00000 0 000100000000000000 0001
110 1 00 1 0 1011 00 0000 000 1   1  0 00001010010 1110 00000 0 000100000000000000 0010
001 1 00 0 0 0011 00 0000 000 1   1  0 00001010010 0000 00000 0 000100000000000000 0010
100 0 00 1 0 1011 00 0000 000 1   0  0 00001010010 1110 00000 1 000100000000000000 0101

到目前为止我发现了什么:

1: mode (cool, dry, fan, etc.)
2: appliance on
3: fan speed (00 = auto)
4: sweep motor
5: constant 0
6: temperature (16 + bit pattern)
7: constant 00
8: 0000, but 1111 if an additional packet is sent with time data ( -> )
9: constant 000
10: light on
11: appliance on
12: blower on
13: constant
14: direction of airflow (low, high, and various angles)
15: constant
16: yet unknown
17: constant
18: error checking (at least temp + mode is a component of this magic number)

EDIT1不添加信息的剥离行/列:

 1  2   6   8   11 16  18
100 1 1011 1111  1  0 1010 ->
100 1 0000 0000  1  1 1010
100 1 1000 0000  1  1 0110
100 1 0100 0000  1  1 1110
100 1 0011 1111  1  0 0010 ->
100 1 1011 0000  1  1 0100
100 1 0011 0000  1  0 1000
000 1 1001 0000  1  0 1011
010 1 0100 0000  1  0 0001
110 1 1011 0000  1  0 0010
001 1 0011 0000  1  0 0010
100 0 1011 0000  0  1 0101
2个回答

我从布尔逻辑简化器的角度来处理这个问题:您可以修剪的值越多,您的校验和函数的输入就越少,理解起来也就越简单。

无论如何都不是一个完整的解决方案,但有一些想法:

  • 修剪数据集中具有相同值的行。它们只是噪音。
  • 第 5、7、9、13、15 和 17 列的每一行都具有相同的值,因此您只能猜测它们是如何计入校验和的。因此,它们无助于确定如何使用其他值。
  • 第 3、4、10、12 和 14 列不包含在校验和中,因为存在所有其他值都相同且校验和相同的行。
  • 第 1、6 和 8 列肯定包含在校验和中,因为有些行的所有其他值都相同,但校验和不同。

TL;DR:简化您的数据集。

我知道这个问题很老,但我在为这种相同类型的 AC 计算位映射时偶然发现了它。在此处查看 Catalyn 的帖子:https ://myesp8266.blogspot.com.ar/2016/05/keep-your-house-cool-with-esp8266.html 它似乎是关于相同的 AC 协议,其中有一些关于如何计算 CRC 的内容。我还没有尝试过,因为我目前正在将这些位映射到功能上。你有一些我还没有找到并为我节省了一些时间。顺便说一句,第 5 列中的常量 0 实际上是睡眠功能。

编辑:我已经解决了这个问题!我发现了一些其他很好的英特尔来源,一些带有有时有效的蹩脚代码,以及一些缺少假设的良好文档。合并它们,现在我有工作代码。我忽略了一些我不关心的部分,但您可以弄清楚如何添加它们。我所做的 CRC 计算已经考虑到了所有问题,而不管它们是否被修复。

此(java)脚本将根据具有适当 CRC 的参数生成数据包:

const header = [9050, 4450];
const zero_bit = [700, 550];
const one_bit = [700, 1650];

const separator = [700, 19900];

const MODE = {
  AUTO:   0x0,
  COOL:   0x1,
  DRY:    0x2,
  FAN:    0x3,
  HEAT:   0x4
};

const POWER = {
  OFF: 0x0,
  ON: 0x1
};

const FAN = {
  AUTO: 0x0,
  SPEED_1: 0x1,
  SPEED_2: 0x2,
  SPEED_3: 0x3,
  SPEED_4: 0x4,
};

const SWING = {
  OFF: 0x0,
  ON: 0x1
};

const SLEEP = {
  OFF: 0x0,
  ON: 0x1
};

const TURBO = {
  OFF: 0x0,
  ON: 0x1
};

const LIGHT = {
  OFF: 0x0,
  ON: 0x1
}

const HEALTH = {
  OFF: 0x0,
  ON: 0x1
}

const XFAN = {
  OFF: 0x0,
  ON: 0x1
}

const TEMPERATURE = {
  BASE: 16
};

let state = {
  mode: MODE.COOL,
  power: POWER.ON,
  temperature: 27 - TEMPERATURE.BASE,
  xfan: XFAN.ON,
  health: HEALTH.ON,
  light: LIGHT.ON,
  turbo: TURBO.OFF,
  swing: SWING.ON,
  fan: FAN.AUTO
};

function reverseBits(x, bitLength) {
    let result = 0;

    for (let index = 0; index < bitLength; ++index) {
      result |= ((x >> index) & 1) << (bitLength - index - 1)
    }
    return result
}

function reverseByte(value) {
  return reverseBits(value, 8);
}

function reverseNibble(value) {
  return reverseBits(value, 4);
}

function buildPacket(state) {
  const byte1 = (reverseBits(state.mode, 3) << 5) | (reverseBits(state.power, 1) << 4) | (reverseBits(state.fan, 2) << 2) | (reverseBits(state.swing, 1) << 1) | (reverseBits(state.sleep, 1) << 0);
  const byte2 = (reverseBits(state.temperature, 4) << 4);
  const byte3 = (reverseBits(state.turbo, 1) << 3) | (reverseBits(state.light, 1) << 2) | (reverseBits(state.health, 1) << 1) | (reverseBits(state.xFan, 1) << 1);
  const byte4 = 0x0A;

  const byte5 = 0;
  const byte6 = 4;
  const byte7 = 0;
  const byte8 = reverseNibble(
  (
    (reverseByte(byte1) & 0x0F) +
    (reverseByte(byte2) & 0x0F) + 
    (reverseByte(byte3) & 0x0F) +
    (reverseByte(byte4) & 0x0F) +
    ((reverseByte(byte5) & 0xF0) >> 4 ) +
    ((reverseByte(byte6) & 0xF0) >> 4 ) + 
    ((reverseByte(byte7) & 0xF0) >> 4 ) + 10
  ) & 0x0F);

  let data = [];
  data = data.concat(header);
  data = pushBits(data, byte1);
  data = pushBits(data, byte2);
  data = pushBits(data, byte3);
  data = pushBits(data, byte4);
  data = data.concat(zero_bit);
  data = data.concat(one_bit);
  data = data.concat(zero_bit);
  data = data.concat(separator);
  data = pushBits(data, byte5);
  data = pushBits(data, byte6);
  data = pushBits(data, byte7);
  data = pushBits(data, byte8);
  data = data.concat([650]);

  return data;
}

function pushBits(data, byte) {
  for (let i = 7; i >= 0; --i) {
    if ((byte & (1 << i)) !== 0) {
      data = data.concat(one_bit);
    }
    else {
      data = data.concat(zero_bit);
    }
  }
  return data;
}

const data = buildPacket(state);
console.log(data)