mirror of
https://github.com/horsicq/Detect-It-Easy.git
synced 2026-06-24 01:54:08 +00:00
117 lines
No EOL
6.8 KiB
JavaScript
Executable file
117 lines
No EOL
6.8 KiB
JavaScript
Executable file
// Detect It Easy: detection rule file
|
|
// Authors: hypn0 <hypn0@mail.ru>, Kaens (TG@kaens)
|
|
|
|
meta("format", "");
|
|
|
|
/* beautify ignore:start */
|
|
function detect() {
|
|
if (Binary.compare("00010000'Standard Jet DB'00")) {
|
|
sName = "Microsoft Access database (.MDB)";
|
|
bDetected = true;
|
|
}
|
|
|
|
function isDBF() {
|
|
// from https://independent-software.com/dbase-dbf-dbt-file-format.html
|
|
// & https://www.clicketyclick.dk/databases/xbase/format/dbf.html
|
|
// & https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
|
|
nv = X.U8(0); v5 = false;
|
|
switch (nv) {
|
|
case 0x02: sv = 'FoxBase 1.0'; break;
|
|
case 0x03: sv = 'FoxBase 2.x / dBASE III, no memo file'; break;
|
|
case 0x04: sv = 'dBASE IV, no memo file'; break;
|
|
case 0x05: sv = 'dBASE V, no memo file'; break;
|
|
case 0x07: sv = "VISUAL OBJECTS v1.x for dBase III, no memo file"; break;
|
|
case 0x30: sv = 'Visual FoxPro (possibly with DBC)'; break;
|
|
case 0x31: sv = 'Visual FoxPro with auto increment'; break;
|
|
case 0x32: sv = 'Visual FoxPro with varchar/varbinary'; break;
|
|
case 0x43: sv = 'dBASE IV SQL Table, no memo file / Flagship .dbv memo var size'; break;
|
|
case 0x64: sv = 'dBASE IV SQL System, no memo file'; break;
|
|
case 0x83: sv = 'FoxBase 2.x / dBASE III+ with memo file'; break;
|
|
case 0x87: sv = 'VisualObjects 1.x with memo file'; break;
|
|
case 0x8B: sv = 'dBASE IV with memo file'; break;
|
|
case 0x8C: sv = 'dBASE V with memo file'; break;
|
|
case 0x8E: sv = 'dBASE IV with SQL table'; break;
|
|
case 0xB3: sv = '.dbv with memo table'; break;
|
|
case 0xCB: sv = 'dBASE IV SQL Table with memo file'; break;
|
|
case 0xE5: sv = 'Clipper SIX with memo file'; break;
|
|
case 0xF5: sv = 'FoxPro 2 with memo file'; break;
|
|
case 0xFB: sv = 'FoxPro 2, no memo file'; break;
|
|
default: return false;
|
|
}
|
|
if (nv == 2) {
|
|
recc = X.U16(1); if (!recc) return false; recsz = X.U16(6); if (!recsz) return false;
|
|
hdrsz = 0x209; rectp = 8; enc = 'IBM437';
|
|
} else {
|
|
y = X.U8(1); if (y < 80) y += 2000; else y += 1900; m = X.U8(2); d = X.U8(3);
|
|
if (X.c('000000', 1)) { upd = 'never' } else {
|
|
if (!isWithin(y, 1970, 2100) || !isWithin(m, 1, 12) || !isWithin(d, 1, 31)) return false;
|
|
upd = y + '-' + m.padStart(2, '0') + d.padStart(2, '0')
|
|
}
|
|
recc = X.U32(4); if (!recc) return false;
|
|
hdrsz = X.U16(8); recsz = X.U16(0xA); if (hdrsz < 0x20 || !recsz) return false;
|
|
res0 = X.U24(0xC); res1 = X.readBytes(0xF, 13); res2 = X.U32(0x1C);
|
|
if ([4, 0x8C].indexOf(nv) >= 0) {
|
|
rectp = 0x44; enc = 'CP' + X.SA(0x22, 3); if (isWithin((t = X.SA(0x25, 1)), '0', '9')) enc += t;
|
|
if (enc == 'CPKOI8') enc += X.SA(0x26, 1); v5 = true
|
|
} else {
|
|
rectp = 0x20;
|
|
switch (X.U8(0x1D)) {
|
|
case 0x02: enc = 'CP850'; break; //DOS Multilingual
|
|
case 0x03: enc = 'CP1252'; break; //Windows ANSI
|
|
case 0x04: enc = 'CP10000'; break; //aka. 'macintosh', MAC Roman/W.European Mac
|
|
case 0x64: enc = 'CP852'; break; //Eastern-European MS-DOS
|
|
case 0x65: enc = 'CP865'; break; //Nordic MS-DOS
|
|
case 0x66: enc = 'CP866'; break; //Russian MS-DOS
|
|
case 0x67: enc = 'IBM861'; break; //Icelandic MS-DOS
|
|
//case 0x68: enc = 'Kamenicky (Czech) MS-DOS'; break;
|
|
//case 0x69: enc = 'Mazovia (Polish) MS-DOS'; break;
|
|
case 0x6A: enc = 'IBM737'; break; //Greek MS-DOS (aka. 437G)
|
|
case 0x6B: enc = 'IBM857'; break; //Turkish MS-DOS
|
|
case 0x96: enc = 'CP10007'; break; // aka. 'x-mac-cyrillic', Russian Mac
|
|
case 0x97: enc = 'CP10029'; break; // aka. 'x-mac-ce', MAC Latin 2/C.European Mac
|
|
case 0x98: enc = 'CP10006'; break; //aka. 'x-mac-greek', Greek Mac
|
|
case 0xC8: enc = 'CP1250'; break; //C.European Windows
|
|
case 0xC9: enc = 'CP1251'; break; //Russian Windows
|
|
case 0xCA: enc = 'CP1254'; break; //Turkish Windows
|
|
case 0xCB: enc = 'CP1253'; break; //Greek Windows
|
|
case 0x01: default: enc = 'IBM437' //OEM US
|
|
}
|
|
}
|
|
//TODO check res* depending on version
|
|
}
|
|
validC = ['C', 'N', 'L', 'D', 'M', 'F', 'B', 'G', 'P', 'Y', 'T', 'I', 'V', 'X', '@', 'O', '+', '0'];
|
|
fldc = 0; totalfldsz = 1 /* we begin with a deletion flag */; p = rectp; old = [0, 1];
|
|
while (X.U8(p) != 0xD && p < hdrsz) {
|
|
var name = X.readBytes(p, v5 ? 0x1F : 11); ns = charStat(name, 1);
|
|
// _log('fld#'+fldc+' @'+Hex(p)+': '+decEncoding(name,CP866)+' (ns=['+ns+'])')
|
|
if (!name[0] || (ns.indexOf('allxsc') < 0 && ns.indexOf('allforeign') < 0)) return false;
|
|
tp = X.SA(v5 ? p + 0x20 : p + 0xB, 1); if (validC.indexOf(tp) < 0) return false;
|
|
if (nv == 2) fldst = X.U16(p + 0xD); else if (v5) fldst = 0; else fldst = X.U32(p + 0xC);
|
|
fldsz = X.U8(nv == 2 ? p + 0xC : v5 ? p + 0x21 : p + 0x10); if (!fldsz) return false;
|
|
// _log(' sz:'+fldsz+', old: '+old+'; '+old[0]+'+'+Hex(old[1])+' = '+Hex(old[0]+old[1])+' ?? '+Hex(fldst))
|
|
if (old[0] && fldst && old[0] + old[1] != fldst) return false; old = [fldsz, fldst];
|
|
totalfldsz += fldsz;
|
|
decn = X.U8(nv == 2 ? p + 0xF : p + 0x11);
|
|
if (tp === 'N' && decn > fldsz) return false;
|
|
fldc++; p += nv == 2 ? 0x10 : v5 ? 0x30 : 0x20;
|
|
if (charStat(name.slice(0, name.indexOf(0)), 1).indexOf('foreign') >= 0
|
|
&& enc == "IBM437") enc = "CP1251"; // pesky Russians?
|
|
}
|
|
// _log('@'+Hex(p)+': '+fldc+' fields total size '+totalfldsz+' vs. '+recsz)
|
|
if (totalfldsz - recsz != 0) return false;
|
|
del = 0; if (X.isDeepScan()) {
|
|
p = hdrsz; for (i = 0; i < recc; i++, p += recc) if (X.U8(p) == 0x2A) del++
|
|
}
|
|
sz = hdrsz + recc * recsz; if (X.U8(sz) == 0x1A) sz++;
|
|
return sz <= X.Sz() || X.isHeuristicScan()
|
|
}
|
|
if (!bDetected && isDBF()) {
|
|
sName = "dBase Database (.DBF)"; sVersion = sv; bDetected = true;
|
|
if (X.isVerbose()) {
|
|
sOption('fld:' + fldc + ' rec: ' + recc + (del ? '(* ' + del + ')' : '') + ' enc: ' + enc + ' sz: ' + outSz(sz))
|
|
}
|
|
}
|
|
|
|
return result();
|
|
}
|
|
/* beautify ignore:end */ |