我遇到了一些用于汽车卫星导航系统的文件。在十六进制编辑器中查看文件会显示‰PNG
签名,但块不遵循格式规范 - 例如:
偏移量(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00000000 05 00 10 00 43 50 52 4E 41 56 5F 32 36 02 00 00 ....CPRNAV_26... 00000010 03 00 01 00 1C 00 00 00 08 01 00 00 4B 00 CA 3D ...............K.Ê= 00000020 FC 06 35 54 38 25 56 C8 1F 50 E9 06 04 58 85 5E ü.5T8%VÈ.Pé..X…^ 00000030 8C 91 E1 AD 84 DF 60 49 FC 01 61 FF 47 A9 D5 6A Œ'á.„ß`Iü.aÿG©Õj 00000040 B5 B2 06 48 65 0D D0 FA BE C3 D3 0E A1 EF 3B BC µ².He.Ðú¾ÃÓ.¡ï;¼ 00000050 EF F0 BE C3 73 0E A1 EF 3B BC EF F0 BE C3 73 0E ïð¾Ãs.¡ï;¼ïð¾Ãs. 00000060 A1 DB E1 0F 58 E4 3E 89 50 4E 47 0D 0A 0A 1A 00¡Ûá.Xä> ‰PNG ....。// PNG 从这里开始 00000070 00 00 0D 49 48 44 52 F0 E0 08 02 B2 E1 7C 5E 00 .. .IHDR ðà..²á|^. // IHDR 块表示为 13 (0x0D) 个字节,但显然不是这种情况 00000080 01 73 52 47 42 00 AE CE 1C E9 06 62 4B 47 44 00 .sRGB.®Î.é.bKGD。 00000090 FF A0 BD A7 93 09 70 48 59 73 0B 11 01 7F 64 5F ÿ ½§“.pHYs....d_ 000000A0 91 07 74 49 4D 45 07 E0 02 18 07 12 13 CC F8 BA '.tIME.à.....Ìøº 000000B0 BA B6 49 44 41 54 78 DA ED D2 C1 0D 04 00 31 C4 º¶IDATxÚíÒÁ...1Ä 000000C0 FE 2B 33 83 AF B4 23 5C 2E A7 27 E0 8B 92 00 43 þ+3ƒ¯´#\.§'à‹'.C 000000D0 83 A1 C1 D0 60 68 0C 0D 86 06 43 83 A1 C1 D0 18 ƒ¡Ð`h..†.Cƒ¡Ð. 000000E0 1A 0C 0D 86 06 31 34 18 1A 63 68 30 34 C6 30 8D ...†.14..ch04Æ0。 000000F0 60 86 AB 05 8F 4F 03 C2 58 19 85 B6 00 49 45 4E `†«..O.ÂX....¶.IEN 00000100 44 AE 42 60 82 00 00 00 D®B`‚...
正如你所看到的,几个标准PNG块名称是否存在(sRGB
,bKGD
,IDAT
等),但它们之间的数据似乎被压缩/加密。
到目前为止我的观察:
- bytes
0x14-17
似乎是一个 DWORD,指示自定义标头大小(0x1C
或 28 个字节) - 字节
0x1C-1D
似乎是一个字,指示它们之间的数据大小与实际 PNG 标头开始的位置(0x4B00
或 75 个字节,包括 2 个大小字节)-这可能是压缩数据表/字典 - 文件与 4 字节块对齐
0x00
- 在2196个压缩PNG文件的,正好一半具有相同的
IHDR
数据:F0 E0 08 02 B2 E1 7C 5E 00 01
; 另一半有01 90 88 08 02 E0 58 21 6D
- 类似地,文件的压缩数据的半/词典开始以相同的22个字节:
FC 06 31 46 85 53 68 85 84 F9 95 6E 40 80 55 E8 C5 18 19 DE 4A F8
; 另一半开始于FC 06 35 54 38 25 56 C8 1F 50 E9 06 04 58 85 5E 8C 91 E1 AD 84
- 注意每个文件是如何开始的FC 03 3x xx
更新 2:我已经创建了一个GitHub 存储库,其中包含迄今为止的进展,供任何愿意查看的人使用。
更新 1:在挖掘之后,我设法找到了包含符号的固件副本(可在此处获得:https : //www.mediafire.com/file/a0u7k2m87aj1jp6/Files.zip/file),我是很确定我已经找到了解压缩文件的正确函数:cpr_tclDecompressAlgorithm::bDecompressData
.
不幸的是,我无法充分理解它,但我可以从符号中看到:
- 解压方法中使用了几个自定义结构,
cpr_tclCodeTable
并且cpr_tclCodeTableEntry
- 该结构然后与调用的方法使用
cpr_tclCodeTable::iu32SearchIndexOfCode
和cpr_tclCodeTable::corfoGetCodeEntry
- 解压开始调用
cpr_tclDecompressAlgorithm::u32GetNextBits
读取 32 位 / 4 字节 - from 的返回值
u32GetNextBits
与& 3
右移 2 位一起使用,这表示前两位用作某种标志
我将在下面发布该函数的 IDA 伪代码,但我不希望任何人在此上花费大量时间 - 我只是想知道是否有人可以识别这里发生的事情,例如 Huffman、LZSS 等。
int __fastcall cpr_tclDecompressAlgorithm::bDecompressData(int a1, int a2, int a3, size_t a4, unsigned int a5, int a6)
{
int v7; // r8
unsigned int v10; // r5
int v11; // r9
void *v12; // r0
unsigned int v13; // r8
unsigned int v14; // r0
const cpr_tclCodeTable *CodeTable; // r11
unsigned int v16; // r6
unsigned int v17; // r7
unsigned int v18; // r0
int v19; // r0
int v20; // r2
int v21; // r3
int v22; // r5
int v23; // r0
int v24; // r7
unsigned int v25; // r1
int v26; // r3
_BYTE *v27; // r0
size_t v28; // r6
__int16 v29; // r12
int v30; // r2
int v31; // r5
int v32; // r0
unsigned int v33; // r10
int v34; // r3
_BYTE *v35; // r1
int v36; // r0
unsigned int v37; // r12
int v38; // r3
void *v39; // r0
size_t v40; // r5
int v41; // r2
int result; // r0
int v43; // r3
int v44; // r2
_BYTE *v45; // r2
int v46; // r0
int v47; // r3
_BOOL4 v48; // r3
int v49; // r0
*(_DWORD *)(a1 + 16) = a4;
v7 = a2 & 3;
*(_DWORD *)(a1 + 12) = a3;
*(_DWORD *)(a1 + 4) = a2;
*(_DWORD *)(a1 + 8) = a2;
if ( (a2 & 3) != 0 )
{
v49 = trc_szGetFileName(
"/opt/bosch/DI_SWNAVI_13.2C5P10/di_swnavi/components/dapi/devicemanager/devicehandler/compression/cpr_decompression.cpp");
trc_tclGlobalTrace::vTraceLevel1(21504, 332, v49, "CPR read access to unaligned adress 0x%x", a2);
return 0;
}
cpr_tclDecompressAlgorithm::vInterpreteHeader((cpr_tclDecompressAlgorithm *)a1, a5);
v10 = a5 - *(_DWORD *)(a1 + 48);
if ( a4 < a5 )
{
if ( a4 <= v10 )
{
*(_DWORD *)(a1 + 48) = v7;
v10 = a4;
v11 = 1;
goto LABEL_7;
}
*(_DWORD *)(a1 + 48) = a4 - v10;
}
v11 = v7;
LABEL_7:
v12 = *(void **)(a1 + 12);
v13 = (unsigned int)v12 + v10;
if ( !v10 )
goto LABEL_34;
if ( a6 == 3 )
{
v14 = cpr_tclDecompressAlgorithm::u32GetNextBits((cpr_tclDecompressAlgorithm *)a1, 0x20u);
CodeTable = (const cpr_tclCodeTable *)(*(_DWORD *)a1 + 44 * (v14 & 3));
v16 = v14 >> 2;
v17 = 2;
cpr_tclDecompressAlgorithm::vInit((cpr_tclDecompressAlgorithm *)a1, CodeTable);
while ( 1 )
{
while ( 1 )
{
if ( *(_DWORD *)(a1 + 12) >= v13 )
goto LABEL_34;
v18 = cpr_tclCodeTable::iu32SearchIndexOfCode(CodeTable, v16);
v19 = cpr_tclCodeTable::corfoGetCodeEntry(CodeTable, v18);
v20 = *(_DWORD *)(v19 + 12);
v21 = *(unsigned __int8 *)(v19 + 16);
v22 = v19;
v17 += v21;
v16 >>= v21;
if ( v20 != 3 )
break;
v23 = cpr_tclDecompressAlgorithm::u32GetNextBits((cpr_tclDecompressAlgorithm *)a1, v17);
v24 = *(unsigned __int8 *)(v22 + 17);
v25 = v23 | v16;
v26 = (v23 | v16) & ~(-1 << v24);
v27 = *(_BYTE **)(a1 + 12);
v28 = (unsigned __int16)(v26 + *(_WORD *)(v22 + 2));
v29 = *(_WORD *)(v22 + 6);
v30 = *(_DWORD *)(a1 + 44);
v31 = *(unsigned __int8 *)(v22 + 18);
if ( v13 < (unsigned int)&v27[v28] )
{
if ( v11 != 1 )
{
v32 = trc_szGetFileName(
"/opt/bosch/DI_SWNAVI_13.2C5P10/di_swnavi/components/dapi/devicemanager/devicehandler/compression/cpr"
"_decompression.cpp");
trc_tclGlobalTrace::vTraceLevel1(
21504,
253,
v32,
"CPR Overwrite Copy n=%d wpos=0x%x epos=0x%x",
v28,
*(_DWORD *)(a1 + 12),
v13);
LABEL_24:
result = 0;
goto LABEL_35;
}
v28 = (unsigned __int16)(v13 - (_WORD)v27);
}
v33 = v25 >> v24;
v34 = -(unsigned __int16)(v29 + (((v25 >> v24) & ~(-1 << v31)) << v30));
v35 = &v27[-(unsigned __int16)(v29 + (((v25 >> v24) & ~(-1 << v31)) << v30))];
if ( v28 == 2 )
{
*v27 = v27[v34];
*(_BYTE *)(*(_DWORD *)(a1 + 12) + 1) = v35[1];
}
else
{
memcpy(v27, v35, v28);
}
v17 = v31 + v24;
*(_DWORD *)(a1 + 12) += v28;
v16 = v33 >> v31;
}
if ( v20 == 2 )
{
v36 = cpr_tclDecompressAlgorithm::u32GetNextBits((cpr_tclDecompressAlgorithm *)a1, v17);
v17 = *(unsigned __int8 *)(v22 + 17);
v37 = v36 | v16;
v38 = (v36 | v16) & ~(-1 << v17);
v39 = *(void **)(a1 + 12);
v40 = (unsigned __int16)(v38 + *(_WORD *)(v22 + 2));
if ( v13 < (unsigned int)v39 + v40 )
{
if ( v11 != 1 )
{
v41 = trc_szGetFileName(
"/opt/bosch/DI_SWNAVI_13.2C5P10/di_swnavi/components/dapi/devicemanager/devicehandler/compression/cpr"
"_decompression.cpp");
trc_tclGlobalTrace::vTraceLevel1(
21504,
291,
v41,
"CPR Overwrite Lit n=%d wpos=0x%x epos=0x%x",
v40,
*(_DWORD *)(a1 + 12),
v13);
goto LABEL_24;
}
v40 = (unsigned __int16)(v13 - (_WORD)v39);
}
v16 = v37 >> v17;
memcpy(v39, *(const void **)(a1 + 8), v40);
v43 = *(_DWORD *)(a1 + 12) + v40;
v44 = *(_DWORD *)(a1 + 8) + v40;
}
else
{
v45 = *(_BYTE **)(a1 + 12);
if ( (_BYTE *)v13 == v45 )
{
v46 = trc_szGetFileName(
"/opt/bosch/DI_SWNAVI_13.2C5P10/di_swnavi/components/dapi/devicemanager/devicehandler/compression/cpr_d"
"ecompression.cpp");
trc_tclGlobalTrace::vTraceLevel1(
21504,
306,
v46,
"CPR Overwrite Lit1 n=1 wpos=0x%x epos=0x%x",
*(_DWORD *)(a1 + 12),
v13);
goto LABEL_24;
}
*v45 = **(_BYTE **)(a1 + 8);
v43 = *(_DWORD *)(a1 + 12) + 1;
v44 = *(_DWORD *)(a1 + 8) + 1;
}
*(_DWORD *)(a1 + 12) = v43;
*(_DWORD *)(a1 + 8) = v44;
}
}
if ( a6 == 1 )
{
memcpy(v12, *(const void **)(a1 + 4), v10);
result = 1;
*(_DWORD *)(a1 + 12) += v10;
}
else
{
LABEL_34:
result = 1;
}
LABEL_35:
v47 = *(_DWORD *)(a1 + 48);
v48 = v47 != 0;
if ( result != 1 )
v48 = 0;
if ( v48 )
{
memset(*(void **)(a1 + 12), 0, *(_DWORD *)(a1 + 48));
result = 1;
}
return result;
}