Fråga:
Strängutvinning från en iNES ROM-dumpning
user3094
2013-11-02 18:42:02 UTC
view on stackexchange narkive permalink

Jag vill extrahera strängarna i Shadowgate för NES. Jag sprang -fil på bilden och sedan strängar , ingen tur. Jag hittade lite information om NES-kassettfilformatet. Dokumenten nämner användningen av "Namntabeller". Finns det ett sätt att ta isär den här filen och visa strängarna? Jag försökte

  strängar -e -T rom.bin  

Jag försökte också:

  objdump -i rom. bin  

Processorn ser ut att vara en M6502-processor och det finns Windows-demonterare tillgängliga.

Om du läser dokumentet ser du att "Namntabell" inte har något att göra med * strängar *. Detta verkar snarare relatera till NES-sättet att lagra * sprite-brickor *, som används för att rulla bakgrunder.
Om du säger det - "0-3 sträng" NES ^ Z "används för att känna igen .NES-filer." Tyvärr var detta den enda referensen till "sträng" som jag kunde hitta i det dokumentet. Jag är inte en iNES-hackare - jag antar att du är det? C-definitionen av sträng är "abcd \ 0" - detta säger i sig ingenting om hur strängen kommer att dras, eller hur? "Namntabeller" diskuteras under "PPU-minne" och det är vad det står: "En namntabell liknar mycket textlägesskärmbufferten som innehåller teckenkoder som ska visas på skärmen." LÄS VÄNLIGT "mycket lik textläge skärmbuffert"
skrivs inte strängar till en skärmbuffert för textläge?
Namntabellen är för brickor vad textbufferten är för text - det är därför de är "mycket * som *", men inte * lika *. När det gäller din ursprungliga fråga: 'strängar' letar efter en mycket specifik typ av text: endast ASCII-text. Jag skannade filen för icke-ASCII-strängar och hittade ingen (användbar eller på annat sätt). Strängarna måste vara krypterade eller komprimerade och det kan behöva demonteras för att hitta dem.
Detta är vad man-sidan för strängar har att säga: "-e-kodning Välj teckenkodning för strängarna som finns. ... Användbar för att hitta breda teckensträngar." Eller kodad?
-T bfdname Ange ett annat objektkodformat än ditt systems standardformat.
Ett svar:
usr2564301
2013-11-03 04:37:00 UTC
view on stackexchange narkive permalink

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.
Wow! Häftigt! Tack :) det var väldigt tydligt!
Här är en tidsbesparing du kanske vill veta om: inmatningsfilen består av flera delar (jag tror att detta härmar de ursprungliga fysiska ROM-chipsen). De första 16 byten är "rubrik" och kan ignoreras. Följ sedan 65 536 byte kod, och resten är grafikdata - ointressant för ditt ändamål. Du behöver bara skanna koddelen.
Hej! använde du ett verktyg för att skanna ?? Jag använder python för att skript manuellt.
Ytterligare en ROM-konstighet: den första och andra halvan av 64K-bilden byts ut! Inte konstigt att det tog mig till 3,00 / natt för att hitta något användbart. Förresten, en lista med användbara strängförskjutningar är vid '0x8000' (efter korrigering av ROM-bildfilen); till exempel vid offset A182: "VISSTE DU? FÖR ^ MIG (DET) SVAR PÅ MIN ^ RIDDLE OCH JAG SKALL LÅTA ^ DE GÅR." Åh, och jag använder vanlig C. Inte så att språket betyder något - så länge du kan manipulera bitströmmar är du bra.
Skrapa faktiskt lite om ROM-halvorna. Hela saken är * definitivt * inte i en logisk ordning, men det är inte så enkelt som jag tänkte. Detta behöver en riktig NES-ROM-hacker att förstå. Att riva ut strängar fungerar fortfarande, men delen "hitta förskjutningar" kan inte om du inte kan få "faktiska" adresser.
En sista punkt: Jag hade rätt i min aning om 5-bitars kodning: en av 5 bitkoderna står för 'använd * nästa * 8 bitar' (vilket indikerar ännu en uppslagningstabell). Så på det här sättet kan du avkoda alla texter med hjälp av en brute force-metod som helt enkelt försöker * varje * enskild byte som utgångspunkt (och därmed också producerar mycket skräp).


Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 3.0-licensen som det distribueras under.
Loading...