Начало
Передо мной встала задача провести реверс-инжиниринг программы мониторинга артериального давления для устройства 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 для создания эмулятора, я смог обойти ограничения, связанные с доступом к реальному устройству, и обеспечить стабильную среду для тестирования и отладки.
Интуитивно исключив команды и алгоритмы, которые не были критически необходимы для работы с устройством, я упростил себе задачу и ускорил процесс разработки консольного приложения. Оно успешно заработало с первого раза без ошибок на реальном устройстве, что подтвердило правильность моих предположений и подходов в этом проекте.
Я уверен, что полученный опыт будет полезен в будущих проектах и поможет мне справляться с более сложными задачами.