Начало
Передо мной встала задача провести реверс-инжиниринг программы мониторинга артериального давления для устройства Spacelabs OnTrak 90227 ABP Monitor.
Вот такого:
Устройство подключается через USB и определяется системой как виртуальный COM-порт.
Программа, с которой мне предстояло работать, 32 битная, написана на C++ с использованием MFC и была выпущена в 2010 году.
Несмотря на поддержку юникода, приложение имеет проблемы с отображением кириллицы — но это не важно для задачи.
Основная цель — найти код, связанный с кнопками «Выгрузить монитор» и «Инициализировать монитор», чтобы осуществить обмен данными с устройством.
На основе найденного кода нужно разработать консольное приложение, которое будет инициализировать устройство для последующих измерений или считывать данные с устройства и записывать результаты в файл.
Экзешник программы называется abpwin.exe, и в одной папке с ним находятся несколько библиотек DLL и вспомогательных программ для работы с базой данных. Кстати, приложение использует MS SQL Server 2005, хотя, для таких задач вполне подошел бы SQLite.
При нажатии на кнопку «Выгрузить монитор» открывается диалог в виде мастера, где и происходит выгрузка данных.
Я попытался найти этот диалог в ресурсах приложения с помощью Resource Hacker, но не нашел его. Я предположил, что он может находиться в одной из библиотек DLL.
Внимание привлекла библиотека ABPDeviceCommunicator.dll, которая, судя по названию, отвечает за обмен данными с устройством.
В ней я обнаружил часть диалога — панель с надписью «Select Communication Mode:»
Кроме того, в ресурсах присутствуют REGISTRY и TYPELIB, что указывает на наличие OLE компонента! Зачем было использовать OLE в этом приложении? Для чего?
Ведь достаточно просто экспортировать функции из библиотеки.
На эти вопросы вряд ли кто-то сможет ответить, кроме разработчиков приложения, но с ними понятное дело связи нет.
Это явно оверинжиниринг. Наверно, разработчики хотели продемонстрировать свои навыки, используя OLE и работу с SQL-сервером, чтобы показать, какие они крутые программисты.
Стоит отметить, что библиотека экспортирует лишь четыре функции: DllCanUnloadNow, DllGetClassObject, DllRegisterServer и DllUnregisterServer. В рамках OLE нет необходимости экспортировать функции из библиотек, и это создает определенные сложности при исследовании и поиске нужного кода.
Для получения списка классов и методов можно воспользоваться инструментом OLE/COM Object Viewer из Windows SDK. Вот что он выдал:
// Generated .IDL file (by the OLE/COM Object Viewer) // // typelib filename: ABPDeviceCommunicator.dll [ uuid(3A9C5D9C-4434-4420-A475-6BB9F4CD720A), version(1.0), helpstring("ABPDeviceCommunicator 1.0 Type Library"), custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 83951780), custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1363618625) ] library ABPDEVICECOMMUNICATORLib { // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046} importlib("stdole2.tlb"); // Forward declare all types defined in this typelib interface IABPCommunicate; [ uuid(91E73282-9D64-4932-B680-18BF6A2DD293), helpstring("ABPDeviceComn Class") ] coclass ABPDeviceComn { [default] interface IABPCommunicate; }; [ odl, uuid(A12CA95D-5EFC-459A-9296-740E44CA79A6), helpstring("IABPCommunicate Interface"), dual, oleautomation ] interface IABPCommunicate : IDispatch { [id(0x00000001), helpstring("method UploadMonitor")] HRESULT UploadMonitor([out, retval] VARIANT* pVarCompleteXMLTree); [id(0x00000002), helpstring("method StartInitializingMonitor")] HRESULT StartInitializingMonitor([out, retval] long* pbInitSucceeded); [id(0x00000003), helpstring("method AddMonitorPeriod")] HRESULT AddMonitorPeriod( [in] VARIANT* pVarStartTime, [in] VARIANT* pVarEndTime, [in] long nCycleTime, [in] long bToneHeard, [in] long bFirstPeriod); [id(0x00000004), helpstring("method AddMonitorSettings")] HRESULT AddMonitorSettings( [in] long bShowReadingsresults, [in] long bClinicalVerifSetup, [in] long bShowCuffPressure, [in] long bClockFormat, [in] BSTR strPatientGuidId, [in] BSTR strReasonForTest, [in] BSTR strPrimaryPassword, [in] BSTR strSecondaryPassword); [id(0x00000005), helpstring("method UseThisLanguage")] HRESULT UseThisLanguage([in, optional, defaultvalue("0")] BSTR bstrLanguage); [id(0x00000006), helpstring("method UploadMonitorVC")] HRESULT UploadMonitorVC( [out] VARIANT* pVarMonitorReading, [out] VARIANT* pVarInitDate, [out] VARIANT* pVarPatientGuid, [out] VARIANT* pVarReasonsForTest, [out] VARIANT* pVarNumberOfReadings, [out, retval] long* pbUploadSucceeded); [id(0x00000007), helpstring("method SetLastUsedComPort")] HRESULT SetLastUsedComPort([in] BSTR bstrComPort); [id(0x00000008), helpstring("method GetLastUsedComPort")] HRESULT GetLastUsedComPort([out] VARIANT* pVarComPort); [id(0x00000009), helpstring("method GetFirmwareVersion")] HRESULT GetFirmwareVersion( [out] VARIANT* pVarModel90207Version, [out] VARIANT* pVarModel90217Version); [id(0x0000000a), helpstring("method GetLastUsedComPortAsp")] HRESULT GetLastUsedComPortAsp([out, retval] VARIANT* pVarComPort); [id(0x0000000b), helpstring("method StopInitMonitor")] HRESULT StopInitMonitor(); [id(0x0000000c), helpstring("method StopReadMonitor")] HRESULT StopReadMonitor(); [id(0x0000000d), helpstring("method DumpMonitorDataToFile")] HRESULT DumpMonitorDataToFile( [in] BSTR bstrFilePath, [out, retval] long* bResult); [id(0x0000000e), helpstring("method CheckForNoCOMPorts")] HRESULT CheckForNoCOMPorts(); }; };
От этого, конечно, мало толку, но имеем то, что имеем.
Судя по всему, за процесс выгрузки данных отвечают методы UploadMonitor и UploadMonitorVC.
Эмулятор на Arduino.
Статическим анализом эти методы не найти, поэтому необходима отладка. Однако возникла загвоздка: устройство находится в офисе в другой стране, и доступ к машине осуществляется через VNC. Отлаживать в таких условиях не очень удобно, в добавок ко всему устройство может «заснуть» и пропасть из системы в любой момент, несмотря на подключение через USB.
Мне нужно было придумать альтернативное решение, и я нашел его. Я перехватил обмен данными по COM-порту с помощью программы «Device Monitoring Studio». Хотя версия программы была урезанной, ее функциональности оказалось достаточно для выполнения задачи.
К тому же, для работы с устройством подходит только опция «Direct», в то время как опция «Modem» не функционирует, что значительно упрощает процесс. Протокол обмена данными интересный, с простым 16-битным шифрованием.
На основе перехваченных команд и данных я разработал скетч для Arduino, который эмулировает устройство. Программа успешно приняла этот эмулятор и прочитала все данные, не вызвав никаких ошибок. Это позволило мне проводить отладку локально, не опасаясь, что устройство «заснет».
Сам скетч:
#include <Arduino.h> #define SERIAL_BAUD_RATE 9600 #define RX_BUFF_SIZE 81 using namespace std; // Commands const uint8_t I66F9[] = { 0x01, 0x49, 0x0D, 0x36, 0x36, 0x46, 0x39 }; const uint8_t V75B4[] = { 0x01, 0x56, 0x0D, 0x37, 0x35, 0x42, 0x34 }; const uint8_t C406[] = { 0x01, 0x3F, 0x0D, 0x43, 0x34, 0x30, 0x36 }; const uint8_t UGENERIC[] = { 0x01, 0x55, 0x47, 0x45, 0x4E, 0x45, 0x52, 0x49, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x41, 0x46, 0x30, 0x32 }; const uint8_t MAA3D[] = { 0x01, 0x4D, 0x0D, 0x41, 0x41, 0x33, 0x44 }; const uint8_t D816022ADAC[] = { 0x01, 0x44, 0x38, 0x31, 0x36, 0x30, 0x32, 0x32, 0x0D, 0x41, 0x44, 0x41, 0x43 }; const uint8_t D81820F2591[] = { 0x01, 0x44, 0x38, 0x31, 0x38, 0x32, 0x30, 0x46, 0x0D, 0x32, 0x35, 0x39, 0x31 }; const uint8_t D819241[] = { 0x01, 0x44, 0x38, 0x31, 0x39, 0x32, 0x34, 0x31, 0x0D, 0x43, 0x32, 0x43, 0x45 }; const uint8_t D81D306[] = { 0x01, 0x44, 0x38, 0x31, 0x44, 0x33, 0x30, 0x36, 0x0D, 0x43, 0x44, 0x44, 0x31 }; const uint8_t D810B01[] = { 0x01, 0x44, 0x38, 0x31, 0x30, 0x42, 0x30, 0x31, 0x0D, 0x46, 0x34, 0x30, 0x37 }; const uint8_t D820078[] = { 0x01, 0x44, 0x38, 0x32, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x41, 0x41, 0x46, 0x32 }; const uint8_t D830078[] = { 0x01, 0x44, 0x38, 0x33, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x45, 0x46, 0x35, 0x32 }; const uint8_t D840078[] = { 0x01, 0x44, 0x38, 0x34, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x32, 0x37, 0x31, 0x33 }; const uint8_t D850078[] = { 0x01, 0x44, 0x38, 0x35, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x36, 0x32, 0x42, 0x33 }; const uint8_t D860078[] = { 0x01, 0x44, 0x38, 0x36, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x41, 0x43, 0x35, 0x33 }; const uint8_t D870078[] = { 0x01, 0x44, 0x38, 0x37, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x45, 0x39, 0x46, 0x33 }; const uint8_t DCA0078[] = { 0x01, 0x44, 0x43, 0x41, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x45, 0x45, 0x43, 0x30 }; const uint8_t DCB0078[] = { 0x01, 0x44, 0x43, 0x42, 0x30, 0x30, 0x37, 0x38, 0x0D, 0x32, 0x30, 0x32, 0x30 }; const uint8_t W81DA011[] = { 0x01, 0x57, 0x38, 0x31, 0x44, 0x41, 0x30, 0x31, 0x31, 0x41, 0x0D, 0x35, 0x45, 0x36, 0x38 }; const uint8_t F21D57[] = { 0x01, 0x46, 0x32, 0x0D, 0x31, 0x44, 0x35, 0x37 }; const uint8_t f7021[] = { 0x01, 0x66, 0x0D, 0x37, 0x30, 0x32, 0x31 }; const uint8_t BBA03[] = { 0x01, 0x42, 0x0D, 0x42, 0x41, 0x30, 0x33 }; const uint8_t D81DA01[] = { 0x01, 0x44, 0x38, 0x31, 0x44, 0x41, 0x30, 0x31, 0x0D, 0x46, 0x42, 0x35, 0x42 }; const uint8_t RB970[] = { 0x01, 0x52, 0x0D, 0x42, 0x39, 0x37, 0x30 }; const uint8_t W8117020401[] = { 0x01, 0x57, 0x38, 0x31, 0x31, 0x37, 0x30, 0x32, 0x30, 0x34, 0x30, 0x31, 0x0D, 0x44, 0x36, 0x42, 0x32 }; const uint8_t W814018[] = { 0x01, 0x57, 0x38, 0x31, 0x34, 0x30, 0x31, 0x38 }; const uint8_t W81D306[] = { 0x01, 0x57, 0x38, 0x31, 0x44, 0x33, 0x30 }; const uint8_t T[] = { 0x01, 0x54 }; const uint8_t W8160[] = { 0x01, 0x57, 0x38, 0x31, 0x36, 0x30 }; const uint8_t W8182[] = { 0x01, 0x57, 0x38, 0x31, 0x38, 0x32 }; const uint8_t W8192[] = { 0x01, 0x57, 0x38, 0x31, 0x39, 0x32 }; const uint8_t W81DA0100[] = { 0x01, 0x57, 0x38, 0x31, 0x44, 0x41, 0x30, 0x31, 0x30, 0x30, 0x0D, 0x35, 0x32, 0x33, 0x30 }; const uint8_t W811702[] = { 0x01, 0x57, 0x38, 0x31, 0x31, 0x37, 0x30, 0x32 }; // Responses const uint8_t Response_I66F9[] PROGMEM = { 0x01, 0x49, 0x39, 0x30, 0x32, 0x31, 0x37, 0x20, 0x56, 0x20, 0x30, 0x33, 0x2E, 0x30, 0x32, 0x2E, 0x30, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x37, 0x43, 0x44, 0x39 }; const uint8_t Response_V75B4[] PROGMEM = { 0x01, 0x56, 0x06, 0x0D, 0x39, 0x37, 0x36, 0x35 }; const uint8_t Response_C406[] PROGMEM = { 0x01, 0x3F, 0x39, 0x30, 0x32, 0x31, 0x37, 0x20, 0x56, 0x20, 0x30, 0x33, 0x2E, 0x30, 0x32, 0x2E, 0x31, 0x36, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x33, 0x43, 0x31, 0x44 }; const uint8_t Response_UGENERIC[] PROGMEM = { 0x01, 0x55, 0x06, 0x0D, 0x43, 0x45, 0x33, 0x35 }; const uint8_t Response_MAA3D[] PROGMEM = { 0x01, 0x4D, 0x30, 0x30, 0x30, 0x30, 0x0D, 0x31, 0x35, 0x43, 0x39 }; const uint8_t Response_D816022ADAC[] PROGMEM = { 0x01, 0x44, 0x36, 0x42, 0x44, 0x37, 0x43, 0x41, 0x38, 0x35, 0x41, 0x44, 0x38, 0x43, 0x43, 0x30, 0x39, 0x37, 0x36, 0x31, 0x31, 0x45, 0x35, 0x46, 0x39, 0x45, 0x38, 0x43, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x0D, 0x44, 0x31, 0x41, 0x44 }; const uint8_t Response_D81820F2591[] PROGMEM = { 0x01, 0x44, 0x32, 0x46, 0x31, 0x32, 0x31, 0x46, 0x38, 0x39, 0x37, 0x43, 0x43, 0x36, 0x35, 0x31, 0x38, 0x45, 0x45, 0x37, 0x45, 0x33, 0x43, 0x42, 0x35, 0x37, 0x32, 0x35, 0x44, 0x34, 0x45, 0x39, 0x0D, 0x44, 0x31, 0x41, 0x44 }; const uint8_t Response_D819241[] PROGMEM = { 0x01, 0x44, 0x33, 0x34, 0x38, 0x32, 0x33, 0x43, 0x36, 0x32, 0x43, 0x43, 0x45, 0x30, 0x44, 0x31, 0x45, 0x39, 0x30, 0x37, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x44, 0x33, 0x42, 0x31, 0x42, 0x44, 0x34, 0x42, 0x42, 0x41, 0x33, 0x44, 0x46, 0x45, 0x37, 0x33, 0x41, 0x32, 0x36, 0x44, 0x34, 0x38, 0x39, 0x45, 0x33, 0x44, 0x44, 0x44, 0x33, 0x44, 0x39, 0x41, 0x37, 0x43, 0x36, 0x42, 0x39, 0x34, 0x37, 0x38, 0x33, 0x30, 0x32, 0x33, 0x33, 0x44, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x41, 0x43, 0x43, 0x41, 0x34, 0x32, 0x31, 0x43, 0x30, 0x31, 0x0D, 0x44, 0x31, 0x41, 0x44 }; const uint8_t Response_D81D306[] PROGMEM = { 0x01, 0x44, 0x43, 0x41, 0x44, 0x46, 0x39, 0x35, 0x45, 0x42, 0x39, 0x45, 0x31, 0x34, 0x0D, 0x34, 0x38, 0x30, 0x37 }; const uint8_t Response_D810B01[] PROGMEM = { 0x01, 0x44, 0x30, 0x34, 0x0D, 0x33, 0x44, 0x31, 0x35 }; const uint8_t Response_D820078[] PROGMEM = { 0x01, 0x44, 0x35, 0x34, 0x32, 0x44, 0x41, 0x33, 0x31, 0x35, 0x35, 0x33, 0x38, 0x41, 0x30, 0x34, 0x31, 0x33, 0x41, 0x43, 0x30, 0x35, 0x31, 0x37, 0x32, 0x41, 0x36, 0x39, 0x45, 0x34, 0x43, 0x43, 0x33, 0x30, 0x42, 0x41, 0x33, 0x43, 0x46, 0x45, 0x45, 0x34, 0x46, 0x31, 0x39, 0x31, 0x31, 0x38, 0x37, 0x30, 0x43, 0x38, 0x32, 0x45, 0x32, 0x39, 0x45, 0x38, 0x41, 0x37, 0x30, 0x41, 0x41, 0x35, 0x33, 0x44, 0x42, 0x35, 0x46, 0x35, 0x32, 0x36, 0x34, 0x34, 0x37, 0x39, 0x36, 0x36, 0x30, 0x36, 0x44, 0x39, 0x33, 0x38, 0x35, 0x39, 0x38, 0x45, 0x38, 0x32, 0x41, 0x39, 0x45, 0x39, 0x39, 0x35, 0x42, 0x45, 0x41, 0x39, 0x34, 0x32, 0x38, 0x41, 0x45, 0x37, 0x44, 0x38, 0x39, 0x37, 0x34, 0x44, 0x45, 0x36, 0x43, 0x33, 0x46, 0x43, 0x43, 0x41, 0x46, 0x31, 0x42, 0x42, 0x36, 0x39, 0x39, 0x34, 0x45, 0x36, 0x31, 0x31, 0x32, 0x46, 0x43, 0x33, 0x42, 0x39, 0x39, 0x46, 0x42, 0x38, 0x46, 0x46, 0x32, 0x44, 0x31, 0x45, 0x38, 0x34, 0x42, 0x32, 0x42, 0x32, 0x36, 0x42, 0x36, 0x41, 0x41, 0x37, 0x38, 0x37, 0x31, 0x46, 0x36, 0x36, 0x35, 0x42, 0x38, 0x33, 0x35, 0x42, 0x30, 0x35, 0x45, 0x44, 0x44, 0x46, 0x42, 0x43, 0x36, 0x32, 0x45, 0x33, 0x42, 0x43, 0x44, 0x38, 0x38, 0x41, 0x31, 0x46, 0x46, 0x34, 0x42, 0x33, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x0D, 0x34, 0x44, 0x37, 0x33 }; const uint8_t Response_D830078[] PROGMEM = { 0x01, 0x44, 0x33, 0x31, 0x31, 0x41, 0x32, 0x39, 0x37, 0x34, 0x42, 0x45, 0x34, 0x31, 0x39, 0x36, 0x34, 0x31, 0x35, 0x38, 0x37, 0x35, 0x44, 0x41, 0x37, 0x39, 0x31, 0x33, 0x35, 0x46, 0x36, 0x33, 0x33, 0x44, 0x37, 0x41, 0x31, 0x33, 0x35, 0x35, 0x39, 0x34, 0x39, 0x44, 0x42, 0x43, 0x38, 0x34, 0x38, 0x36, 0x33, 0x43, 0x42, 0x35, 0x45, 0x35, 0x45, 0x36, 0x43, 0x33, 0x46, 0x43, 0x43, 0x41, 0x46, 0x31, 0x42, 0x42, 0x36, 0x39, 0x39, 0x34, 0x45, 0x36, 0x31, 0x31, 0x32, 0x46, 0x43, 0x33, 0x42, 0x39, 0x39, 0x46, 0x42, 0x38, 0x46, 0x46, 0x32, 0x44, 0x31, 0x45, 0x38, 0x34, 0x42, 0x32, 0x42, 0x32, 0x36, 0x42, 0x36, 0x41, 0x41, 0x37, 0x38, 0x37, 0x31, 0x46, 0x36, 0x36, 0x35, 0x42, 0x38, 0x33, 0x35, 0x42, 0x30, 0x35, 0x45, 0x44, 0x44, 0x46, 0x42, 0x43, 0x36, 0x32, 0x45, 0x33, 0x42, 0x43, 0x44, 0x38, 0x38, 0x41, 0x31, 0x46, 0x46, 0x34, 0x42, 0x33, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x44, 0x33, 0x42, 0x31, 0x42, 0x44, 0x34, 0x42, 0x42, 0x41, 0x33, 0x44, 0x46, 0x45, 0x37, 0x33, 0x41, 0x32, 0x36, 0x44, 0x34, 0x38, 0x39, 0x45, 0x33, 0x44, 0x44, 0x44, 0x33, 0x44, 0x39, 0x41, 0x37, 0x43, 0x36, 0x42, 0x39, 0x34, 0x37, 0x38, 0x33, 0x30, 0x32, 0x33, 0x33, 0x44, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x0D, 0x44, 0x39, 0x38, 0x46 }; const uint8_t Response_D840078[] PROGMEM = { 0x01, 0x44, 0x36, 0x33, 0x30, 0x41, 0x38, 0x37, 0x36, 0x30, 0x39, 0x42, 0x32, 0x32, 0x45, 0x31, 0x39, 0x46, 0x30, 0x32, 0x44, 0x32, 0x35, 0x35, 0x33, 0x38, 0x31, 0x38, 0x34, 0x46, 0x31, 0x42, 0x42, 0x30, 0x36, 0x41, 0x42, 0x35, 0x45, 0x35, 0x35, 0x35, 0x39, 0x37, 0x43, 0x34, 0x33, 0x30, 0x45, 0x43, 0x35, 0x44, 0x32, 0x45, 0x35, 0x42, 0x46, 0x39, 0x34, 0x46, 0x41, 0x43, 0x30, 0x33, 0x42, 0x30, 0x44, 0x33, 0x43, 0x41, 0x44, 0x33, 0x42, 0x46, 0x35, 0x46, 0x42, 0x43, 0x36, 0x45, 0x46, 0x34, 0x32, 0x39, 0x30, 0x41, 0x38, 0x41, 0x43, 0x41, 0x35, 0x44, 0x46, 0x42, 0x42, 0x30, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x41, 0x43, 0x43, 0x41, 0x34, 0x32, 0x31, 0x43, 0x30, 0x31, 0x38, 0x43, 0x43, 0x39, 0x31, 0x45, 0x34, 0x46, 0x43, 0x41, 0x46, 0x30, 0x36, 0x33, 0x33, 0x34, 0x43, 0x46, 0x36, 0x35, 0x35, 0x41, 0x45, 0x39, 0x30, 0x37, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x44, 0x33, 0x42, 0x31, 0x42, 0x44, 0x34, 0x42, 0x42, 0x41, 0x33, 0x44, 0x46, 0x45, 0x37, 0x33, 0x41, 0x32, 0x36, 0x44, 0x34, 0x38, 0x39, 0x45, 0x33, 0x44, 0x44, 0x44, 0x33, 0x44, 0x39, 0x41, 0x37, 0x43, 0x36, 0x42, 0x39, 0x34, 0x37, 0x38, 0x33, 0x30, 0x32, 0x33, 0x33, 0x44, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x0D, 0x45, 0x32, 0x43, 0x38 }; const uint8_t Response_D850078[] PROGMEM = { 0x01, 0x44, 0x35, 0x38, 0x33, 0x44, 0x35, 0x39, 0x36, 0x33, 0x31, 0x39, 0x42, 0x46, 0x38, 0x34, 0x31, 0x30, 0x42, 0x30, 0x36, 0x30, 0x42, 0x42, 0x31, 0x36, 0x46, 0x34, 0x43, 0x44, 0x35, 0x38, 0x30, 0x35, 0x43, 0x31, 0x45, 0x45, 0x38, 0x32, 0x30, 0x35, 0x42, 0x31, 0x35, 0x33, 0x38, 0x34, 0x35, 0x45, 0x41, 0x39, 0x39, 0x42, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x41, 0x43, 0x41, 0x43, 0x39, 0x30, 0x42, 0x37, 0x0D, 0x44, 0x44, 0x46, 0x37 }; const uint8_t Response_D860078[] PROGMEM = { 0x01, 0x44, 0x30, 0x35, 0x43, 0x36, 0x45, 0x32, 0x42, 0x46, 0x42, 0x45, 0x32, 0x32, 0x32, 0x39, 0x44, 0x42, 0x35, 0x30, 0x36, 0x34, 0x44, 0x33, 0x31, 0x42, 0x39, 0x41, 0x38, 0x34, 0x43, 0x42, 0x31, 0x31, 0x38, 0x45, 0x36, 0x44, 0x30, 0x36, 0x37, 0x42, 0x44, 0x37, 0x46, 0x39, 0x46, 0x44, 0x42, 0x44, 0x39, 0x36, 0x33, 0x46, 0x43, 0x43, 0x37, 0x41, 0x41, 0x32, 0x45, 0x35, 0x45, 0x35, 0x38, 0x43, 0x39, 0x34, 0x35, 0x34, 0x44, 0x33, 0x44, 0x43, 0x41, 0x31, 0x45, 0x31, 0x43, 0x32, 0x33, 0x45, 0x38, 0x43, 0x35, 0x39, 0x46, 0x30, 0x42, 0x35, 0x30, 0x33, 0x42, 0x37, 0x43, 0x44, 0x33, 0x45, 0x41, 0x39, 0x42, 0x30, 0x34, 0x35, 0x43, 0x38, 0x43, 0x42, 0x36, 0x32, 0x45, 0x33, 0x42, 0x43, 0x44, 0x38, 0x38, 0x41, 0x31, 0x46, 0x46, 0x34, 0x42, 0x33, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x44, 0x33, 0x42, 0x31, 0x42, 0x44, 0x34, 0x42, 0x42, 0x41, 0x33, 0x44, 0x46, 0x45, 0x37, 0x33, 0x41, 0x32, 0x36, 0x44, 0x34, 0x38, 0x39, 0x45, 0x33, 0x44, 0x44, 0x44, 0x33, 0x44, 0x39, 0x41, 0x37, 0x43, 0x36, 0x42, 0x39, 0x34, 0x37, 0x38, 0x33, 0x30, 0x32, 0x33, 0x33, 0x44, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x41, 0x43, 0x43, 0x41, 0x34, 0x32, 0x31, 0x43, 0x30, 0x31, 0x38, 0x43, 0x43, 0x39, 0x31, 0x45, 0x0D, 0x32, 0x45, 0x38, 0x44 }; const uint8_t Response_D870078[] PROGMEM = { 0x01, 0x44, 0x41, 0x37, 0x45, 0x34, 0x34, 0x42, 0x31, 0x34, 0x44, 0x35, 0x46, 0x39, 0x33, 0x46, 0x36, 0x45, 0x46, 0x39, 0x38, 0x35, 0x36, 0x30, 0x32, 0x38, 0x42, 0x34, 0x38, 0x38, 0x42, 0x32, 0x44, 0x30, 0x44, 0x44, 0x37, 0x36, 0x35, 0x41, 0x36, 0x42, 0x42, 0x39, 0x44, 0x43, 0x34, 0x44, 0x43, 0x31, 0x42, 0x43, 0x31, 0x42, 0x45, 0x30, 0x45, 0x33, 0x31, 0x34, 0x41, 0x31, 0x44, 0x42, 0x35, 0x46, 0x42, 0x43, 0x36, 0x45, 0x46, 0x34, 0x32, 0x39, 0x30, 0x41, 0x38, 0x41, 0x43, 0x41, 0x35, 0x44, 0x46, 0x42, 0x42, 0x30, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x41, 0x43, 0x43, 0x41, 0x34, 0x32, 0x31, 0x43, 0x30, 0x31, 0x38, 0x43, 0x43, 0x39, 0x31, 0x45, 0x34, 0x46, 0x43, 0x41, 0x46, 0x30, 0x36, 0x33, 0x33, 0x34, 0x43, 0x46, 0x36, 0x35, 0x35, 0x41, 0x45, 0x39, 0x30, 0x37, 0x36, 0x38, 0x41, 0x33, 0x33, 0x45, 0x43, 0x35, 0x44, 0x33, 0x36, 0x39, 0x46, 0x37, 0x35, 0x33, 0x32, 0x45, 0x42, 0x43, 0x39, 0x44, 0x44, 0x33, 0x42, 0x36, 0x46, 0x38, 0x45, 0x36, 0x44, 0x33, 0x41, 0x32, 0x39, 0x44, 0x33, 0x44, 0x39, 0x34, 0x37, 0x46, 0x39, 0x38, 0x34, 0x31, 0x44, 0x33, 0x42, 0x31, 0x42, 0x44, 0x34, 0x42, 0x42, 0x41, 0x33, 0x44, 0x46, 0x45, 0x37, 0x33, 0x41, 0x32, 0x36, 0x44, 0x34, 0x38, 0x39, 0x45, 0x33, 0x44, 0x44, 0x44, 0x33, 0x44, 0x39, 0x41, 0x37, 0x43, 0x36, 0x42, 0x39, 0x34, 0x37, 0x38, 0x33, 0x30, 0x32, 0x33, 0x33, 0x44, 0x33, 0x37, 0x33, 0x45, 0x43, 0x42, 0x36, 0x37, 0x32, 0x37, 0x41, 0x43, 0x43, 0x41, 0x34, 0x32, 0x31, 0x43, 0x0D, 0x39, 0x36, 0x43, 0x39 }; const uint8_t Response_DCA0078[] PROGMEM = { 0x01, 0x44, 0x44, 0x43, 0x44, 0x33, 0x32, 0x46, 0x43, 0x45, 0x42, 0x45, 0x37, 0x37, 0x30, 0x41, 0x37, 0x36, 0x41, 0x42, 0x30, 0x39, 0x36, 0x39, 0x30, 0x33, 0x30, 0x37, 0x34, 0x38, 0x42, 0x32, 0x35, 0x36, 0x46, 0x43, 0x45, 0x46, 0x45, 0x32, 0x31, 0x35, 0x35, 0x38, 0x44, 0x38, 0x46, 0x45, 0x41, 0x46, 0x37, 0x44, 0x32, 0x35, 0x46, 0x35, 0x45, 0x37, 0x36, 0x45, 0x35, 0x36, 0x35, 0x44, 0x41, 0x34, 0x34, 0x39, 0x46, 0x42, 0x46, 0x36, 0x45, 0x38, 0x31, 0x46, 0x33, 0x45, 0x31, 0x46, 0x46, 0x38, 0x35, 0x39, 0x43, 0x43, 0x32, 0x35, 0x35, 0x46, 0x38, 0x44, 0x46, 0x41, 0x41, 0x45, 0x37, 0x41, 0x31, 0x46, 0x33, 0x44, 0x35, 0x38, 0x32, 0x37, 0x41, 0x42, 0x42, 0x35, 0x41, 0x46, 0x42, 0x37, 0x31, 0x45, 0x42, 0x32, 0x44, 0x37, 0x42, 0x44, 0x45, 0x39, 0x46, 0x38, 0x36, 0x45, 0x42, 0x45, 0x37, 0x33, 0x30, 0x37, 0x32, 0x36, 0x36, 0x45, 0x31, 0x46, 0x30, 0x41, 0x39, 0x35, 0x44, 0x34, 0x42, 0x35, 0x46, 0x31, 0x34, 0x31, 0x44, 0x37, 0x30, 0x42, 0x42, 0x34, 0x46, 0x36, 0x33, 0x35, 0x36, 0x38, 0x45, 0x34, 0x46, 0x33, 0x43, 0x35, 0x42, 0x41, 0x35, 0x45, 0x42, 0x35, 0x44, 0x41, 0x46, 0x41, 0x34, 0x36, 0x38, 0x46, 0x41, 0x36, 0x38, 0x46, 0x39, 0x30, 0x39, 0x37, 0x45, 0x31, 0x33, 0x30, 0x41, 0x44, 0x43, 0x34, 0x46, 0x31, 0x37, 0x35, 0x37, 0x42, 0x37, 0x45, 0x36, 0x30, 0x33, 0x42, 0x41, 0x46, 0x35, 0x44, 0x35, 0x38, 0x45, 0x37, 0x45, 0x34, 0x45, 0x33, 0x31, 0x32, 0x31, 0x46, 0x34, 0x36, 0x44, 0x31, 0x46, 0x41, 0x41, 0x45, 0x37, 0x41, 0x31, 0x46, 0x33, 0x44, 0x0D, 0x43, 0x46, 0x32, 0x46 }; const uint8_t Response_DCB0078[] PROGMEM = { 0x01, 0x44, 0x44, 0x43, 0x41, 0x41, 0x44, 0x43, 0x36, 0x46, 0x45, 0x45, 0x35, 0x30, 0x32, 0x34, 0x34, 0x37, 0x34, 0x39, 0x41, 0x36, 0x34, 0x46, 0x45, 0x38, 0x38, 0x32, 0x30, 0x35, 0x37, 0x46, 0x35, 0x38, 0x43, 0x45, 0x44, 0x45, 0x35, 0x30, 0x38, 0x32, 0x35, 0x35, 0x37, 0x31, 0x43, 0x41, 0x32, 0x43, 0x33, 0x37, 0x43, 0x31, 0x45, 0x35, 0x30, 0x33, 0x36, 0x34, 0x46, 0x31, 0x31, 0x37, 0x43, 0x36, 0x38, 0x39, 0x34, 0x30, 0x46, 0x42, 0x35, 0x42, 0x37, 0x44, 0x36, 0x44, 0x41, 0x37, 0x32, 0x45, 0x30, 0x39, 0x43, 0x37, 0x35, 0x42, 0x44, 0x36, 0x45, 0x35, 0x38, 0x39, 0x36, 0x38, 0x43, 0x34, 0x42, 0x44, 0x37, 0x41, 0x31, 0x31, 0x34, 0x35, 0x41, 0x44, 0x35, 0x45, 0x46, 0x31, 0x37, 0x42, 0x31, 0x36, 0x41, 0x46, 0x38, 0x46, 0x46, 0x41, 0x45, 0x30, 0x37, 0x42, 0x45, 0x44, 0x45, 0x36, 0x36, 0x35, 0x44, 0x41, 0x46, 0x41, 0x34, 0x36, 0x38, 0x46, 0x41, 0x36, 0x38, 0x46, 0x39, 0x30, 0x39, 0x37, 0x45, 0x31, 0x33, 0x30, 0x41, 0x44, 0x43, 0x34, 0x46, 0x31, 0x37, 0x35, 0x37, 0x42, 0x37, 0x45, 0x36, 0x30, 0x33, 0x42, 0x41, 0x46, 0x35, 0x44, 0x35, 0x38, 0x45, 0x37, 0x45, 0x34, 0x45, 0x33, 0x31, 0x32, 0x31, 0x46, 0x34, 0x36, 0x44, 0x31, 0x46, 0x41, 0x41, 0x45, 0x37, 0x41, 0x31, 0x46, 0x33, 0x44, 0x35, 0x38, 0x32, 0x37, 0x41, 0x42, 0x42, 0x35, 0x41, 0x46, 0x42, 0x37, 0x31, 0x45, 0x42, 0x32, 0x44, 0x37, 0x42, 0x44, 0x45, 0x39, 0x46, 0x38, 0x36, 0x45, 0x42, 0x45, 0x37, 0x33, 0x30, 0x37, 0x32, 0x36, 0x36, 0x45, 0x31, 0x46, 0x30, 0x41, 0x39, 0x35, 0x44, 0x34, 0x0D, 0x33, 0x45, 0x33, 0x35 }; const uint8_t Response_F21D57[] PROGMEM = { 0x01, 0x46, 0x06, 0x0D, 0x44, 0x34, 0x30, 0x36 }; const uint8_t Response_f7021[] PROGMEM = { 0x01, 0x66, 0x06, 0x0D, 0x35, 0x32, 0x43, 0x30 }; const uint8_t Response_BBA03[] PROGMEM = { 0x01, 0x42, 0x30, 0x33, 0x42, 0x41, 0x0D, 0x43, 0x36, 0x31, 0x36 }; const uint8_t Response_D81DA01[] PROGMEM = { 0x01, 0x44, 0x37, 0x30, 0x0D, 0x44, 0x31, 0x41, 0x44 }; const uint8_t Response_RB970[] PROGMEM = { 0x01, 0x52, 0x06, 0x0D, 0x34, 0x42, 0x41, 0x35 }; const uint8_t Response_T[] PROGMEM = { 0x01, 0x54, 0x06, 0x0D, 0x46, 0x39, 0x30, 0x35 }; const uint8_t Response_W8160[] PROGMEM = { 0x01, 0x57, 0x06, 0x0D, 0x41, 0x30, 0x35, 0x35 }; const uint8_t Response_W811702[] PROGMEM = { 0x01, 0x52, 0x06, 0x0D, 0x34, 0x42, 0x41, 0x35 }; struct CMD { uint16_t cmd; size_t cmd_size; uint8_t *responce; size_t responce_size; }; uint16_t crc16(const uint8_t* pcBlock, size_t len) { uint16_t crc = 0x0000; unsigned char i; while (len--) { crc ^= *pcBlock++ << 8; for (i = 0; i < 8; i++) crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1; } return crc; } CMD makeCmd(const uint8_t* cmd, size_t cmd_size, const uint8_t* responce, const size_t responce_size) { return CMD{crc16(cmd, cmd_size), cmd_size, const_cast<uint8_t*>(responce), (size_t)responce_size}; } CMD cmds[33] = { makeCmd(I66F9, sizeof(I66F9), Response_I66F9, sizeof(Response_I66F9)), makeCmd(V75B4, sizeof(V75B4), Response_V75B4, sizeof(Response_V75B4)), makeCmd(C406, sizeof(C406), Response_C406, sizeof(Response_C406)), makeCmd(UGENERIC, sizeof(UGENERIC), Response_UGENERIC, sizeof(Response_UGENERIC)), makeCmd(MAA3D, sizeof(MAA3D), Response_MAA3D, sizeof(Response_MAA3D)), makeCmd(D816022ADAC, sizeof(D816022ADAC), Response_D816022ADAC, sizeof(Response_D816022ADAC)), makeCmd(D81820F2591, sizeof(D81820F2591), Response_D81820F2591, sizeof(Response_D81820F2591)), makeCmd(D819241, sizeof(D819241), Response_D819241, sizeof(Response_D819241)), makeCmd(D81D306, sizeof(D81D306), Response_D81D306, sizeof(Response_D81D306)), makeCmd(D810B01, sizeof(D810B01), Response_D810B01, sizeof(Response_D810B01)), makeCmd(D820078, sizeof(D820078), Response_D820078, sizeof(Response_D820078)), makeCmd(D830078, sizeof(D830078), Response_D830078, sizeof(Response_D830078)), makeCmd(D840078, sizeof(D840078), Response_D840078, sizeof(Response_D840078)), makeCmd(D850078, sizeof(D850078), Response_D850078, sizeof(Response_D850078)), makeCmd(D860078, sizeof(D860078), Response_D860078, sizeof(Response_D860078)), makeCmd(D870078, sizeof(D870078), Response_D870078, sizeof(Response_D870078)), makeCmd(DCA0078, sizeof(DCA0078), Response_DCA0078, sizeof(Response_DCA0078)), makeCmd(DCB0078, sizeof(DCB0078), Response_DCB0078, sizeof(Response_DCB0078)), makeCmd(W81DA011, sizeof(W81DA011), Response_W8160, sizeof(Response_W8160)), makeCmd(F21D57, sizeof(F21D57), Response_F21D57, sizeof(Response_F21D57)), makeCmd(f7021, sizeof(f7021), Response_f7021, sizeof(Response_f7021)), makeCmd(BBA03, sizeof(BBA03), Response_BBA03, sizeof(Response_BBA03)), makeCmd(D81DA01, sizeof(D81DA01), Response_D81DA01, sizeof(Response_D81DA01)), makeCmd(RB970, sizeof(RB970), Response_RB970, sizeof(Response_RB970)), makeCmd(W8117020401, sizeof(W8117020401), Response_W8160, sizeof(Response_W8160)), makeCmd(W814018, sizeof(W814018), Response_T, sizeof(Response_T)), makeCmd(W81D306, sizeof(W81D306), Response_T, sizeof(Response_T)), makeCmd(T, sizeof(T), Response_T, sizeof(Response_T)), makeCmd(W8160, sizeof(W8160), Response_W8160, sizeof(Response_W8160)), makeCmd(W8182, sizeof(W8182), Response_W8160, sizeof(Response_W8160)), makeCmd(W8192, sizeof(W8192), Response_W8160, sizeof(Response_W8160)), makeCmd(W81DA0100, sizeof(W81DA0100), Response_W8160, sizeof(Response_W8160)), makeCmd(W811702, sizeof(W811702), Response_W811702, sizeof(Response_W811702)), }; const CMD find(uint8_t* cmd, size_t bytesRead) { size_t count = sizeof(cmds); size_t old_size = 0; uint16_t crc = 0; for(size_t i = 0; i <= count; i++) { CMD result = cmds[i]; if(bytesRead >= result.cmd_size) { if(old_size != result.cmd_size) { old_size = result.cmd_size; crc = crc16(cmd, result.cmd_size); } if(result.cmd == crc) { return result; } } } return CMD{0}; } void setup() { Serial.begin(SERIAL_BAUD_RATE); } void sendResponce(const uint8_t *response, size_t responseLen) { uint8_t *buff = (uint8_t *)malloc(responseLen); memcpy_P(buff, response, responseLen); Serial.write(buff, responseLen); free(buff); } void loop() { int len = Serial.available(); if (len > 0) { uint8_t rxBuff[RX_BUFF_SIZE] = {0}; size_t bytesRead = Serial.readBytes(rxBuff, RX_BUFF_SIZE); if(bytesRead) { const CMD cmd = find(rxBuff, bytesRead); if(cmd.responce) { sendResponce(cmd.responce, cmd.responce_size); } } } }
Ответы на команды пришлось записать в ПЗУ Arduino с помощью PROGMEM, так как все данные не помещались в оперативную память.
Чтение данных с устройства
Во время выгрузки данных с устройства отображаются сообщения, такие как «Checking monitor availability…», расположенные над прогресс-баром.
Чтобы выяснить, где происходит вызов функции UploadMonitor
или UploadMonitorVC
, я загрузил библиотеку в Ghidra и нашел соответствующую строку.
Вернее, было найдено три таких строки. Две из них находятся в юникоде в ресурсах, а одна — в данных в ANSI; на последнюю ссылаются две функции.
Я загрузил библиотеку в отладчик и поставил точки останова на эти строки. Сработала точка останова в первой функции.
В стеке меня привлекло внимание, что вызов библиотеки происходит из core.dll
, одной из библиотек приложения. Я выбрал в стеке соответствующую строку и обнаружил, что это вызов UploadMonitorVC
. Это указывает на то, что библиотека core.dll
использует ABPDeviceCommunicator.dll
и вызывает методы через COM. Однако функция FUN_100016ef
не является UploadMonitorVC
, так как она также вызывается при инициализации. Вместо этого я переименовал FUN_10006c8d
в UploadMonitorVC
, так как именно она является ею.
undefined4 UploadMonitorVC(void) { int iVar1; int iVar2; int iVar3; int extraout_ECX; int unaff_EBP; undefined4 uVar4; FUN_1000e9d0(); CByteArray::SetSize((CByteArray *)(extraout_ECX + 0x548),0,-1); if (*(int *)(extraout_ECX + 0x518) == 1) { (**(code **)(*(int *)(extraout_ECX + 0x504) + 0x34))(); } CString::CString((CString *)(unaff_EBP + -0x18)); *(undefined4 *)(unaff_EBP + -4) = 0; FUN_1000957f(); *(undefined **)(unaff_EBP + -0x10) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Checking monitor availability ....."); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x500) = 0; *(undefined4 *)(extraout_ECX + 0x4f8) = 0; CString::CString((CString *)(unaff_EBP + -0x14)); *(undefined *)(unaff_EBP + -4) = 1; CString::LoadStringW((CString *)(unaff_EBP + -0x14),0xc35c); CString::GetBuffer((CString *)(extraout_ECX + 0xc),0x14); iVar1 = OpenComPort(); if (iVar1 == 0) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Failed to open COM port"); FUN_1000e0e9(); FUN_1000957f(); goto LAB_10007386; } *(undefined **)(unaff_EBP + -0x10) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"COM port opened"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 1; if (*(int *)(extraout_ECX + 1280) == 1) goto LAB_100072fb; if (*(int *)(extraout_ECX + 1228) == 2) { FUN_1000957f(); iVar1 = FUN_1000d79e(); if (iVar1 == 0) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Initialize modem failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 2; CString::CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 3; *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x10), *(LPCWSTR *)(unaff_EBP + 8),0); iVar1 = 0x3a9a; *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 1; LAB_10007033: CString::~CString((CString *)(unaff_EBP + -0x10)); LAB_10007253: if (*(int *)(extraout_ECX + 0x4cc) == 2) { iVar2 = *(int *)(extraout_ECX + 0x4f8); if (((iVar2 == 0) || (iVar2 == 2)) || (iVar2 == 1)) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"No modem connection has been made.."); FUN_1000e0e9(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Have to close the port"); FUN_1000e0e9(); } else { FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Breaking the modems\' connection...."); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 4; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100072fb; FUN_1000dca5(); } } *(undefined4 *)(extraout_ECX + 0x4f8) = 9; if (*(int *)(extraout_ECX + 0x500) != 1) { FUN_1000a781(extraout_ECX); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Closing COM port"); FUN_1000e0e9(); if (iVar1 == 0) { CString::operator=((CString *)(extraout_ECX + 0x18),(CString *)(extraout_ECX + 0xc)); FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Monitor successfully read"); FUN_1000e0e9(); uVar4 = 1; goto LAB_10007388; } FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Monitor read failed"); FUN_1000e0e9(); goto LAB_10007386; } } else { *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Initialize modem succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 2; if (*(int *)(extraout_ECX + 0x500) != 1) { FUN_1000957f(); iVar1 = FUN_1000dbb4(); if (iVar1 == 0) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting the modems failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 4; CString::CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 5; *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x10), *(LPCWSTR *)(unaff_EBP + 8),0); iVar1 = 0x3a9a; *(undefined *)(unaff_EBP + -4) = 4; CString::~CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 1; goto LAB_10007033; } *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting the modems succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 3; if (*(int *)(extraout_ECX + 0x500) != 1) goto LAB_10006f5e; } } LAB_100072fb: FUN_1000dd49(); } else { LAB_10006f5e: iVar1 = DetectMonitorVersion(); if (iVar1 == -1) goto LAB_10007386; if ((iVar1 != 0) && (iVar1 != 0x3b86)) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting with monitor failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 6; CString::CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 7; *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd8; CString::CString((CString *)&stack0xffffffd8,(CString *)(unaff_EBP + -0x10)); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; *(undefined *)(unaff_EBP + -4) = 8; CString::CString((CString *)&stack0xffffffd4,(CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 7; FUN_1000a511(); *(undefined *)(unaff_EBP + -4) = 6; CString::~CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 1; goto LAB_10007033; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting with monitor succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 5; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100072fb; if ((iVar1 == 0) || (iVar1 == 15238)) { CString::LoadStringW((CString *)(unaff_EBP + -0x14),50012); iVar1 = EstablishLink(); *(undefined4 *)(extraout_ECX + 0x4f8) = 8; if ((*(int *)(extraout_ECX + 0x500) == 1) && (iVar2 = FUN_1000dd49(), iVar2 != 0)) goto LAB_10007386; } iVar2 = *(int *)(unaff_EBP + 8); if (iVar1 == 0) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Establish Link for read to Monitor succeeded"); FUN_1000e0e9(); iVar1 = FUN_100074d9(); } else { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Establish Link for read to Monitor failed"); FUN_1000e0e9(); } if (iVar1 != -1) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Read raw readings from monitor"); FUN_1000e0e9(); if ((*(int *)(extraout_ECX + 0x500) != 1) || (iVar3 = FUN_1000dd49(), iVar3 == 0)) { if (iVar1 == 0) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Read raw readings from monitor succeeded"); FUN_1000e0e9(); iVar1 = FUN_1000866c(*(undefined4 *)(iVar2 + 0xc)); } else if (iVar1 != 0x3a9a) { *(undefined **)(unaff_EBP + 8) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Read raw readings from monitor failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 9; CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 10; *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); if (iVar1 == 0x3b94) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; } else if (iVar1 == 0x3b98) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; } else { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; } CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd8; CString::CString((CString *)&stack0xffffffd8,(CString *)(unaff_EBP + -0x10)); *(undefined **)(unaff_EBP + -0x1c) = &stack0xffffffd4; *(undefined *)(unaff_EBP + -4) = 0xb; CString::CString((CString *)&stack0xffffffd4,(CString *)(unaff_EBP + 8)); *(undefined *)(unaff_EBP + -4) = 10; FUN_1000a511(); *(undefined *)(unaff_EBP + -4) = 9; CString::~CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 1; CString::~CString((CString *)(unaff_EBP + 8)); } if ((*(int *)(extraout_ECX + 0x500) != 1) || (iVar2 = FUN_1000dd49(), iVar2 == 0)) goto LAB_10007253; } } } LAB_10007386: uVar4 = 0; LAB_10007388: *(undefined *)(unaff_EBP + -4) = 0; CString::~CString((CString *)(unaff_EBP + -0x14)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; CString::~CString((CString *)(unaff_EBP + -0x18)); ExceptionList = *(void **)(unaff_EBP + -0xc); return uVar4; }
Функция OpenComPort
undefined4 OpenComPort(void) { LPCWSTR _Source; undefined4 uVar1; int iVar2; HANDLE pvVar3; BOOL BVar4; int extraout_ECX; undefined4 uVar5; int unaff_EBP; FUN_1000e9d0(); _Source = *(LPCWSTR *)(unaff_EBP + 8); CString::CString((CString *)(unaff_EBP + 8),(ushort *)_Source); uVar5 = 0; *(undefined4 *)(unaff_EBP + -4) = 0; iVar2 = CString::Find((CString *)(unaff_EBP + 8),(ushort *)&this_10015028); if (iVar2 + 4 < *(int *)(*(int *)(unaff_EBP + 8) + -8)) { swprintf((wchar_t *)(unaff_EBP + -0x23c),0x10015018,_Source); } else { wcscpy((wchar_t *)(unaff_EBP + -0x23c),_Source); } if (*(int *)(extraout_ECX + 0x4cc) == 1) { pvVar3 = CreateFileW((LPCWSTR)(unaff_EBP + -0x23c),0xc0000000,0,(LPSECURITY_ATTRIBUTES)0x0,3,0, (HANDLE)0x0); *(HANDLE *)(extraout_ECX + 0x2c) = pvVar3; if (pvVar3 == (HANDLE)0xffffffff) goto LAB_1000a762; *(undefined4 *)(unaff_EBP + -0x3c) = 0x1c; GetCommState(pvVar3,(LPDCB)(unaff_EBP + -0x3c)); uVar1 = *(undefined4 *)(extraout_ECX + 0x43c); *(undefined *)(unaff_EBP + -0x2a) = 8; *(undefined4 *)(unaff_EBP + -0x38) = uVar1; *(undefined *)(unaff_EBP + -0x29) = 0; *(undefined *)(unaff_EBP + -0x28) = 0; *(uint *)(unaff_EBP + -0x34) = CONCAT31((uint3)((uint)*(undefined4 *)(unaff_EBP + -0x34) >> 8) & 0xffff80,1); BVar4 = SetCommState(*(HANDLE *)(extraout_ECX + 0x2c),(LPDCB)(unaff_EBP + -0x3c)); if (BVar4 == 0) goto LAB_1000a762; GetCommTimeouts(*(HANDLE *)(extraout_ECX + 0x2c),(LPCOMMTIMEOUTS)(unaff_EBP + -0x20)); *(undefined4 *)(unaff_EBP + -0x1c) = 0; *(undefined4 *)(unaff_EBP + -0x20) = 1000; *(undefined4 *)(unaff_EBP + -0x18) = 1000; *(undefined4 *)(unaff_EBP + -0x14) = 10; *(undefined4 *)(unaff_EBP + -0x10) = 20000; iVar2 = SetCommTimeouts(*(HANDLE *)(extraout_ECX + 0x2c),(LPCOMMTIMEOUTS)(unaff_EBP + -0x20)); LAB_1000a72e: if (iVar2 != 0) { uVar5 = 1; } } else { pvVar3 = CreateFileW(_Source,0xc0000000,0,(LPSECURITY_ATTRIBUTES)0x0,3,0x40000080,(HANDLE)0x0); *(HANDLE *)(extraout_ECX + 0x2c) = pvVar3; if (pvVar3 == (HANDLE)0xffffffff) goto LAB_1000a762; *(undefined4 *)(unaff_EBP + -0x20) = 0xffffffff; *(undefined4 *)(unaff_EBP + -0x1c) = 0; *(undefined4 *)(unaff_EBP + -0x18) = 0; *(undefined4 *)(unaff_EBP + -0x14) = 0; *(undefined4 *)(unaff_EBP + -0x10) = 5000; SetCommTimeouts(pvVar3,(LPCOMMTIMEOUTS)(unaff_EBP + -0x20)); pvVar3 = CreateEventW((LPSECURITY_ATTRIBUTES)0x0,1,0,(LPCWSTR)0x0); *(HANDLE *)(extraout_ECX + 0x4e0) = pvVar3; pvVar3 = CreateEventW((LPSECURITY_ATTRIBUTES)0x0,1,0,(LPCWSTR)0x0); *(HANDLE *)(extraout_ECX + 0x4f4) = pvVar3; *(undefined4 *)(unaff_EBP + -0x3c) = 0x1c; GetCommState(*(HANDLE *)(extraout_ECX + 0x2c),(LPDCB)(unaff_EBP + -0x3c)); *(undefined4 *)(unaff_EBP + -0x38) = 0x4b0; *(undefined *)(unaff_EBP + -0x2a) = 8; BVar4 = SetCommState(*(HANDLE *)(extraout_ECX + 0x2c),(LPDCB)(unaff_EBP + -0x3c)); if (BVar4 != 0) { BVar4 = SetupComm(*(HANDLE *)(extraout_ECX + 0x2c),10000,10000); if (((BVar4 != 0) && (*(int *)(extraout_ECX + 0x4e0) != 0)) && (*(int *)(extraout_ECX + 0x4f4) != 0)) { iVar2 = EscapeCommFunction(*(HANDLE *)(extraout_ECX + 0x2c),5); goto LAB_1000a72e; } } GetLastError(); if (*(HANDLE *)(extraout_ECX + 0x4e0) != (HANDLE)0x0) { CloseHandle(*(HANDLE *)(extraout_ECX + 0x4e0)); } if (*(HANDLE *)(extraout_ECX + 0x4f4) != (HANDLE)0x0) { CloseHandle(*(HANDLE *)(extraout_ECX + 0x4f4)); } CloseHandle(*(HANDLE *)(extraout_ECX + 0x2c)); } LAB_1000a762: *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; CString::~CString((CString *)(unaff_EBP + 8)); ExceptionList = *(void **)(unaff_EBP + -0xc); return uVar5; }
Функция DetectMonitorVersion
реализует интересную логику: она последовательно перебирает скорости соединения — 4800, 1200, 2400 и 9600 бод — до тех пор, пока не получит ответ на команду I
, которая запрашивает версию устройства.
Такая логика предназначена для работы с устройствами, поддерживающими разные скорости соединения. Однако имеется только одно устройство, функционирующее на скорости 9600 бод.
Это делает текущую логику неактуальной, и её можно просто не брать во внимание.
BOOL DetectMonitorVersion(void) { BOOL BVar1; CString *pCVar2; void *in_ECX; int iVar3; wchar_t *pwStack_20; wchar_t *pwStack_1c; wchar_t *pwStack_18; int iStack_14; void *pvStack_10; undefined *puStack_c; undefined4 uStack_8; uStack_8 = 0xffffffff; puStack_c = &LAB_1000f8ec; pvStack_10 = ExceptionList; iVar3 = 0; ExceptionList = &pvStack_10; memset((void *)((int)in_ECX + 0x131),0,0x101); memset((void *)((int)in_ECX + 0x232),0,0x101); if (*(int *)((int)in_ECX + 0x4cc) == 2) { // Под отладкой условие не выполняется BVar1 = EscapeCommFunction(*(HANDLE *)((int)in_ECX + 0x2c),5); if (BVar1 == 0) { ExceptionList = pvStack_10; return 0; } do { iStack_14 = SendCommand("I",0x1f); CString::CString((CString *)&pwStack_1c,(char *)&this_100157d4); uStack_8 = 0; if (iStack_14 == 0) { uStack_8 = 0xffffffff; CString::~CString((CString *)&pwStack_1c); goto LAB_1000aaa8; } if (*(int *)((int)in_ECX + 0x500) == 1) { FUN_1000dd49(); uStack_8 = 0xffffffff; CString::~CString((CString *)&pwStack_1c); goto LAB_1000abd1; } uStack_8 = 0xffffffff; CString::~CString((CString *)&pwStack_1c); iVar3 = iVar3 + 1; } while (iVar3 < 0x1e); } else { pwStack_1c = (wchar_t *)0x0; do { /* В цикле оправляем команду I и если не смогли прочитать данные меняем скорость соединения и пытаемся еще раз оправить команду. Повторяем до тех пор, пока число попыток не достигнет 2 */ iStack_14 = SendCommand("I",0x1f); if (iStack_14 == 0) goto LAB_1000aaa8; if (*(int *)((int)in_ECX + 0x500) == 1) goto LAB_1000abcc; Sleep(200); FUN_1000a863(in_ECX,0x12c0); iStack_14 = SendCommand("I",0x1f); if (iStack_14 == 0) { *(undefined4 *)((int)in_ECX + 0x43c) = 0x12c0; goto LAB_1000aaa8; } if (*(int *)((int)in_ECX + 0x500) == 1) goto LAB_1000abcc; Sleep(200); FUN_1000a863(in_ECX,0x4b0); iStack_14 = SendCommand("I",0x1f); if (iStack_14 == 0) { *(undefined4 *)((int)in_ECX + 0x43c) = 0x4b0; goto LAB_1000aaa8; } if (*(int *)((int)in_ECX + 0x500) == 1) goto LAB_1000abcc; Sleep(200); FUN_1000a863(in_ECX,0x2580); iStack_14 = SendCommand("I",0x1f); if (iStack_14 == 0) { *(undefined4 *)((int)in_ECX + 0x43c) = 0x2580; goto LAB_1000aaa8; } if (*(int *)((int)in_ECX + 0x500) == 1) goto LAB_1000abcc; Sleep(200); FUN_1000a863(in_ECX,0x960); iStack_14 = SendCommand("I",0x1f); if (iStack_14 == 0) { *(undefined4 *)((int)in_ECX + 0x43c) = 0x960; break; } pwStack_1c = (wchar_t *)((int)pwStack_1c + 1); } while ((int)pwStack_1c < 2); } if (iStack_14 == 0) { LAB_1000aaa8: CString::CString((CString *)&pwStack_18); uStack_8 = 1; CString::operator=((CString *)((int)in_ECX + 0x444),(char *)((int)in_ECX + 0x232)); pCVar2 = (CString *)CString::Mid((CString *)((int)in_ECX + 0x444),&pwStack_20,4); uStack_8._0_1_ = 2; CString::operator=((CString *)&pwStack_18,pCVar2); uStack_8 = CONCAT31(uStack_8._1_3_,1); CString::~CString((CString *)&pwStack_20); CString::CString((CString *)&pwStack_1c,"202"); iVar3 = wcscmp(pwStack_18,pwStack_1c); CString::~CString((CString *)&pwStack_1c); if (iVar3 == 0) { *(undefined4 *)((int)in_ECX + 0x440) = 0xca; } else { CString::CString((CString *)&pwStack_1c,"207"); iVar3 = wcscmp(pwStack_18,pwStack_1c); CString::~CString((CString *)&pwStack_1c); if (iVar3 == 0) { *(undefined4 *)((int)in_ECX + 0x440) = 0xcf; } else { CString::CString((CString *)&pwStack_20,"217"); iVar3 = wcscmp(pwStack_18,pwStack_20); CString::~CString((CString *)&pwStack_20); if (iVar3 == 0) { *(undefined4 *)((int)in_ECX + 0x440) = 0xd9; } else { *(undefined4 *)((int)in_ECX + 0x440) = 0; iStack_14 = 0x3b7f; } } } uStack_8 = 0xffffffff; CString::~CString((CString *)&pwStack_18); if ((iStack_14 == 0) && (*(int *)((int)in_ECX + 0x440) != 0xca)) { if (*(int *)((int)in_ECX + 0x500) == 1) { LAB_1000abcc: FUN_1000dd49(); LAB_1000abd1: iStack_14 = -1; } else { iStack_14 = FUN_1000c2be((int)in_ECX); } } } ExceptionList = pvStack_10; return iStack_14; }
Функция SendCommand:
int SendCommand(undefined4 param_1,undefined4 param_2) { bool bVar1; undefined3 extraout_var; int iVar2; bVar1 = Command2Com(); // Формирует пакет из команды и оправляет его if (CONCAT31(extraout_var,bVar1) == 0) { iVar2 = 0x20; } else { iVar2 = GetResponseData(); // Читает ответ и расшифровывает его } return iVar2; }
Функция Command2Com
формирует пакет, имеющий следующую структуру: 0x01 + команда + возврат каретки + CRC16(0x01 + команда + возврат каретки)
. После этого пакет отправляется.
bool Command2Com(void) { char *_Dest; char cVar1; char *_Source; size_t sVar2; uint uVar3; int iVar4; void *this; CString *this_00; CString *this_01; int unaff_EBP; FUN_1000e9d0(); CString::CString((CString *)(unaff_EBP + -0x10)); _Source = *(char **)(unaff_EBP + 8); *(undefined4 *)(unaff_EBP + -4) = 0; CString::Format(this_00,(ushort *)(unaff_EBP + -0x10)); *(undefined **)(unaff_EBP + 8) = &stack0xffffffe8; CString::CString((CString *)&stack0xffffffe8,(CString *)(unaff_EBP + -0x10)); FUN_1000e0e9(); _Dest = (char *)((int)this + 0x30); strcpy(_Dest, 0x01); // Начало пакета if (*_Source == 'c') { cVar1 = _Source[3]; *(undefined4 *)(unaff_EBP + -0x14) = 0; *(uint *)(unaff_EBP + 8) = (uint)(byte)(cVar1 + 9); iVar4 = (byte)(cVar1 + 9) - 1; if (0 < iVar4) { uVar3 = 0; do { cVar1 = _Source[uVar3]; *(int *)(unaff_EBP + -0x14) = *(int *)(unaff_EBP + -0x14) + 1; *(char *)(uVar3 + 0x31 + (int)this) = cVar1; uVar3 = (uint)*(ushort *)(unaff_EBP + -0x14); } while ((int)uVar3 < iVar4); } } else { strcat(_Dest,_Source); // Команда strcat(_Dest, 0x0D); // Возврат каретки sVar2 = strlen(_Dest); FUN_1000ad6b((byte *)((int)this + 0x31),(sVar2 & 0xffff) - 1); // crc16(0x01 + команда + возврат каретки) sprintf((char *)((sVar2 & 0xffff) + 0x30 + (int)this),(char *)&_Format_100150b8); sVar2 = strlen(_Dest); *(size_t *)(unaff_EBP + 8) = sVar2; } memset((void *)((int)this + 0x131),0,0x101); memset((void *)((int)this + 0x232),0,0x101); CString::Format(this_01,(ushort *)(unaff_EBP + -0x10)); *(undefined **)(unaff_EBP + -0x14) = &stack0xffffffec; CString::CString((CString *)&stack0xffffffec,(CString *)(unaff_EBP + -0x10)); FUN_1000e0e9(); if (*(int *)((int)this + 0x4cc) == 1) { iVar4 = WriteFile(*(HANDLE *)((int)this + 0x2c),_Dest,(uint)*(ushort *)(unaff_EBP + 8), (LPDWORD)(unaff_EBP + -0x18),(LPOVERLAPPED)0x0); } else { iVar4 = FUN_1000d43e(this,_Dest,(uint)*(ushort *)(unaff_EBP + 8)); } *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; CString::~CString((CString *)(unaff_EBP + -0x10)); ExceptionList = *(void **)(unaff_EBP + -0xc); return iVar4 != 0; }
Функция GetResponseData
получает данные, парсит их и расшифровывает, если команда начинается с символа D
. В этом случае контрольная сумма представляет собой 16-битный ключ для расшифровки данных.
Структура ответа на команды, начинающиеся с D
, выглядит следующим образом: 0x01 + D + зашифрованные данные + возврат каретки + CRC16(расшифрованные данные + возврат каретки)
.
int GetResponseData(void) { LPCSTR lpString; void *_Dst; uchar uVar1; ushort uVar2; HANDLE hHandle; size_t sVar3; int iVar4; char *_Str; ulong uVar5; void *in_ECX; CHAR *pCVar6; char *in_stack_00000004; char **_EndPtr; DWORD dwMilliseconds; CByteArray aCStack_58 [4]; int iStack_54; int iStack_50; uchar auStack_44 [4]; char acStack_40 [4]; uchar uStack_3c; undefined3 uStack_3b; char acStack_38 [4]; int iStack_34; int iStack_30; uint uStack_2c; int iStack_28; uint uStack_24; LPCSTR pCStack_20; int iStack_1c; int iStack_18; int iStack_14; void *pvStack_10; undefined *puStack_c; undefined4 uStack_8; uStack_8 = 0xffffffff; puStack_c = &LAB_1000f914; pvStack_10 = ExceptionList; iStack_18 = 1; ExceptionList = &pvStack_10; *(undefined *)((int)in_ECX + 0x232) = 0; lpString = (LPCSTR)((int)in_ECX + 0x232); iStack_28 = 0; iStack_30 = 0; uStack_24 = 0; pCStack_20 = (LPCSTR)0x0; uStack_2c = 0; iStack_34 = 3; do { if (*(int *)((int)in_ECX + 0x4cc) == 1) { memset((void *)((int)in_ECX + 0x131),0,0x101); iStack_1c = FUN_1000b0db(); iStack_14 = 0; if (0 < iStack_1c) { do { CByteArray::SetAtGrow ((CByteArray *)((int)in_ECX + 0x548),*(int *)((int)in_ECX + 0x550), *(uchar *)((int)in_ECX + 0x131 + iStack_14)); iStack_14 = iStack_14 + 1; } while (iStack_14 < iStack_1c); goto LAB_1000af3f; } } else { CByteArray::CByteArray(aCStack_58); uStack_8 = 0; _Dst = (void *)((int)in_ECX + 0x131); while( true ) { memset(_Dst,0,0x101); dwMilliseconds = *(DWORD *)((int)in_ECX + 0x544); hHandle = GetCurrentThread(); WaitForSingleObject(hHandle,dwMilliseconds); iStack_1c = FUN_1000b0db(); iStack_14 = 0; if (iStack_1c < 1) break; do { _uStack_3c = CONCAT31(uStack_3b,*(uchar *)((int)_Dst + iStack_14)); CByteArray::SetAtGrow(aCStack_58,iStack_50,*(uchar *)((int)_Dst + iStack_14)); iStack_14 = iStack_14 + 1; } while (iStack_14 < iStack_1c); if ((iStack_1c < 1) || ((int)in_stack_00000004 <= iStack_50)) break; } iStack_14 = 0; if (0 < iStack_50) { do { uVar1 = *(uchar *)(iStack_54 + iStack_14); auStack_44[0] = uVar1; *(uchar *)((int)_Dst + iStack_14) = uVar1; CByteArray::SetAtGrow ((CByteArray *)((int)in_ECX + 0x548),*(int *)((int)in_ECX + 0x550),uVar1); iStack_14 = iStack_14 + 1; } while (iStack_14 < iStack_50); } iStack_1c = iStack_50; CByteArray::SetSize(aCStack_58,0,-1); uStack_8 = 0xffffffff; CByteArray::~CByteArray(aCStack_58); LAB_1000af3f: pCVar6 = (CHAR *)((int)in_ECX + 0x131); if (0 < iStack_1c) { iStack_18 = 0; do { if (*pCVar6 == '\x01') { *lpString = '\0'; uStack_24 = 0; iStack_30 = 0; pCStack_20 = (LPCSTR)0x0; iStack_28 = 0; uStack_2c = 0; } else if (*pCVar6 == '\r') { iStack_30 = 1; uStack_2c = uStack_24; pCStack_20 = lpString + uStack_24; } lpString[uStack_24] = *pCVar6; *(undefined *)((int)in_ECX + uStack_24 + 0x233) = 0; uStack_24 = uStack_24 + 1; if (0x101 < (int)uStack_24) { iStack_18 = 0x3b8b; break; } pCVar6 = pCVar6 + 1; } while ((int)(pCVar6 + (-0x131 - (int)in_ECX)) < iStack_1c); } } if ((iStack_30 != 0) && (sVar3 = strlen(pCStack_20), 4 < sVar3)) { iStack_28 = 1; } iStack_34 = iStack_34 + -1; if (iStack_34 < 1) { iStack_18 = 0x3b80; if (iStack_28 == 0) { ExceptionList = pvStack_10; return 0x3b80; } LAB_1000aff8: if (*(char *)((int)in_ECX + 0x233) == '\x15') { ExceptionList = pvStack_10; return 0x3b88; } if (*(char *)((int)in_ECX + 0x234) == '\x15') { ExceptionList = pvStack_10; return 0x3b89; } if (*(char *)((int)in_ECX + 0x233) == 'D') { FUN_1000b1f8(in_ECX,(char *)((int)in_ECX + 0x32)); iVar4 = lstrlenA(lpString); FUN_1000b273((LPCSTR)((int)in_ECX + 0x234),(int)in_ECX + 0x333,iVar4); *(undefined *)((uStack_2c >> 1) + 0x332 + (int)in_ECX) = 0xd; uVar2 = FUN_1000ad6b((byte *)((int)in_ECX + 0x333),uStack_2c >> 1); strcpy(acStack_40,pCStack_20 + 1); _EndPtr = &stack0x00000004; _Str = acStack_40; } else { uVar2 = FUN_1000ad6b((byte *)((int)in_ECX + 0x233),uStack_2c); strcpy(acStack_38,pCStack_20 + 1); _EndPtr = (char **)auStack_44; _Str = acStack_38; } uVar5 = strtoul(_Str,_EndPtr,0x10); ExceptionList = pvStack_10; return -(uint)(uVar2 != uVar5) & 0x3b8a; } if (iStack_28 != 0) goto LAB_1000aff8; if (iStack_18 != 0) { ExceptionList = pvStack_10; return iStack_18; } } while( true ); }
Функция EstablishLink
int __thiscall EstablishLink(void *this) { int iVar1; undefined4 *unaff_FS_OFFSET; CString aCStack_18 [4]; CString aCStack_14 [4]; undefined4 uStack_10; undefined *puStack_c; int iStack_8; iStack_8 = 0xffffffff; puStack_c = &LAB_1000f448; uStack_10 = *unaff_FS_OFFSET; *unaff_FS_OFFSET = &uStack_10; FUN_1000957f(); iVar1 = FUN_1000bb19(); if (iVar1 == 0) { iVar1 = FUN_1000c4b7(); if (iVar1 == 0) { iVar1 = SendCommand("M",0xb); if (iVar1 == 0) { FUN_1000c118(this,(char *)((int)this + 0x234)); } } } Sleep(100); if ((iVar1 != 0) && (iVar1 != 0x3a9a)) { CString::CString(aCStack_18); iStack_8 = 0; CString::CString(aCStack_14); iStack_8._0_1_ = 1; CString::CString((CString *)&stack0xffffffbc,(CString *)((int)this + 0x10)); FUN_1000871b(); CString::CString((CString *)&stack0xffffffbc,(CString *)((int)this + 0x10)); FUN_1000871b(); CString::CString((CString *)&stack0xffffffc0,aCStack_14); iStack_8._0_1_ = 2; CString::CString((CString *)&stack0xffffffbc,aCStack_18); iStack_8._0_1_ = 1; FUN_1000a511(); iStack_8 = (uint)iStack_8._1_3_ << 8; CString::~CString(aCStack_14); iStack_8 = 0xffffffff; CString::~CString(aCStack_18); } *unaff_FS_OFFSET = uStack_10; return iVar1; }
Функция FUN_1000bb19
отвечает за отправку пароля с использованием определённого формата.
Формат команды включает в себя букву U
, за которой следует сам пароль и затем добавляются 7 пробелов.
undefined4 FUN_1000bb19(void) { CString *pCVar1; wchar_t *pwVar2; int iVar3; int iVar4; ushort *puVar5; int extraout_ECX; int unaff_EBP; size_t sVar6; FUN_1000e9d0(); *(int *)(unaff_EBP + -0x14) = extraout_ECX; CString::CString((CString *)(unaff_EBP + -0x20)); *(undefined4 *)(unaff_EBP + -4) = 0; CString::CString((CString *)(unaff_EBP + -0x1c)); *(undefined *)(unaff_EBP + -4) = 1; CString::CString((CString *)(unaff_EBP + -0x10),(CString *)(extraout_ECX + 0x44c)); *(undefined *)(unaff_EBP + -4) = 2; if (*(int *)(*(int *)(unaff_EBP + -0x10) + -8) == 0) { CString::LoadStringW((CString *)(unaff_EBP + -0x10), 50006); // GENERIC } CString::CString((CString *)(unaff_EBP + -0x24), " "); *(undefined *)(unaff_EBP + -4) = 3; CString::CString((CString *)(unaff_EBP + -0x18), "U"); *(undefined *)(unaff_EBP + -4) = 4; operator+(); *(undefined *)(unaff_EBP + -4) = 5; pCVar1 = (CString *)operator+(); *(undefined *)(unaff_EBP + -4) = 6; CString::operator=((CString *)(unaff_EBP + -0x10),pCVar1); *(undefined *)(unaff_EBP + -4) = 5; CString::~CString((CString *)(unaff_EBP + -0x28)); *(undefined *)(unaff_EBP + -4) = 4; CString::~CString((CString *)(unaff_EBP + -0x2c)); *(undefined *)(unaff_EBP + -4) = 3; CString::~CString((CString *)(unaff_EBP + -0x18)); *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x24)); sVar6 = 0x14; pwVar2 = (wchar_t *)CString::GetBuffer((CString *)(unaff_EBP + -0x10),0x14); wcstombs((char *)(unaff_EBP + -0x40),pwVar2,sVar6); Sleep(200); iVar3 = SendCommand((char *)(unaff_EBP + -0x40),8); *(int *)(unaff_EBP + -0x18) = iVar3; if (iVar3 == 0) goto LAB_1000c0e2; CString::operator=((CString *)(unaff_EBP + -0x10),(CString *)(*(int *)(unaff_EBP + -0x14) + 0x450) ); if (*(int *)(*(int *)(unaff_EBP + -0x10) + -8) == 0) { CString::LoadStringW((CString *)(unaff_EBP + -0x10), 50006); // GENERIC } CString::CString((CString *)(unaff_EBP + -0x18), " "); *(undefined *)(unaff_EBP + -4) = 7; CString::CString((CString *)(unaff_EBP + -0x24), "U"); *(undefined *)(unaff_EBP + -4) = 8; operator+(); *(undefined *)(unaff_EBP + -4) = 9; pCVar1 = (CString *)operator+(); *(undefined *)(unaff_EBP + -4) = 10; CString::operator=((CString *)(unaff_EBP + -0x10),pCVar1); *(undefined *)(unaff_EBP + -4) = 9; CString::~CString((CString *)(unaff_EBP + -0x2c)); *(undefined *)(unaff_EBP + -4) = 8; CString::~CString((CString *)(unaff_EBP + -0x28)); *(undefined *)(unaff_EBP + -4) = 7; CString::~CString((CString *)(unaff_EBP + -0x24)); *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x18)); sVar6 = 0x14; pwVar2 = (wchar_t *)CString::GetBuffer((CString *)(unaff_EBP + -0x10),0x14); wcstombs((char *)(unaff_EBP + -0x40),pwVar2,sVar6); Sleep(500); iVar3 = SendCommand((char *)(unaff_EBP + -0x40),8); *(int *)(unaff_EBP + -0x18) = iVar3; if (iVar3 == 0) { iVar3 = *(int *)(unaff_EBP + -0x14); *(undefined **)(unaff_EBP + -0x2c) = &stack0xffffffa4; CString::CString((CString *)&stack0xffffffa4,(CString *)(iVar3 + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x2c) = &stack0xffffffa4; CString::CString((CString *)&stack0xffffffa4,(CString *)(iVar3 + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x2c) = &stack0xffffffa8; CString::CString((CString *)&stack0xffffffa8,(CString *)(unaff_EBP + -0x20)); *(undefined **)(unaff_EBP + -0x28) = &stack0xffffffa4; *(undefined *)(unaff_EBP + -4) = 0xb; CString::CString((CString *)&stack0xffffffa4,(CString *)(unaff_EBP + -0x1c)); *(undefined *)(unaff_EBP + -4) = 2; iVar4 = FUN_1000a511(); if (iVar4 != 1) goto LAB_1000c0e2; CString::operator=((CString *)(unaff_EBP + -0x10),(CString *)(iVar3 + 0x44c)); if (*(int *)(*(int *)(unaff_EBP + -0x10) + -8) == 0) { CString::LoadStringW((CString *)(unaff_EBP + -0x10), 50006); // GENERIC } CString::CString((CString *)(unaff_EBP + -0x18), " "); *(undefined *)(unaff_EBP + -4) = 0xc; CString::CString((CString *)(unaff_EBP + -0x24), 0x4e); *(undefined *)(unaff_EBP + -4) = 0xd; operator+(); *(undefined *)(unaff_EBP + -4) = 0xe; pCVar1 = (CString *)operator+(); *(undefined *)(unaff_EBP + -4) = 0xf; CString::operator=((CString *)(unaff_EBP + -0x10),pCVar1); *(undefined *)(unaff_EBP + -4) = 0xe; CString::~CString((CString *)(unaff_EBP + -0x2c)); *(undefined *)(unaff_EBP + -4) = 0xd; CString::~CString((CString *)(unaff_EBP + -0x28)); *(undefined *)(unaff_EBP + -4) = 0xc; CString::~CString((CString *)(unaff_EBP + -0x24)); *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x18)); sVar6 = 0x14; pwVar2 = (wchar_t *)CString::GetBuffer((CString *)(unaff_EBP + -0x10),0x14); wcstombs((char *)(unaff_EBP + -0x40),pwVar2,sVar6); Sleep(500); iVar4 = SendCommand((char *)(unaff_EBP + -0x40),8); *(int *)(unaff_EBP + -0x18) = iVar4; LAB_1000c057: if (*(int *)(unaff_EBP + -0x18) == 0) goto LAB_1000c0e2; } else { CString::LoadStringW((CString *)(unaff_EBP + -0x10), 50006); // GENERIC CString::CString((CString *)(unaff_EBP + -0x18), " "); *(undefined *)(unaff_EBP + -4) = 0x10; CString::CString((CString *)(unaff_EBP + -0x24),s_U_10015250); *(undefined *)(unaff_EBP + -4) = 0x11; operator+(); *(undefined *)(unaff_EBP + -4) = 0x12; pCVar1 = (CString *)operator+(); *(undefined *)(unaff_EBP + -4) = 0x13; CString::operator=((CString *)(unaff_EBP + -0x10),pCVar1); *(undefined *)(unaff_EBP + -4) = 0x12; CString::~CString((CString *)(unaff_EBP + -0x2c)); *(undefined *)(unaff_EBP + -4) = 0x11; CString::~CString((CString *)(unaff_EBP + -0x28)); *(undefined *)(unaff_EBP + -4) = 0x10; CString::~CString((CString *)(unaff_EBP + -0x24)); *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x18)); Sleep(5000); pCVar1 = (CString *)CString::Left((CString *)(unaff_EBP + -0x10)); iVar3 = 8; *(undefined *)(unaff_EBP + -4) = 0x14; puVar5 = CString::GetBuffer(pCVar1,8); iVar3 = SendCommand((char *)puVar5,iVar3); *(int *)(unaff_EBP + -0x18) = iVar3; *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x2c)); if (*(int *)(unaff_EBP + -0x18) == 0) { *(undefined **)(unaff_EBP + -0x2c) = &stack0xffffff98; CString::CString((CString *)&stack0xffffff98,(CString *)(*(int *)(unaff_EBP + -0x14) + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x2c) = &stack0xffffff98; CString::CString((CString *)&stack0xffffff98,(CString *)(*(int *)(unaff_EBP + -0x14) + 0x10)); FUN_1000871b(); CString::operator=((CString *)(unaff_EBP + -0x10), (CString *)(*(int *)(unaff_EBP + -0x14) + 0x44c)); if (*(int *)(*(int *)(unaff_EBP + -0x10) + -8) == 0) { CString::LoadStringW((CString *)(unaff_EBP + -0x10), 50006); // GENERIC } CString::CString((CString *)(unaff_EBP + -0x18), " "); *(undefined *)(unaff_EBP + -4) = 0x15; CString::CString((CString *)(unaff_EBP + -0x24),0x4e); *(undefined *)(unaff_EBP + -4) = 0x16; operator+(); *(undefined *)(unaff_EBP + -4) = 0x17; pCVar1 = (CString *)operator+(); *(undefined *)(unaff_EBP + -4) = 0x18; CString::operator=((CString *)(unaff_EBP + -0x10),pCVar1); *(undefined *)(unaff_EBP + -4) = 0x17; CString::~CString((CString *)(unaff_EBP + -0x2c)); *(undefined *)(unaff_EBP + -4) = 0x16; CString::~CString((CString *)(unaff_EBP + -0x28)); *(undefined *)(unaff_EBP + -4) = 0x15; CString::~CString((CString *)(unaff_EBP + -0x24)); *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x18)); Sleep(500); pCVar1 = (CString *)CString::Left((CString *)(unaff_EBP + -0x10)); iVar3 = 8; *(undefined *)(unaff_EBP + -4) = 0x19; puVar5 = CString::GetBuffer(pCVar1,8); iVar3 = SendCommand((char *)puVar5,iVar3); *(int *)(unaff_EBP + -0x18) = iVar3; *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x2c)); iVar3 = *(int *)(unaff_EBP + -0x14); goto LAB_1000c057; } iVar3 = *(int *)(unaff_EBP + -0x14); } if (*(int *)(unaff_EBP + -0x18) != 0x3a9a) { *(undefined **)(unaff_EBP + -0x28) = &stack0xffffff8c; CString::CString((CString *)&stack0xffffff8c,(CString *)(iVar3 + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x28) = &stack0xffffff8c; CString::CString((CString *)&stack0xffffff8c,(CString *)(iVar3 + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x28) = &stack0xffffff90; CString::CString((CString *)&stack0xffffff90,(CString *)(unaff_EBP + -0x20)); *(undefined **)(unaff_EBP + -0x24) = &stack0xffffff8c; *(undefined *)(unaff_EBP + -4) = 0x1a; CString::CString((CString *)&stack0xffffff8c,(CString *)(unaff_EBP + -0x1c)); *(undefined *)(unaff_EBP + -4) = 2; FUN_1000a511(); *(undefined4 *)(unaff_EBP + -0x18) = 0x3b85; } LAB_1000c0e2: *(undefined *)(unaff_EBP + -4) = 1; CString::~CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 0; CString::~CString((CString *)(unaff_EBP + -0x1c)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; CString::~CString((CString *)(unaff_EBP + -0x20)); ExceptionList = *(void **)(unaff_EBP + -0xc); return *(undefined4 *)(unaff_EBP + -0x18); }
Чтобы начать отправлять команды для чтения данных, достаточно отправить только пароль.
Команды, которые идут перед паролем, такие как команда V
, можно не отправлять, и устройство воспринимает это нормально.
Список команд с префиксом D
, которые используются для чтения данных с устройства:
-
D816022
— Уникальный идентификатор пациента -
D81820F
— То же самое -
D819241
— Причины для исследования -
D81D306
— Дата и время инициализации -
D810B01
— Количество измерений -
D820078
— Систолические значения -
D830078
— Диастолические значения -
D840078
— Значения среднего артериального давления (MAP) -
D850078
— Показатели частоты сердечных сокращений -
D860078
— Время считывания в часах -
D870078
— Время считывания в минутах -
DCA0078
— Информация о дне месяца считывания -
DCB0078
— Информация о месяце считывания
Инициализация устройства
Аналогично процессу выгрузки данных с монитора, я нахожу функцию StartInitializingMonitor
, которая используется для инициализации устройства.
undefined4 StartInitializingMonitor(void) { AFX_MODULE_STATE *pAVar1; LPWSTR lpReturnedString; ushort *puVar2; int iVar3; undefined4 uVar4; int unaff_EBX; LPWSTR unaff_ESI; UINT unaff_EDI; int *in_stack_00000004; undefined4 *in_stack_00000008; undefined4 uStack_2c; int iStack_28; undefined *puStack_24; LPCWSTR pWStack_20; CString aCStack_1c [4]; LPCWSTR pWStack_18; undefined *puStack_14; void *pvStack_10; undefined *puStack_c; undefined4 uStack_8; puStack_c = &LAB_1000f198; pvStack_10 = ExceptionList; uStack_8 = 0; puStack_14 = &stack0xffffffc8; ExceptionList = &pvStack_10; pAVar1 = (AFX_MODULE_STATE *)FUN_1000e7f9(); AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2((AFX_MAINTAIN_STATE2 *)&uStack_2c,pAVar1); uStack_8._0_1_ = 1; if (in_stack_00000004[0x180] != 0) { FUN_10006204(in_stack_00000004); uVar4 = InitMonitor(); *in_stack_00000008 = uVar4; goto LAB_100055a3; } CString::CString((CString *)&pWStack_20); uStack_8._0_1_ = 2; CString::CString((CString *)&pWStack_18); uStack_8._0_1_ = 3; CString::CString((CString *)&stack0x00000004,(char *)&this_100157d4); uStack_8._0_1_ = 4; lpReturnedString = (LPWSTR)CString::GetBuffer((CString *)&stack0x00000004,0x104); GetPrivateProfileStringW (L"DevTest",L"Language",(LPCWSTR)¶m_3_100157d0,lpReturnedString,0x104,L"abpwin.ini") ; CString::ReleaseBuffer((CString *)&stack0x00000004,-1); CString::CString(aCStack_1c,(char *)&this_100157d4); uStack_8 = CONCAT31(uStack_8._1_3_,5); puVar2 = CString::GetBuffer((CString *)&stack0x00000004,0x104); iVar3 = _strcmpi(&_Str1_100143d0,(char *)puVar2); if (iVar3 == 0) { LAB_10005520: CString::operator=(aCStack_1c,"ABD Report Management System"); CString::operator=((CString *)&pWStack_18,aCStack_1c); } else { puVar2 = CString::GetBuffer((CString *)&stack0x00000004,0x104); iVar3 = _strcmpi(&_Str1_100143cc,(char *)puVar2); if (iVar3 == 0) goto LAB_10005520; CString::LoadStringW((HINSTANCE)&DAT_00000065,unaff_EDI,unaff_ESI,unaff_EBX); } puStack_24 = &stack0xffffffbc; CString::CString((CString *)&stack0xffffffbc,(CString *)(in_stack_00000004 + 0x2c)); FUN_1000871b(); MessageBoxW((HWND)in_stack_00000004[0x14],pWStack_20,pWStack_18,0x40); uStack_8._0_1_ = 4; *in_stack_00000008 = 0; CString::~CString(aCStack_1c); uStack_8._0_1_ = 3; CString::~CString((CString *)&stack0x00000004); uStack_8._0_1_ = 2; CString::~CString((CString *)&pWStack_18); uStack_8 = CONCAT31(uStack_8._1_3_,1); CString::~CString((CString *)&pWStack_20); LAB_100055a3: *(undefined4 *)(iStack_28 + 4) = uStack_2c; ExceptionList = pvStack_10; return 0; }
Функция InitMonitor
. Оправляет команды инициализации
undefined4 InitMonitor(void) { undefined8 uVar1; int iVar2; undefined4 uVar3; int extraout_ECX; CString *this; int unaff_EBP; uint uVar4; char *pcVar5; FUN_1000e9d0(); if (*(int *)(extraout_ECX + 0x518) == 1) { (**(code **)(*(int *)(extraout_ECX + 0x504) + 0x34))(); } FUN_1000957f(); *(undefined **)(unaff_EBP + -0x14) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Checking monitor availability ....."); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x500) = 0; *(undefined4 *)(extraout_ECX + 0x4f8) = 0; CString::GetBuffer((CString *)(extraout_ECX + 0xc),10); iVar2 = OpenComPort(); if (iVar2 == 0) { *(undefined **)(unaff_EBP + -0x14) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Failed to open COM port"); FUN_1000e0e9(); FUN_1000957f(); goto LAB_10009e80; } *(undefined **)(unaff_EBP + -0x14) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"COM port opened"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 1; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100096cd; if (*(int *)(extraout_ECX + 0x4cc) == 2) { FUN_1000957f(); iVar2 = FUN_1000d79e(); if (iVar2 == 0) { *(undefined **)(unaff_EBP + -0x14) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Initialize modem failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x14)); *(undefined4 *)(unaff_EBP + -4) = 0; CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined *)(unaff_EBP + -4) = 1; *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x14), *(LPCWSTR *)(unaff_EBP + -0x10),0); *(undefined *)(unaff_EBP + -4) = 0; uVar4 = 0x3a9a; CString::~CString((CString *)(unaff_EBP + -0x10)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; this = (CString *)(unaff_EBP + -0x14); LAB_10009a68: CString::~CString(this); LAB_10009d88: if (*(int *)(extraout_ECX + 0x4cc) == 2) { iVar2 = *(int *)(extraout_ECX + 0x4f8); if (((iVar2 == 0) || (iVar2 == 2)) || (iVar2 == 1)) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"No modem connection has been made.."); FUN_1000e0e9(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Have to close the port"); FUN_1000e0e9(); } else { FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Breaking the modems\' connection...."); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 4; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100096cd; FUN_1000dca5(); } } *(undefined4 *)(extraout_ECX + 0x4f8) = 9; if (*(int *)(extraout_ECX + 0x500) != 1) { FUN_1000a781(extraout_ECX); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Closing COM port"); FUN_1000e0e9(); if (uVar4 == 0) { CString::operator=((CString *)(extraout_ECX + 0x18),(CString *)(extraout_ECX + 0xc)); FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Monitor successfully initialized"); FUN_1000e0e9(); uVar3 = 1; goto LAB_10009ebb; } FUN_1000957f(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Initialization failed"); FUN_1000e0e9(); goto LAB_10009e80; } } else { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Initialize modem succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 2; if (*(int *)(extraout_ECX + 0x500) != 1) { FUN_1000957f(); iVar2 = FUN_1000dbb4(); if (iVar2 == 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting the modems failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined4 *)(unaff_EBP + -4) = 2; CString::CString((CString *)(unaff_EBP + -0x14)); *(undefined *)(unaff_EBP + -4) = 3; *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x10), *(LPCWSTR *)(unaff_EBP + -0x14),0); uVar4 = 0x3a9a; *(undefined *)(unaff_EBP + -4) = 2; CString::~CString((CString *)(unaff_EBP + -0x14)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; this = (CString *)(unaff_EBP + -0x10); goto LAB_10009a68; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Connecting the modems succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 3; if (*(int *)(extraout_ECX + 0x500) != 1) goto LAB_100098a7; } } LAB_100096cd: FUN_1000dd49(); } else { LAB_100098a7: uVar4 = DetectMonitorVersion(); if (uVar4 == 0xffffffff) goto LAB_10009e80; if (((uVar4 != 0) && (uVar4 != 0x3b86)) && (uVar4 != 0x3b89)) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,(ushort *)L"Connecting with monitor failed"); FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x10)); *(undefined4 *)(unaff_EBP + -4) = 4; CString::CString((CString *)(unaff_EBP + -0x14)); *(undefined *)(unaff_EBP + -4) = 5; *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x10), *(LPCWSTR *)(unaff_EBP + -0x14),0); *(undefined *)(unaff_EBP + -4) = 4; CString::~CString((CString *)(unaff_EBP + -0x14)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; this = (CString *)(unaff_EBP + -0x10); goto LAB_10009a68; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,(ushort *)L"Connecting with monitor succeeded"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 5; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100096cd; uVar4 = FUN_1000a0a6(); if (uVar4 == 0xffffffff) goto LAB_10009e80; if (uVar4 == 0x3a9a) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,(ushort *)L"Failed to Establish Link to Monitor") ; LAB_10009d81: FUN_1000e0e9(); goto LAB_10009d88; } if (uVar4 != 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,(ushort *)L"Failed to Establish Link to Monitor") ; FUN_1000e0e9(); CString::CString((CString *)(unaff_EBP + -0x1c)); *(undefined4 *)(unaff_EBP + -4) = 6; CString::CString((CString *)(unaff_EBP + -0x18)); *(undefined *)(unaff_EBP + -4) = 7; *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; CString::CString((CString *)&stack0xffffffd4,(CString *)(extraout_ECX + 0x10)); FUN_1000871b(); MessageBoxW(*(HWND *)(extraout_ECX + 0x14),*(LPCWSTR *)(unaff_EBP + -0x1c), *(LPCWSTR *)(unaff_EBP + -0x18),0); *(undefined *)(unaff_EBP + -4) = 6; CString::~CString((CString *)(unaff_EBP + -0x18)); *(undefined4 *)(unaff_EBP + -4) = 0xffffffff; this = (CString *)(unaff_EBP + -0x1c); goto LAB_10009a68; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Established Link to the Monitor"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 6; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100096cd; FUN_1000957f(); iVar2 = SendCommand("R",8); // Сброс if ((iVar2 != 0) && (uVar4 = SendCommand("R",8), uVar4 != 0)) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to reset the monitor"; goto LAB_10009d7c; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Successfully reset the monitor"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 7; if (*(int *)(extraout_ECX + 0x500) == 1) goto LAB_100096cd; FUN_1000957f(); uVar4 = FUN_1000b50a(extraout_ECX); if (uVar4 != 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to send control flags to the monitor"; goto LAB_10009d7c; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc, "Successfully sent the control flags to the monitor"); FUN_1000e0e9(); *(undefined4 *)(extraout_ECX + 0x4f8) = 8; if ((*(int *)(extraout_ECX + 0x500) == 1) && (iVar2 = FUN_1000dd49(), iVar2 != 0)) goto LAB_10009e80; FUN_1000957f(); if (*(int *)(extraout_ECX + 0x46c) == 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to build monitor BP cycle"; LAB_10009d7c: CString::CString((CString *)&stack0xffffffdc,pcVar5); goto LAB_10009d81; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Succeeded in building monitor BP cycle"); FUN_1000e0e9(); FUN_1000957f(); uVar4 = FUN_1000b578(); if (uVar4 != 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to build cycle time information and send to monitor"; goto LAB_10009d7c; } *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc, "Failed to build cycle time information and send to monitor"); FUN_1000e0e9(); if ((*(int *)(extraout_ECX + 0x500) != 1) || (iVar2 = FUN_1000dd49(), iVar2 == 0)) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc, "Succeeded in building cycle time information and sending to monitor"); FUN_1000e0e9(); FUN_1000957f(); uVar1 = *(undefined8 *)(extraout_ECX + 0x48c); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; uVar4 = FUN_1000b758(SUB81(uVar1,0)); if (uVar4 == 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc, "Succeeded in sending initialization time to monitor"); FUN_1000e0e9(); if ((*(int *)(extraout_ECX + 0x500) == 1) && (iVar2 = FUN_1000dd49(), iVar2 != 0)) goto LAB_10009e80; uVar1 = *(undefined8 *)(extraout_ECX + 0x48c); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffd4; uVar4 = FUN_1000b7c8(SUB81(uVar1,0)); if (uVar4 == 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Succeeded in sending monitor clock"); FUN_1000e0e9(); if ((*(int *)(extraout_ECX + 0x500) == 1) && (iVar2 = FUN_1000dd49(), iVar2 != 0)) goto LAB_10009e80; FUN_1000957f(); uVar4 = FUN_1000b827(); if (uVar4 == 0) { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; CString::CString((CString *)&stack0xffffffdc,"Succeeded in sending biographical data"); FUN_1000e0e9(); if ((*(int *)(extraout_ECX + 0x500) == 1) && (iVar2 = FUN_1000dd49(), iVar2 != 0)) goto LAB_10009e80; uVar4 = FUN_1000bb0c(); *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "set processed readings flag to zero"; } else { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to send biographical data"; } } else { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to send monitor clock"; } } else { *(undefined **)(unaff_EBP + -0x20) = &stack0xffffffdc; pcVar5 = "Failed to send initialization time to monitor"; } goto LAB_10009d7c; } } LAB_10009e80: uVar3 = 0; LAB_10009ebb: ExceptionList = *(void **)(unaff_EBP + -0xc); return uVar3; }
Функция FUN_1000b50a
. Оправляет флаги управления монитором.
undefined4 __fastcall FUN_1000b50a(int param_1) { char *_Dest; undefined4 uVar1; byte bVar2; bVar2 = *(int *)(param_1 + 1148) == 0; // Показать результаты измерения if (*(int *)(param_1 + 1160) == 0) { // Формат отображения времени (false: 12-часовой формат, true: 24-часовой формат) bVar2 = bVar2 | 8; } if (*(int *)(param_1 + 1156) != 0) { // Отображение давления в манжете bVar2 = bVar2 | 16; } if (*(int *)(param_1 + 1152) != 0) { // Установка клинической верификации bVar2 = bVar2 | 64; } _Dest = (char *)operator_new(0x10); sprintf(_Dest,"W811702%02X%02X",4,(uint)bVar2); uVar1 = SendCommand(_Dest,8); operator_delete(_Dest); return uVar1; }
Функция FUN_1000b578
устанавливает расписание измерений по часам. Ее особенностью является использование связанного списка, который, как правило, не применяется в практических задачах.
int __thiscall FUN_1000b578(void *this) { byte timerValue; byte *_timers; wchar_t **currentSoftwareVersion; wchar_t **incomingVersion; int isNextVersionGreaterOrEqual; uint ActiveStateHour; int iVar1; uint hourIndex; CycleTimeInformation *currentCycleInfo; char *_Dest; undefined4 *unaff_FS_OFFSET; double ActiveStateTimestamp; int local_40; double NextStateTimestamp; int local_34; undefined2 HourlyReadInterval; dword Tone; CString local_28 [4]; char *Destination; void *local_20; int isNewVersion; uint NextStateHour; byte *Timers; undefined4 local_10; undefined *puStack_c; undefined4 local_8; char *Command; CycleTimeInformation *nextCycleInfo; local_8 = 0xffffffff; puStack_c = &LAB_1000f944; local_10 = *unaff_FS_OFFSET; *unaff_FS_OFFSET = &local_10; local_20 = this; _timers = (byte *)operator_new(24); Timers = _timers; Destination = (char *)operator_new(128); for (iVar1 = 6; iVar1 != 0; iVar1 = iVar1 + -1) { _timers[0] = 0x80; _timers[1] = 0x80; _timers[2] = 0x80; _timers[3] = 0x80; _timers = _timers + 4; } if ((*(int *)(*(int *)((int)this + 0x448) + -8) != 0) || (iVar1 = FUN_1000c2be((int)this), iVar1 == 0)) { isNewVersion = 0; currentSoftwareVersion = (wchar_t **)CString::CString(local_28,"02.11"); local_8 = 0; incomingVersion = (wchar_t **)CString::Mid((CString *)((int)this + 0x448),&NextStateHour,10); isNextVersionGreaterOrEqual = wcscmp(*incomingVersion,*currentSoftwareVersion); CString::~CString((CString *)&NextStateHour); local_8 = 0xffffffff; CString::~CString(local_28); if (-1 < isNextVersionGreaterOrEqual) { isNewVersion = 1; } currentCycleInfo = *(CycleTimeInformation **)((int)local_20 + 0x464); while (Command = Destination, currentCycleInfo != (CycleTimeInformation *)0x0) { nextCycleInfo = currentCycleInfo->Next; ActiveStateTimestamp = currentCycleInfo->ActiveStateHour; local_40 = currentCycleInfo->v0; NextStateTimestamp = currentCycleInfo->NextStateHour; local_34 = currentCycleInfo->v1; HourlyReadInterval = *(undefined2 *)¤tCycleInfo->HourlyReadInterval; Tone = currentCycleInfo->Tone; ActiveStateHour = COleDateTime::GetHour((COleDateTime *)&ActiveStateTimestamp); NextStateHour = COleDateTime::GetHour((COleDateTime *)&NextStateTimestamp); timerValue = 0; if (((byte)HourlyReadInterval == 0) || (59 < (byte)HourlyReadInterval)) { if ((byte)HourlyReadInterval == 100) { timerValue = 120; } } else { timerValue = (byte)(60 / (byte)HourlyReadInterval); } hourIndex = 0; if (isNewVersion == 0) { if ((timerValue < 6) || (0x3c < timerValue)) { iVar1 = 0x3b9d; goto LAB_1000b735; } } else if ((timerValue != 0) && ((timerValue < 6 || (120 < timerValue)))) { iVar1 = 0x3b9e; goto LAB_1000b735; } do { if (ActiveStateHour < NextStateHour) { if (ActiveStateHour <= hourIndex) { LAB_1000b6c1: if (hourIndex < NextStateHour) goto LAB_1000b6c6; } } else { if (hourIndex < ActiveStateHour) goto LAB_1000b6c1; LAB_1000b6c6: Timers[hourIndex] = timerValue; if (Tone == 0) { Timers[hourIndex] = timerValue + 128; } } hourIndex = hourIndex + 1; currentCycleInfo = nextCycleInfo; } while (hourIndex < 24); } strcpy(Destination,"W814018"); iVar1 = 0; _Dest = Command + 7; do { sprintf(_Dest,"%02X",(uint)Timers[iVar1]); iVar1 = iVar1 + 1; _Dest = _Dest + 2; } while (iVar1 < 24); iVar1 = SendCommand(Command,8); LAB_1000b735: operator_delete(Timers); operator_delete(Destination); } *unaff_FS_OFFSET = local_10; return iVar1; }
Функция FUN_1000b758
. Оправляет время инициализации.
undefined4 FUN_1000b758(undefined param_1) { char *_Dest; int Minute; int Hour; int Year; int Day; int Month; undefined4 uVar1; _Dest = (char *)operator_new(0x1e); Minute = COleDateTime::GetMinute((COleDateTime *)¶m_1); Hour = COleDateTime::GetHour((COleDateTime *)¶m_1); Year = COleDateTime::GetYear((COleDateTime *)¶m_1); Year = Year % 100; Day = COleDateTime::GetDay((COleDateTime *)¶m_1); Month = COleDateTime::GetMonth((COleDateTime *)¶m_1); sprintf(_Dest,"W81D306%02X%02X%02X%02X%02X%02X",Month,Day,Year,Hour,Minute); uVar1 = SendCommand(_Dest,8); operator_delete(_Dest); return uVar1; }
Функция FUN_1000b7c8
. Устанавливает время устройства
undefined4 FUN_1000b7c8(undefined param_1) { char *_Dest; int Month; int Day; int Minute; int Hour; undefined4 uVar1; _Dest = (char *)operator_new(0x1e); Month = COleDateTime::GetMonth((COleDateTime *)¶m_1); Day = COleDateTime::GetDay((COleDateTime *)¶m_1); Minute = COleDateTime::GetMinute((COleDateTime *)¶m_1); Hour = COleDateTime::GetHour((COleDateTime *)¶m_1); sprintf(_Dest,"T%2.2d%2.2d%2.2d%2.2d",Hour,Minute,Day,Month); uVar1 = SendCommand(_Dest,8); operator_delete(_Dest); return uVar1; }
Перед началом инициализации также отправляется пароль GENERIC
с пробелами в конце.
Команды инициализации:
-
R
— Выполняет сброс устройства. -
W8117020401
— Устанавливает флаги управления монитором. ПрефиксW811702
, далее следует04
и флаги, закодированные в одном байте. -
W814018BCBCBCBCBCBC14141414141414141414141414141414BCBC
— Устанавливает расписание времени измерения. ПрефиксW814018
, далее идет расписание, закодированное в HEX-строке особым образом. -
W81D3060C04180F2400
— Устанавливает время инициализации. ПрефиксW81D306
, далее в HEX формате указываются месяц, день, год (двумя цифрами), час и минута. -
T15360412
— Устанавливает время устройства. ПрефиксT
, далее идут час, минута, день и месяц. -
W81600100
,W818202200
,W81920100
— Отправляют данные о пациенте. -
W81DA0100
— Сбрасывает число отработанных показаний.
Таким образом я собрал достаточно данных для написания консольного приложения. Исходный код которого можно посмотреть на гитхабе.
Заключение
В результате проведенного реверс-инжиниринга программы мониторинга артериального давления Spacelabs OnTrak 90227 ABP Monitor мне удалось достичь своей цели — разработать консольное приложение для инициализации устройства и считывания данных. Весь процесс занял две недели.
В ходе работы я столкнулся с различными задачами, включая необходимость в эмуляции устройства, однако техническая смекалка и креативный подход помогли мне преодолеть эти трудности. Используя Arduino для создания эмулятора, я смог обойти ограничения, связанные с доступом к реальному устройству, и обеспечить стабильную среду для тестирования и отладки.
Интуитивно исключив команды и алгоритмы, которые не были критически необходимы для работы с устройством, я упростил себе задачу и ускорил процесс разработки консольного приложения. Оно успешно заработало с первого раза без ошибок на реальном устройстве, что подтвердило правильность моих предположений и подходов в этом проекте.
Я уверен, что полученный опыт будет полезен в будущих проектах и поможет мне справляться с более сложными задачами.
ссылка на оригинал статьи https://habr.com/ru/articles/868092/
Добавить комментарий