工业逆向工程

电子产品开发中的借贷过程的故事就是一个很好的例子。



记录自制嗅探器的电梯日志


一旦我需要复制一个相当简单的设备。 该制造公司不复存在,但在全国各地仍然有更换损坏或用过的设备的需求。


设备本身是左侧照片中的电梯呼叫按钮。 为了进行实验,他们给了我两份,其中一份可以完全拆开。


总体工作计划如下所示:


  1. 研究电路板;
  2. 研究电路板本身的元素基础;
  3. 画出她的电路图;
  4. 尝试从微控制器读取固件文件;
  5. 拆卸固件;
  6. 提取运算算法;
  7. 开发新的董事会;
  8. 编写新固件。

如果第4款失败,则进一步的计划将会更加复杂,但我很幸运。


我们研究实验



主微控制器



电梯的一块电路,其上的电路板用红色圈出


该板组装在基于Intel MCS-51架构的1997年微控制器AT89C2051上。 在2020年,她庆祝了自己在嵌入式系统市场40周年。


一个小小的解释:微控制器就是这样的微电路,它包含一个计算核心和一组用于控制外部设备的外围设备。 例如,在现代洗衣机中,微控制器会轮询控制按钮,传感器,在屏幕上显示信息并控制泵,加热器,阀门和滚筒驱动器。 对于大多数这些功能,它不需要中间设备,而只需要一组无源电子组件。


我们拆卸电路板

将来草绘电路板的原始电路图将有助于找出微控制器引脚的用途,这是解析固件代码所必需的。


原始设备是由一家中国公司开发的,因此其电路非常混乱,并且包含许多不必要的组件。 例如,继电器通过双极晶体管,光耦合器和现场设备的三级串联(按该顺序)接通。


一位与中国制造商合作的熟人告诉我,如果只有一个人,中国人会参与类似的复杂计划,以增加开发和生产成本。 在此之后,我倾向于相信他:



双方在中文两层板上的同一位置。 三个大电阻未连接任何东西。 我什至用强力手电筒照亮了主板,以确保。


方案被复制,神秘的地方在multisim中建模,我们占用了固件。


尝试读取固件


我很幸运,没有在控制器的两个板上都启用读保护,所以我成功地将两个固件选项合并为类似的色情内容:



美国发烧友个人博客的照片


拆卸固件


下一步,我们需要将此机器代码转换为更具可读性的内容:



我们使用著名的IDA Pro工具,该工具已经具有包含所有外设寄存器的控制器,然后打开HEX固件文件:



处理董事会以汇编语言接收的数据


之后,有一个相当繁琐的过程来研究我们的计算内核的指令集,对汇编代码进行注释和解码。


中断处理程序本身位于中断向量表的地址中;外设寄存器中的条目提供了有关通信接口配置的信息。 一步一步,未命名的汇编代码已变成可以读取的内容。


提取工作算法


由于我需要在不同的元件基础上开发新设备,因此有必要从代码中提取算法。 一段时间后,这样的伪代码诞生了:


void UartISR (void) { counter500ms = 0; //ClearFlag(isrFlags, ISR_FLAG_3); ProcessUart(recievedByte); } void ProcessUart(uint8_t recievedData) { static uint8_t uartPacketsToRxLeft, uartRecievedCmd, uartCurrPacketCRC; static uint8_t i, carryFlag; static uint16_t uartIsrPointer; static uint8_t uartBuffer1[8], uartBuffer2[6]; static uint8_t uartBuffer1Pos, uartBuffer2Pos; // 0 - // 1 - // 2 - // 3 - led state, 0x0F // 4 - // 5 - // 6 - // 7 - // 8 - buttons time static uint8_t dataRegisters[9]; // RAM:0050 uint8_t tmpVal, i; uint8_t dataToSend; if (GetFlag(UartISRFlags, UART_RECIEVED_FLAG)) { ClearFlag(UartISRFlags, UART_RECIEVED_FLAG); if (recieved9thBit) { switch (recievedData) { case 0xC1: uartPacketsToRxLeft = 8; uartRecievedCmd = 1; uartBuffer1Pos = 0; uartBuffer1[uartBuffer1Pos] = recievedData; //uartIsrPointer = 0x0037; //tmpVal_0037 = recievedData; uartCurrPacketCRC = recievedData; UartRxOn(); return; break; case 0xC2: uartPacketsToRxLeft = 3; uartRecievedCmd = 2; 

对接收到的数据进行相同的处理


谁在乎传输协议:


电梯控制站通过全双工24伏接口与呼叫按钮板通信。 在正常模式下,按钮卡监听线路,等待9位数据包。 如果该板的地址位于此数据包中(由板上的DIP开关设置),则该板将切换为8位接收模式,其余所有板均会被硬件中的其他板忽略。

地址之后的第一个是带有控制命令代码的数据包。 具体来说,该委员会只招募了3个团队:
  1. 写入数据寄存器。 例如,通话中按钮闪烁的频率和持续时间;
  2. 打开按钮背光;
  3. 查询按钮的状态(是否按下)。


最后一个字节是校验和,它是地址后所有字节的简单XOR。
校验和之后,开发板再次进入待机模式以获取其地址。

新板开发


在开发新的接线图和印刷电路板的阶段,我没有照片,但这是这样的:


接线和接线在Altium Designer中完成。 印刷电路板的制造在Zelenograd“ Resonite ”中订购。


编写新固件


当我们的新板投入生产时,我们转到安装了此类呼叫按钮的对象,并使用arduino上组装的嗅探器检查解析的传输协议的正确性:

一块与原始电子等效的发射器电路。 接收器只是一个光耦合器。


 //UART1 initialize // desired baud rate:19200 // actual baud rate:19231 (0,2%) // char size: 9 bit // parity: Disabled void uart1_init(void) { UCSR1B = 0x00; //disable while setting baud rate UCSR1A = 0x00; UCSR1C = 0x06; UBRR1L = 0x33; //set baud rate lo UBRR1H = 0x00; //set baud rate hi UCSR1B = 0x94; } #pragma interrupt_handler uart1_rx_isr:iv_USART1_RXC void uart1_rx_isr(void) { unsigned char tmp; unsigned int rcv = 0; if (UCSR1B & 0x02) { rcv = 0x100; } rcv |= UDR1; tmp = (rcv >> 4) & 0x0F; if (rcv & 0x100) { tmp |= 0xC0; } else { tmp |= 0x80; } txBuf12 = (rcv & 0x0F); txBuf11 = tmp; txState1 = 0; TX_ON(); msCounter0 = 5000; } 

谈谈我们在ICC AVR中的嗅探器


接下来,必须非常小心地采取行动,以免在电梯中燃烧任何东西并防止其停止。



我们进入通话按钮。 黄色粗线-电路板电源和传输接口。 4针连接器上的白色-连接按钮及其背光。


我们检查一切正常,修复门框并为我们的设备编写新的固件:


 //ICC-AVR application builder : 11.02.2015 12:25:51 // Target : M328p // Crystal: 16.000Mhz #include <macros.h> #include <iccioavr.h> #include <avrdef.h> #include "types.h" #include "gpio.h" #define TX_OFF() UCSR0B &= 0b11011111; #define TX_ON() UCSR0B |= 0b00100000; #define TX_STATE() (UCSR0B & 0b00100000) #define MAX_TIMEOUT 3000 //#define SNIFFER_MODE 1 //#define MASTER_MODE 1 // #pragma avr_fuse (fuses0, fuses1, fuses2, fuses3, fuses4, fuses5) #pragma avr_fuse (0xFF, 0xD1, 0xFC) #pragma avr_lockbits (0xFC) // AVR signature is always three bytes. Signature0 is always the Atmel // manufacturer code of 0x1E. The other two bytes are device dependent. #pragma avr_signature (0x1E, 0x95, 0x0F) // atmega32 static GPIOx errorLed, rcvLed, butUp, butDn, ledUp, ledDn, butLedUp, butLedDn, ledButUp, ledButDn; static uint8_t msFlag = 0; static uint8_t ledState = 0, buttonsState = 0; static uint16_t rcvLedLitTime = 0, butMaskCalcTime = 0, timeoutTimer = 0; typedef struct { uint16_t buffer[10]; uint8_t dataLength; } UartPacket; static UartPacket txPacket, rxPacket; #ifdef SNIFFER_MODE static uint8_t txBuffer[64], txBufferLength = 0, bufferMutex = 0; #endif static uint8_t GetPacketCRC(UartPacket* packet); static void SendLedState(void); uint8_t GetAddress(void) { return (PINC & 0x3F); } 

基于AVR ATmega328P微控制器的新板的C代码


设备和固件的简单性可以通过代码量来估计,它仅包含约600行C语言。


构建过程如下所示:



费用不同,但原理相同


我无法附上完成后的设备的照片,只是相信它仍在生产和销售中。


抒情结论


关于电梯按钮在地板上的“上”和“下”。 我注意到许多人完全不了解他们的目的,并且一次摇摇了。



从这里


电梯有两组按钮:在驾驶室中有一个订购面板,在地板上有一个呼叫面板。 您已经可以从名称中猜测到订单面板具有更高的控制优先级。


所有带有呼叫面板,带有向上和向下按钮的电梯均采用某种行程优化算法,其目的是在最短时间内运送最大人数的乘客,并在楼层上等待最长等待时间的单独条件(由国家标准规定)。


这种算法通常涉及选择楼层上的乘客,如果他们按按“上”或“下”呼叫按钮指示的相同方向行驶。


想象一下这样一种情况:载有乘客的电梯向下行驶并收到下面一层的“向下”呼叫。 电梯将停下来接客(是的,重量传感器仍在考虑客舱的负载,但我们会降低它)。


电梯继续运行,并从下面的楼层接收“向上”呼叫。 顺理成章的是,电梯不会停下来接客,因为它不会改变行进方向(这也是标准规定的),并会接送乘客上下然后走-浪费了电梯中的能量和空间。


电梯继续运行,并从下面的楼层接到两个“上下”呼叫,这是由一些急躁需要上来的乘客按下的。 电梯将停在此楼层是合乎逻辑的,但乘客不会进入该楼层,但是机舱中的人员会花一些时间来减速并停止电梯,打开门,等待,关闭门并加速至额定速度。


如果电梯在地板上只有一个按钮,则在99%的情况下,电梯将根据“集体下降”算法运行,并且如果机舱中有命令,则仅在下降时才停止。


如果您具有JS编程技能,则可以尝试在在线游戏Elevator Saga中实现类似的控制算法。 它具有优化行程的所有方面,而无需像电梯安全电路的操作那样深入了解核心。



电报频道中,我张贴了类似的材料。 现在,您可以在其中跟踪下一个设备的开发。

Source: https://habr.com/ru/post/zh-CN459492/


All Articles