Det finns flera sätt att hitta strängar i en okänd fil. En du redan försökt: strängar
. Detta letar efter vanlig, okodad ASCII-text:
Strängar söker efter ASCII-strängar i en binär fil [..] En sträng är vilken sekvens som helst med 4 (standard) eller fler utskriftstecken som slutar med en newline eller en null. ( mansträngar
)
Men det finns många anledningar till varför detta naiva tillvägagångssätt kan misslyckas. Först och främst: inte alla texter i världen är ASCII-kodade. Faktum är att när du undersöker din fil med en binär redaktör kan du hitta grafiska bilder för teckensnittet som används i spelet vid offset 0x20010 - monokroma bitmappar på 8x16 pixlar. Om du antar att det första tecknet (a '0') är numrerat noll, så är 'A' vid position 31 - definitivt inte ASCII-text. Naturligtvis är det möjligt att textritningsrutinen vet detta och ombeställer tecken som ska skrivas ut enligt detta schema. men med tanke på åldern på det här spelet (1987) är det mer troligt att textdata lagras enligt denna konstiga kodning.
I sig bör detta dock inte vara ett problem.
Googling för det här spelet ger ett antal skärmdumpar, och du kan läsa några av de texter som kan visas - "Det sista du kommer ihåg", "Word of your historic quest" , etc. -, och en anmärkningsvärd poäng är att all text verkar vara i ALL CAPS.
Hur hjälper det? Tja, om kodningen är fjärr "normal" kan teckenkoden för ett "A" vara vad som helst, men du kan säkert anta att kod + 1 är "B" , code + 2
är 'C' och så vidare. Låt oss nu anta att texten "THE" förekommer var som helst (ett säkert antagande). Subtrahera 'T' från den första byten i data och notera skillnaden. Subtrahera denna skillnad från nästa byte och testa om det är ett 'H'; Om så är fallet, testa samma skillnad på nästa byte och se om det är ett "E". Tre gånger är en charm (i det här fallet), och eftersom strängen "THE" borde komma upp mycket ofta bör du se många träffar med samma skillnad. Då kan du skriva en anpassad rutin för att "konvertera" alla databyte enligt detta schema och kontrollera igen om du hittar användbara strängar.
Det fungerade inte för Shadowgate.
Ett annat alternativ är att texten medvetet har fördunkats. Ett populärt (eftersom snabbt ) alternativ var att XOR text med en konstant. På så sätt var texten inte lätt synlig när den inspekterades med en hexvisare, men kunde ändå lätt visas. Så jag gjorde samma sak som ovan, först nu med en XOR-operation istället för en konstant subtraktion. Det fungerade inte heller.
Nästa: med tanke på att SG är ett text äventyr är det självklart att författarna försökte fylla så mycket som möjligt text i det dåliga NES-minnet . Att hitta verklig komprimering (ZIP, LZW) i ett sådant gammalt spel är ganska sällsynt, kompressionsscheman tenderade att vara ganska enkla. När allt kommer omkring var inte bara RAM begränsat utan CPU-hastighet också. Vad händer om varje tecken lagras som en 5-bitars sekvens? Det skulle spara mycket minne - var åtta tecken i text kunde lagras på bara 5 byte, en komprimeringshastighet på 62,5%.
Varför "5-bitars"? Vi pratar här engelsk text, plus en handfull skiljetecken, plus (kanske) siffror '0' till '9'. Alfabetet i sig är 26 tecken långt, vilket lämnar ytterligare 6 värden för allt annat - och hej, en av de extra koderna kan betyda "för nästa tecken använd alla åtta bitarna".
Kontroll var femte bitar mot min teststräng (som i kryptografi kallas en "spjälsäng"), jag hittade följande:
kandidat vid 0570, delta är 41 H_A \ `THE [TROLL [kandidat vid 0670, delta är 41 _H \ ʻATHE [TROLL [kandidat vid 0878, delta är 41 ʻAN`QTHE [TROLL [kandidat vid 09E3, delta är 41 FRÅN ^ THE [DEPTHS Kandidat vid 1380, delta är 41 E [OF [THEM_A [THIkandidat vid 13F0, delta är 41] NX_ATHE [WORDS [kandidat vid 14C0, delta är 41 PD ^ `QTHE [FLAME [kandidat vid 1BBA, delta är 41 UDGE [THEM [BY_A_kandidat vid 22E0, delta är 41] BX_ATHE [GLASS [kandidat vid 230D, delta är 41 ID_A [THE ^ SIGN [Ocandidate at 2375, delta is 41 S [ON [THEM_A \ ʻABcandidate at 2390, delta is 41 LOWOW [THE ^ VISCOU Kandidate at 2528, delta is 41 F ] PX_THE [STONE [kandidat vid 25E6, delta är 36 @ CP = KTHE @? OFHBS kandidat vid 27F8, delta är 41 YDP] ATH E [BARK [Kandidat vid 2B1E, delta är 41 D_H \] THE [WATER [
.. och många fler. Du kan se att det fungerar, för jag avkodade också några byte före och efter teststrängen, och det är också igenkännbart som "något". Det "delta" som visas är skillnaden mellan fembitskoden (0..31) och ASCII, och du kan se att den är 41 för de flesta strängar (det enda undantaget verkar vara falskt positivt) .
För att försäkra mig om att denna är korrekt, försökte jag med en annan spjälsäng: KING
(det är ett fantasispel):
kandidat vid 0661, delta är 41 Y [Söker [SPEARkandidat vid 23B4, delta är 41 [DRINKING [TAR_A kandidat vid 2B5D, delta är 41 [DRINKING_A \ ʻAKandidat vid 8E1B, delta är 43 \ XVFDKINGDHEEVEkandidat vid 146F9, delta JL54HKING48A4: D
Det verkar också fungera: inte "kungen" jag förväntade mig, men ändå bra resultat med ett delta på 41, slumpmässiga saker med ett annat delta.
Men att hitta användbara strängar på detta sätt är ganska lyckligt, för det finns naturligtvis ingen garanti för att läsning var 5: e bit börjar vid den första byten ska visa något användbart. Det kan finnas många andra strängar mellan de visade, men de började inte på en multipel av 5 * 8 bitar. Anta att det inte fanns någon text på position # 0, men det var på position # 1, då kan jag inte se den:
bitar för byte 0,1 0000,0000 TTTT. T000 (T = text teckenbitar) --- läsning 1: a 5 bitar 1111.1 ??? ????. ???? 2: a 5 bitar - fel! .... .111 11 ??. ????
För att korrekt avkoda alla strängar, skulle du nu ta följande väg:
- min resultatlista innehåller läsbar text, men också något sopor. Ta reda på vad "sopor" är (
[
verkar vara ett enkelt utrymme, men THEM_A \ 'AB
behöver granskas närmare). - hitta så mycket som möjligt sträng startar och anteckna deras adresser
- sök binär efter dessa adresser. När allt kommer omkring, om de "används", måste det finnas någon hänvisning till dem.
- Före och efter dessa adresser kommer det att finnas fler. Det här är adresser till strängar som sökalgoritmen inte hittade, men ändå kan vara giltig.
- Vanligtvis är en lista av denna typ sammanhängande (även om det kan finnas vissa data associerad med varje sträng). Skanna binärfilmerna upp och ner efter liknande adresser tills du hittade vad som säkert är början och slutet.
- Slinga över listan och visa allt du kan enligt avkodningsschemat.
- Luta dig tillbaka och njut av ett väl gjort jobb.