integrato ;)
Speed Racer in The Challenge of Racer X (1993) - Reverse engineering
Superare la protezione anti-copia

 
Introduzione e disclaimer
 
Come praticamente la totalità dei giochi dell'epoca anche nel titolo che stiamo per studiare è presente una (semplice) protezione anti-copia.
Trattandosi di software su (3) floppy disk copiarlo era estremamente semplice anche a quel tempo e l'unico tipo di protezione esistente (e adottato sulla maggior parte dei programmi di allora) consisteva nel proporre all'avvio del gioco una domanda la cui risposta è reperibile sul manuale fornito con la scatola originale del prodotto.
In pratica dunque per giocare a questi titoli "piratandoli" occorreva oltre che la copia dei floppy anche una fotocopia di questo manuale e in casi un po più "fantasiosi" era addirittura necessario ricostruirselo (mi riferisco ad esempio al disco di cartone di protezione per monkey island).
In questo specifico caso il gioco ha una protezione molto semplice: All'avvio viene proposta una domanda la cui risposta si trova sul manuale di istruzioni allegato.
Io personalmente mi sono ritrovato a studiare questa protezione in quanto pur possedendo il gioco originale, con tanto di scatola dell'epoca, avevo perso il manuale interno ma volevo comunque riprovare questo titolo. (Una copia del gioco è presente nella sezione )
Trattandosi di una protezione molto semplice analisi di questo genere possono essere un'ottimo inizio per coloro che intendono imparare l'arte del reversing partendo da zero. Ricordo comunque che anche per questo tipo di software, anche se ormai molto datati, il copyright appartiene ancora alla casa produttrice e quindi il possesso di una copia non autorizzata è ritenuto illegale.

 
SpeedRacer: Richiesta di codici di avvio
 
Data l'età del gioco l'utilizzo sui pc moderni può avvenire correttamente solo sotto l'utilizzo di un emulatore quale. Avviato il gioco dopo la sigla ci verrà presentata una schermata con una domanda alla quale dovremo rispondere correttamente per poter proseguire con l'esecuzione. Come si può notare negli esempi qui sotto le domande sono formate da frasi presenti su 2 o 3 righe e a volte la domanda è realizzata componendo più righe di una stesse domanda con altre:

Partiamo con l'analisi del gioco (SRV10.EXE).

 
SpeedRacer: Analisi dead listing
 
L'unica vera difficoltà nel reversing di questo programma è che si tratta di un software a 16-bit, il che ci impedisce a priori la possibilità di utilizzare degubber "semplici" (ma soprattutto visuali) come ollydbg, w32Dasm e simili e ci costringe a rivolgersci a software più datati come Turbo Debugger.
Sebbene una buon compromesso potrebbe essere l'utilizzo del debugger integrato di DosBox vedremo subito che trattandosi di una procedura di protezione estremamente semplice in questo caso basta l'utilizzo di un buon disassemblatore che supporti i 16-bit.
Fortunatamente limitandoci a questo tipo di approccio (approccio "dead listing") possiamo utilizzare uno dei migliori disassemblatori/debugger esistenti sulla rete: della datarescue (che per i programmi a 16-bit non supporta il debugging)
Aprendo l'SRV10.EXE con IDA la prima cosa che si nota dalla finestra delle stringhe contenute nell'eseguibile è la prenseza di queste const char* definite nel programma:
  1. dseg04:00052D8C Array_1_riga dd offset aOnP_3GeneralWh ; "On p.3, GENERAL, who is the"
  2. dseg04:00052D90 dd offset aOnP_3EngineWha ; "On p.3, ENGINE, what is the"
  3. dseg04:00052D94 dd offset aOnP_3Capacitie ; "On p.3, CAPACITIES, what is"
  4. dseg04:00052D98 dd offset aOnP_3Capacitie ; "On p.3, CAPACITIES, what is"
  5. dseg04:00052D9C dd offset aOnP_4SteeringW ; "On p.4, STEERING, what is the"
  6. dseg04:00052DA0 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  7. dseg04:00052DA4 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  8. dseg04:00052DA8 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  9. dseg04:00052DAC dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  10. dseg04:00052DB0 dd offset aOnP_5Calculate ; "On p.5, CALCULATED DATA,"
  11. dseg04:00052DB4 dd offset aOnP_5Calculate ; "On p.5, CALCULATED DATA,"
  12. dseg04:00052DB8 dd offset aOnP_5Accelerat ; "On p.5, ACCELERATION SPECS,"
  13. dseg04:00052DBC dd offset aOnP_5Accelerat ; "On p.5, ACCELERATION SPECS,"
  14. dseg04:00052DC0 dd offset aOnP_5Accelerat ; "On p.5, ACCELERATION SPECS,"
  15. dseg04:00052DC4 dd offset aOnP_5BrakingHo ; "On p.5, BRAKING, how many"
  16. dseg04:00052DC8 dd offset aOnP_5BrakingHo ; "On p.5, BRAKING, how many"
  17. dseg04:00052DCC dd offset aOnP_5BrakingHo ; "On p.5, BRAKING, how many"
  18. dseg04:00052DD0 dd offset aOnP_1Par_1What ; "On p.1 par.1, what is 'Speed'"
  19. dseg04:00052DD4 dd offset aOnP_2Par_1What ; "On p.2 par.1, what is the"
  20. dseg04:00052DD8 dd offset aOnP_6Par_2What ; "On p.6 par.2, what is the"
  21. dseg04:00052DDC dd offset aOnP_6Par_3TheM ; "On p.6 par.3, the Mach 5's"
  22. dseg04:00052DE0 dd offset aOnP_7Par_1What ; "On p.7 par.1 what Corporation"
  23. dseg04:00052DE4 dd offset aOnP_10Par_2OnW ; "On p.10 par.2, on what"
  24. dseg04:00052DE8 dd offset aOnP_11Par_1Wha ; "On p.11 par.1, what does"
  25. dseg04:00052DEC dd offset aOnP_12Par_3Wha ; "On p.12 par.3, what"
  26. dseg04:00052DF0 dd offset aOnP_12Par_3W_0 ; "On p.12 par.3, what does"
  27. dseg04:00052DF4 dd offset aOnP_13Par_1Wha ; "On p.13 par.1, what type of"
  28. dseg04:00052DF8 dd offset aOnP_14Par_1Whi ; "On p.14 par.1, which Safety"
  29. dseg04:00052DFC dd offset aOnP_14Par_1Wha ; "On p.14 par.1, what type"
  30. dseg04:00052E00 dd offset aOnP_14Par_3Wha ; "On p.14 par.3, what is"
  31. dseg04:00052E04 dd offset aOnP_16Par_1Wha ; "On p.16 par.1, what are"
  32. dseg04:00052E08 dd offset aOnP_16Par_2Wha ; "On p.16 par.2, what system"
  33.  
  34. dseg04:00052E0C Array_2_riga dd offset aVehicleMfr_? ; "VEHICLE MFR.?"
  35. dseg04:00052E10 dd offset aMax_EngineSpee ; "MAX. ENGINE SPEED in RPM?"
  36. dseg04:00052E14 dd offset aTheCapacityOfT ; "the capacity of the fuel tank"
  37. dseg04:00052E18 dd offset aTheCapacityFor ; "the capacity for LUGGAGE in"
  38. dseg04:00052E1C dd offset aTurningCircleC ; "TURNING CIRCLE, CURB TO"
  39. dseg04:00052E20 dd offset aTheCurbWeightI ; "the CURB WEIGHT in lbs.?"
  40. dseg04:00052E24 dd offset aTheWheelBaseIn ; "the WHEEL BASE in IN.?"
  41. dseg04:00052E28 dd offset aTheOverallLeng ; "the OVERALL LENGTH in IN.?"
  42. dseg04:00052E2C dd offset aTheGroundClear ; "the GROUND CLEARANCE in IN.?"
  43. dseg04:00052E30 dd offset aWhatIsTheMach5 ; "what is the Mach 5's TOP"
  44. dseg04:00052E34 dd offset aWhatIsTheMac_0 ; "what is the Mach 5's fuel"
  45. dseg04:00052E38 dd offset aHowManySecsToG ; "how many secs to go from"
  46. dseg04:00052E3C dd offset aHowManySecsToG ; "how many secs to go from"
  47. dseg04:00052E40 dd offset aHowManySecsToG ; "how many secs to go from"
  48. dseg04:00052E44 dd offset aFtForTheMach5T ; "FT for the Mach 5 to go from"
  49. dseg04:00052E48 dd offset aFtForTheMach5T ; "FT for the Mach 5 to go from"
  50. dseg04:00052E4C dd offset aFtForTheMach5T ; "FT for the Mach 5 to go from"
  51. dseg04:00052E50 dd offset aRacerSRealFirs ; "Racer's real first name?"
  52. dseg04:00052E54 dd offset aClassification ; "classification of the Mach 5?"
  53. dseg04:00052E58 dd offset aNickelTitanium ; "nickel/titanium alloy called?"
  54. dseg04:00052E5C dd offset aBodyIsReminisc ; "body is reminiscent of whose"
  55. dseg04:00052E60 dd offset aIsTestingSuper ; "is testing super conductive"
  56. dseg04:00052E64 dd offset aPrincipleDoesT ; "principle does the Mach 5"
  57. dseg04:00052E68 dd offset aTheIStandForIn ; "the 'I' stand for in IRS?"
  58. dseg04:00052E6C dd offset aCorporationMak ; "Corporation makes the XIF"
  59. dseg04:00052E70 dd offset aTheXStandForIn ; "the 'X' stand for in XIF?"
  60. dseg04:00052E74 dd offset aOperationsMake ; "operations makes the canopy"
  61. dseg04:00052E78 dd offset aEquipmentCompa ; "Equipment company created"
  62. dseg04:00052E7C dd offset aOfGlassMakesUp ; "of glass makes up the canopy?"
  63. dseg04:00052E80 dd offset aActivatedToDet ; "activated to determine a safe,"
  64. dseg04:00052E84 dd offset aTheBushingComp ; "the bushing components made"
  65. dseg04:00052E88 dd offset aIsComputerAssi ; "is computer-assisted?"
  66.  
  67. dseg04:00052E8C Array_3_riga dd offset asc_50C14 ; " "
  68. dseg04:00052E90 dd offset asc_50C14 ; " "
  69. dseg04:00052E94 dd offset aInGallons? ; "in gallons?"
  70. dseg04:00052E98 dd offset aInCubicFt? ; "in cubic FT?"
  71. dseg04:00052E9C dd offset aCurbInFt? ; "CURB in FT?"
  72. dseg04:00052EA0 dd offset asc_50C14 ; " "
  73. dseg04:00052EA4 dd offset asc_50C14 ; " "
  74. dseg04:00052EA8 dd offset asc_50C14 ; " "
  75. dseg04:00052EAC dd offset asc_50C14 ; " "
  76. dseg04:00052EB0 dd offset aSpeedInMph? ; "SPEED in MPH?"
  77. dseg04:00052EB4 dd offset aUsageInMpg? ; "usage in MPG?"
  78. dseg04:00052EB8 dd offset a060Mph? ; "0-60 MPH?"
  79. dseg04:00052EBC dd offset a070Mph? ; "0-70 MPH?"
  80. dseg04:00052EC0 dd offset a090Mph? ; "0-90 MPH?"
  81. dseg04:00052EC4 dd offset a300Mph? ; "30-0 MPH?"
  82. dseg04:00052EC8 dd offset a600Mph? ; "60-0 MPH?"
  83. dseg04:00052ECC dd offset a900Mph? ; "90-0 MPH?"
  84. dseg04:00052ED0 dd offset asc_50C14 ; " "
  85. dseg04:00052ED4 dd offset asc_50C14 ; " "
  86. dseg04:00052ED8 dd offset asc_50C14 ; " "
  87. dseg04:00052EDC dd offset aAutomobiles? ; "automobiles?"
  88. dseg04:00052EE0 dd offset aMaterials? ; "materials?"
  89. dseg04:00052EE4 dd offset aEngineWork? ; "engine work?"
  90. dseg04:00052EE8 dd offset asc_50C14 ; " "
  91. dseg04:00052EEC dd offset aTire? ; "tire?"
  92. dseg04:00052EF0 dd offset asc_50C14 ; " "
  93. dseg04:00052EF4 dd offset aANecessity? ; "a necessity?"
  94. dseg04:00052EF8 dd offset aTheHelmet? ; "the helmet?"
  95. dseg04:00052EFC dd offset asc_50C14 ; " "
  96. dseg04:00052F00 dd offset aClearPath? ; "clear path?"
  97. dseg04:00052F04 dd offset aOf? ; "of?"
  98. dseg04:00052F08 dd offset asc_50C14 ; " "
  99.  
  100. dseg04:00052F0C Array_Risposte dd offset aPopsRacer ; "Pops Racer"
  101. dseg04:00052F10 dd offset a60000 ; "60000"
  102. dseg04:00052F14 dd offset a21 ; "21"
  103. dseg04:00052F18 dd offset a5_2 ; "5.2"
  104. dseg04:00052F1C dd offset a37_3 ; "37.3"
  105. dseg04:00052F20 dd offset a3150 ; "3150"
  106. dseg04:00052F24 dd offset a92_0 ; "92.0"
  107. dseg04:00052F28 dd offset a180_0 ; "180.0"
  108. dseg04:00052F2C dd offset a4_0 ; "4.0"
  109. dseg04:00052F30 dd offset a220 ; "220"
  110. dseg04:00052F34 dd offset a17 ; "17"
  111. dseg04:00052F38 dd offset a6_32 ; "6.32"
  112. dseg04:00052F3C dd offset a7_49 ; "7.49"
  113. dseg04:00052F40 dd offset a9_87 ; "9.87"
  114. dseg04:00052F44 dd offset a33_2 ; "33.2"
  115. dseg04:00052F48 dd offset a132_0 ; "132.0"
  116. dseg04:00052F4C dd offset a196_0 ; "196.0"
  117. dseg04:00052F50 dd offset aGreg ; "Greg"
  118. dseg04:00052F54 dd offset aPrototype ; "Prototype"
  119. dseg04:00052F58 dd offset aMemorite ; "Memorite"
  120. dseg04:00052F5C dd offset aPininfarinna ; "Pininfarinna"
  121. dseg04:00052F60 dd offset aGensystems ; "GenSystems"
  122. dseg04:00052F64 dd offset aHighHeat ; "high-heat"
  123. dseg04:00052F68 dd offset aIndependent ; "Independent"
  124. dseg04:00052F6C dd offset aUnitire ; "UniTire"
  125. dseg04:00052F70 dd offset aExperimental ; "Experimental"
  126. dseg04:00052F74 dd offset aUnderwater ; "underwater"
  127. dseg04:00052F78 dd offset aFisch ; "Fisch"
  128. dseg04:00052F7C dd offset aInfragreen ; "infragreen"
  129. dseg04:00052F80 dd offset aRadar ; "radar"
  130. dseg04:00052F84 dd offset aNylon ; "nylon"
  131. dseg04:00052F88 dd offset aBraking ; "braking"
Perfetto. L'analisi volendo è gia terminata!
Nonostante come visto all'inizio alcune righe nelle domande vengano utilizzate più volte per comporre richieste diverse dagli array riportati dal listato di IDA si nota anche che questo non comporta problema in quanto esse sono anche duplicate in memoria; in pratica:
  1. dseg04:00052DA0 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  2. dseg04:00052DA4 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  3. dseg04:00052DA8 dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
  4. dseg04:00052DAC dd offset aOnP_4Dimension ; "On p.4, DIMENSIONS, what is"
Viene memorizzata 4 volte piuttosto che una solamente e composta diversamente tramite algoritmi speficifi per realizzare domande diverse.
Poco male, per quel che ci riguarda è ancora più semplice così, ci basta quindi ricostruire le 32 domande con le rispettive risposte semplicemente componendo i 4 array così come sono per ottenere di nuovo il nostro "manuale":

Array_1_riga[i] + Array_2_riga[i] + Array_3_riga[i] + Array_Risposte[i]

Niente di più banale.
Tralasciando questo punto (il risultato è comunque riportato nella sezione) vediamo almeno per sommi capi l'algoritmo di costruzione della domanda per trovare il punto per applicare un'eventuale patch.

 
SpeedRacer: Cracking
 
Spostandoci nel punto in cui viene fatto uso dell'Array_1_riga (per IDA tasto destro "Jump to xref to operand..") si trova la seguente porzione di codice, veramente semplice da interpretare:
  1. ;ebp+Offset_var_rand contiene un valore random calcolato in precedenza
  2. cseg01:00012DB7 mov eax, [ebp+Offset_var_rand] ; Prendo l'indice random
  3. cseg01:00012DBA shl eax, 2
  4. cseg01:00012DBD push Array_1_riga[eax] ; La stringa per la prima riga
  5. cseg01:00012DC3 push 0FAh ; '·'
  6. cseg01:00012DC8 push 0CDh ; '-'
  7. cseg01:00012DCD call printLine ; E la stampo
Proseguendo con il codice (tralasciando le parti che non ci interessano) si arriva allo stesso tipo di algoritmo per la stampa della seconda riga:
  1. cseg01:00012DE1 mov eax, [ebp+Offset_var_rand] ; Prendo l'indice random
  2. cseg01:00012DE4 shl eax, 2
  3. cseg01:00012DE7 push Array_2_riga[eax] ; La stringa per la seconda riga
  4. cseg01:00012DED push 108h
  5. cseg01:00012DF2 push 0C5h ; '+'
  6. cseg01:00012DF7 call printLine ; E la stampo
E per la terza:
  1. cseg01:00012E0B mov eax, [ebp+Offset_var_rand] ; Prendo l'indice random
  2. cseg01:00012E0E shl eax, 2
  3. cseg01:00012E11 push Array_3_riga[eax] ; La stringa per l'ultima riga
  4. cseg01:00012E17 push 116h
  5. cseg01:00012E1C push 0C5h ; '+'
  6. cseg01:00012E21 call printLine ; E la stampo
Ultimata la stampa delle 3 righe (eventualmente la terza nulla) si trova chiaramente poco più in basso la parte di algoritmo dedicata al confronto della risposta introdotta dall'utente con quella in memoria:
  1. cseg01:00012F2F mov eax, [ebp+Offset_var_rand] ; Prendo l'indice random
  2. cseg01:00012F32 shl eax, 2
  3. cseg01:00012F35 mov edx, Array_Risposte[eax] ; La risposta corrispondente
  4. cseg01:00012F3B add edx, [ebp+var_10]
  5. cseg01:00012F3E mov eax, [ebp+var_10] ; La risposta introdotta
  6. cseg01:00012F41 mov al, byte_5360C[eax]
  7. cseg01:00012F47 cmp al, [edx] ; Confronto
  8. cseg01:00012F49 jz short RispostaCorretta
Come si nota tutto ai limiti della banalità.
Volendo patchare l'eseguibile basta quindi cambiare il salto all'indirizzo cseg01:00012F49 da jz (Jump if equal) in un jnz (Jump if is Not equal) per rendere valide tutte le risposte non corrette.
Per applicare questa patch apriamo l'SRV10.EXE con un editor esadecimale, spostiamoci all'indirizzo assoluto 0x1373F (mostrato anche da IDA relativo all'operazione di jz del segmento di codice cseg01:00012F49) e cambiato il codice operativo del salto condizionato da 0x74 (jz) in 0x75 (jnz).

 
Conclusioni
 
E' impressionante vedere lo sviluppo che l'industria software ha avuto dagli anni 90 ad ora; anche senza poter paragonare il ramo della pirateria informatica di allora con quella di adesso (e neanche gli strumenti in possesso alla gente per praticare l'arte del reversing) vedere questo tipo di protezioni anti-copia all'interno di programmi commerciali è quasi imbarazzante!
Dal punto di vista dello studioso non c'è niente di cui lamentarsi però: alla fine si tratta comunque di un piccolo esercizio che vale la pena fare visto il tempo richiesto e soprattutto la soddisfazione che da poter rigiocare ad un titolo come questo 15 anni dopo.
Colgo l'occasione per ringraziare disti per i consigli e Baldas per la lettura dei floppy del gioco ;)

 
Appendici
 
Downloads: 202
Il gioco trattato nell'articolo
Downloads: 208
L'eseguibile crakkato.
Downloads: 825
Il manuale delle riposte.

Script Execution Time: 0.104656 seconds - Visite: 641942
Copyright © 2007-2017 Suondmao v0.1.5-1