starcraft: remastered - shortjump!0xeb.net/wp-content/uploads/2018/02/starcraft_eud... · 2018. 2....
TRANSCRIPT
StarCraft:RemasteredEmulatingabufferoverflowforfunandprofit
AnotebeforewebeginBlizzardEntertainmentinnowayendorsesorcondonesreverseengineeringofourproperties.
Theexerciseshereinwereconductedtounderstandthemethodsusedtocreateunlicensedbehaviors.
• Anti-CheatEngineer,BlizzardEntertainment
• PreviouslyworkedatHex-RaysandMicrosoft
• Technicalwriter:• PracticalReverseEngineering,AntivirusHackers
Handbook• Batchography
• Passionateaboutreverseengineeringandlow-levelprogrammingonMS-Windows
• Interestedindebuggers,emulators,APIhooking,dynamicbinaryinstrumentationandvirtualizationtechnologies
• Contact• Email:ebachaalany atblizzard.com• Twitter:@0xeb
AboutMe:EliasBachaalany
Mycolleagues• GuillaumeBreuil,YiDeng,ChrisGenova,Mark
Chandler,JamesTouton,PeteStilwell,ZakBennettandGrantDavies
Tools• SCMDraft2mapeditor- HenrikArlinghaus• trgk (TriggerKing)- https://github.com/phu54321/• MPQtools– Ladislav Zezula• BWAPI- AdamHeinermann• IDAPro- Hex-Rays• Diaphora – Joxean Koret• EUDEnabler andtheEUDDB- Farty1Billion-
http://farty1billion.dyndns.org/EUDDB/
SouthKoreanmapmakersandtoolscommunity• Kongze1004– RandomTowerDefensemapauthor• Sksljh2091– MarioExodusmapauthor• Jacksell12,Deation,Sato
CommunitySites• TeamLiquid,StarEdit Network,Naver.com
Comradesontheadventure
SorryifImissedanyone!
• StarCraftisasciencefictionRTS(real-timestrategy)
• ReleasedforPCandMaconMarch31,1998
• StarCraft:BroodWar- ExpansionpackreleasedonNovember30,1998
• Significantpatchestothistalk:• 1.16.1- 01/21/2009– Lastpatchfor8years• 1.18.0- 04/18/2017– Firstmodernpatch• 1.20.0– 08/14/2017– StarCraft:Remastered• 1.21.0– 12/07/2017– EUDreintroducedvia
emulation
Backstory/1
• StarCrafthadvariousbufferoverflowbugs,butonewasrelatedtoaparticulartriggerconditionandaction:• TheExtendedUnitDeathtriggerØ Orsimply:EUD
• BlizzarddidnotupdateStarCraftbetween2009andearly2017• Thecommunityre-enabledthebugwith
customlaunchersandtools
• Patch1.17wasslatedforreleasebutwasheldbackbecauseitwouldbreakmods,tools,andlaunchers:• wMode• wLauncher,ChaosLauncher• BWAPI– PlugintowriteAIbotsthatplay
StarCraft
Backstory/2
• StarCraftmapsbasedonEUDtriggersthrivedamongtheSouthKoreanmapmakerscommunity
• TheEUDtriggers:• Areencodedinthemapfile• Allowedarbitrarymemoryreadandwrite:
• ThemajorityofthepublicEUDmapsincirculationhavehardcodedaddressescompatiblewithStarCraft1.16.1 onWindows
Ø IamnotawareofanyEUDmapsfortheMacOS versionofthegame
• TheEUDexploitallowedmodders toauthormapsthatmodifythegameradically:• RandomTowerDefense• MarioExodusMap• Etc.
Backstory/3
RandomTowerDefense– EUDmap
BouncingBallEUDmap(SC1.16.1)
BouncingBallEUDmap(SC:Rw/emulation)
• TheMarioExodusmapauthorcreatedaleveleditor!
• Themapwasdevelopedusingtrgk’s epScriptlanguageandcompiler
• TheyarejustMPQarchives• TheMPQformathasbeenextensivelyreverse
engineeredanddocumentedbythecommunity
• Theycontainvariousfiles:• TheycontaincustomWAVaudiousedbythe
map• staredit/scenario.chkß Theactualmapchunk
file• Thisfilecontainsthetriggerschunk• Itcontainsstringstablechunk• Itcontainsachunkdescribingbuildings
andunits• Etc.
StarCraftmapfileformat
MapfileinMPQEditor• Ladik’s MPQeditorcanbeusedto
viewormodifythecontentsofanMPQmapfilehttp://zezula.net/en/mpq/download.html
Notethechunkfile:“staredit/scenario.chk”
• Madeofoneormorechunks: • Chunkheaderisfollowedbythechunkbody• ThegameparseseachchunkbasedonitsID:
Scenariochunkfile/1
• Somechunksmighthavetheirownsub-headers
• Thestringschunkissuchanexample:
Scenariochunkfile/2
• Thestringschunkcanbeusedtohidedatanotusedbythegamedirectly• WhenCK_HDR.ckSize >(sizeof(thecompleteTStrTbl header)+∑strlen(ofallstringsinthetable))
• Themodders hideadditionaltriggersinthecaveareaofthestringchunk
Scenariochunkfile/3
• Thisscreenshotshowsthelaststringinthestringstable• That’snotthechunk’sendthough,itisjustthestringtable’send• TheremainingbytesareadditionaltriggersinsertedbytheEUDtriggercompiler
Scenariochunkfile/4
• https://github.com/phu54321/
• Theyareasetofconditionsandactionsthatgetevaluatedduringthegameloop
• Therearetriggerconditionsthattellyouwhen:• Acertaintimeperiodhaselapsed(timers)• Playerresourcesreachedacertainamount• Amaplocationhasbeenreached• Etc.
• Whenallthetriggerconditionsarefulfilled,thenyoucandoactionssuchas:• PlayWAVfile• Displayamessage• Create,kill,moveaunit,etc.• Changeunitownerandhealthpoints• Giveplayerresources• Etc.
Whataretriggers?/1
• Triggersarestoredinsidethemapchunkfile
• Thetriggerschunkissimplyanarrayof_trigger structs
• EachtriggerhasanarrayoftheCONDITION andACTION structures
• ThedwPlayer andwType fieldsareusercontrolledØ Theyareusedtoread/write
out-of-boundsinsideanarray
• ThebOpCode fielddictatesthetriggerconditionandactiontype
Whataretriggers?/2
• ThebOpCode fieldisusedtoselectwhichconditionoractiontoexecute:
Whataretriggers?/3
• Eachtriggerconditionisevaluated,thentheactionsareperformedifallconditionssucceed:
Whataretriggers?/4
Whataretriggers?/5
• Classic(visual)triggereditor(SCMDraft 2.0– byHenrikArlinghaus)
• Notethelargevalues:• UnitID• Deathtableindex• Etc.
Whataretriggers?/6
• Texttriggereditor
• AprivatebuildofSCMDraftshowstheEUDoverflowaddresses
Whataretriggers?/7
• Thebufferoverflowbuginquestionisfoundinthe“ExtendedUnitDeath”triggercode:• Thedeath_count()triggercondition
• à Readanywhereprimitive
• Theset/add/sub_death_count()triggeraction• àWriteanywhereprimitive
• Triggersarereadas-isfromthechunkfileandstoredinadoubly-linkedlist:
Thebufferoverflow/1
• Adeathconditionwithout-of-boundsunittype(wType)orplayernumber(dwPlayer)causesthereadanywhereprimitive
Thebufferoverflow/2
• Asetdeathactioncausesawriteanywhere andprovidethefollowingprimitives:• [mem]+=lQuantity• [mem]-=lQuantity• [mem]=lQuantity
Thebufferoverflow/3
• AnexampleofEUDtriggersfoundinsideanEUDmap:
Thebufferoverflow/4
• GivenaStarCraftmapthatcontainsmalformedinputthattriggersaread/writeanywhere:• Isthereisawaytoemulatethebufferoverflow
inanewergameversionwhere:• Thebufferoverflowbugisfixed• Someaddressesnolongerexistinthe
newgameversion• Someaddressesrefertonew/different
datastructureformat?
• Cantheemulatorworkondifferentarchitecturesandoperatingsystems?
EUDmapemulation– Problemstatement
1. Identify• Identify/tracealltheaddressesusedbyan
EUDmap• Buildatableoftheaddressesandidentify
whattheyrepresentinthegamesourcecode
2. Intercept• Interceptallout-of-boundsaccess• Redirectaccessusingatranslationtable
• Oldaddressà Newaddress
3. Emulate1. Missingmemoryaddressesshouldbe
handledbycode2. Dangerousmemorychangesshouldbe
filtered/changedaccordingly(pointers,functioncallbacks,etc.)
Threestepssolution
1. Identify• Unfortunately,wedidnothaveprivateor
publicsymbolsforStarCraft1.16.1.Ihadtostartreversingthegameexecutablefromscratch
• HowcanItellwhataddressesthemapsareaccessing?
• Whatisthegoal/intentbehindamemoryaccess?
2. Intercept1. Noproblemshere.Luckily,wecanfunnelall
theout-of-boundsread/writestotheemulationlayer
3. Emulate1. Handlebasicmemoryaccessemulation2. Emulateaddressesthatarenolongerpresent3. Emulateincompatiblestructuretypes
Implementationchallenges
1. Reverseengineeringeffortswereimpededbythelackofdebuggingsymbols:• Reverseengineeredthegameclientfrom
scratch• Usedtheclosestsourcecodesnapshotfor
1.16.1• Foundtherightcompiler(VS2003)andthe
approximateoptimizationswitchesØ NowIhavedebuggingsymbolsfora
binarythatisveryclosetothepublicbuild
2. IusedbinarydiffingpluginsforIDAPro1. PatchDiff2- TenableNetworkSecurity,Inc2. Diaphora - http://diaphora.re/
Identify– Reversingthegame/1
• Binarydiffingwaslimited:• Mismatchedfunctionsbetweenthediffed
binaries• Globalvariableswerenotidentified• Optimizedcodeandinlined functionsmade
diffingharder
• ResortedtomanualreverseengineeringtobridgethelimitationsfromBinDiffing
• Usedscriptingtoautomatethereversingtask• LotsofIDAPython scriptingwasinvolved
Identify– Reversingthegame/2
SourcecodevsDisassemblyview
SourcecodevsHex-Rayspseudo-code
Automatingdatastructurerecovery
• StarCraftRemasteredcollectsgametelemetry(includingmapinformation,etc.)
• AsofOctober2017,wehadaround~603,773totaluniquemapsplayed• Ofwhich17,916wereEUDmaps(i.e.containedoutofbounds
indices)
• AfterImanagedtoreverseengineerenoughofthegame,Iwroteatooltoprocessallthemaps,identifyEUDmapsanddumptheout-of-boundsEUDaddresses
Identify– Staticallyidentifyalladdresses/1
Identify– Staticallyidentifyalladdresses/2
• AfteraggregatingtheuniqueEUDaddressesacrossallofthe17kEUDmaps,Iendedupwitharound~800variablesusedbypopularEUDmaps
• IwroteanIDAPython scripttoemitatableforalltheuniqueaddresses,theirnamesandsizes
Identify– Staticallyidentifyalladdresses/3
• Staticaddressdiscoverywasnotenough:• SomeEUDmapsweredereferencing
pointersandreachingintotheheap• Somestructuresarecomplicatedand
linkedtootherstructures(linkedlists,TCtrl*,TDialog*,etc.)
• Needmoretools:• IrealizedtheneedforadynamicEUD
addresstracer• Ialsoneededawaytosinglestep/debug
triggers
• IdevelopedanEUDTracer,aDLLthathooksthegameandinstrumentsalltherelevanttriggerhandlingcode
Identify– Staticallyidentifyalladdresses/4
• TheinstrumentedgamebinarycallsintothetracerDLLuponeachread/write
Identify– Dynamictracer/1
• ThePythontablecontainingEUDaddressesispassedtoasourcecodegeneratortoemitCcodeandtables
• Thetracerusesthattabletoaccountformemoryaccess
Identify– Dynamictracer/2
• WhenthegameloadsanEUDmap,thetracerDLLinterceptsallout-of-boundsaccess
• Anyunknownaddresstriggersabreakpointforfurtheranalysisandidentification
• AfterIidentifyanunknownaddress,IaddittothePythontablewhichisusedtoupdatethetracer’sEUDitemstable
Identify– Dynamictracer/3
• Thetracer’smainroleistoguaranteethatalltheaddressesreferredtofromtheEUDmapareaccountedfor
Identify– Dynamictracer/4
• HavingawaytorecordallaccessedEUDaddresseswasnotenoughtounderstandtheintentbehindtheaccess
• IhadnorealwaytodebuganEUDmap:• IneededawaytonicelyrepresentanEUD
address• Ineededtosinglestepaftereachtrigger• Ineededawaytoconvertaseriesof
read/writeprimitivestopseudo-code
Identify– Moredebuggingtools
• IfIwantedtotracetriggers,Ineededtohaveawaytoconvertanaddresstoanicevariablerepresentation
• Sowhatisthesymbolicrepresentationof:• 0x5187E8+(0xC*3)+4?Ø gCards[3].pBtns
Identify– EUDaddresstosymbolicname/1
• WiththehelpoftheHex-Raysdecompilerandothermetadata,Iwrotethefunction“R”toresolveanaddressintoanicesymbolicname
Identify– EUDaddresstosymbolicname/2
Ø Ifthearray’sindicesarebasedonenums,then“R”willproperlyshowtheenum nameinsteadofanumericindex
• SCMDraft triggereditortextuallyrepresentsthetriggerscript:
Identify– Staticpseudocodegenerator/1
• IwroteaconverterfromthetriggerstexttoCpseudo-code(converttriggerstoanASTandthenemitasCpseudo-code)
Identify– Staticpseudocodegenerator/2
• TriggertextconvertedtoCpseudo-code(trig2cpp()):
Identify– Staticpseudocodegenerator/3
• WithIDA’sconditionalbreakpointsandtheAppcall feature,Iwroteadynamicpseudocodegenerator:• Ithelpsdebugthemaptriggerlogicduringruntime• Ithelpsinthediscoveryandunderstandingof
dynamictriggers(generatedbytheEUDcompilerfromtrgk)
• Conditionalbreakpointsaresetatstrategicentrypoints(pre,inandposttriggerexecution)
Identify– Dynamicpseudocodegenerator/1
• ConditionalbreakpointsdynamicallybuildtheASTonaccess
Identify– Dynamicpseudocodegenerator/2
• Thedebugscripthasa‘Singlestep’switchtobreakaftereachtrigger• Pseudocodeisemittedonthefly
Demo– Dynamicpseudocodegenerator/1
• The“Singlestep”switchcanbeconfiguredtoprintthepseudocodeontheflyasthemaptriggersexecuteswithoutsuspendingthegame
Demo– Dynamicpseudocodegenerator/2
Inthefirststep(identify):1. Webuiltalltherequiredstaticanddynamictracers
2. WecreatedtheEUDtablewithallknownaddressesandtheirsymbolicnames
3. Wehaveenoughtoolstoidentifyanyaddressandtracewhereitcamefrom
Nowweneedtointercepttheout-of-boundsaccessinthenewcodebase
Intercept/1
Readprimitivesinterception Writeprimitivesinterception
Intercept/2
• Fromtheemulator’sperspective,allEUDmaplogicboilsdowntotwoactions:
1. Readanywhereà value=read_vmem(eud_addr)2. Writeanywhereà write_vmem(eud_addr,value)
Intercept/3
Inbasicscenarios,theemulationisverysimple:1. Computethefullvirtualaddress(EUD
address)fromthedwPlayer andwTypeindices
2. FromtheEUDaddress,findtheequivalentnewaddress(backingdata)inthecurrentgameversion
3. Computetheoffsetandreadorwritefrom/tothenewaddress
Emulate
• Let’sextendthepreviousPythontableandattachthesourcefilenamewereeachvariableislocated
• Thetabledefines:virtualaddress,itemsize,sourcefilename,emulationflags,andbackingvariablename
Emulate– Variablesmapping/1
RunningtheEUDtablegenerationscriptpatchesthesourcecodeandexportsallreferencedvariables:
Emulate– Variablesmapping/2
Exportedvariablesexample:
Emulate– Variablesmapping/3
Noneedtomakestaticvariablesglobal:• Thegeneratorhasanoptionthatletsyoupickanamefortheexportedvariable
Emulate– Variablesmapping/4
• The“eud_table.cpp”isautogeneratedfromthePythontable.Itreferstoalltheexportedvariablesfromvarioussourcecodefiles
• Itisusedtopopulatetheemulator’svirtualmemorylayout
• ItemsalsohaveassociatedflagsthatinstructtheemulatorwhichEUDadapterhandleswhichaddress
• Note:the“g_nothing”variablesarealignmentbytesinSC1.16.1.Themapmakersusethatspaceforstoringvariables
• A“nullptr”backingdataalmostalwaysindicatesthatthevariableistobehandledpurelybyanadaptercode
Emulate– TheEUDtable/1
• The“eud_extern.h”isautogeneratedfromthePythontable
• ItexposesalltheknownEUDvariables• Veryhandyforaccessingstaticvariablesfrom
anywhereinthecodewhenneeded
Emulate– TheEUDtable/2
EUDTable{addr1,size1,backing_data1,handler_flags1}{addr2,size2,backing_data2,handler_flags2}{addr3,size3,backing_data3,handler_flags3}…
EUDEmulator
Shadowtable
VirtualMemoryEUDaddress
ÛHandlersmapping
table
EUDAdapters
Datastructure#1adapter
Datastructure#nadapter…
Duetothenatureoftheoverflow,thefollowingrestrictionsapply:• AnEUDaddressisalways4bytesaligned• AnEUDvalueisa32bitsinteger
StarCraftRemastered
VirtualSC1.16.1memory
Realgamememory
Emulatorarchitecture/1
Shadowtable• Itcontainstheneededmemorycontents
fromtheSC1.16.1binary
Virtualmemory• Itusestheaddress-to-handlerslookuptable• ItmapsanEUDaddressrangetoanEUD
tableentryà EUDhandler/adapter
• ThetableentryforanEUDitemdescribes:• Thebackingdata(thenewvariable
address,ifpresent)• Theflagswhichtelltheemulatorwhich
EUDadapter(handler)touseforemulation
Emulatorarchitecture/2
AspecializedEUDadapterisneededwhen:• Handlingnon-standarddatatypes• WhendealingwithEUDaddressesthatnolongermap
toanythinginthenewgameclient
Thefollowing5virtualmethodsareexposed• read_vmem() à Returna32bitsvalue• write_vmem() àWritea32bitsvalue• backup() à Itemspecificbackupcode• restore() à Itemspecificrestorecode• deferred_write() à Invokedafterallthetriggers
haveexecuted.Givesachancetobatchprocesswrites
Emulatorarchitecture/3
ThebasicEUDadapter(eud_vmemitem_t class)handlesbasicdatatypes:1. TheemulatorcomputesthefullEUDaddress2. Findsthenewvariable’sbaseaddressandconvertstheEUDaddresstoanoffset3. Theappropriateadapteristhencalledwiththedesiredoffsettoread/writefrom/to
Thissimpletranslationapproachworksnicelyforbasictypes
EUDadapters– Basic/1
Thebasic(pass-thru)adapterisgoodformostcases:• Byte,Word,Dword• Theemulatorcancrossboundariesbetweentwoitems• Basictypesarraysarealsosupported
UWORDa[2] UWORDb[4]
Readingavaluefromtheendinvolvesreadingfromtwodifferent adapters(handlers)
EUDadapters– Basic/2
• Wecoveredtwoprimitives:
1. *memasg_op =const• asg_opà +=,=,-=
2. if(*memcmp_op const){actions…}• cmp_opà ==,>=,<=
• Howdowegetthefollowingprimitive?• *mem1asg_op *mem2
Usingbinarysearch!
Waitaminute,weneedonemoreprimitive!
• Triggercondition:1. Probesthevalueofsrc_var
• Triggeraction:1. Incrementsthevalueofdst_var2. Decrementthevalueofsrc_var3. src_var’s valueeventuallyreaches
zero4. Backupchangesintovar_copy
Thesameprimitiveisrepeatedtocopyvar_copy backtodst_var
The*a=*bprimitive
Thisprimitiveisexpensiveandgenerateslotsoftriggers
• Pointersare32bitsinSC1.16.1
• Obviously,wecannotjustusethepass-thrubasicemulation• Pointershavetobetranslatedfrom
EUDvirtualaddressestorealaddresses
• Theprimitive“*ptr1=*ptr2”invokedfromtheEUDtriggerswillspoilthepointervalueuntilthebinarysearchisover• Whattodowithincompletepointer
values?
EUDadapters– Pointers/1
• Changestoaphysicalpointervalueshouldnottakeeffectunlessthevirtualpointervaluepassesa“pointervaliditycheckfunction”à Doesthevirtualpointerhaveaproperrealpointerequivalent?
• Relyontheshadowpointervaluewhenworkingwithincompletevirtualpointervaluesforfuturereads/writes:
Realmemory EUDvirtualmemory
void*game_ptr;
uint32_tgame_ptr_shadow;boolgame_ptr_dirty;
uint32_tgame_ptr;
EUDadapters– Pointers/2
• Theeud_cobject_ptr_adapter_t isconstructedwithbackingdatapointingtoareferencetoarealpointerthatwewanttoexposetotheEUDemulator
EUDadapters– Pointers/3
• WhataboutEUDlogicthatdoesfunctionpointerarithmetic?
EUDadapters– Functionpointers/1
• PointerarithmeticmakesenseonlyintheEUDvirtualmemoryaddressingspace
• Fortherealpointeraddressingwehavetotranslatetoproperpointersandaccountforfunctionprototypecompatibility
• Basicimplementationidea:1. vaddr +=voffs2. paddr =find_real_fptr(vaddr,function_prototype_id)3. if(paddr !=nullptr)à struct.pFn =paddr;
• Intheemulator,suchcasesarehandledwiththeeud_struct_with_ptr_adapter_t
Virtualfunctionpointersandtheirprototypestable
EUDadapters– Functionpointers/2
• VariousdatastructureshavechangedbetweenSC1.16.1andSC:R
• Pass-thruadaptersarenothelpfulinthiscase
• Aspecializedadapterisneededtoconvertbetweenbothstructures:• Readoperation: translatesfromphysicalstructuretovirtual
structure• Writeoperation: translatesfromvirtualstructuretophysical
structure
EUDadapters– Incompatiblestructures/1
EUDadapters– Incompatiblestructures/2
• InSC1.16.1• TriggerswerestoredinaStorm linked
listdatastructure• Storm isalibrarythatprovides
containersandplatformindependentfunctionality
• InSC:R• Triggersarestoredasblz::list<_trigger>• ‘blz’istheequivalentofSTL’sstd
namespace
• OtherstructuresintheoldgamealsouseStorm listswhilethenewgameusesdifferentcontainers
EUDadapters– Linkedlists
Becausetriggersarehardtoprogram,theSouthKoreanhacker(nicknamedTriggerKing/trgk)wroteatriggercompiler:
1. YouwriteproperlogicinaJavaScript/PythonlikelanguagecalledepScript
2. TheepScript getscompiledintoabunchoftriggersandistheninjectedintotheappropriatemapchunks
3. MapcontainingtriggerscompiledwithepScript canbeidentifiedusingthebootstrapcodethatlinksregulartriggersintothedynamictriggers(insidethestringstable)
EUDadapters– Triggers/1
• epScript isaverypowerfullanguage:• TheMarioExodusEUDmapwaswritten
inthatlanguage
• Itscompilerhidesadditionaltriggersinthecaveareaofthestringschunk:
Ø Makingithardtoreverse-engineercompiledtriggers
Ø Oneneedstowriteatriggersdecompilertorecoverthelogic
• Compiledtriggersareself-modifyingandveryoptimized:
Ø Loops,functioncallsandothercontrolflowrelatedfunctionalityareimplementusingself-modifyingtriggersthatchangethetriggernodelinks(nextandprev links)
EUDadapters– Triggers/2
• EUDmapslocatethepointertothestringtable(gpMapStr)andaddsaconstantoffsetpointingtotheadditionaldynamictriggersinsidethestringtable(seeslide17)
• EUDmapsthenpatchthem_prevlink andm_next linksasneededtointroduceasmanytriggersasneeded• Insertingnewtriggersdynamicallywasnever
supportedinStarCraft.OnlytheEUDemulatorallowssuchactivity.
• Compiled/dynamictriggersarethebasisofcomplexandelaborateEUDmaps• Therefore,supportingdynamictriggerswasthefirst
thingaddedtotheEUDemulator
EUDadapters– Triggers/3
• Fromtheemulator’sperspective,therearetwokindsoftriggers:• Initialtriggersoriginatingfromthetriggerschunk• Dynamictriggerslinkedtothetriggerslistbypatchingtheirnodelinks
• WhenStarCraftneedstoexecutetriggersaftereachgameloop:• TheemulatorknowshowtoservebothstatictriggersanddynamicEUDtriggers• Theemulatordoesnotreplicatethebackingdata(thetriggernodedata)whenever
possible
EUDadapters– Triggers/4
SC:Rà blz::list<_trigger>: _trigger0 _trigger1 … _triggerN
SC1.16:stormlist<_trigger>: _trigger0 _trigger1 … _triggerN
shadow:prev|next shadow:prev|next
Stringtable:
(Dynamictriggersinsertedattheendofthestringstable)
Stringschunkdata
Actualstringtable(TStrTbl) Extrachunkdata:dynamictriggers
shadow:prev|next
TheStormnodeEUDadapterhoststhenodelinksasshadowvariables
EUDadapters– Triggers/5
• TheStormlistadapterimplementsanSTLcompatibleiterator
• Fromtheiterator’sperspective,anynodepointersoutsidethelisthastheirnodelinksanddatainthevirtualmemory
EUDadapters– Triggers/6
• Partialbuffersadaptersareusedwheneverthevirtualitemsizeisgreaterthanthephysicalitemsize:
SC1.16.1item(virtual):
SC:Ritem(physical):
data
smallerdata unmapped
• Theadapterservesthemappeddatawhentheaccessoffsetiswithinthemappedrange
• Itwillservezerosw/ofailingwhentheunmappedareaisaccessed
EUDadapters– Partialbuffers
1. Certainadaptersresorttousingdeferredwritesasmeanstospeed-uptheemulation
2. TheEUDmapwritesinchunksof4bytesatatimeØ Wedon’twanttore-constructrealgamedata
whiletheEUDmapisstillwritingthechanges
3. Instead,awritehandlersimplypasses-thruthewritestoatemporarybufferandmarkstheadapterasdirty• (Readsfromdirtyoffsetsareservedfromthe
temporarybufferforconsistency)
4. Afteralltriggersareexecutedinthatgameloop,theemulatorinvokesallthedirtyadapters’deferredwritecallbacks
5. Insidethedeferredwritecallback,thetemporarybufferisthenusedtoreconstructtherealstructuresusedbythegame.Theadapterdirtyflagisthencleared.
EUDadapters– Deferredwrites/1
1. ThestatustextadapterletstheEUDmapswritetoatemporarybuffer
2. Afterwards,theadapterre-constructstheproperstatustextstructuresthatarecompatiblewiththenewgame(SC:R)code
EUDadapters– Deferredwrites/2
Deferredwriteexampleadapter:
• Variousgamedatavariablesareintegerarrays
• Sometimes,theelementsinthearraymusthaveboundedvalues• Naturally,thepass-thru(basic)adapterisnot
suitable(becausenovalidationtakesplace)
• Theboundedarrayadapteralsoleverageashadowarraytableforalltheelementsthathaveincomplete/invalidvalues
• Onlyafterthewrittenvaluesarevalid(withinthespecifiedbounds)thenchangesarereflectedintothebackingdata
EUDadapters– Boundedarrayelements/1
• TheUnitFlingy array’svalueshaveanupperboundof209EUDadapters– Boundedarrayelements/2
ThroughoutthecreationoftheEUDemulator,variousadaptersweredevisedwheneveranewproblemisencountered:
• eud_adapter_cards• Supportstotalcustomizationofunits
commandcards
• eud_adapter_csprites andeud_adapter_cunit• Allowscontrolledmodificationsintothe
CSprite andCUnit structures
• eud_adapter_group• Allowsbitmapshufflinginsidecertaingame
animationframes
• eud_adapter_keytable• AllowsEUDmapstointerceptkeypresses(‘a’,
‘s’,‘w’,‘d’,keyupandkeydownforexample)
EUDadapters– Fulladapterslist/1
• eud_adapter_mpq• Allowssupportforprotectedmaps.• RefertoMPQfrozenmaps:
https://github.com/phu54321/euddraft/tree/master/freeze
• eud_adapter_msgtbl• Readaccessintothein-gamechatmessages
(“ChattingWar”EUDmaps)
• eud_adapter_partial_buffer• Variousnon-emulatedornolongerexistent
variablesarehandledwiththisadapter
• eud_adapter_playerdata• LetsEUDmapsreadplayerinformation
(name,race,color,etc.)
EUDadapters– Fulladapterslist/2
• eud_adapter_pointers• Allpointerrelatedadaptioncode• Supportspartialpointers(backedbyshadow
values)
• eud_adapter_stattxt• Unitstatustextandhotkeysmanipulation
• eud_adapter_stormlist• Allowshigh-levelemulationofStormlists
• eud_adapter_structwithptr• Usedtoemulatestructuresthatcontainamixof
basictypes(pass-thru)andpointers(incompletepointers+virtual<->physicalconversion)
• eud_adapter_triggers• Supportsdynamictriggersemulation
EUDadapters– Fulladapterslist/3
Questions?