02. Я уже даже не вижу код. Я вижу блондинку, брюнетку и рыжую

Структуры — кирпичики

Предыдущие статьи о реверсе данных автомобильных навигаторов Siemens VDO Dayton CARMiN

Блоки данных carindb состоят из однотипных кирпичиков, структур данных, несущих определенную информацию. Значительную часть из них я уже описал в предыдущих статьях, напомню:

  • PTR. Размер 16 бит (точнее, размер данных в бинарнике, которые описывает структура, размер самой структуры больше). Относительное от начала блока смещение в ushort ptr. Часть структуры, не учитывающаяся в размере — byte руку, располагающийся в hex по значению смещения структуры, визуально показывает голубым фоном, куда PTR ссылается. В окне hex PTR отображается синими символами на голубом фоне. По определению, не может быть больше размера блока, к которому относится.

  • LIST. Размер 32 бита. Последовательно расположенные: PTR ptr и ushort cnt, где ptr — указатель на адрес внутри блока, а cnt — количество элементов массива, начинающегося с этого адреса. Тип данных массива определяется тем, где в блоке расположен LIST. Абсолютный адрес начала может быть запрошен у структуры через offset. Светло-голубой фон, ptr синими символами, cnt — тёмно-фиолетовым.

  • BL_ADDR. Размер 32 бита. Первые 24-бита — addr — абсолютное смещение от начала файла в страницах размером 0×800 байт, т.е. для абсолютного смещения в байтах умножаем на 0×800 или побитово сдвигаем влево на 7 позиций. Последние 8 бит — size — размер блока в 0×800 байтных страницах. Обращаясь к «виртуальному» элементу offset, получается значение абсолютного смещения. По определению, по данному смещению должно располагаться значение, равное значению этого BL_ADDR. Если не так, то данные, которые пытаемся описать как BL_ADDR, к этому типу не относятся. Структура отслеживает ситуацию и сигнализирует об этом, окрашивая фон красным и выводя сообщение о несоответствии в лог. Валидный BL_ADDR в окне hex — на оранжевом фоне, желтые — символы addr и темно-голубые (cDkAqua) — size.

  • BL_HEAD. Размер 64 бита. Первые 32 — BL_ADDR, затем байт zero_aligment всегда равный нулю, затем байт type, определяющий тип блока (enum en_BL_TYPE), и 2 байта is_compressed и uncompressed_size, в русском carindb всегда равные нулю. Это заголовок блока, поэтому его BL_ADDR обязан быть не только валидным, но и указывать именно на тот адрес, по которому расположен BL_HEAD. В структуре добавлен утилитарный байт here_last_byte, броско выделенный (bgcolor=cPurple, fgcolor=cAqua) в hex, отмечающий последний байт блока, в размере BL_HEAD не учитывается. Расцветка BL_HEAD в окне hex — оранжевый фон, байт type cDkPurple, остальные незначащие байты — серые.

В прошлой статье выяснили, что блока типа 0xB «внешние» «ссылки» ведут в 0xA. Из блока типа 0xD ссылки ведут в 0xC. Из 0×0F в 0×0E. Из 0×11 в 0×10.
Если 0xB — это блок с начальными буквами стран, то 0xA, куда ведут следы, должен содержать информацию о странах.

На файл carindb_bnl, официальную карту Бенилюкса (удобный вариант, всего три страны — Бельгия, Нидерланды и Люксембург) применяю результаты прошлой статьи: размечаю блок 0xB вызовом block(FindBlockByType(0x0B));.

image-loader.svg

Коллаж для наглядности: на скрин результатов функции добавил уменьшенный скриншот hex с адреса 0×2000, начала блока 0xA, идущего сразу после 0xB, и часть этого же 0xA тоже увеличена.

  • В блоке 0xB три main_data, они содержат буквы B, N и L и ссылаются соответственно на абсолютные адреса 0×2030, 0×2038, 0×2040 — синие точечные стрелки, о факте голубеньким маякуют соответствующие PTR.here в main_data.

  • На увеличенной части выделил желтым фоном заголовок блока: — '00000401 000A0000' это BL_HEAD, — '00300003' — LIST на массив из 3х элементов, на которые идут ссылки из 0xB, что сразу и дает размер каждого элемента. — '00480003' — еще один LIST, указывает на данные сразу после данных первого. — uint zero — '00f00017' LIST на массив из 17h элементов, ptr F0h позволит рассчитать размер элемента предыдущего LIST, (f0 — 30) /3 =0×40 — Шесть uint zero — вероятно, всегда равны нолю.

  • На уменьшенной картинке скрина содержимое блока 0xA поместилось целиком, в самом низу, с адреса 0×2210 три zero-ended строковых значения: belgië, luxembourg, nederland. БИНГО!

  • Значение, на которое указывает элемент main_data из блока 0xB, содержащий символ «B» — 0210h, смещение строки «belgië», «L» — «luxembourg», «N» — «nederland»

  • Последние 2 байта элементов данных блока 0xA (LIST '00300003'), (на которые ведут ссылки из 0xB по значениям) — ссылки на (LIST '00480003')

Новые кирпичики: CONST_B, CONST_S, CONST_I, PSTR

Добавляю в vdo_inc.bt новые типы.

  • CONST_B, CONST_S, CONST_I — константы, структуры, требующие инициализации ожидаемым значением при объявлении.Размер соответственно 8, 16 и 32 бита. В hex белые буквы на темно-сером фоне, но если значение под константой не равно значению инициализации, фон красный, запись в лог.

  • PSTR. Размер 16 бит. Аналог PTR с типом содержимого по ссылке — оканчивающаяся на ноль строка, структура сохраняет в свой элемент str эту строку, заодно раскрашивая её зеленым фоном и темно-оранжевыми символами. Цвет в hex — голубой фон, как у PTR, но символы темно-зеленые, а не синие.

//}CONST_B
typedef struct(uchar val){
    if(ReadUByte(FTell()) != val){
        SetBackColor(cRed);
        Printf("0f:%04X const ubyte(%02Xh) != %Xh\n", 
            FTell(), val, ReadUByte(FTell()));
    }
    ubyte value;
}CONST_B 

Блок 0×0A. Информация о странах

В инклюде @inc_block.bt» в функцию block () в swith выбора структуры добавляю раздел с типом структуры BT_0×0A для соответствующего значения типа.

    // reading block type
    local uchar type = ReadUByte(start_offset + 5);
    FSeek(start_offset);
    switch (type){  // choice template for every known type
       case 0x0B:
            BT_0x0B_0x0D_0x0F_0x11     block_0x0B ;
            break;
       case 0x0A:
            BT_0x0A              block_0x0A ;
            break;

В основном темплейте описываю typedef с новой структурой BT_0×0A.

 typedef struct{
    BL_HEAD head; // заголовок
    local ushort size 

И применяю его на файлах carindb_bnl, carindb_ee и carindb_rus.

image-loader.svg

  • На скрине выделен стрелкой единственный случай, когда байт CONST_B zero (0), идущий после PSTR pstr_name равен 1, а не ожидаемому 0. Эта запись соответствует Австрии — единственной стране, которая есть в списке дважды в 2х вариантах написания — с умляутами и без (в консоли верхняя часть ascii выводится как черный ромбик-вопросик, в теле файла написано Österreich), и на одном из этих вариантов значение единица. Признак синонима? Переименовываю zero (0) в is_synonym (0).

  • Подсвеченный желтым ubyte unk гораздо интереснее, о нем следующий раздел.

Language codes en_LANG

В вывод в консоль названия страны Printf("%s \n", pstr_name.str); добавляю вывод значения ubyte unk: Printf("%02X\t(%i)\t%s \n", unk, unk, pstr_name.str);
Результаты стоят цитирования

carindb_bnl
01	(1)	belgi� 
03	(3)	luxembourg 
01	(1)	nederland 

carindb_ee
FF	(255)	balgaria 
13	(19)	ceska republika 
FF	(255)	eesti 
1A	(26)	hrvatska 
1B	(27)	latvija 
18	(24)	lietuva 
FF	(255)	magyarorszag 
12	(18)	polska 
FF	(255)	rom�nia 
17	(23)	slovenija 
14	(20)	slovenska republika 

carindb_rus
0B	(11)	andorra 
FF	(255)	azarbaycan 
01	(1)	belgie 
FF	(255)	bosna i hercegovina 
FF	(255)	bulgaria 
FF	(255)	byelarus 
FF	(255)	ceska republika 
0A	(10)	danmark 
04	(4)	deutschland 
FF	(255)	eesti vabariik 
02	(2)	�ire 
FF	(255)	ellas 
06	(6)	espa�a 
03	(3)	france 
FF	(255)	hrvatska 
05	(5)	italia 
FF	(255)	kibris 
FF	(255)	latvija 
FF	(255)	lietuva 
FF	(255)	luxembourg 
FF	(255)	lyoveldio island 
FF	(255)	magyarorszag 
FF	(255)	makedonija 
FF	(255)	moldova 
01	(1)	nederland 
0E	(14)	norge 
0f:2102 const ubyte(00h) != 1h
04	(4)	oesterreich 
04	(4)	�sterreich 
FF	(255)	polska 
0F	(15)	portugal 
FF	(255)	romania 
FF	(255)	rossiya 
FF	(255)	sak'art'velo 
04	(4)	schweiz 
FF	(255)	shqiperia 
FF	(255)	slovenija 
FF	(255)	slovensko 
FF	(255)	srbija i crna gora 
0C	(12)	suomen tasavalta 
07	(7)	sverige 
FF	(255)	turkiye 
FF	(255)	ukrayina 
02	(2)	united kingdom 

Очевидно: для стран с одинаковыми значениями unk общее — официальный язык, значение FF — для отсутствующего в списке языков. То, что в rus карте для стран, имеющих валидные коды в официальных картах, равны FF, можно объяснить свежестью официальных карт. Видимо, эти языки были добавлены позже. Список значений взят из какой-то стандартов?

Но ни в одном из найденных вариантов кодирования языков сочетаний найденных конкретных чисел конкретным странам не встречалось. ISO_3166 трёхсимвольный, CLDR — нет, IETF — нет, country codes — нет.

Нет, нет и нет. Единственное, что смог найти с этими значениями кодов языка у стран, — учебный пример в книге Relational Database Programming: A Set-Oriented Approach, Таблица 5–2 содержит начало составленного по вышеприведенным данным перечисления кодов языков, сводной информации по трём carindb enum en_LANG. Его добавляю в inc_common.bt, и unk заменяю типом этого перечисления en_LANG en_lang ; .

//en_LANG
typedef enum {
typedef enum {
	_Nederlands =   1,		//01 (1) 	 nederland, belgie - Dutch 
	_English    =   2,  	//02 (2) 	 united kingdom, eire
	_French     =   3,  	//03 (3) 	 france, luxembourg
	_Deutch     =   4,  	//04 (4) 	 deutschland oesterreich osterreich schweiz
	_Italian    =   5,  	//05 (5) 	 italia
	_Hispain    =   6,  	//06 (6) 	 espana
	_Svedian    =   7,  	//07 (7) 	 sverige
	__unk_08	=	8,
	__unk_09	=	9,
	_Danian 	=   0xA, 	//0A (10) 	 danmark
	_Catalan 	=   0xB, 	//0B (11) 	 andorra
	_Finnish    =   0xC, 	//0C (12) 	 suomen tasavalta
	__unk_0d	=	0xd,
	_Norvegian  =   0xE, 	//0E (14) 	 norge    
	_Portugal   =   0xF, 	//0F (15) 	 portugal  
	__unk_10	=	0x10,
	__eng_TOO   =   0x11,
	_Polish     =   0x12, 	//12 (18) 	 polska
	_Czech      =   0x13, 	//13 (19) 	 ceska republika
	_Slovak     =   0x14, 	//14 (20) 	 slovenska republika
	_Croatian	=	0x1A,	//1A (26) 	 hrvatska
	_Latvian	=	0x1B,	//1B (27) 	 latvija
	_Lithuanian	=	0x18,	//18 (24) 	 lietuva
	_Slovene	=	0x17,	//17 (23) 	 slovenija
	_UNK_lng  = 0xFF
}en_LANG;  

В структуре BL_0xA структуру try_data переименовываю в brief_geo, и смотрю на следующую, на которую указывает LIST pl_moreinfo, и начала которых PTR p_moreinfo из brief_geo уже раскрасили голубеньким фоном, что задаёт размер каждого элемента 0×38 байт.

  • Значение '00000506' в начале каждого элемента похоже на BL_ADDR

  • Далее 4 байта, вероятно LISTы, адресующие в BL_ADDR.

  • Затем 4 константы 32 битная со значениями Bh, 16h, 21h, 2Ch, или если десятичные, 11,22,33,44.

  • Вероятно LIST, адресующий дальше в блоке что-то.

  • Константа hex01f4012c / dec32768300 / bin01111101000000000100101100

  • Константа hex03e801f4 / dec65536500 / bin11111010000000000111110100

  • Константа 32 битная, равная 1.

  • Непонятное 16 битное значение, надо ближе посмотреть, что это может быть

  • Константа 32 битная, равная 0.

  • Строка 0-ended кода страны по ISO_3166–1

  • Константа 8 битная, равная 0.

  • Строка-константа zero-ended, равная '---'

  • Константа 16 битная, равная 0.

Размер каждого элемента немаленький, но множество констант с непонятной информационной наполненностью. Вот для чего в каждом элементе хранить значения 32768300 или 65536500? Что они могут значить? Что значат 32768 или 65536, это понятно — 2 в 15 и 16 степени. Но 300 и 500, что за этим? Загадка.

Кирпичик FAR_LIST moooooooooooooooooooo

Назову сочетание последовательно идущих BL_ADDR и LIST, как FAR_LIST, ссылка на далёкий, не в этом блоке список-массив. Размер данных 64 бита, расцветка BL_ADDR обычная, а у половины LIST, у cnt фон оранжевый, чуть другого оттенка, чем BL_ADDR, bgcolor=0×22BFFF.

typedef struct{
    BL_ADDR far_block; // link to block type 0xd
local ushort size = far_block.size * 0x800;
local uint offset = far_block.offset;
    LIST    pl_data ;  // far pointer list, BL_ADDR+LIST
}FAR_LIST ;
string Read_FAR_LIST (FAR_LIST &a){
    local string s;
    SPrintf( s, "%04X+%02X=%04X cnt=%i(%02Xh); %s", 
            a.far_block.offset, a.pl_data.ptr.ptr, a.pl_data.offset,
            a.pl_data.cnt, a.pl_data.cnt,
            Read_BL_ADDR(a.far_block));
    return s;
}

Вернусь к блоку 0xA, описав массив структур по вышеописанным данным.

    struct{
        local ushort size 

Применяю к carindb_bnl — все отлично, к carindb_ee уже не так здорово — в некоторых местах красные несоответствия константы CONST_I const_1(1), у некоторых записей не 1, а 0.
Темплейт раскрашивает carindb_rus, как граната курятник.

image-loader.svg

  • В русском варианте карты элемент more_info меньше, чем в «официальных» на 12 байт. Необходимо отыскать признак, позволяющий однозначно отличить «официальный» вариант от «русского». Не знаю, как навигатор на самом деле определяет, где какой, но байт с абсолютным смещением 0×2e в официальных картах равен 1, а в неофициальной русской — 2. В самом начале инклюд-файла inc_common.bt добавляю определение локальной переменной, область видимости которой при таком расположении будет «везде».

// only here i find different between 0A addinfo fields count
// 1 - new, 2 - old, non-crypted, not-compressed
local ubyte IS_OFICIAL_MAP = ( ReadUShort(0x2e) == 1);
  • Красными стрелками на скрине флуктуации CONST_I const_1(1);. Разбиваю 32 битную константу на 2 CONST_S const_a_0(0) и const_b_0(0). Уже понятно, что это не константа, принимает не только значения 0, но оставляю тип, чтобы попытаться понять — в каких случаях какое значение.

  • Элементы массива more_info[pl_all_moreinfo.cnt] адресуются из предыдущего блока brief_geo (PTR p_moreinfo). Структуру more_info копирую, как typedef структуры MORE_INFO_0xA, и добавляю в brief_geo определение переменной с этим типом. В консоль вывожу переменную unk_1, подсвеченную желтым фоном, строку названия и наименование в enum кода языка.

typedef struct{
    local ushort size 

image-loader.svg

  • Значения unk_1 и в русской, и в официальных картах равны у соответствующих стран.

  • Увеличение номера, похоже, связано с алфавитным порядком, если сортировать по алфавиту английские названия стран, а не строки из карт. Осталось только нагуглить — есть ли в природе такой список, где Албания (shqiperia) unk_1 = 2, а Андорра (andorra) unk_1 = 5, Австрия (oesterreich) — 14, Азербайджан — 15. И ведь есть, удовлетворяющий условию: World Countries List, однако Но условия ставить надо чётче: где-то после Боснии и Герцеговины (27) нумерация сбивается, и порядковый номер Болгарии 31, а не 33, как в carindb. Но если ввести поправку -2, то до Латвии страны из carindb соответствуют, затем менять коэффициент на +1, и снова, и снова (у Македонии он аж 33), на скрине выделил желтым. Самая последняя страна, 241 'srbija i crna gora' или 'Serbia and Montenegro' в современном списке nationsonline отсуствует (и с чего бы?).

    image-loader.svg

Очевидно, первоначальный список захардкожен значениями в прошивки. И это явно коды английских наименований, которые, в отличие от местных, на CD отсутствуют. Архитекторы не подумали о том, что география изменится, а потом ради совместимости с ранее выпущенными картами изменить нумерацию стало невозможно.

Жаль, планировал сделать полный enum список стран, в том числе и тех, которые не представлены на моих CD.

Сделаю сокращенный, взяв страны, которые были на анализируемых 3х CD.

//en_ENG_COUNTRY_NAME
typedef enum {
    Albania	=	2,
    Andorra	=	5,
    Austria	=	14,
    Azerbaijan	=	15,
    Belarus	=	20,
    Belgium	=	21,
    Bosnia_and_Herzegovina	=	27,
    Bulgaria	=	33,
    Croatia	=	53,
    Cyprus	=	55,
    Czech_Republic	=	56,
    Denmark	=	57,
    Estonia	=	67,
    Finland	=	72,
    France	=	73,
    Georgia	=	80,
    Germany	=	81,
    Greece	=	84,
    Hungary	=	97,
    Iceland	=	98,
    Ireland	=	103,
    Italy	=	105,
    Latvia	=	117,
    Lithuania	=	123,
    Luxembourg	=	124,
    North_Macedonia	=	126,
    Moldova_Republic_of	=	140,
    Netherlands	=	150,
    Norway	=	160,
    Poland	=	171,
    Portugal	=	172,
    Romania	=	176,
    Russian_Federation	=	177,
    Slovakia_Slovak_Republic	=	190,
    Slovenia	=	191,
    Spain	=	196,
    Sweden	=	204,
    Switzerland	=	205,
    Turkey	=	216,
    Ukraine	=	221,
    United_Kingdom	=	223,
    Serbia_and_Montenegro	=	241
}en_ENG_COUNTRY_NAME  ;

Острова и союз

В MORE_INFO_0xA пара CONST_S, которые вовсе не константы: const_a_0(0) и const_b_0(0), собираю все варианты значений, сопоставленные странам, сортирую.

image-loader.svg

Желтым выделены Ирландия, Кипр и Великобритания, у которых const_a_0(0) становится = 1. Больше островов в списке нет, ushort is_island.

Зеленым выделены страны, у которых const_b_0(0) = 1. Вот нет Великобритании, Швеции, но есть Швейцария… А так был бы [список стран ЕС]https://ru.wikipedia.org/wiki/Государства_—_члены_Европейского_союза). Впрочем, спишу на разногодность карт, и назову переменную ushort is_EU. Если примут значения не 1 и не 0 — лог, красное, как обычно.

Ссылка (и) на города (и сёла) страны

image-loader.svg

Осталась нераспознанной часть данных между more_info и строковыми значениями. Начало этого блока указывает LIST в заголовке BT_0×0A с именем pl_all_addinfo. На элементы этого раздела ссылается LIST pl_addinfo в структуре MORE_INFO_0xA.

  • В carindb_rus каждый элемент more_info ссылается на единственный элемент pl_all_addinfo, в LIST pl_all_addinfo.cnt=2Ah, LIST pl_all_moreinfo.cnt=2A. Это видно на скриншоте — через каждые 12 байт — голубое пятнышко следа от more_info.pl_addinfo.

  • В carindb_bnl значений этой непознанной структуры не 3, как можно было бы ожидать по аналогии с русской картой, а 23. Из Бельгии просят 8 значений, из Люксембурга 7, из Голлании — опять 8.

  • первые 8 байт неизвестной структуры — FAR_ADDR, 2 байта — непонятно, последние 2 — ссылка на начало строк.

    struct{
		local string char_list="";
        FAR_LIST ch_idx;
        ushort   unkn ;
        PSTR     const_str_begin;
        Printf("%X \t%i\n", unkn, unkn);
    }addinfo[pl_all_addinfo.cnt + 1] ;
  • В carindb_rus все unkn = 30h. То есть запрашивается единственный список индексов символов.

  • Между последним элементов pl_all_addinfo и началом строк — «пустота» размером 12 байт, оканчивающаяся PTR на начало строк, как и у остальных элементов, прибавить к массиву addinfo дополнительный элемент.

  • В carindb_bnl по more_info.pl_addinfo для Бельгии, Люксембурга и Голландии соответственно unkn {14 20 25 26 27 34 35 3a}, {14 20 25 26 27 34 3a } и {14 20 25 26 27 34 35 3a}. В разных элементах — разные FAR_ADDR, могут совпадать адреса блоков, но индексы символов из них запрашиваются с разных смещений и в разном количестве. unkn — размер города? Статус — столица, районный центр? Может, географические места, не только города, но и реки или холмы, места? Названия по-разному для разных системных языков, не, там шесть вариантов. Разные масштабы карты? Необходимы дополнительные исследования — получать тип блоков и список ch, на которые ссылается LIST.

    image-loader.svg

А це пiд помидоры: жадные структуры

В исследовании для максимизации получаемой информации у меня многие структуры излишне жадные. Проверка каждой константы, что она в этом месте константа, для BL_ADDR прочитывается и запоминается рядом лежащий тип, в Value значений выводится не только та информация, которая в данных самой структуры, но и расчетная, и прочитанные связные со стороны. Для боевых решений — совершенно вредный подход. Но для реверса не просто приемлемый, а крайне полезный.

Важно при этом не увлекаться. В прошлой статье в структуре, описывающей блок типа struct BT_0×0B_0×0D_0×0F_0×11, показалась хорошей идея использовать рекурсивную структуру. Это может быть ошибочным решением — на больших файлах, которые появляются глубже, 010Editor ложится, т.к. цепочки получаются чрезмерно глубокими.
И понятно, что реальный автонавигатор оперирует гораздо более простыми структурами данных, хотя по информационному наполнению и последовательности чтения они близки к рассматриваемым.

Рефакторинг BT_0×0B_0×0D_0×0F_0×11

Пара функций

  • string getChList(LIST &ch_idx) формирует и возвращает строку из char, расположенных через 12 байт — размер данных BT_0×0B_0×0D_0×0F_0×11 — по начальному адресу и в количестве входного параметра LIST.

  • string getPStrList(uint base_offset, LIST &brif_idx, uchar max_result) собирает строку из строк, ссылки на которые расположены через 8 байт от начального адреса brif_idx, в количестве brif_idx.cnt, но не более max_result

//parameter - LIST CH_IDX,  return - string
string getChList(LIST &ch_idx){
    local string s;
    local uint i; //cnt
    for(i=ch_idx.offset+4;          // ch absolute addr  
        i<(ch_idx.offset + 4 +ch_idx.cnt * 12); // LIST end, 12=sizeof(CH_IDX)
        i+= 12){                   // 12 = sizeof(CH_IDX)
            SPrintf(s,"%s %c", s, ReadByte(i)); //ch = ReadByte(i);
    }
    return s;
}
//parameter - far block begin, LIST BRIEF_GEO,  return - string OF STRINGS
string getPStrList(uint base_offset, LIST &brif_idx,  uchar max_result){
    local string s, res;
    local uint offset_str , tu< format=hex>;
    local uint i, max;   //cnt
    max = (brif_idx.cnt > max_result)? max_result: brif_idx.cnt;
    for(i=brif_idx.offset;             // ch absolute addr  
        i<(brif_idx.offset + max * 8); // 8=sizeof(BRIEF_GEO)
        i+= 8){ 
			ReadString( ReadUShort(i) + base_offset ) sometimes work strange
            offset_str = ReadUShort(i);
            offset_str += base_offset;
            s = ReadString(offset_str); // 
            SPrintf(res,"%s, %s", res, s);
    }
    return res;
}

Добавляю в enum типов блоков новые значения


// Block types enum ------------------------------------------
typedef enum {
    ABSTRACT    = 12h,
    CH_country  = 0Bh,  //fully parsed
    COUNTRY     = 0Ah,  // -- block0xA.addinfo.unknown   rus = 30h
    CH_idx_d    = 0Dh,  //fully parsed

    CH_idx_f    = 0Fh,  //fully parsed

    CH_idx_11   = 11h,  //fully parsed
    Invalid  = 0xFF
}en_BL_TYPE ;

Рефакторю темплейт индексов букв BT_0×0B_0×0D_0×0F_0×11 — в блоке только массив CH_IDX, каждый из которых в колонке Value выводит (Read_CH_IDX) строковое значение, полученное вышеописанными новыми функциями — список строк-названий из блока в который идет адресация (с адресом и типом блока-цели), или список символов-детей.

//{BT_0x0B_0x0D_0x0F_0x11;
//{CH_IDX
struct CH_IDX;
typedef struct{
    BL_ADDR   bl_postaddr;
    char      ch ; // char
    local     en_BL_TYPE en_curr_bl_type = head.type; // current bl type
    // is_ptr_out - boolean
    if(bl_postaddr.type == (en_curr_bl_type-1) ){ // outer link
        ubyte is_ptr_out ;
    }else{                                          // innler link
        ubyte is_ptr_out ;
    }
    // next for LIST far_away, have use size and offset - from bl_type_0c
    local uint size   

Применяю на двух первых попавшихся блоках 0xB и 0xD.

image-loader.svg

Содержимое блоков индексов букв почтовых адресов в интерфейсе отображает строковые наименования адресов, адресуемое количество, адрес блока и его тип, если ссылка элемента ведёт наружу.
Если элемент адресуется внутрь, на следующий за буквой список букв — то создаётся рекурсивный тип CH_IDX childs, в интерфейсе исследуемый точно так же. Естественно, у него тоже могут быть дети — пока не дойдёт до списка, ведущего «наружу».

Рефакторинг BT_0×0A

Подобным образом реорганизую полученные элементы BT_0×0A. Идеология: блоке есть главный массив информации типа BRIF_0xA, адресуемый самым первым в заголовке LIST pl_all_data.

Описание этой структуры содержит объявления адресуемых структур MORE_INFO_0xA, внутри которых, в свою очередь, адресуются соответствующие им ADDINFO_0xA. Каждая из структур выводит основные значение в интерфейс 010, в Values:

  • BRIF_0xA: английское и локальное наименование страны, официальный язык.

  • MORE_INFO_0xA: английское название, двухбуквенный код по ISO3166_1 (если есть), принадлежность к ЕС (EU, если да), остров (если это остров), и количество элементов ADDINFO_0xA

  • ADDINFO_0xA: значение с неизвестным назначением , количество элементов адресуемого, и, раз известно, что адресуются элементы типа CH_IDX, список символов через функцию getChList. Аттрибутивная функция comment=Comment_ADDINFO_0xA создаёт в колонке Comment вкладки Variables вызов функции block для копипаста в темплейт и возможности исследования

//{BT_0x0A

//ADDINFO_0xA - additional data - part of MORE_INFO_0xA 
typedef struct{
    FAR_LIST ch_idx;
    ushort   unkn ;
    PSTR     const_str_begin;  
}ADDINFO_0xA ;
string Read_ADDINFO_0xA(ADDINFO_0xA &a){
    local string s;
    SPrintf(s, "%X -[%i] %08X t(%02X)> %s\n", a.unkn, 
        a.ch_idx.pl_data.cnt, a.ch_idx.far_block.raw,
        a.ch_idx.far_block.type,
        getChList(a.ch_idx.pl_data) );
    return s;
}
string Comment_ADDINFO_0xA(ADDINFO_0xA &a){
    local string s;
    SPrintf(s, "block(0x%04X); // comment ADDINFO_0xA", a.ch_idx.far_block.offset);
    return s;
}
//}ADDINFO_0xA

//MORE_INFO_0xA; - call from BRIF_0xA
typedef struct{
    local ushort size 

image-loader.svg

  • ADDINFO_0xA отсылает к типу 0×11 (индексы букс POI), хотя мне ожидалось, что это будет 0xD (индексы букв городов), судя по следованию типов в файле и логике.

  • В русском варианте у MORE_INFO_0xA по одному ADDINFO_0xA, и тип его 0×30

  • В официальных картах количество MORE_INFO_0xA от 4 до 10.

  • Получили возможность, описав в темплейте блок из комментария ADDINFO_0xA, и кликнув по MORE_INFO_0xA.FAR_LIST.PTR.here — посмотреть строковые значения, на которые оттуда ссылаются: блок описан, если в окне hex нажать +, вкладка Variables сфокусируется на элементе темплейта CH_IDX char_of.

    image-loader.svg

Для Бельгии:

  • 14 -[7] 0045D708 t(11)> a d g l m t z — в блоке 0045D708 ссылается на строки: a [1]>004A5508 10()>, atomium, d - d [2]>004A5508 10()>, dierenpark planckendael, domaine des grottes de han ; g [2]>004A5508 10()>, grand hornu, grottes de han; g [2]>004A5508 10()>, grand hornu, grottes de han; m [1]>004A5508 10()>, manneken pis; t [1]>004A5508 10()>, trois bornes; z [1]>004A5508 10()>, zoo antwerpen Достопримечательности страны.

  • 20 -[3] 0045D708 t(11)> c k m в блоке 0045D708: c [1]>004A5508 10()>, centre historique de bastogne; k [3]>004A5508 10()>, koninklijk legermuseum, koninklijk museum voor midden afrik, koninklijke musea v. schone kunsten; m [9]>004A5508 10()>, musee d'art et d'histoire, musee d'art moderne, musee de l'armee, musee des sciences naturelles, musee royal d'afrique centrale 2 Музеи.

  • 25 -[9] 0045D708 t(11)> b c g j k l o p s в блоке 0045D708: b [4]>004A5508 10()>, basiliek van het heilig hart, basilique du sacre coeur, belfort, butte du lion; c [2]>004A5508 10()>, cathedrale notre dame de tournai, chateau de laeken; g [2]>004A5508 10()>, grand place, grote markt; j [1]>004A5508 10()>, justitiepaleis; k [2]>004A5508 10()>, kasteel van laken, koninklijk paleis; l [2]>004A5508 10()>, l'abbaye de villers la ville, la collegiale sainte gertrude; o [2]>004A5508 10()>, onze lieve vrouwebasiliek, onze lieve vrouwekathedraal; p [2]>004A5508 10()>, palais de justice, palais royal; s [1]>004A5508 10()>, stadhuis leuven . Исторические, памятники архитектуры.

  • 26 -[4] 0045D708 t(11)> b p t w в блоке 0045D708: b [4]>004A5508 10()>, bellewaerde park, bobbejaanland, boudewijn seapark, bruparck; p [4]>004A5508 10()>, pairi daiza, parc d'aventures scientifiques, plopsa coo, plopsaland; t [1]>004A5508 10()>, technopolis; w [1]>004A5508 10()>, walibi belgium Парки развлечений.

  • 27 -[4] 0045D708 t(11)> h n p s в блоке 0045D708: h [1]>004A5508 10()>, het zwin; n [1]>004A5508 10()>, nationale plantentuin; p [1]>004A5508 10()>, parc naturel des hautes fagnes; s [1]>004A5508 10()>, signal de botrange

  • 34 -[4] 0045D708 t(11)> a b c l в блоке 0045D708: a [2]>004A5508 10()>, aeroport charleroi bruxelles sud, aeroport de charleroi gosselies; b [3]>004A5508 10()>, bru, brussel nationaal, brussels airport; c [1]>004A5508 10()>, crl; l [1]>004A5508 10()>, luchthaven brussel Аэропорты

  • 35 -[2] 0045D708 t(11)> o z в блоке 0045D708: o [1]>004A5508 10()>, oostende ramsgate; z [1]>004A5508 10()>, zeebrugge Порт (Но Антверпена нет? Паром?

  • 3A -[15] 0045D708 t(11)> a b c d e h k m n p q s t v z в блоке 0045D708: a [7]>004A5508 10()>, abele n38 frankrijk, antwerpen a12 nederland 1, arendonk e34 nederland, arlon a28 france, arlon e411 luxembourg; b [8]>004A5508 10()>, baarle hertog chaamseweg nederland, baarle hertog turnhoutsew nederland, bastogne n84 luxembourg, beauraing n40 france, berneau n627 nederland; c [2]>004A5508 10()>, chimay france, couvin n5 france; d [1]>004A5508 10()>, dinant n96 france; e [5]>004A5508 10()>, erquelinnes n54 france, essen n117 nederland, estaimpuis n511 france, eupen e40 deutschland, eynatten n68 deutschland; h [1]>004A5508 10()>, hoogstraten e19 nederland; k [3]>004A5508 10()>, kelmis n3 deutschland, kinrooi n78 nederland, knokke n376 nederland; m [7]>004A5508 10()>, maaseik n761 nederland, maasmechelen e314 nederland, maldegem n410 nederland, martelange n4 luxembourg, moelingen e25 nederland; n [1]>004A5508 10()>, neerpelt n74 nederland; p [2]>004A5508 10()>, paal n403 nederland, philippeville n40 france; q [1]>004A5508 10()>, quevry le grand n6 france; s [2]>004A5508 10()>, sankt vith e42 deutschland, st. vith e421 luxembourg; t [4]>004A5508 10()>, tongeren n79 nederland, tournai e42 france, turnhout n119 nederland, turnhout n12 nederland; v [4]>004A5508 10()>, veldwezelt n2 nederland, veurne e40 frankrijk, vielsalm n68 luxembourg, virton n87 france; z [1]>004A5508 10()>, zelzate n423 nederland Пограничные переходы?

  • Заворачиваю свои догадки в enum:

typedef enum {
	Sites_of_interest = 0x14,
	Museum	= 0x20,	//musee d'art moderne, musee de l'armee, musee des sciences Naturelles
	Architecture = 0x25,	//
	Fun_ park = 0x26,	//boudewijn seapark, bruparck
	Nature_park = 0x27,	//het zwin, nationale plantentuin
	City	= 0x30,	//russian map
	Aeroport	= 0x3a,	//brussel nationaal, brussels airport; , luchthaven brussel
	// 0x35  // oostende ramsgate (tonnel), zeebrugge (port), need mode exmpls
	Border_point = 0x34 //
}en_PLACE_CATEGORY	

В carindb_bnl пока неясна категория 0×35. Чуть правлю атрибутивный Read_ADDINFO_0xA — добавляю вывод строкового значения нового enum, и добавляю вывод абсолютного адреса начала списка.

image-loader.svg

На закладке Variables копипащу (35) -[4] 0045D708 of:022EBD7C ty(11)> e h i r. Перехожу по адресу в hex окне: выделить 022EBD7C, +, клик на hex окне, +

+ — и в окне Variables фокус автоматически переходит на конкретный элемент массива, описанного в темплейте.

image-loader.svg

e [2]>004A5D08 10()>, eemshaven, europoort hull
h [2]>004A5D08 10()>, hoek van holland harwich, hoek van holland stena line
i [2]>004A5D08 10()>, ijmuiden felison terminal, ijmuiden newcastle
r [1]>004A5D08 10()>, rotterdam europoort

Понятно, значит, категория Seaport = 0×35 в en_PLACE_CATEGORY.
Файл carindb_ee дает пару новых значений категорий:
Sport = 0x23, //automotodrom brno, o2 arena, ski areal jasna, o2 arena
И 0×28 с единственным представителем h [2]>015A6408 10()>, hala ludowa, hala stulecia. Объект — понятен, это «Зал Столетия» или Народный зал (польск. Hala Stulecia, Hala Ludowa) во Вроцлаве. Но какую категорию он представляет?
UNESCO World Heritage Site? Автор назначение характеризовал, как «structure to host «exhibitions, concerts, theatrical and opera performances, and sporting events)»

Резюме

  • Структуры CONST_B, CONST_S, CONST_I — константы с инициализирующим параметром — ожидаемым значением

  • Структура PSTR — указатель PTR на строку, оканчивающуюся нолем

  • Структура FAR_LIST — указатель-счетчик на массив в дальнем блоке

  • Перечисление en_LANG — коды разговорных языков

  • Глобальный local ubyte IS_OFICIAL_MAP = ( ReadUShort(0x2e) == 1); — вид файла, официальный, или carindb_rus

  • На кончике пера описано перечисление en_ENG_COUNTRY_NAME

  • Гипотеза о информации принадлежности страны к Евросоюзу, и признак того, что страна — островная.

  • Блок описания страны содержит ссылки на категории POI, points of interests, буквенные индексы блоки типа 11h, но не содержат ссылок на города, относящиеся к стране.

  • На кончике пера — en_PLACE_CATEGORY, типы POI

  • Рефакторинг BT_0×0B_0×0D_0×0F_0×11 — полностью описаны данные и их назначение

  • Полностью распарсен, в т.ч. и семантически блок 0×0A — информация о странах. То есть вообще весь, до последнего байта.

Дальнейший анализ — в следующей статье.

© Habrahabr.ru