ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 no starch press and the no starch press logo...

379

Upload: others

Post on 14-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names
Page 2: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

GAMEHACKINGDevelopingAutonomousBotsforOnlineGames

NickCano

SanFrancisco

Page 3: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

GAMEHACKING.Copyright©2016byNickCano.

Allrightsreserved.Nopartofthisworkmaybereproducedortransmittedinanyformorbyanymeans,electronicormechanical,includingphotocopying,recording,orbyanyinformationstorageorretrievalsystem,withoutthepriorwrittenpermissionofthecopyrightownerandthepublisher.

PrintedinUSA

Firstprinting

2019181716123456789

ISBN-10:1-59327-669-9ISBN-13:978-1-59327-669-0

Publisher:WilliamPollockProductionEditor:LaurelChunCoverIllustration:RyanMilnerInteriorDesign:OctopodStudiosDevelopmentalEditor:JenniferGriffith-DelgadoTechnicalReviewer:StephenLawlerCopyeditor:RachelMonaghanCompositor:LaurelChunProofreader:PaulaL.FlemingIndexer:BIMCreatives,LLC

Forinformationondistribution,translations,orbulksales,pleasecontactNoStarchPress,Inc.directly:NoStarchPress,Inc.2458thStreet,SanFrancisco,CA94103phone:415.863.9900;[email protected]

LibraryofCongressCataloging-in-PublicationData

Cano,Nick,author.Gamehacking:developingautonomousbotsforonlinegames/byNickCano.pagescmIncludesindex.Summary:"Ahands-onguidetohackingcomputergames.Showsprogrammershowtodissectcomputergamesandcreatebotstoaltertheirgamingenvironment.Coversthebasicsofgamehacking,includingreverseengineering,assemblycodeanalysis,programmaticmemorymanipulation,persistenthacks,responsivehacks,andcodeinjection."--Providedbypublisher.ISBN978-1-59327-669-0--ISBN1-59327-669-91.Intelligentagents(Computersoftware)2.Internetprogramming.3.Internetgames--Programming.4.Hacking.I.Title.QA76.76.I58C362016

Page 4: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

005.8--dc23

2015036294

NoStarchPressandtheNoStarchPresslogoareregisteredtrademarksofNoStarchPress,Inc.Otherproductandcompanynamesmentionedhereinmaybethetrademarksoftheirrespectiveowners.Ratherthanuseatrademarksymbolwitheveryoccurrenceofatrademarkedname,weareusingthenamesonlyinaneditorialfashionandtothebenefitofthetrademarkowner,withnointentionofinfringementofthetrademark.

Theinformationinthisbookisdistributedonan“AsIs”basis,withoutwarranty.Whileeveryprecautionhasbeentakeninthepreparationofthiswork,neithertheauthornorNoStarchPress,Inc.shallhaveanyliabilitytoanypersonorentitywithrespecttoanylossordamagecausedorallegedtobecauseddirectlyorindirectlybytheinformationcontainedinit.

Page 5: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AbouttheAuthorNickCanowrotehisfirstscriptsforopensourcegameserverswhenhewas12andstartedabusinesssellinghisbotswhenhewas16.Hehasbeenapartofthegame-hackingcommunityeversinceandadvisesgamedevelopersanddesignersonbestpracticestoprotecttheirgamesagainstbots.Nickalsohasyearsofexperienceindetectinganddefendingagainstmalware,andhehasspokenatmanyconferencesabouthisresearchandtools.

Page 6: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AbouttheTechnicalReviewerStephenLawleristhefounderandpresidentofasmallcomputersoftwareandsecurityconsultingfirm.Hehasbeenactivelyworkingininformationsecurityforover10years,primarilyinreverseengineering,malwareanalysis,andvulnerabilityresearch.HewasamemberoftheMandiantmalwareanalysisteamandassistedwithhigh-profilecomputerintrusionsaffectingseveralFortune100companies.StephenalsodevelopedandteachesthePracticalARMExploitationclass,whichhasbeenofferedatBlackHatandseveralothersecurityconferencesforthepastfiveyears.

Page 7: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

BRIEFCONTENTS

ForewordbyDr.JaredDeMott

Acknowledgments

Introduction

PART1:TOOLSOFTHETRADEChapter1:ScanningMemoryUsingCheatEngine

Chapter2:DebuggingGameswithOllyDbg

Chapter3:ReconnaissancewithProcessMonitorandProcessExplorer

PART2:GAMEDISSECTIONChapter4:FromCodetoMemory:AGeneralPrimer

Chapter5:AdvancedMemoryForensics

Chapter6:ReadingfromandWritingtoGameMemory

PART3:PROCESSPUPPETEERINGChapter7:CodeInjection

Chapter8:ManipulatingControlFlowinaGame

PART4:CREATINGBOTSChapter9:UsingExtrasensoryPerceptiontoWardOffFogofWar

Chapter10:ResponsiveHacks

Chapter11:PuttingItAllTogether:WritingAutonomousBots

Page 8: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Chapter12:StayingHidden

Index

Page 9: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CONTENTSINDETAIL

FOREWORDbyDr.JaredDeMott

ACKNOWLEDGMENTS

INTRODUCTIONPrerequisitesfortheReaderABriefGameHackingHistoryWhyHackGames?HowThisBookIsOrganizedAbouttheOnlineResourcesHowtoUseThisBook

PART1TOOLSOFTHETRADE

1SCANNINGMEMORYUSINGCHEATENGINEWhyMemoryScannersAreImportantBasicMemoryScanningCheatEngine’sMemoryScanner

ScanTypesRunningYourFirstScanNextScansWhenYouCan’tGetaSingleResultCheatTables

MemoryModificationinGamesManualModificationwithCheatEngine

Page 10: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

TrainerGeneratorPointerScanning

PointerChainsPointerScanningBasicsPointerScanningwithCheatEnginePointerRescanning

LuaScriptingEnvironmentSearchingforAssemblyPatternsSearchingforStrings

ClosingThoughts

2DEBUGGINGGAMESWITHOLLYDBGABriefLookatOllyDbg’sUserInterfaceOllyDbg’sCPUWindow

ViewingandNavigatingaGame’sAssemblyCodeViewingandEditingRegisterContentsViewingandSearchingaGame’sMemoryViewingaGame’sCallStack

CreatingCodePatchesTracingThroughAssemblyCodeOllyDbg’sExpressionEngine

UsingExpressionsinBreakpointsUsingOperatorsintheExpressionEngineWorkingwithBasicExpressionElementsAccessingMemoryContentswithExpressions

OllyDbgExpressionsinActionPausingExecutionWhenaSpecificPlayer’sNameIsPrintedPausingExecutionWhenYourCharacter’sHealthDrops

OllyDbgPlug-insforGameHackersCopyingAssemblyCodewithAsm2ClipboardAddingCheatEnginetoOllyDbgwithCheatUtilityControllingOllyDbgThroughtheCommandLineVisualizingControlFlowwithOllyFlow

Page 11: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ClosingThoughts

3RECONNAISSANCEWITHPROCESSMONITORANDPROCESSEXPLORERProcessMonitor

LoggingIn-GameEventsInspectingEventsintheProcessMonitorLogDebuggingaGametoCollectMoreData

ProcessExplorerProcessExplorer’sUserInterfaceandControlsExaminingProcessPropertiesHandleManipulationOptions

ClosingThoughts

PART2GAMEDISSECTION

4FROMCODETOMEMORY:AGENERALPRIMERHowVariablesandOtherDataManifestinMemory

NumericDataStringDataDataStructuresUnionsClassesandVFTables

x86AssemblyCrashCourseCommandSyntaxProcessorRegistersTheCallStackImportantx86InstructionsforGameHacking

Page 12: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ClosingThoughts

5ADVANCEDMEMORYFORENSICSAdvancedMemoryScanning

DeducingPurposeFindingthePlayer’sHealthwithOllyDbgDeterminingNewAddressesAfterGameUpdates

IdentifyingComplexStructuresinGameDataThestd::stringClassThestd::vectorClassThestd::listClassThestd::mapClass

ClosingThoughts

6READINGFROMANDWRITINGTOGAMEMEMORYObtainingtheGame’sProcessIdentifier

ObtainingProcessHandlesWorkingwithOpenProcess()

AccessingMemoryWorkingwithReadProcessMemory()andWriteProcessMemory()AccessingaValueinMemorywithReadProcessMemory()andWriteProcessMemory()WritingTemplatedMemoryAccessFunctions

MemoryProtectionDifferentiatingx86WindowsMemoryProtectionAttributesChangingMemoryProtection

AddressSpaceLayoutRandomizationDisablingASLRtoSimplifyBotDevelopmentBypassingASLRinProduction

ClosingThoughts

Page 13: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PART3PROCESSPUPPETEERING

7CODEINJECTIONInjectingCodeCaveswithThreadInjection

CreatinganAssemblyCodeCaveTranslatingtheAssemblytoShellcodeWritingtheCodeCavetoMemoryUsingThreadInjectiontoExecutetheCodeCave

HijackingaGame’sMainThreadtoExecuteCodeCavesBuildingtheAssemblyCodeCaveGeneratingSkeletonShellcodeandAllocatingMemoryFindingandFreezingtheMainThread

InjectingDLLsforFullControlTrickingaProcessintoLoadingYourDLLAccessingMemoryinanInjectedDLLBypassingASLRinanInjectedDLL

ClosingThoughts

8MANIPULATINGCONTROLFLOWINAGAMENOPingtoRemoveUnwantedCode

WhentoNOPHowtoNOP

HookingtoRedirectGameExecutionCallHookingVFTableHookingIATHookingJumpHooking

ApplyingCallHookstoAdobeAIR

Page 14: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AccessingtheRTMPGoldmineHookingtheRTMPSencode()FunctionHookingtheRTMPSdecode()FunctionPlacingtheHooks

ApplyingJumpHooksandVFHookstoDirect3DTheDrawingLoopFindingtheDirect3DDeviceWritingaHookforEndScene()WritingaHookforReset()What’sNext?

ClosingThoughts

PART4CREATINGBOTS

9USINGEXTRASENSORYPERCEPTIONTOWARDOFFFOGOFWARBackgroundKnowledgeRevealingHiddenDetailswithLighthacks

AddingaCentralAmbientLightSourceIncreasingtheAbsoluteAmbientLightCreatingOtherTypesofLighthacks

RevealingSneakyEnemieswithWallhacksRenderingwithZ-BufferingCreatingaDirect3DWallhackFingerprintingtheModelYouWanttoReveal

GettingaWiderFieldofVisionwithZoomhacksUsingNOPingZoomhacksScratchingtheSurfaceofHookingZoomhacks

DisplayingHiddenDatawithHUDsCreatinganExperienceHUD

Page 15: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

UsingHookstoLocateDataAnOverviewofOtherESPHacksClosingThoughts

10RESPONSIVEHACKSObservingGameEvents

MonitoringMemoryDetectingVisualCuesInterceptingNetworkTraffic

PerformingIn-GameActionsEmulatingtheKeyboardSendingPackets

TyingthePiecesTogetherMakingthePerfectHealerResistingEnemyCrowd-ControlAttacksAvoidingWastedMana

ClosingThoughts

11PUTTINGITALLTOGETHER:WRITINGAUTONOMOUSBOTSControlTheoryandGameHackingStateMachinesCombiningControlTheoryandStateMachines

ABasicHealerStateMachineAComplexHypotheticalStateMachineErrorCorrection

PathfindingwithSearchAlgorithmsTwoCommonSearchTechniquesHowObstaclesDisruptSearchesAnA*SearchAlgorithmWhenA*SearchesAreParticularlyUseful

Page 16: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CommonandCoolAutomatedHacksLootingwithCavebotsAutomatingCombatwithWarbots

ClosingThoughts

12STAYINGHIDDENProminentAnti-CheatSoftwareThePunkBusterToolkit

Signature-BasedDetectionScreenshotsHashValidation

TheESEAAnti-CheatToolkitTheVACToolkit

DNSCacheScansBinaryValidationFalsePositives

TheGameGuardToolkitUser-ModeRootkitKernel-ModeRootkit

TheWardenToolkitCarefullyManagingaBot’sFootprint

MinimizingaBot’sFootprintMaskingYourFootprintTeachingaBottoDetectDebuggersAnti-DebuggingTechniques

DefeatingSignature-BasedDetectionDefeatingScreenshotsDefeatingBinaryValidationDefeatinganAnti-CheatRootkitDefeatingHeuristicsClosingThoughts

Page 17: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

INDEX

Page 18: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

FOREWORD

Nickisgreat.Wefirsthititoffinalltherightandwrongways,asyoucanimagine.I’vebeeninthesecurityfieldawhile;he’salittleyounger.I’vehadtheschooling,whereashe’snotmuchforcollege.I’mafaithguy,andhe’snot.Theinterestingthingisthatnoneofthatmatters;we’vehadablastanyway.Age,race,gender,degrees—whenitcomestogaming,hacking,andcoding,noonecares!

Nickgetsitdone.He’sfun.He’sbrilliant.He’shardworking.Andprobablymostpertinent:he’soneoftherarefewwhounderstandtheintersectionofgaming,hacking,andcoding.He’sworkedinthisnicheandcreatedprofitablebots.

Inthisfirst-of-its-kindbook,Nickwalksyouthroughwhatitmeanstopullapartgames.Heteachesyouthesoftwareinvestigationtoolsandtricksofthetrade.You’lllearnaboutgameinternals,howtopullthemapart,andhowtomodifyplay.Forexample,Nickteacheshowtoavoidanti-cheatsothatyoucanautomateplay.Wouldn’titbecooltohaveyourownbotthatcollectsexperience,gold,items,andmore—allwhileyou’reaway?

Everwonderhowthecheaterscheat?Everwantedtopatchorprotectyourgame?Grabacoffee,crackopenyourlaptop,andenjoy.

Blessingstoyouandyours,

Dr.JaredDeMottSecurityExpert&SoftwareBuilder

Page 19: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ACKNOWLEDGMENTS

Writingthisbookwasanamazingjourney,andIcouldn’thavedoneitalone.NoStarchPresshasbeenextremelysupportiveandworkedcloselywithmetotakethisbookfromconcepttoreality.Inparticular,I’dliketothankmydevelopmentaleditor,JenniferGriffith-Delgado,andmyproductioneditor,LaurelChun.BillPollock,TylerOrtman,AlisonLaw,andtherestoftheteamatNoStarcharewonderfulpeople,andI’mpleasedtohaveworkedwiththem.

ThankstocopyeditorRachelMonaghan,proofreaderPaulaL.Fleming,andtechnicalreviewerStephenLawler.ThanksalsotomyfriendsCavitt“synt4x”GloverandVadimKotov,whotookthetimetoskimsomechaptersbeforesubmission,andtoJaredDeMottforwritingthebook’sforeword.

I’dliketothankallofthepeopleonTPForumswhotookmeinwhenIwasjustanaivekidandhelpedmelearnhowtohackgames.Inparticular,IowemythankstoJoseph“jo3bingham”Bingham,IanObermiller,andjeremic,whoallhadasignificantinfluenceonmyprogressionasahacker,andtoTPForumsfounderJosh“Zyphrus”Hartzell,whohelpedmefindmyconfidenceandskillswhenmyfuturelookeditsbleakest.

Thanksalsotomyentireforumstaffandeverycustomerwhohaseverusedmybots.Andfinally,thankstomyfamily,friends,andcolleagues,whohavebeenfunandsupportiveandhelpedshapemeintothemanIamtoday.

Page 20: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

INTRODUCTION

Acommonmisconceptionintheworldofonlinegamingistheideathattheonlygameyoucanplayistheoneinthetitle.Infact,gamehackersenjoyplayingthegamethathidesbehindthecurtain:acat-and-mousegameofwitsbetweenthemandthegamedevelopers.Whilegamehackersworktoreverseengineergamebinaries,automateaspectsofgameplay,andmodifygamingenvironments,gamedeveloperscombatthehacker-designedtools(normallyreferredtoasbots)usinganti-reversingtechniques,botdetectionalgorithms,andheuristicdatamining.

Asthebattlebetweengamehackersanddevelopershasprogressed,thetechnicalmethodsimplementedbybothparties—manyofwhichresembletechniquesutilizedbymalwaredevelopersandantivirusvendors—haveevolved,becomingmorecomplex.Thisbookhighlightsthefightputupbygamehackers,andtheadvancedmethodstheyhaveengineeredtomanipulategameswhilesimultaneouslyeludinggamedevelopersinthedarkcornersoftheirownsoftware.

Althoughthebookfocusesonteachingyoutodeveloptoolsthatwouldlikelybeconsideredanuisanceorevenmaliciousbygamingcompanies,you’llfindthatmanyofthetechniquesareusefulfordevelopmentoftoolsthatareperfectlybenignandneutral.Furthermore,theknowledgeofhowthesetechniquesareimplementediskeyforthegamedevelopersworkingtopreventtheiruse.

Page 21: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PrerequisitesfortheReaderThisbookdoesnotaimtoteachyousoftwaredevelopment,andthereforeassumesthatyouhave,atminimum,asolidsoftwaredevelopmentbackground.ThisbackgroundshouldincludefamiliaritywithnativeWindows-baseddevelopment,aswellaslightexperiencewithgamedevelopmentandmemorymanagement.Whiletheseskillswillbeenoughforyoutofollowthisbook,experiencewithx86assemblyandWindowsinternalswillensurethatdetailsofmoreadvancedimplementationsarenotlostonyou.

Furthermore,sincealltheadvancedhacksdiscussedinthisbookrelyoncodeinjection,anabilitytowritecodeinanativelanguagelikeCorC++isamust.AlloftheexamplecodeinthisbookiswritteninC++andcanbecompiledwithMicrosoftVisualC++ExpressEdition.(YoucandownloadMSVC++ExpressEditionfromhttp://www.visualstudio.com/en-US/products/visual-studio-express-vs.)

NOTE

Otherlanguagesthatcompiletonativecode,suchasDelphi,arealsocapableofinjection,butIwillnotdiscusstheminthisbook.

ABriefGameHackingHistorySincethedawnofonlinePCgamingintheearly1980s,anongoingwarofwitsbetweengamehackersandgamedevelopershasbeentakingplace.Thisseeminglyendlessstrugglehaspromptedgamedeveloperstodevotecountlesshourstowardpreventinghackersfromtakingtheirgamesapartandgreasingbetweenthegears.Thesehackers,whofightbackwiththeirsophisticatedstealthimplementations,havemanymotivations:customizedgraphics,betterperformance,easeofuse,autonomousplay,in-gameassetacquisition,and,ofcourse,real-lifeprofit.

Thelate1990sandearly2000swerethegoldenageofgamehacking,whenonlinePCgamesbecameadvancedenoughtodrawlargecrowdsbutwerestillsimpleenoughtoeasilyreverseengineerandmanipulate.Online

Page 22: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

gamesthatcameoutduringthistime,suchasTibia(January1997),Runescape(January2001),andUltimaOnline(September1997),wereheavilytargetedbybotdevelopers.Thedevelopersofthesegamesandotherslikethemstillstruggletodaytocontrolthemassivecommunitiesofbotdevelopersandbotusers.Thegamedevelopers’lackofactionandthehackers’tenacityhavenotonlycompletelyshatteredtheeconomieswithinthegames,buthavealsoproducedathrivingfor-profitindustryfocusedaroundbotdevelopmentandbotdefense.

Intheyearssincethegoldenage,morematuregamecompaniesstartedtakingbotdefenseveryseriously.Thesecompaniesnowhavededicatedteamsfocusedondevelopingbotpreventionsystems,andmanyalsoviewbotsasalegalmatterandwillnothesitatetobanishplayerswhousebotsandsuethebotdeveloperswhoprovidedthem.Asaresult,manygamehackershavebeenforcedtodevelopadvancedstealthtechniquestokeeptheiruserssafe.

Thiswarwageson,andthenumbersonbothsidesofthefightwillcontinuetogrowasonlinegamingbecomesmoreprevalentoverthecomingyears.Majorgamedevelopersarepursuinghackerswithendlessdetermination,evenslammingsomegamehackinggiantswithmultimillion-dollarlawsuits.Thismeansthatgamehackerswhoareseriousabouttheirbusinessmusteithertargetsmallergamingcompanies,oranonymouslymarkettheirproductsfromtheshadowsinordertoescapeprosecution.Fortheforeseeablefuture,gamehackingandbotdevelopmentwillcontinuetogrowintoalargerandmorelucrativeindustryforthosegamehackersboldenoughtotaketherisks.

WhyHackGames?Asidefromitsobviousallureandchallengingnature,gamehackinghassomepracticalandprofitablepurposes.Everyday,thousandsofnoviceprogrammersexperimentwithsmall-scalegamehackingasawaytoautomatemonotonoustasksorperformmenialactions.ThesescriptkiddieswilluseautomationtoolslikeAutoItfortheirsmall,relativelyharmlesshacks.Ontheotherhand,professionalgamehackers,backedbytheirlargetoolkitsandyearsofprogrammingexperience,willdevotehundredsofhourstothedevelopmentofadvancedgamehacks.Thesetypesofgamehacks,whicharethefocusofthisbook,areoftencreatedwiththeintentofmaking

Page 23: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

whicharethefocusofthisbook,areoftencreatedwiththeintentofmakinglargeamountsofmoney.

Gamingisahugeindustrythatgenerated$22.4billioninsalesin2014,accordingtotheEntertainmentSoftwareAssociation.Ofthetensofmillionsofplayerswhoplaygamesdaily,20percentplaymassivelymultiplayeronlinerole-playinggames(MMORPGs).TheseMMORPGsoftenhavethousandsofplayerswhotradevirtualgoodswithinthrivingin-gameeconomies.Playersoftenhaveaneedforin-gameassetsandarewillingtobuytheseassetswithreal-worldmoney.Consequently,MMORPGplayersendupdevelopinglargecommunitiesthatprovidegold-for-cashservices.Theseservicesoftengoasfarasenforcingexchangeratesfromin-gamegoldtoreal-worldcurrencies.

Totakeadvantageofthis,gamehackerswillcreatebotsthatarecapableofautomaticallyfarminggoldandlevelingcharacters.Then,dependingontheirgoal,hackerswilleithersetupmassivegoldfarmsandselltheirin-gameprofits,orperfectandselltheirsoftwaretoplayerswhowishtoseamlesslyobtainlevelsandgoldwithminimalinterference.DuetothemassivecommunitiessurroundingpopularMMORPGs,thesegamehackerscanmakebetweensixandsevenfiguresannually.

WhileMMORPGsprovidethelargestattacksurfaceforhackers,theyhavearelativelysmallaudienceoverall.About38percentofgamersfavorreal-timestrategy(RTS)andmassiveonlinebattlearena(MOBA)games,andanother6percentplayprimarilyfirst-personshooter(FPS)games.Thesecompetitiveplayerversusplayer(PvP)gamescollectivelyrepresent44percentofthegamingmarketandprovidegreatrewardstodeterminedgamehackers.

PvPgamesareoftenepisodicinnature;eachmatchisanisolatedgame,andthere’stypicallynotmuchprofitableprogressionforbottingawayfromkeyboard(AFK).Thismeansthat,insteadofrunninggoldfarmsorcreatingautonomousbotstolevelupcharacters,hackerswillcreatereactivebotsthatassistplayersincombat.

Thesehighlycompetitivegamesareaboutskillandtactics,andmostplayersparticipatetoprovetheirabilitytothemselvesandothers.Asaconsequence,thenumberofpeopleseekingbotsforPvP-typegamesissubstantiallylowerthanyou’dfindinthegrind-heavyworldofMMORPGs.Nevertheless,hackerscanstillmakeaprettypennysellingtheirPvPbots,whichareoftenmucheasiertodevelopthanfull-fledgedautonomousbots.

Page 24: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

HowThisBookIsOrganizedThisbookissplitintofourparts,eachofwhichfocusesonadifferentcoreaspectofgamehacking.InPart1:ToolsoftheTrade,you’llgetaboxfulloftoolstohelpyouhackgames.

•Chapter1:ScanningMemoryUsingCheatEnginewillteachyouhowtoscanagame’smemoryforimportantvaluesusingCheatEngine.

•InChapter2:DebuggingGameswithOllyDbg,you’llgetacrashcourseindebuggingandreverseengineeringwithOllyDbg.Theskillsyoulearnherewillbeextremelyusefulwhenyoustartmakingadvancedbotsandinjectingcode.

•Towrapup,Chapter3:ReconnaissancewithProcessMonitorandProcessExplorer,willteachyouhowtousetworeconnaissancetoolstoinspecthowgamesinteractwithfiles,otherprocesses,thenetwork,andtheoperatingsystem.

TheonlineresourcesforeachchapterinPart1includecustombinariesIcreatedtogiveyouasafeplacetotestandhoneyournewlydiscoveredskills.

Onceyou’recomfortablewitheverywrenchandhammer,Part2:GameDissection,willteachyouhowtogetunderthehoodandfigureouthowgameswork.

•InChapter4:FromCodetoMemory:AGeneralPrimer,you’lllearnwhatagame’ssourcecodeanddatalooklikeoncecompiledintoagamebinary.

•Chapter5:AdvancedMemoryForensicsbuildsontheknowledgeyou’llgainfromChapter4.You’lllearnhowtoscanmemoryandusedebuggingtoseamlesslylocatetrickymemoryvaluesanddissectcomplexclassesandstructures.

•Finally,Chapter6:ReadingfromandWritingtoGameMemoryshowsyouhowtoreadandmodifydatawithinarunninggame.

Thesechaptersprovidelotsofin-depthproof-of-conceptexamplecodethatyoucanusetoverifyeverythingyouread.

Page 25: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

InPart3:ProcessPuppeteering,you’llbecomeapuppeteerasyoulearnhowtoturnanygameintoamarionette.

•BuildingontheskillsfromParts1and2,Chapter7:CodeInjectiondescribeshowtoinjectandexecuteyourowncodeintheaddressspaceofagame.

•Onceyou’vemasteredinjection,Chapter8:ManipulatingControlFlowinaGamewillteachyouhowtouseinjectiontointercept,modify,ordisableanyfunctioncallmadebyagame,andwillwrapupwithsomeusefulreal-worldexamplesforthecommonlibrariesAdobeAIRandDirect3D.

Tocomplementyourpuppeteeringclasses,thesechaptersareaccompaniedbythousandsoflinesofproduction-readycodethatyoucanuseasaboilerplatelibraryforafuturebot.

InPart4:CreatingBots,you’llseehowtocombineyourtoolbox,dissectionabilities,puppeteeringskills,andsoftwareengineeringbackgroundtocreatepowerfulbots.

•Chapter9:UsingExtrasensoryPerceptiontoWardOffFogofWarexploreswaystomakeagamedisplayusefulinformationthatisn’texposedbydefault,suchasthelocationsofhiddenenemiesandtheamountofexperienceyouearnperhour.

•Chapter10:ResponsiveHacksshowscodepatternsyoucanusetodetectin-gameevents,likedecreasesinhealth,andtomakebotsthatreacttothoseeventsfasterthanhumanplayers.

•Chapter11:PuttingItAllTogether:WritingAutonomousBotsrevealshowbotsthatplaygameswithouthumaninteractionwork.Automatedbotscombinecontroltheory,statemachines,searchalgorithms,andmathematicalmodels,andthischapterisacrashcourseinthosetopics.

•InChapter12:StayingHidden,you’lllearnaboutsomeofthehigh-leveltechniquesyoucanusetoescapeandevadeanysystemthatwouldinterferewithyourbots.

Asyou’veprobablycometoexpect,thesechaptershavelotsofexamplecode.Someofthehacksshowninthispartarebuiltonexamplecodefrom

Page 26: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

previouschapters.Othersexploresuccinct,straightforwarddesignpatternsyoucanusetocreateyourownbots.Onceyou’vefinishedallfourpartsofthisbook,you’llbesentoffintothevirtualworldwithyournewsuperpower.

AbouttheOnlineResourcesYou’llfindmanyadditionalresourcesforthisbookathttps://www.nostarch.com/gamehacking/.Theseresourcesincludecompiledbinariestotestyourskills,aconsiderableamountofexamplecode,andquiteafewsnippetsofproduction-readygamehackingcode.Theseresourcesgohand-in-handwiththebook,anditreallyisn’tcompletewithoutthem,somakesuretodownloadthembeforeyoucontinue.

HowtoUseThisBookThisbookshouldbeusedfirstandforemostasaguidetogetyoustartedingamehacking.Theprogressionissuchthatthecontentofeachchapterintroducesnewskillsandabilitiesthatbuildonallpreviouschapters.Asyoucompletechapters,Iencourageyoutoplaywiththeexamplecodeandtestyourskillsonarealgamebeforecontinuingyourreading.Thisisimportant,assomecoveredtopicswillhaveusecasesthatdon’tbecomeevidentuntilyou’re10feetdeepinthemud.

Onceyou’vefinishedthebook,Ihopeitcanstillbeusefultoyouasafieldmanual.Ifyoucomeacrosssomedatastructureyou’reunsureof,maybethedetailsinChapter5canhelp.Ifyoureverseengineeragame’smapformatandarereadytocreateapathfinder,youcanalwaysfliptoChapter11,studythecontent,andusesomeoftheexamplecodeasastartingpoint.Althoughit’simpossibletoanticipatealltheproblemsyoumightfacewhenyou’rehackingaway,I’vetriedtoensureyou’llfindsomeanswerswithinthesepages.

ANOTEFROMTHEPUBLISHERThisbookdoesnotcondonepiracy,violatingtheDMCA,infringingcopyright,orbreakingin-gameTermsofService.Gamehackershave

Page 27: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

copyright,orbreakingin-gameTermsofService.Gamehackershavebeenbannedfromgamesforlife,suedformillionsofdollars,andevenjailedfortheirwork.

Page 28: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PART1TOOLSOFTHETRADE

Page 29: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

1SCANNINGMEMORYUSINGCHEATENGINE

Thebestgamehackersintheworldspendyearspersonalizingexpansivearsenalswithcustom-builttools.Suchpotenttoolkitsenablethesehackerstoseamlesslyanalyzegames,effortlesslyprototypehacks,andeffectivelydevelopbots.Atthecore,however,eachuniquekitisbuiltfromthesamefour-piecepowerhouse:amemoryscanner,anassembler-leveldebugger,aprocessmonitor,andahexeditor.

Memoryscanningisthegatewaytogamehacking,andthischapterwillteachyouaboutCheatEngine,apowerfulmemoryscannerthatsearchesagame’soperatingmemory(whichlivesinRAM)forvaluesliketheplayer’slevel,health,orin-gamemoney.First,I’llfocusonbasicmemoryscanning,memorymodification,andpointerscanning.Followingthat,we’lldiveintoCheatEngine’spowerfulembeddedLuascriptingengine.

NOTE

YoucangrabCheatEnginefromhttp://www.cheatengine.org/.Payattentionwhenrunningtheinstallerbecauseitwilltrytoinstallsometoolbarsandotherbloatware.Youcandisablethoseoptionsifyouwish.

WhyMemoryScannersAreImportantKnowingagame’sstateisparamounttointeractingwiththegame

Page 30: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Knowingagame’sstateisparamounttointeractingwiththegameintelligently,butunlikehumans,softwarecan’tdeterminethestateofagamesimplybylookingatwhat’sonthescreen.Fortunately,underneathallofthestimuliproducedbyagame,acomputer’smemorycontainsapurelynumericrepresentationofthatgame’sstate—andprogramscanunderstandnumberseasily.Hackersusememoryscannerstofindthosevaluesinmemory,andthenintheirprograms,theyreadthememoryintheselocationstounderstandthegame’sstate.

Forexample,aprogramthathealsplayerswhentheyfallbelow500healthneedstoknowhowtodotwothings:trackaplayer’scurrenthealthandcastahealingspell.Theformerrequiresaccesstothegame’sstate,whilethelattermightonlyrequireabuttontobepressed.Giventhelocationwhereaplayer’shealthisstoredandthewaytoreadagame’smemory,theprogramwouldlooksomethinglikethispseudocode:

//dothisinsomeloophealth=readMemory(game,HEALTH_LOCATION)if(health<500)pressButton(HEAL_BUTTON)

AmemoryscannerallowsyoutofindHEALTH_LOCATIONsothatyoursoftwarecanqueryitforyoulater.

BasicMemoryScanningThememoryscanneristhemostbasic,yetmostimportant,toolfortheaspiringgamehacker.Asinanyprogram,alldatainthememoryofagameresidesatanabsolutelocationcalledamemoryaddress.Ifyouthinkofthememoryasaverylargebytearray,amemoryaddressisanindexpointingtoavalueinthatarray.Whenamemoryscanneristoldtofindsomevaluex(calledascanvalue,becauseit’sthevalueyou’rescanningfor)inagame’smemory,thescannerloopsthroughthebytearraylookingforanyvalueequaltox.Everytimeitfindsamatchingvalue,itaddstheindexofthematchtoaresultlist.

Duetothesheersizeofagame’smemory,however,thevalueofxcanappearinhundredsoflocations.Imaginethatxistheplayer’shealth,whichiscurrently500.Ourxuniquelyholds500,but500isnotuniquelyheldbyx,

Page 31: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

soascanforxreturnsallvariableswithavalueof500.Anyaddressesnotrelatedtoxareultimatelyclutter;theyshareavalueof500withxonlybychance.Tofilterouttheseunwantedvalues,thememoryscannerallowsyoutorescantheresultlist,removingaddressesthatnolongerholdthesamevalueasx,whetherxisstill500orhaschanged.

Fortheserescanstobeeffective,theoverallstateofthegamemusthavesignificantentropy—ameasureofdisorder.Youincreaseentropybychangingthein-gameenvironment,oftenbymovingaround,killingcreatures,orswitchingcharacters.Asentropyincreases,unrelatedaddressesarelesslikelytocontinuetoarbitrarilyholdthesamevalue,andgivenenoughentropy,afewrescansshouldfilteroutallfalsepositivesandleaveyouwiththetrueaddressofx.

CheatEngine’sMemoryScannerThissectiongivesyouatourofCheatEngine’smemory-scanningoptions,whichwillhelpyoutrackdowntheaddressesofgamestatevaluesinmemory.I’llgiveyouachancetotrythescanneroutin“BasicMemoryEditing”onpage11;fornow,openCheatEngineandhavealookaround.Thememoryscanneristightlyencapsulatedinitsmainwindow,asshowninFigure1-1.

Page 32: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure1-1:CheatEnginemainscreen

Tobeginscanningagame’smemory,clicktheAttachicon➊toattachtoaprocessandthenenterthescanvalue(referredtoasxinourconceptualscanner)youwanttolocate➌.Byattachingtoaprocess,we’retellingCheatEnginetopreparetooperateonit;inthiscase,thatoperationisascan.IthelpstoalsotellCheatEnginewhatkindofscantorun,asI’lldiscussnext.

ScanTypesCheatEngineallowsyoutoselecttwodifferentscandirectives,calledScanTypeandValueType➍.ScanTypetellsthescannerhowtocompareyourscanvaluewiththememorybeingscannedusingoneofthefollowingscantypes:

Page 33: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ExactValueReturnsaddressespointingtovaluesequaltothescanvalue.Choosethisoptionifthevalueyouarelookingforwon’tchangeduringthescan;health,mana,andleveltypicallyfallintothiscategory.

BiggerThanReturnsaddressespointingtovaluesgreaterthanthescanvalue.Thisoptionisusefulwhenthevalueyou’researchingforissteadilyincreasing,whichoftenhappenswithtimers.

SmallerThanReturnsaddressespointingtovaluessmallerthanthescanvalue.LikeBiggerThan,thisoptionisusefulforfindingtimers(inthiscase,onesthatcountdownratherthanup).

ValueBetweenReturnsaddressespointingtovalueswithinascanvaluerange.ThisoptioncombinesBiggerThanandSmallerThan,displayingasecondaryscanvalueboxthatallowsyoutoinputamuchsmallerrangeofvalues.

UnknownInitialValueReturnsalladdressesinaprogram’smemory,allowingrescanstoexaminetheentireaddressrangerelativetotheirinitialvalues.Thisoptionisusefulforfindingitemorcreaturetypes,sinceyouwon’talwaysknowtheinternalvaluesthegamedevelopersusedtorepresenttheseobjects.

TheValueTypedirectivetellstheCheatEnginescannerwhattypeofvariableit’ssearchingfor.

RunningYourFirstScanOncethetwoscandirectivesareset,clickFirstScan➋torunaninitialscanforvalues,andthescannerwillpopulatetheresultslist➎.Anygreenaddressesinthislistarestatic,meaningthattheyshouldremainpersistentacrossprogramrestarts.Addresseslistedinblackresideindynamicallyallocatedmemory,memorythatisallocatedatruntime.

Whentheresultslistisfirstpopulated,itshowstheaddressandreal-timevalueofeachresult.Eachrescanwillalsoshowthevalueofeachresultduringthepreviousscan.(Anyreal-timevaluesdisplayedareupdatedatanintervalthatyoucansetinEdit▸Settings▸GeneralSettings▸Updateinterval.)

Page 34: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NextScansOncetheresultslistispopulated,thescannerenablestheNextScan➋button,whichofferssixnewscantypes.Theseadditionalscantypesallowyoutocomparetheaddressesintheresultslisttotheirvaluesinthepreviousscan,whichwillhelpyounarrowdownwhichaddressholdsthegamestatevalueyou’rescanningfor.Theyareasfollows:

IncreasedValueReturnsaddressespointingtovaluesthathaveincreased.ThiscomplementstheBiggerThanscantypebykeepingthesameminimumvalueandremovinganyaddresswhosevaluehasdecreased.

IncreasedValueByReturnsaddressespointingtovaluesthathaveincreasedbyadefinedamount.Thisscantypeusuallyreturnsfarfewerfalsepositives,butyoucanuseitonlywhenyouknowexactlyhowmuchavaluehasincreased.

DecreasedValueThisoptionistheoppositeofIncreasedValue.

DecreasedValueByThisoptionistheoppositeofIncreasedValueBy.

ChangedValueReturnsaddressespointingtovaluesthathavechanged.Thistypeisusefulwhenyouknowavaluewillmutate,butyou’reunsurehow.

UnchangedValueReturnsaddressespointingtovaluesthathaven’tchanged.Thiscanhelpyoueliminatefalsepositives,sinceyoucaneasilycreatealargeamountofentropywhileensuringthedesiredvaluestaysthesame.

You’llusuallyneedtousemultiplescantypesinordertonarrowdownalargeresultlistandfindthecorrectaddress.Eliminatingfalsepositivesisoftenamatterofproperlycreatingentropy(asdescribedin“BasicMemoryScanning”onpage4),tacticallychangingyourscandirectives,bravelypressingNextScan,andthenrepeatingtheprocessuntilyouhaveasingleremainingaddress.

WhenYouCan’tGetaSingleResultSometimesitisimpossibletopinpointasingleresultinCheatEngine,in

Page 35: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

whichcaseyoumustdeterminethecorrectaddressthroughexperimentation.Forexample,ifyou’relookingforyourcharacter’shealthandcan’tnarrowitdowntofewerthanfiveaddresses,youcouldtrymodifyingthevalueofeachaddress(asdiscussedin“ManualModificationwithCheatEngine”onpage8)untilyouseethehealthdisplaychangeortheothervaluesautomaticallychangetotheoneyouset.

CheatTablesOnceyou’vefoundthecorrectaddress,youcandouble-clickittoaddittothecheattablepane➏;addressesinthecheattablepanecanbemodified,watched,andsavedtocheattablefilesforfutureuse.

Foreachaddressinthecheattablepane,youcanaddadescriptionbydouble-clickingtheDescriptioncolumn,andyoucanaddacolorbyright-clickingandselectingChangeColor.Youcanalsodisplaythevaluesofeachaddressinhexadecimalordecimalformatbyright-clickingandselectingShowashexadecimalorShowasdecimal,respectively.Lastly,youcanchangethedatatypeofeachvaluebydouble-clickingtheTypecolumn,oryoucanchangethevalueitselfbydouble-clickingtheValuecolumn.

Sincethemainpurposeofthecheattablepaneistoallowagamehackertoneatlytrackaddresses,itcanbedynamicallysavedandloaded.GotoFile▸SaveorFile▸SaveAstosavethecurrentcheattablepanetoa.ctdocumentfilecontainingeachaddresswithitsvaluetype,description,displaycolor,anddisplayformat.Toloadthesaved.ctdocuments,gotoFile▸Load.(You’llfindmanyready-madecheattablesforpopulargamesathttp://cheatengine.org/tables.php.)

NowthatI’vedescribedhowtoscanforagamestatevalue,I’lldiscusshowyoucanchangethatvaluewhenyouknowwhereitlivesinmemory.

MemoryModificationinGamesBotscheatagamesystembymodifyingmemoryvaluesinthegame’sstateinordertogiveyoulotsofin-gamemoney,modifyyourcharacter’shealth,changeyourcharacter’sposition,andsoon.Inmostonlinegames,acharacter’svitals(suchashealth,mana,skills,andposition)areheldinmemorybutarecontrolledbythegameserverandrelayedtoyourlocal

Page 36: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

memorybutarecontrolledbythegameserverandrelayedtoyourlocalgameclientovertheInternet,somodifyingsuchvaluesduringonlineplayismerelycosmeticanddoesn’taffecttheactualvalues.(Anyusefulmemorymodificationtoanonlinegamerequiresamuchmoreadvancedhackthat’sbeyondCheatEngine’scapabilities.)Inlocalgameswithnoremoteserver,however,youcanmanipulateallofthesevaluesatwill.

ManualModificationwithCheatEngineWe’lluseCheatEnginetounderstandhowthememorymodificationmagicworks.

Tomodifymemorymanually,dothefollowing:

1. AttachCheatEnginetoagame.2. Eitherscanfortheaddressyouwishtomodifyorloadacheattablethat

containsit.3. Double-clickontheValuecolumnfortheaddresstoopenaninput

promptwhereyoucanenteranewvalue.4. Ifyouwanttomakesurethenewvaluecan’tbeoverwritten,selectthe

boxundertheActivecolumntofreezetheaddress,whichwillmakeCheatEnginekeepwritingthesamevaluebacktoiteverytimeitchanges.

Thismethodworkswondersforquick-and-dirtyhacks,butconstantlychangingvaluesbyhandiscumbersome;anautomatedsolutionwouldbemuchmoreappealing.

TrainerGeneratorCheatEngine’strainergeneratorallowsyoutoautomatethewholememorymodificationprocesswithoutwritinganycode.

Tocreateatrainer(asimplebotthatbindsmemorymodificationactionstokeyboardhotkeys),gotoFile▸CreategenerictrainerLuascriptfromtable.ThisopensaTrainergeneratordialogsimilartotheoneshowninFigure1-2.

Page 37: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure1-2:CheatEngineTrainergeneratordialog

Thereareanumberoffieldstomodifyhere:

ProcessnameThenameoftheexecutablethetrainershouldattachto.ThisisthenameshownintheprocesslistwhenyouattachwithCheatEngine,anditshouldbeautofilledwiththenameoftheprocessCheatEngineisattachedto.

PopuptraineronkeypressOptionallyenablesahotkey—whichyousetbyenteringakeycombinationintheboxbelowthecheckbox—todisplaythetrainer’smainwindow.

TitleThenameofyourtrainer,whichwillbedisplayedonitsinterface.Thisisoptional.

AbouttextThedescriptionofyourtrainer,tobedisplayedontheinterface;thisisalsooptional.

Freezeinterval(inmilliseconds)Theintervalduringwhichafreezeoperationoverwritesthevalue.Youshouldgenerallyleavethisat250,aslowerintervalscansapresourcesandhighervaluesmaybetooslow.

Oncethesevaluesareconfigured,clickAddHotkeytosetupakeysequencetoactivateyourtrainer.Youwillbepromptedtoselectavalue

Page 38: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

fromyourcheattable.Enteravalue,andyouwillbetakentoaSet/ChangehotkeyscreensimilartoFigure1-3.

Figure1-3:CheatEngineSet/Changehotkeyscreen

Onthisscreen,placeyourcursorintheboxlabeledTypethekeysyouwanttosetthehotkeyto➊andenterthedesiredkeycombination.Next,choosethedesiredactionfromthedrop-downmenu➋;youroptionsshouldappearinthefollowingorder:

TogglefreezeTogglesthefreezestateoftheaddress.

TogglefreezeandallowincreaseTogglesthefreezestateoftheaddressbutallowsthevaluetoincrease.Anytimethevaluedecreases,thetraineroverwritesitwithitspreviousvalue.Increasedvalueswillnotbeoverwritten.

TogglefreezeandallowdecreaseDoestheoppositeofTogglefreezeandallowincrease.

FreezeSetstheaddresstofrozenifit’snotfrozenalready.

UnfreezeUnfreezestheaddressifit’sfrozen.

Page 39: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

SetvaluetoSetsthevaluetowhateveryouspecifyinthevaluebox➌.

DecreasevaluewithDecreasesthevaluebytheamountyouspecifyinthevaluebox➌.

IncreasevaluewithDoestheoppositeofDecreasevaluewith.

Finally,youcansetadescriptionfortheaction➍.ClickApply,thenOK,andyouractionwillappearinthelistontheTrainergeneratorscreen.Atthispoint,CheatEnginerunsthetrainerinthebackground,andyoucansimplypressthehotkeysyouconfiguredtoexecutethememoryactions.

Tosaveyourtrainertoaportableexecutable,clickGeneratetrainer.RunningthisexecutableafterthegameislaunchedwillattachyourtrainertothegamesoyoucanuseitwithoutstartingCheatEngine.

NowthatyouknowyourwayaroundCheatEngine’smemoryscannerandtrainergenerator,trymodifyingsomememoryyourself.

BASICMEMORYEDITINGDownloadthefilesforthisbookfromhttps://www.nostarch.com/gamehacking/,andrunthefileBasicMemory.exe.Next,startupCheatEngineandattachtothebinary.Then,usingonlyCheatEngine,findtheaddressesforthex-andy-coordinatesofthegrayball.(Hint:Usethe4Bytesvaluetype.)

Onceyou’vefoundthevalues,modifythemtoplacetheballontopoftheblacksquare.Thegamewillletyouknowonceyou’vesucceededbydisplayingthetext“Goodjob!”(Hint:Eachtimetheballismoved,itsposition—storedasa4-byteinteger—inthatplaneischangedby1.Also,trytolookonlyforstatic[green]results.)

PointerScanningAsI’vementioned,onlinegamesoftenstorevaluesindynamicallyallocatedmemory.Whileaddressesthatreferencedynamicmemoryareuselesstous

Page 40: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

inandofthemselves,somestaticaddresswillalwayspointtoanotheraddress,whichinturnpointstoanother,andsoon,untilthetailofthechainpointstothedynamicmemorywe’reinterestedin.CheatEnginecanlocatethesechainsusingamethodcalledpointerscanning.

Inthissection,I’llintroduceyoutopointerchainsandthendescribehowpointerscanningworksinCheatEngine.Whenyouhaveagoodgraspoftheuserinterface,youcangetsomehands-onexperiencein“PointerScanning”onpage18.

PointerChainsThechainofoffsetsI’vejustdescribediscalledapointerchainandlookslikethis:

list<int>chain={start,offset1,offset2[,...]}

Thefirstvalueinthispointerchain(start)iscalledamemorypointer.It’sanaddressthatstartsthechain.Theremainingvalues(offset1,offset2,andsoon)makeuptheroutetothedesiredvalue,calledapointerpath.

Thispseudocodeshowshowapointerchainmightberead:

intreadPointerChain(chain){➊ret=read(chain[0])fori=1,chain.len-1,1{offset=chain[i]ret=read(ret+offset)}returnret}

ThiscodecreatesthefunctionreadPointerPath(),whichtakesapointerchaincalledchainasaparameter.ThefunctionreadPointerPath()treatsthepointerpathinchainasalistofmemoryoffsetsfromtheaddressret,whichisinitiallysettothememorypointerat➊.Itthenloopsthroughtheseoffsets,updatingthevalueofrettotheresultofread(ret+offset)oneachiterationandreturningretonceit’sfinished.ThispseudocodeshowswhatreadPointerPath()lookslikewhentheloopisunrolled:

list<int>chain={0xDEADBEEF,0xAB,0x10,0xCC}value=readPointerPath(chain)//thefunctioncallunrollstothisret=read(0xDEADBEEF)//chain[0]

Page 41: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ret=read(0xDEADBEEF)//chain[0]ret=read(ret+0xAB)ret=read(ret+0x10)ret=read(ret+0xCC)intvalue=ret

Thefunctionultimatelycallsreadfourtimes,onfourdifferentaddresses—oneforeachelementinchain.

NOTE

Manygamehackersprefertocodetheirchainreadsinplace,insteadofencapsulatingtheminfunctionslikereadPointerPath().

PointerScanningBasicsPointerchainsexistbecauseeverychunkofdynamicallyallocatedmemorymusthaveacorrespondingstaticaddressthatthegame’scodecanusetoreferenceit.Gamehackerscanaccessthesechunksbylocatingthepointerchainsthatreferencethem.Becauseoftheirmultitierstructure,however,pointerchainscannotbelocatedthroughthelinearapproachthatmemoryscannersuse,sogamehackershavedevisednewwaystofindthem.

Fromareverseengineeringperspective,youcouldlocateandanalyzetheassemblycodeinordertodeducewhatpointerpathitusedtoaccessthevalue,butdoingsoisverytime-consumingandrequiresadvancedtools.Pointerscannerssolvethisproblembyusingbrute-forcetorecursivelyiterateovereverypossiblepointerchainuntiltheyfindonethatresolvestothetargetmemoryaddress.

TheListing1-1pseudocodeshouldgiveyouageneralideaofhowapointerscannerworks.

list<int>pointerScan(target,maxAdd,maxDepth){➊foraddress=BASE,0x7FFFFFF,4{ret=rScan(address,target,maxAdd,maxDepth,1)if(ret.len>0){ret.pushFront(address)returnret}}return{}}

Page 42: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

list<int>rScan(address,target,maxAdd,maxDepth,curDepth){➋foroffset=0,maxAdd,4{value=read(address+offset)➌if(value==target)returnlist<int>(offset)}➍if(curDepth<maxDepth){curDepth++➎foroffset=0,maxAdd,4{ret=rScan(address+offset,target,maxAdd,maxDepth,curDepth)➏if(ret.len>0){ret.pushFront(offset)➐returnret}}}return{}}

Listing1-1:Pseudocodeforapointerscanner

ThiscodecreatesthefunctionspointerScan()andrScan().

pointerScan()ThepointerScan()functionistheentrypointtothescan.Ittakestheparameterstarget(thedynamicmemoryaddresstofind),maxAdd(themaximumvalueofanyoffset),andmaxDepth(themaximumlengthofthepointerpath).Itthenloopsthroughevery4-bytealignedaddress➊inthegame,callingrScan()withtheparametersaddress(theaddressinthecurrentiteration),target,maxAdd,maxDepth,andcurDepth(thedepthofthepath,whichisalways1inthiscase).

rScan()TherScan()functionreadsmemoryfromevery4-bytealignedoffsetbetween0andmaxAdd➋,andreturnsifaresultisequaltotarget➌.IfrScan()doesn’treturninthefirstloopandtherecursionisnottoodeep➍,itincrementscurDepthandagainloopsovereachoffset➎,callingitselfforeachiteration.

Ifaselfcallreturnsapartialpointerpath➏,rScan()willprependthe

Page 43: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

currentoffsettothepathandreturnuptherecursionchain➐untilitreachespointerScan().WhenacalltorScan()frompointerScan()returnsapointerpath,pointerScan()pushesthecurrentaddresstothefrontofthepathandreturnsitasacompletechain.

PointerScanningwithCheatEngineThepreviousexampleshowedthebasicprocessofpointerscanning,buttheimplementationI’veshownisprimitive.Asidefrombeinginsanelyslowtoexecute,itwouldgeneratecountlessfalsepositives.CheatEngine’spointerscannerusesanumberofadvancedinterpolationstospeedupthescanandmakeitmoreaccurate,andinthissection,I’llintroduceyoutothesmorgasbordofavailablescanningoptions.

ToinitiateapointerscaninCheatEngine,right-clickonadynamicmemoryaddressinyourcheattableandclickPointerscanforthisaddress.Whenyouinitiateapointerscan,CheatEnginewillaskyouwheretostorethescanresultsasa.ptrfile.Onceyouenteralocation,aPointerscannerscanoptionsdialogsimilartotheoneshowninFigure1-4willappear.

Page 44: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure1-4:CheatEnginePointerscannerscanoptionsdialog

TheAddresstofindinputfieldatthetopdisplaysyourdynamicmemoryaddress.NowcarefullyselectfromamongCheatEngine’smanyscanoptions.

KeyOptionsSeveralofCheatEngine’sscanoptionstypicallyretaintheirdefaultvalues.Thoseoptionsareasfollows:

Addressesmustbe32-bitsalignedTellsCheatEnginetoscanonlyaddressesthataremultiplesof4,whichgreatlyincreasesthescanspeed.

Page 45: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Asyou’lllearninChapter4,compilersaligndatasothatmostaddresseswillbemultiplesof4anywaybydefault.You’llrarelyneedtodisablethisoption.

OnlyfindpathswithastaticaddressSpeedsupthescanbypreventingCheatEnginefromsearchingpathswithadynamicstartpointer.Thisoptionshouldalwaysbeenabledbecausescanningforapathstartingatanotherdynamicaddresscanbecounterproductive.

Don’tincludepointerswithread-onlynodesShouldalsoalwaysbeenabled.Dynamicallyallocatedmemorythatstoresvolatiledatashouldneverberead-only.

StoptraversingapathwhenastatichasbeenfoundTerminatesthescanwhenitfindsapointerpathwithastaticstartaddress.Thisshouldbeenabledtoreducefalsepositivesandspeedupthescan.

PointerpathmayonlybeinsidethisregionCantypicallybeleftasis.Theotheroptionsavailabletoyoucompensateforthislargerangebyintelligentlynarrowingthescopeofthescan.

FirstelementofpointerstructmustpointtomoduleTellsCheatEnginenottosearchheapchunksinwhichvirtualfunctiontablesarenotfound,undertheassumptionthatthegamewascodedusingobjectorientation.Whilethissettingcanimmenselyspeedupscans,it’shighlyunreliableandyoushouldalmostalwaysleaveitdisabled.

NoloopingpointersInvalidatesanypathsthatpointtothemselves,weedingoutinefficientpathsbutslightlyslowingdownthescan.Thisshouldusuallybeenabled.

MaxlevelDeterminesthemaximumlengthofthepointerpath.(RememberthemaxDepthvariableintheexamplecodeinListing1-1?)Thisshouldbekeptaround6or7.Ofcourse,therewillbetimeswhenyou’llneedtochangetheseoptions

fromthesettingsdescribed.Forexample,failingtoobtainreliableresultswiththeNoloopingpointersorMaxlevelsettingstypicallymeansthatthevalueyou’relookingforexistsinadynamicdatastructure,likealinkedlist,binarytree,orvector.AnotherexampleistheStoptraversingapathwhenastatichasbeenfoundoption,whichinrarecasescanpreventyoufromgettingreliableresults.

Page 46: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

SituationalOptionsUnlikethepreviousoptions,yoursettingsfortheremainingoneswilldependonyoursituation.Here’showtodeterminethebestconfigurationforeach:

ImprovepointerscanwithgatheredheapdataAllowsCheatEnginetousetheheapallocationrecordtodetermineoffsetlimits,effectivelyspeedingupthescanbyweedingoutmanyfalsepositives.Ifyourunintoagameusingacustommemoryallocator(whichisbecomingincreasinglycommon),thisoptioncanactuallydotheexactoppositeofwhatit’smeanttodo.Youcanleavethissettingenabledininitialscans,butitshouldbethefirsttogowhenyou’reunabletofindreliablepaths.

OnlyallowstaticandheapaddressesinthepathInvalidatesallpathsthatcan’tbeoptimizedwithheapdata,makingthisapproachevenmoreaggressive.

MaxdifferentoffsetspernodeLimitsthenumberofsame-valuepointersthescannerchecks.Thatis,ifndifferentaddressespointto0x0BADF00D,thisoptiontellsCheatEnginetoconsideronlythefirstmaddresses.Thiscanbeextremelyhelpfulwhenyou’reunabletonarrowdownyourresultset.Inothercases,youmaywanttodisableit,asitwillmissmanyvalidpaths.

Allowstackaddressesofthefirstthread(s)tobehandledasstaticScansthecallstacksofoldestmthreadsinthegame,consideringthefirstnbytesineachone.ThisallowsCheatEnginetoscantheparametersandlocalvariablesoffunctionsinthegame’scallchain(thegoalbeingtofindvariablesusedbythegame’smainloop).Thepathsfoundwiththisoptioncanbebothhighlyvolatileandextremelyuseful;IuseitonlywhenIfailtofindheapaddresses.

StackaddressesasonlystaticaddressTakesthepreviousoptionevenfurtherbyallowingonlystackaddressesinpointerpaths.

PointersmustendwithspecificoffsetsCanbeusefulifyouknowtheoffset(s)attheendofavalidpath.Thisoptionwillallowyoutospecifythoseoffsets(startingwiththelastoffsetatthetop),greatlyreducingthescopeofthescan.

NrofthreadsscanningDetermineshowmanythreadsthescannerwill

Page 47: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

use.Anumberequaltothenumberofcoresinyourprocessoroftenworksbest.Adrop-downmenuwithoptionsallowsyoutospecifythepriorityforeachthread.Idleisbestifyouwantyourscantogoveryslowly,Normaliswhatyoushoulduseformostscans,andTimecriticalisusefulforlengthyscansbutwillrenderyourcomputeruselessforthescanduration.

MaximumoffsetvalueDeterminesthemaximumvalueofeachoffsetinthepath.(RememberthemaxAddvariableinListing1-1?)Itypicallystartwithalowvalue,increasingitonlyifmyscanfails;128isagoodstartingvalue.Keepinmindthatthisvalueismostlyignoredifyou’reusingtheheapoptimizationoptions.

NOTE

WhatifbothOnlyallowstaticandheapaddressesinthepathandStackaddressesasonlystaticaddressareenabled?Willthescancomeupempty?Seemslikeafun,albeituseless,experiment.

Onceyouhavedefinedyourscanoptions,clickOKtostartapointerscan.Whenthescancompletes,aresultswindowwillappearwiththelistofpointerchainsfound.Thislistoftenhasthousandsofresults,containingbothrealchainsandfalsepositives.

PointerRescanningThepointerscannerhasarescanfeaturethatcanhelpyoueliminatefalsepositives.Tobegin,pressCTRL-RfromtheresultswindowtoopentheRescanpointerlistdialog,asshowninFigure1-5.

Page 48: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure1-5:CheatEngineRescanpointerlistdialog

TherearetwomainoptionstoconsiderwhenyoutellCheatEnginetorescan:

OnlyfilteroutinvalidpointersIfyoucheckthisbox➊,therescanwilldiscardonlypointerchainsthatpointtoinvalidmemory,whichhelpsifyourinitialresultsetisverylarge.Disablethistofilteroutpathsthatdon’tresolvetoaspecificaddressorvalue(asshowninthefigure).

RepeatrescanuntilstoppedIfyoucheckthisbox➋,therescanwillexecuteinacontinuousloop.Ideally,youshouldenablethissettingandletrescanrunwhileyoucreatealargeamountofmemoryentropy.

Fortheinitialrescan,enablebothOnlyfilteroutinvalidpointersandRepeatrescanuntilstopped,andthenpressOKtoinitiatetherescan.Therescanwindowwillgoaway,andaStoprescanloopbuttonwillappearintheresultswindow.TheresultlistwillbeconstantlyrescanneduntilyouclickStoprescanloop,butspendafewminutescreatingmemoryentropybeforedoingso.

Inrarecases,rescanningusingarescanloopmaystillleaveyouwithalargelistofpossiblepaths.Whenthishappens,youmayneedtorestartthegame,findtheaddressthatholdsyourvalue(itmayhavechanged!),andusetherescanfeatureonthisaddresstofurthernarrowresults.Inthisscan,leaveOnlyfilteroutinvalidpointersuncheckedandenterthenewaddress

Page 49: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

intheAddresstofindfield.

NOTE

Ifyouhadtoclosetheresultswindow,youcanreopenitandloadtheresultlistbygoingtothemainCheatEnginewindowandpressingtheMemoryViewbuttonbelowtheresultspane.Thisshouldbringupamemorydumpwindow.Whenthewindowappears,pressCTRL-Ptoopenthepointerscanresultslist.ThenpressCTRL-Otoopenthe.ptrfilewhereyousavedthepointerscan.

Ifyourresultsstillaren’tnarrowenough,tryrunningthesamescanacrosssystemrestartsorevenondifferentsystems.Ifthisstillyieldsalargeresultset,eachresultcansafelybeconsideredstaticbecausemorethanonepointerchaincanresolvetothesameaddress.

Onceyou’venarroweddownyourresultset,double-clickonausablepointerchaintoaddittoyourcheattable.Ifyouhaveahandfulofseeminglyusablechains,grabtheonewiththefewestoffsets.Ifyoufindmultiplechainswithidenticaloffsetsthatstartwiththesamepointerbutdivergeafteracertainpoint,yourdatamaybestoredinadynamicdatastructure.

That’sallthereistopointerscanninginCheatEngine.Tryityourself!

POINTERSCANNINGGotohttps://www.nostarch.com/gamehacking/anddownloadMemoryPointers.exe.Unlikethelasttask,whichrequiredyoutowinonlyonce,thisonerequiresthatyouwin50timesin10seconds.Uponeachwin,thememoryaddressesforthex-andy-coordinateswillchange,meaningyouwillbeabletofreezethevalueonlyifyouhavefoundaproperpointerpath.Startthisexercisethesamewayasthepreviousone,butonceyou’vefoundtheaddresses,usethePointerscanfeaturetolocatepointerpathstothem.Then,placetheballontopoftheblacksquare,freezethevalueinplace,andpressTABtobeginthetest.Justasbefore,thegamewillletyouknowonceyou’vewon.(Hint:Trysettingthemaximumlevelto5andthe

Page 50: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

maximumoffsetvalueto512.Also,playwiththeoptionstoallowstackaddresses,terminatethescanwhenastaticisfound,andimprovethepointerscanwithheapdata.Seewhichcombinationofoptionsgivesthebestresults.)

LuaScriptingEnvironmentHistorically,botdevelopersrarelyusedCheatEnginetoupdatetheiraddresseswhenagamereleasedapatchbecauseitwasmucheasiertodosoinOllyDbg.ThismadeCheatEngineuselesstogamehackersotherthanforinitialresearchanddevelopment—thatis,untilapowerfulLua-basedembeddedscriptingenginewasimplementedaroundCheatEngine’srobustscanningenvironment.WhilethisenginewascreatedtoenablethedevelopmentofsimplebotswithinCheatEngine,professionalgamehackersfoundtheycouldalsouseittoeasilywritecomplexscriptstoautomaticallylocateaddressesacrossdifferentversionsofagame’sbinary—ataskthatmightotherwisetakehours.

NOTE

You’llfindmoredetailabouttheCheatEngineLuascriptingengineonthewikiathttp://wiki.cheatengine.org/.

TostartusingtheLuaengine,pressCTRL-ALT-LfromthemainCheatEnginewindow.Oncethewindowopens,writeyourscriptinthetextareaandclickExecutescripttorunit.SaveascriptwithCTRL-SandopenasavedscriptwithCTRL-O.

Thescriptingenginehashundredsoffunctionsandinfiniteusecases,soI’llgiveyoujustaglimpseofitsabilitiesbybreakingdowntwoscripts.Everygameisdifferentandeverygamehackerwritesscriptstoaccomplishuniquegoals,sothesescriptsareonlyusefulfordemonstratingconcepts.

SearchingforAssemblyPatternsThisfirstscriptlocatesfunctionsthatcomposeoutgoingpacketsandsendsthemtothegameserver.Itworksbysearchingagame’sassemblycodefor

Page 51: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

themtothegameserver.Itworksbysearchingagame’sassemblycodeforfunctionsthatcontainacertaincodesequence.

➊BASEADDRESS=getAddress("Game.exe")➋functionLocatePacketCreation(packetType)➌foraddress=BASEADDRESS,(BASEADDRESS+0x2ffffff)dolocalpush=readBytes(address,1,false)localtype=readInteger(address+1)localcall=readInteger(address+5)➍if(push==0x68andtype==packetTypeandcall==0xE8)thenreturnaddressendendreturn0endFUNCTIONHEADER={0xCC,0x55,0x8B,0xEC,0x6A}➎functionLocateFunctionHead(checkAddress)if(checkAddress==0)thenreturn0end➏foraddress=checkAddress,(checkAddress-0x1fff),-1dolocalmatch=truelocalcheckheader=readBytes(address,#FUNCTIONHEADER,true)➐fori,vinipairs(FUNCTIONHEADER)doif(v~=checkheader[i])thenmatch=falsebreakendend➑if(match)thenreturnaddress+1endendreturn0end

➒localfuncAddress=LocateFunctionHead(LocatePacketCreation(0x64))if(funcAddress~=0)thenprint(string.format("0x%x",funcAddress))elseprint("Notfound!")end

ThecodebeginsbygettingthebaseaddressofthemodulethatCheatEngineisattachedto➊.Onceithasthebaseaddress,thefunctionLocatePacketCreation()isdefined➋.Thisfunctionloopsthroughthefirst0x2FFFFFFbytesofmemoryinthegame➌,searchingforasequencethatrepresentsthisx86assemblercode:

Page 52: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PUSHtype;Datais:0x68[4bytetype]CALLoffset;Datais:0xE8[4byteoffset]

ThefunctionchecksthatthetypeisequaltopacketType,butitdoesn’tcarewhatthefunctionoffsetis➍.Oncethissequenceisfound,thefunctionreturns.

Next,theLocateFunctionHead()functionisdefined➎.Thefunctionbacktracksupto0x1FFFbytesfromagivenaddress➏,andateachaddress,itchecksforastubofassemblercode➐thatlookssomethinglikethis:

INT3;0xCCPUSHEBP;0x55MOVEBP,ESP;0x8B0xECPUSH[-1];0x6A0xFF

Thisstubwillbepresentatthebeginningofeveryfunction,becauseit’spartofthefunctionprologuethatsetsupthefunction’sstackframe.Onceitfindsthecode,thefunctionwillreturntheaddressofthestubplus1➑(thefirstbyte,0xCC,ispadding).

Totiethesestepstogether,theLocatePacketCreation()functioniscalledwiththepacketTypethatI’mlookingfor(arbitrarily0x64)andtheresultingaddressispassedintotheLocateFunctionHead()function➒.ThiseffectivelylocatesthefirstfunctionthatpushespacketTypeintoafunctioncallandstoresitsaddressinfuncAddress.Thisstubshowstheresult:

INT3;LocateFunctionHeadback-trackedtoherePUSHEBP;andreturnedthisaddressMOVEBP,ESPPUSH[-1]--snip--PUSH[0x64];LocatePacketCreationreturnedthisaddressCALL[something]

This35-linescriptcanautomaticallylocate15differentfunctionsinunderaminute.

SearchingforStringsThisnextLuascriptscansagame’smemoryfortextstrings.ItworksmuchastheCheatEngine’smemoryscannerdoeswhenyouusethestringvaluetype.

Page 53: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

type.

BASEADDRESS=getAddress("Game.exe")➊functionfindString(str)locallen=string.len(str)➋localchunkSize=4096➌localchunkStep=chunkSize-lenprint("Found'"..str.."'at:")➍foraddress=BASEADDRESS,(BASEADDRESS+0x2ffffff),chunkStepdolocalchunk=readBytes(address,chunkSize,true)if(notchunk)thenbreakend➎forc=0,chunkSize-lendo➏checkForString(address,chunk,c,str,len)endendendfunctioncheckForString(address,chunk,start,str,len)fori=1,lendoif(chunk[start+i]~=string.byte(str,i))thenreturnfalseendend➐print(string.format("\t0x%x",address+start))end

➑findString("hello")➒findString("world")

Aftergettingthebaseaddress,thefindString()functionisdefined➊,whichtakesastring,str,asaparameter.Thisfunctionloopsthroughthegame’smemory➍in4,096-byte-longchunks➋.Thechunksarescannedsequentially,eachonestartinglen(thelengthofstr)bytesbeforetheendofthepreviousone➌topreventmissingastringthatbeginsononechunkandendsonanother.

AsfindString()readseachchunk,ititeratesovereverybyteuntiltheoverlappointinthechunk➎,passingeachsubchunkintothecheckForString()function➏.IfcheckForString()matchesthesubchunktostr,itprintstheaddressofthatsubchunktotheconsole➐.

Lastly,tofindalladdressesthatreferencethestrings"hello"and"world",thefunctionsfindString("hello")➑andfindString("world")➒arecalled.

Page 54: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Byusingthiscodetosearchforembeddeddebugstringsandpairingitwiththepreviouscodetolocatefunctionheaders,I’mabletofindalargenumberofinternalfunctionswithinagameinmereseconds.

OPTIMIZINGMEMORYCODEDuetothehighoverheadofmemoryreading,optimizationisextremelyimportantwhenyou’rewritingcodethatperformsmemoryreads.Inthepreviouscodesnippet,noticethatthefunctionfindString()doesnotusetheLuaengine’sbuiltinreadString()function.Instead,itreadsbigchunksofmemoryandsearchesthemforthedesiredstring.Let’sbreakdownthenumbers.

AscanusingreadString()wouldtrytoreadastringoflenbytesateverypossiblememoryaddress.Thismeansitwouldread,atmost,(0x2FFFFFF*len+len)bytes.However,findString()readschunksof4,096bytesandscansthemlocallyformatchingstrings.Thismeansitwouldread,atmost,(0x2FFFFFF+4096+(0x2FFFFFF/(4096-10))*len)bytes.Whensearchingforastringwithalengthof10,thenumberofbytesthateachmethodwouldreadis503,316,480and50,458,923,respectively.

NotonlydoesfindString()readanorderofmagnitudelessdata,italsoinvokesfarfewermemoryreads.Readinginchunksof4,096byteswouldrequireatotalof(0x2FFFFFF/(4096-len))reads.ComparethattoascanusingreadString(),whichwouldneed0x2FFFFFFreads.ThescanthatusesfindString()isahugeimprovementbecauseinvokingareadismuchmoreexpensivethanincreasingthesizeofdatabeingread.(NotethatIchose4,096arbitrarily.Ikeepthechunkrelativelysmallbecausereadingmemorycanbetime-consuming,anditmightbewastefultoreadfourpagesatatimejusttofindthestringinthefirst.)

ClosingThoughts

Page 55: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Bythispoint,youshouldhaveabasicunderstandingofCheatEngineandhowitworks.CheatEngineisaveryimportanttoolinyourkit,andIencourageyoutogetsomehands-onexperiencewithitbyfollowing“BasicMemoryEditing”onpage11and“PointerScanning”onpage18andplayingaroundwithitonyourown.

Page 56: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

2DEBUGGINGGAMESWITHOLLYDBG

YoucanscratchthesurfaceofwhathappensasagamerunswithCheatEngine,butwithagooddebugger,youcandigdeeperuntilyouunderstandthegame’sstructureandexecutionflow.ThatmakesOllyDbgessentialtoyourgame-hackingarsenal.It’spackedwithamyriadofpowerfultoolslikeconditionalbreakpoints,referencedstringsearch,assemblypatternsearch,andexecutiontracing,makingitarobustassembler-leveldebuggerfor32-bitWindowsapplications.

I’llcoverlow-levelcodestructureindetailinChapter4,butforthischapter,Iassumeyou’reatleastfamiliarwithmoderncode-leveldebuggers,suchastheonepackagedwithMicrosoftVisualStudio.OllyDbgisfunctionallysimilartothose,withonemajordifference:itinterfaceswiththeassemblycodeofanapplication,workingevenintheabsenceofsourcecodeand/ordebugsymbols,makingitidealwhenyouneedtodigintotheinternalsofagame.Afterall,gamecompaniesarerarelynice(ordumb)enoughtoshiptheirgameswithdebugsymbols!

Inthischapter,I’llgooverOllyDbg’suserinterface,showyouhowtouseitsmostcommondebuggingfeatures,breakdownitsexpressionengine,andprovidesomereal-worldexamplesofhowyoucantieitintoyourgamehackingendeavors.Asawrap-up,I’llteachyouaboutsomeusefulplug-insandsendyouoffwithatestgamedesignedtogetyoustartedinOllyDbg.

Page 57: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NOTE

ThischapterfocusesonOllyDbg1.10andmaynotbeentirelyaccurateforlaterversions.Iusethisversionbecause,atthetimeofwriting,theplug-ininterfaceforOllyDbg2isstillfarlessrobustthantheoneforOllyDbg1.

WhenyoufeellikeyouhaveahandleonOllyDbg’sinterfaceandfeatures,youcantryitonagameyourselfwith“Patchinganif()Statement”onpage46.

ABriefLookatOllyDbg’sUserInterfaceGototheOllyDbgwebsite(http://www.ollydbg.de/),downloadandinstallOllyDbg,andopentheprogram.YoushouldseethetoolbarshowninFigure2-1aboveamultiplewindowinterfacearea.

Figure2-1:OllyDbgmainwindow

Thistoolbarcontainstheprogramcontrols➊,thedebugbuttons➋,theGotobutton➌,thecontrolwindowbuttons➍,andtheSettingsbutton➎.

Thethreeprogramcontrolsallowyoutoopenanexecutableandattachtotheprocessitcreates,restartthecurrentprocess,orterminateexecutionofthecurrentprocess,respectively.YoucanalsocompletethesefunctionswiththehotkeysF3,CTRL-F2,andALT-F2,respectively.Toattachtoaprocessthatisalreadyrunning,clickFile▸Attach.

Thedebugbuttonscontrolthedebuggeractions.Table2-1describeswhatthesebuttonsdo,alongwiththeirhotkeysandfunctions.Thistablealsoliststhreeusefuldebuggeractionsthatdon’thavebuttonsonthedebug

Page 58: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

toolbar.

Table2-1:DebugButtonsandOtherDebuggerFunctions

Button Hotkey Function

Play F9 Resumesnormalexecutionoftheprocess.

Pause F12 PausesexecutionofallthreadswithintheprocessandbringsuptheCPUwindowattheinstructioncurrentlybeingexecuted.

Stepinto

F7 Single-stepstothenextoperationtobeexecuted(willdivedownintofunctioncalls).

Stepover

F8 Stepstothenextoperationtobeexecutedwithincurrentscope(willskipoverfunctioncalls).

Traceinto

CTRL-F11

Runsadeeptrace,tracingeveryoperationthatisexecuted.

Traceover

CTRL-F12

Runsapassivetracethattracesonlyoperationswithinthecurrentscope.

Executeuntilreturn

CTRL-F9

Executesuntilareturnoperationishitwithinthecurrentscope.

CTRL-F7

Automaticallysingle-stepsoneveryoperation,followingexecutioninthedisassemblywindow.Thismakesexecutionappeartobeanimated.

CTRL-F8

Alsoanimatesexecution,butstepsoverfunctionsinsteadofsteppingintothem.

ESC Stopsanimation,pausingexecutiononthecurrentoperation.

TheGotobuttonopensadialogaskingforahexadecimaladdress.Onceyouentertheaddress,OllyDbgopenstheCPUwindowandshowsthedisassemblyatthespecifiedaddress.WhentheCPUwindowisinfocus,youcanalsoshowthatinformationwiththehotkeyCTRL-G.

Thecontrolwindowbuttonsopendifferentcontrolwindows,whichdisplay

Page 59: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

usefulinformationabouttheprocessyou’redebuggingandexposemoredebuggingfunctions,liketheabilitytosetbreakpoints.OllyDbghasatotalof13controlwindows,whichcanallbeopensimultaneouslywithinthemultiplewindowinterface.Table2-2describesthesewindows,listedintheorderinwhichtheyappearonthewindowbuttonstoolbar.

Table2-2:OllyDbg’sControlWindows

Window HotkeyFunction

Log ALT-L

Displaysalistoflogmessages,includingdebugprints,threadevents,debuggerevents,moduleloads,andmuchmore.

Modules ALT-E Displaysalistofallexecutablemodulesloadedintotheprocess.Double-clickamoduletoopenitintheCPUwindow.

Memorymap

ALT-M

Displaysalistofallblocksofmemoryallocatedbytheprocess.Double-clickablockinthelisttobringupadumpwindowofthatmemoryblock.

Threads Displaysalistofthreadsrunningintheprocess.Foreachthreadinthislist,theprocesshasastructurecalledaThreadInformationBlock(TIB).OllyDbgallowsyoutovieweachthread’sTIB;simplyright-clickathreadandselectDumpthreaddatablock.

Windows Displaysalistofwindowhandlesheldbytheprocess.Right-clickawindowinthislisttojumptoorsetabreakpointonitsclassprocedure(thefunctionthatgetscalledwhenamessageissenttothewindow).

Handles Displaysalistofhandlesheldbytheprocess.(NotethatProcessExplorerhasamuchbetterhandlelistthanOllyDbg,asIwilldiscussinChapter3.)

CPU ALT-C

Displaysthemaindisassemblerinterfaceandcontrolsamajorityofthedebuggerfunctionality.

Patches CTRL-P

Displaysalistofanyassemblycodemodificationsyouhavemadetomoduleswithintheprocess.

Page 60: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Callstack ALT-K

Displaysthecallstackfortheactivethread.Thewindowupdateswhentheprocesshalts.

BreakpointsALT-B Displaysalistofactivedebuggerbreakpointsandallowsyoutotogglethemonandoff.

References Displaysthereferencelist,whichtypicallyholdsthesearchresultsformanydifferenttypesofsearches.Itpopsuponitsownwhenyourunasearch.

Runtrace Displaysalistofoperationsloggedbyadebuggertrace.

Source Displaysthesourcecodeofthedisassembledmoduleifaprogramdebugdatabaseispresent.

Finally,theSettingsbuttonopenstheOllyDbgsettingswindow.Keepthedefaultsettingsfornow.

Nowthatyou’vehadatourofthemainOllyDbgwindow,let’sexploretheCPU,Patches,andRuntracewindowsmoreclosely.You’llusethosewindowsextensivelyasagamehacker,andknowingyourwayaroundthemiskey.

OllyDbg’sCPUWindowTheCPUwindowinFigure2-2iswheregamehackersspendmostoftheirtimeinOllyDbgbecauseitisthemaincontrolwindowforthedebuggingfeatures.

Page 61: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure2-2:OllyDbgCPUwindow

Thiswindowhousesfourdistinctcontrolpanes:thedisassemblerpane➊,theregisterspane➋,thedumppane➌,andthestackpane➍.ThesefourpanesencapsulateOllyDbg’smaindebuggerfunctions,soit’simportanttoknowtheminsideandout.

ViewingandNavigatingaGame’sAssemblyCodeYou’llnavigategamecodeandcontrolmostaspectsofdebuggingfromOllyDbg’sdisassemblerpane.Thispanedisplaystheassemblycodeforthecurrentmodule,anditsdataisneatlydisplayedinatablecomposedoffourdistinctcolumns:Address,Hexdump,Disassembly,andComment.

TheAddresscolumndisplaysthememoryaddressesofeachoperationinthegameprocessyou’reattachedto.Youcandouble-clickanaddressinthis

Page 62: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

columntotogglewhetherit’sthedisplaybase.Whenanaddressissetasthedisplaybase,theAddresscolumndisplaysallotheraddressesasoffsetsrelativetoit.

TheHexdumpcolumndisplaysthebytecodeforeachoperation,groupingoperationcodesandparametersaccordingly.Blackbracesspanningmultiplelinesontheleftsideofthiscolumnmarkknownfunctionboundaries.Operationsthathavejumpsgoingtothemareshownwitharight-facingarrowontheinsideofthesebraces.Operationsthatperformjumpsareshownwitheitherup-facingordown-facingarrows,dependingonthedirectioninwhichtheyjump,ontheinsideofthesebraces.Forexample,inFigure2-2,theinstructionataddress0x779916B1(highlightedingray)hasanup-facingarrow,indicatingit’sanupwardjump.Youcanthinkofajumpasagotooperator.

TheDisassemblycolumndisplaystheassemblycodeofeachoperationthegameperforms.So,forexample,youcanconfirmthattheinstructionat0x779916B1inFigure2-2isajumpbylookingattheassembly,whichshowsaJNZ(jumpifnonzero)instruction.Blackbracesinthiscolumnmarktheboundariesofloops.Right-facingarrowsattachedtothesebracespointtotheconditionalstatementsthatcontrolwhethertheloopscontinueorexit.Thethreeright-facingarrowsinthiscolumninFigure2-2pointtoCMP(compare)andTESTinstructions,whichareusedbyassemblycodetocomparevalues.

TheCommentcolumndisplayshuman-readablecommentsabouteachoperationthegameperforms.IfOllyDbgencountersknownAPIfunctionnames,itwillautomaticallyinsertacommentwiththenameofthefunction.Similarly,ifitsuccessfullydetectsargumentsbeingpassedtoafunction,itwilllabelthem(forexample,Arg1,Arg2,...,ArgN).Youcandouble-clickinthiscolumntoaddacustomizedcomment.Blackbracesinthiscolumnmarktheassumedboundariesoffunctioncallparameters.

NOTE

OllyDbginfersfunctionboundaries,jumpdirections,loopstructures,andfunctionparametersduringcodeanalysis,soifthesecolumnslackboundarylinesorjumparrows,justpressCTRL-Atorunacodeanalysisonthebinary.

Page 63: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Whenthedisassemblerpaneisinfocus,thereareafewhotkeysyoucanusetoquicklynavigatecodeandcontrolthedebugger.UseF2forTogglebreakpoint,SHIFT-F12forPlaceconditionalbreakpoint,-(hyphen)forGobackand+(plus)forGoforward(thesetwoworkasyou’dexpectinawebbrowser),*(asterisk)forGotoEIP(whichistheexecutionpointerinthex86architecture),CTRL--(hyphen)forGotopreviousfunction,andCTRL-+

forGotonextfunction.ThedisassemblercanalsopopulatetheReferenceswindowwithdifferent

typesofsearchresults.WhenyouwanttochangetheReferenceswindow’scontents,right-clickinthedisassemblerpane,mouseovertheSearchformenutoexpandit,andselectoneofthefollowingoptions:

AllintermodularcallsSearchesforallcallstofunctionsinremotemodules.Thiscan,forexample,allowyoutoseeeverywherethatagamecallsSleep(),PeekMessage(),oranyotherWindowsAPIfunction,enablingyoutoinspectorsetbreakpointsonthecalls.

AllcommandsSearchesforalloccurrencesofagivenoperationwritteninassembly,wheretheaddedoperatorsCONSTandR32willmatchaconstantvalueoraregistervalue,respectively.OneuseforthisoptionmightbesearchingforcommandslikeMOV[0xDEADBEEF],CONST;MOV[0xDEADBEEF],R32;andMOV[0xDEADBEEF],[R32+CONST]tolistalloperationsthatmodifymemoryattheaddress0xDEADBEEF,whichcouldbeanything,includingtheaddressofyourplayer’shealth.

AllsequencesSearchesforalloccurrencesofagivensequenceofoperations.Thisissimilartothepreviousoptions,butitallowsyoutospecifymultiplecommands.

AllconstantsSearchesforallinstancesofagivenhexadecimalconstant.Forinstance,ifyouentertheaddressofyourcharacter’shealth,thiswilllistallofthecommandsthatdirectlyaccessit.

AllswitchesSearchesforallswitch-caseblocks.

AllreferencedtextstringsSearchesforallstringsreferencedincode.Youcanusethisoptiontosearchthroughallreferencedstringsandseewhatcodeaccessesthem,whichcanbeusefulforcorrelatingin-gametextdisplayswiththecodethatdisplaysthem.Thisoptionisalsoveryusefulforlocatinganydebugassertionorloggingstrings,whichcanbea

Page 64: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

tremendoushelpindeterminingthepurposeofcodeparts.

ThedisassemblercanalsopopulatetheNameswindowwithalllabelsinthecurrentmodule(CTRL-N)orallknownlabelsinallmodules(Searchfor▸Nameinallmodules).KnownAPIfunctionswillbeautomaticallylabeledwiththeirnames,andyoucanaddalabeltoacommandbyhighlightingit,pressingSHIFT-;andenteringthelabelwhenprompted.Whenalabeledcommandisreferencedincode,thelabelwillbeshowninplaceoftheaddress.Onewaytousethisfeatureistonamefunctionsthatyou’veanalyzed(justsetalabelonthefirstcommandinafunction)soyoucanseetheirnameswhenotherfunctionscallthem.

ViewingandEditingRegisterContentsTheregisterspanedisplaysthecontentsoftheeightprocessorregisters,alleightflagbits,thesixsegmentregisters,thelastWindowserrorcode,andEIP.Underneaththesevalues,thispanecandisplayeitherFloating-PointUnit(FPU)registersordebugregisters;clickonthepane’sheadertochangewhichregistersaredisplayed.Thevaluesinthispanearepopulatedonlyifyoufreezeyourprocess.Valuesthataredisplayedinredhavebeenchangedsincethepreviouspause.Double-clickonvaluesinthispanetoeditthem.

ViewingandSearchingaGame’sMemoryThedumppanedisplaysadumpofthememoryataspecificaddress.Tojumptoanaddressanddisplaythememorycontents,pressCTRL-Gandentertheaddressintheboxthatappears.YoucanalsojumptotheaddressofanentryintheotherCPUwindowpanesbyright-clickingontheAddresscolumnandselectingFollowindump.

Whiletherearealwaysthreecolumnsinthedumppane,theonlyoneyoushouldalwaysseeistheAddresscolumn,whichbehavesmuchlikeitscousinwithinthedisassemblerpane.Thedatadisplaytypeyouchoosedeterminestheothertwocolumnsshown.Right-clickthedumppanetochangethedisplaytype;fortheoneshowninFigure2-2,you’dright-clickandselectHex▸Hex/ASCII(8bytes).

Youcansetamemorybreakpointonanaddressshowninthedumppanebyright-clickingthataddressandexpandingtheBreakpointsubmenu.Select

Page 65: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Memory▸Onaccessfromthismenutobreakonanycodethatusestheaddressatall,orselectMemory▸Onwritetobreakonlyoncodethatwritestothatspaceinmemory.Toremoveamemorybreakpoint,selectRemovememorybreakpointinthesamemenu;thisoptionappearsonlywhentheaddressyouright-clickhasabreakpoint.

Withoneormorevaluesselectedinthedump,youcanpressCTRL-Rtosearchthecurrentmodule’scodeforreferencestoaddressesoftheselectedvalues;resultsofthissearchappearintheReferenceswindow.YoucanalsosearchforvaluesinthispaneusingCTRL-BforbinarystringsandCTRL-Nforlabels.Afteryouinitiateasearch,pressCTRL-Ltojumptothenextmatch.CTRL-Eallowsyoutoeditanyvaluesyouhaveselected.

NOTE

ThedumpwindowsthatyoucanopenfromtheMemorywindowworkinthesamewayasthedumppane.

ViewingaGame’sCallStackThefinalCPUpaneisthestackpane,andasthenamesuggests,itshowsthecallstack.Likethedumpanddisassemblerpanes,thestackpanehasanAddresscolumn.ThestackpanealsohasaValuecolumn,whichshowsthestackasanarrayof32-bitintegers,andaCommentcolumn,whichshowsreturnaddresses,knownfunctionnames,andotherinformativelabels.Thestackpanesupportsallthesamehotkeysasthedumppane,withtheexceptionofCTRL-N.

MULTICLIENTPATCHINGOnetypeofhack,calledamulticlientpatch,overwritesthesingle-instancelimitationcodewithinagame’sbinarywithno-operationcode,allowingtheusertorunmultiplegameclients,evenwhendoingsoisnormallyforbidden.Becausethecodethatperformsinstancelimitationmustbeexecutedveryearlyafteragameclientislaunched,itcanbenearlyimpossibleforabottoinjectitspatchontime.The

Page 66: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

easiestworkaroundforthisistomakemulticlientpatchespersistbyapplyingthemwithinOllyDbgandsavingthemdirectlytothegamebinary.

CreatingCodePatchesOllyDbg’scodepatchesletyoumakeassemblycodemodificationsforagameyouwanttohack,removingtheneedtoengineeratooltailoredtothatspecificgame.Thismakesprototypingcontrolflowhacks—whichmanipulategamebehaviorthroughamixofgamedesignflaws,x86assemblyprotocols,andcommonbinaryconstructs—mucheasier.

Gamehackerstypicallyincludeperfectedpatchesasoptionalfeaturesinabot’stoolsuite,butinsomecases,makingthosefeaturespersistentisactuallymoreconvenientforyourenduser.Luckily,OllyDbgpatchesprovidethecompletefunctionalityyouneedtodesign,test,andpermanentlysavecodemodificationstoanexecutablebinaryusingonlyOllyDbg.

Toplaceapatch,navigatetothelineofassemblycodeyouwanttopatchintheCPUwindow,double-clicktheinstructionyouwishtomodify,placeanewassemblyinstructioninthepop-upprompt,andclickAssemble,asshowninFigure2-3.

Figure2-3:PlacingapatchwithOllyDbg

Page 67: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Alwayspayattentiontothesizeofyourpatch—youcan’tjustresizeandmovearoundassembledcodehoweveryou’dlike.Patcheslargerthanthecodeyouintendtoreplacewilloverflowintosubsequentoperations,potentiallyremovingcriticalfunctionality.Patchessmallerthantheoperationsyouintendtoreplacearesafe,aslongasFillwithNOPsischecked.Thisoptionfillsanyabandonedbyteswithno-operation(NOP)commands,whicharesingle-byteoperationsthatdonothingwhenexecuted.

Allpatchesyouplacearelisted,alongwiththeaddress,size,state,oldcode,newcode,andcomment,inthePatcheswindow.Selectapatchinthislisttoaccessasmallbutpowerfulsetofhotkeys,showninTable2-3.

Table2-3:PatchesWindowHotkeys

OperatorFunction

ENTER Jumpstothepatchinthedisassembler.

spacebar Togglesthepatchonoroff.

F2 Placesabreakpointonthepatch.

SHIFT-F2 Placesaconditionalbreakpointonthepatch.

SHIFT-F4 Placesaconditionallogbreakpointonthepatch.DEL Removesthepatchentryfromthelistonly.

InOllyDbg,youcanalsosaveyourpatchesdirectlytothebinary.First,right-clickinthedisassemblerandclickCopytoexecutable▸Allmodifications.Ifyouwanttocopyonlycertainpatches,highlighttheminthedisassemblypaneandpressCopytoexecutable▸Selectioninstead.

DETERMININGPATCHSIZEThereareafewwaystodeterminewhetheryourpatchwillbeadifferentsizethantheoriginalcode.Forexample,inFigure2-3,youcanseethecommandat0x7790ED2EbeingchangedfromSHRAL,6toSHRAL,7.Ifyoulookatthebytestotheleftofthecommand,yousee3bytesthatrepresentthememoryofthecommand.Thismeansour

Page 68: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

newcommandmusteitherbe3bytesorpaddedwithNOPsifit’slessthan3bytes.Furthermore,thesebytesarearrangedintwocolumns.Thefirstcolumncontains0xC0and0x08,whichrepresentthecommandSHRandthefirstoperand,AL.Thesecondcolumncontains0x06,whichrepresentstheoriginaloperand.Becausethesecondcolumnshowsasinglebyte,anyreplacementoperandmustalsobe1byte(between0x00and0xFF).Ifthiscolumnhadshown0x00000006instead,areplacementoperandcouldbeupto4bytesinlength.

TypicalcodepatcheswilleitheruseallNOPstocompletelyremoveacommand(byleavingtheboxemptyandlettingitfilltheentirecommandwithNOPs)orjustreplaceasingleoperand,sothismethodofcheckingpatchsizeisalmostalwayseffective.

TracingThroughAssemblyCodeWhenyourunatraceonanyprogram,OllyDbgsingle-stepsovereveryexecutedoperationandstoresdataabouteachone.Whenthetraceiscomplete,theloggeddataisdisplayedintheRuntracewindow,showninFigure2-4.

Figure2-4:TheRuntracewindow

TheRuntracewindowisorganizedintothefollowingsixcolumns:

Page 69: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

BackThenumberofoperationsloggedbetweenanoperationandthecurrentexecutionstate

ThreadThethreadthatexecutedtheoperation

ModuleThemodulewheretheoperationresides

AddressTheaddressoftheoperation

CommandTheoperationthatwasexecuted

ModifiedregistersTheregisterschangedbytheoperationandtheirnewvalues

Whenhackinggames,IfindOllyDbg’stracefeatureveryeffectiveathelpingmefindpointerpathstodynamicmemorywhenCheatEnginescansproveinconclusive.ThisworksbecauseyoucanfollowthelogintheRuntracewindowbackwardfromthepointwhenthememoryisusedtothepointwhereitisresolvedfromastaticaddress.

Thispotentfeature’susefulnessislimitedonlybythecreativityofthehackerusingit.ThoughItypicallyuseitonlytofindpointerpaths,I’vecomeacrossafewothersituationswhereithasproveninvaluable.Theanecdotesin“OllyDbgExpressionsinAction”onpage36willhelptoilluminatethefunctionalityandpoweroftracing.

OllyDbg’sExpressionEngineOllyDbgishometoacustomexpressionenginethatcancompileandevaluateadvancedexpressionswithasimplesyntax.Theexpressionengineissurprisinglypowerfuland,whenutilizedproperly,canbethedifferencebetweenanaverageOllyDbguserandanOllyDbgwizard.Youcanusethisenginetospecifyexpressionsformanyfeatures,suchasconditionalbreakpoints,conditionaltraces,andthecommandlineplug-in.Thissectionintroducestheexpressionengineandtheoptionsitprovides.

NOTE

Partsofthissectionarebasedontheofficialexpressionsdocumentation(http://www.ollydbg.de/Help/i_Expressions.htm).Ihavefound,however,thatafewofthecomponentsdefinedinthedocumentationdon’tseemtowork,

Page 70: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

atleastnotinOllyDbgv1.10.TwoexamplesaretheINTandASCIIdatatypes,whichmustbesubstitutedwiththealiasesLONGandSTRING.Forthisreason,hereIincludeonlycomponentsthatI’vepersonallytestedandfullyunderstand.

UsingExpressionsinBreakpointsWhenaconditionalbreakpointistoggledon,OllyDbgpromptsyoutoenteranexpressionforthecondition;thisiswheremostexpressionsareused.Whenthatbreakpointisexecuted,OllyDbgsilentlypausesexecutionandevaluatestheexpression.Iftheresultoftheevaluationisnonzero,executionremainspausedandyouwillseethebreakpointgettriggered.Butiftheresultoftheevaluationis0,OllyDbgsilentlyresumesexecutionasifnothinghappened.

Withthehugenumberofexecutionsthathappenwithinagameeverysecond,you’lloftenfindthatapieceofcodeisexecutedinfartoomanycontextsforabreakpointtobeaneffectivewayofgettingthedatayouarelookingfor.Aconditionalbreakpointpairedwithagoodunderstandingofthecodesurroundingitisafoolproofwaytoavoidthesesituations.

UsingOperatorsintheExpressionEngineFornumericdatatypes,OllyDbgexpressionssupportgeneralC-styleoperators,asseeninTable2-4.Whilethereisnocleardocumentationontheoperatorprecedence,OllyDbgseemstofollowC-styleprecedenceandcanuseparenthesizedscoping.

Table2-4:OllyDbgNumericOperators

OperatorFunction

a==b Returns1ifaisequaltob,elsereturns0.a!=b Returns1ifaisnotequaltob,elsereturns0.a>b Returns1ifaisgreaterthanb,elsereturns0.a<b Returns1ifaislessthanb,elsereturns0.a>=b Returns1ifaisgreaterthanorequaltob,elsereturns0.a<=b Returns1ifaislessthanorequaltob,elsereturns0.

Page 71: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

a<=b Returns1ifaislessthanorequaltob,elsereturns0.a&&b

Returns1ifaandbarebothnonzero,elsereturns0.a||b Returns1ifeitheraorbarenonzero,elsereturns0.a^b ReturnstheresultofXOR(a,b).a%b ReturnstheresultofMODULUS(a,b).a&b ReturntheresultofAND(a,b).a|b ReturntheresultofOR(a,b).a<<b Returnstheresultofashiftedbbitstotheleft.a>>b Returnstheresultofashiftedbbitstotheright.a+b Returnsthesumofaplusb.a-b Returnsthedifferenceofaminusb.a/b Returnsthequotientofadividedbyb.a*b Returnstheproductofatimesb.+a Returnsthesignedrepresentationofa.-a Returnsa*-1.!a Returns1ifais0,elsereturns0.

Forstrings,ontheotherhand,theonlyavailableoperatorsare==and!=,whichbothadheretothefollowingsetofrules:

•Stringcomparisonsarecaseinsensitive.

•Ifonlyoneoftheoperandsisastringliteral,thecomparisonwillterminateafteritreachesthelengthoftheliteral.Asaresult,theexpression[STRINGEAX]=="ABC123",whereEAXisapointertothestringABC123XYZ,willevaluateto1insteadof0.

•Ifnotypeisspecifiedforanoperandinastringcomparisonandtheotheroperandisastringliteral(forexample,"MyString"!=EAX),thecomparisonwillfirstassumethenonliteraloperandisanASCIIstring,and,ifthatcomparewouldreturn0,itwilltryasecondcompareassumingthe

Page 72: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

operandisaUnicodestring.

Ofcourse,operatorsaren’tmuchusewithoutoperands.Let’slookatsomeofthedatayoucanevaluateinexpressions.

WorkingwithBasicExpressionElementsExpressionsareabletoevaluatemanydifferentelements,including:

CPUregistersEAX,EBX,ECX,EDX,ESP,EBP,ESI,andEDI.Youcanalsousethe1-byteand2-byteregisters(forexample,ALforthelowbyteandAXforthelowwordofEAX).EIPcanalsobeused.

SegmentregistersCS,DS,ES,SS,FS,andGS.

FPUregistersST0,ST1,ST2,ST3,ST4,ST5,ST6,andST7.

SimplelabelsCanbeAPIfunctionnames,suchasGetModuleHandle,oruser-definedlabels.

WindowsconstantsSuchasERROR_SUCCESS.

IntegersArewritteninhexadecimalformatordecimalformatiffollowedbyatrailingdecimalpoint(forexample,FFFFor65535.).

Floating-pointnumbersAllowexponentsindecimalformat(forexample,654.123e-5).

StringliteralsArewrappedinquotationmarks(forexample,"mystring").

Theexpressionsenginelooksfortheseelementsintheorderthey’relistedhere.Forexample,ifyouhavealabelthatmatchesthenameofaWindowsconstant,theengineusestheaddressofthelabelinsteadoftheconstant’svalue.Butifyouhavealabelnamedafteraregister,suchasEAX,theengineusestheregistervalue,notthelabelvalue.

AccessingMemoryContentswithExpressionsOllyDbgexpressionsarealsopowerfulenoughtoincorporatememoryreading,whichyoucandobywrappingamemoryaddress,oranexpressionthatevaluatestoone,insquarebrackets.Forexample,[EAX+C]and[401000]

Page 73: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

representthecontentsattheaddressesEAX+Cand401000.ToreadthememoryasatypeotherthanDWORD,youcanspecifythedesiredtypeeitherbeforethebrackets,asinBYTE[EAX],orasthefirsttokenwithinthem,asin[STRINGESP+C].SupportedtypesarelistedinTable2-5.

Table2-5:OllyDbgDataTypes

DatatypeInterpretationBYTE 8-bitinteger(unsigned)CHAR 8-bitinteger(signed)WORD 16-bitinteger(unsigned)SHORT 16-bitinteger(signed)DWORD 32-bitinteger(unsigned)LONG 32-bitinteger(signed)FLOAT 32-bitfloating-pointnumberDOUBLE 64-bitfloating-pointnumberSTRING PointertoanASCIIstring(null-terminated)UNICODE PointertoaUnicodestring(null-terminated)

PluggingmemorycontentsdirectlyintoyourOllyDbgexpressionsisincrediblyusefulingamehacking,inpartbecauseyoucantellthedebuggertocheckacharacter’shealth,name,gold,andsooninmemorybeforebreaking.You’llseeanexampleofthisin“PausingExecutionWhenaSpecificPlayer’sNameIsPrinted”onpage37.

OllyDbgExpressionsinActionExpressionsinOllyDbguseasyntaxsimilartothatofmostprogramminglanguages;youcanevencombinemultipleexpressionsandnestoneexpressionwithinanother.Gamehackers(really,allhackers)commonlyusethemtocreateconditionalbreakpoints,asIdescribedin“UsingExpressionsinBreakpoints”onpage34,butyoucanusetheminmanydifferentplacesinOllyDbg.Forinstance,OllyDbg’scommandlineplug-incanevaluate

Page 74: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

expressionsinplaceanddisplaytheirresults,allowingyoutoeasilyreadarbitrarymemory,inspectvaluesthatarebeingcalculatedbyassemblycode,orquicklygettheresultsofmathematicalequations.Furthermore,hackerscanevencreateintelligent,position-agnosticbreakpointsbycouplingexpressionswiththetracefeature.

Inthissection,I’llsharesomeanecdoteswheretheexpressionenginehascomeinhandyduringmywork.Iwillexplainmythoughtprocess,walkthroughmyentiredebuggingsession,andbreakeachexpressiondownintoitscomponentpartssoyoucanseesomewaystouseOllyDbgexpressionsingamehacking.

NOTE

Theseexamplescontainsomeassemblycode,butifyoudon’thavemuchexperiencewithassembly,don’tworry.JustignorethefinedetailsandknowthatvalueslikeECX,EAX,andESPareprocessregistersliketheonesdiscussedin“ViewingandEditingRegisterContents”onpage29.Fromthere,I’llexplaineverythingelse.

Ifyougetconfusedaboutanoperator,element,ordatatypeinanexpressionasIwalkthroughtheseanecdotes,justreferto“OllyDbg’sExpressionEngine”onpage33.

PausingExecutionWhenaSpecificPlayer’sNameIsPrintedDuringoneparticulardebuggingsession,Ineededtofigureoutexactlywhatwashappeningwhenagamewasdrawingthenamesofplayersonscreen.Specifically,Ineededtoinvokeabreakpointbeforethegamedrewthename“Player1,”ignoringallothernamesthatweredrawn.

FiguringOutWheretoPauseAsastartingpoint,IusedCheatEnginetofindtheaddressofPlayer1’snameinmemory.OnceIhadtheaddress,IusedOllyDbgtosetamemorybreakpointonthefirstbyteofthestring.Everytimethisbreakpointgothit,IquicklyinspectedtheassemblycodetodeterminehowitwasusingPlayer

Page 75: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

1’sname.Eventually,IfoundthenamebeingaccesseddirectlyaboveacalltoafunctionthatIhadpreviouslygiventhenameprintText().Ihadfoundthecodethatwasdrawingthename.

IremovedmymemorybreakpointandreplaceditwithacodebreakpointonthecalltoprintText().Therewasaproblem,however:becausethecalltoprintText()wasinsidealoopthatiteratedovereveryplayerinthegame,mynewbreakpointwasgettinghiteverytimeanamewasdrawn—andthatwasmuchtoooften.Ineededtofixittohitonlyonaspecificplayer.

Inspectingtheassemblycodeatmypreviousmemorybreakpointtoldmethateachplayer’snamewasaccessedusingthefollowingassemblycode:

PUSHDWORDPTRDS:[EAX+ECX*90+50]

TheEAXregistercontainedtheaddressofanarrayofplayerdata;I’llcallitplayerStruct.ThesizeofplayerStructwas0x90bytes,theECXregistercontainedtheiterationindex(thefamousvariablei),andeachplayer’snamewasstored0x50bytesafterthestartofitsrespectiveplayerStruct.ThismeantthatthisPUSHinstructionessentiallyputEAX[ECX].name(thenameoftheplayeratindexi)onthestacktobepassedasanargumenttotheprintText()functioncall.Theloop,then,brokedowntosomethinglikethefollowingpsuedocode:

playerStructEAX[MAX_PLAYERS];//thisisfilledelsewherefor(int➊ECX=0;ECX<MAX_PLAYERS;ECX++){char*name=➋EAX[ECX].name;breakpoint();//mycodebreakpointwasbasicallyrighthereprintText(name);}

Purelythroughanalysis,IdeterminedthattheplayerStruct()functioncontaineddataforallplayers,andtheloopiteratedoverthetotalnumberofplayers(countingupwithECX➊),fetchedthecharactername➋foreachindex,andprintedthename.

CraftingtheConditionalBreakpointKnowingthat,topauseexecutiononlywhenprinting“Player1”allIhadtodowascheckthecurrentplayernamebeforeexecutingmybreakpoint.Inpseudocode,thenewbreakpointwouldlooklikethis:

Page 76: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

if(EAX[ECX].name=="Player1")breakpoint();

OnceIfiguredouttheformofmynewbreakpoint,IneededtoaccessEAX[ECX].namefromwithintheloop.That’swhereOllyDbg’sexpressionenginecamein:Icouldachievemygoalbymakingslightmodificationstotheexpressionthattheassemblycodeused,leavingmewiththisexpression:

[STRINGEAX+ECX*0x90+0x50]=="Player1"

IremovedthecodebreakpointonprintText()andreplaceditwithaconditionalbreakpointthatusedthisexpression,whichtoldOllyDbgtobreakonlyifthestringvaluestoredatEAX+ECX*0x90+0x50matchedPlayer1’sname.Thisbreakpointhitonlywhen"Player1"wasbeingdrawn,allowingmetocontinuemyanalysis.

Theamountofworkittooktoengineerthisbreakpointmightseemextensive,butwithpractice,theentireprocessbecomesasintuitiveaswritingcode.Experiencedhackerscandothisinamatterofseconds.

Inpractice,thisbreakpointenabledmetoinspectcertainvaluesintheplayerStruct()functionfor"Player1"assoonasheappearedonscreen.Doingitthiswaywasimportant,asthestatesofthesevalueswererelevanttomyanalysisonlyinthefirstfewframesaftertheplayerenteredthescreen.Creativelyusingbreakpointslikethiscanenableyoutoanalyzeallsortsofcomplexgamebehavior.

PausingExecutionWhenYourCharacter’sHealthDropsDuringanotherdebuggingsession,Ineededtofindthefirstfunctioncalledaftermycharacter’shealthdroppedbelowthemaximum.Iknewtwowaystoapproachthisproblem:

•Findeverypieceofcodethataccessesthehealthvalueandplaceaconditionalbreakpointthatchecksthehealthoneachone.Then,onceoneofthesebreakpointsishit,single-stepthroughthecodeuntilthenextfunctioncall.

•UseOllyDbg’stracefunctiontocreateadynamicbreakpointthatcanstopexactlywhereIneed.

Thefirstmethodrequiredmoresetupandwasnoteasilyrepeatable,mostlyduetothesheernumberofbreakpointsneededandthefactthatI’d

Page 77: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

mostlyduetothesheernumberofbreakpointsneededandthefactthatI’dhavetosingle-stepbyhand.Incontrast,thelattermethodhadaquicksetup,andsinceitdideverythingautomatically,itwaseasilyrepeatable.Thoughusingthetracefunctionwouldslowthegamedownconsiderably(everysingleoperationwascapturedbythetrace),Ichosethelattermethod.

WritinganExpressiontoCheckHealthOnceagain,IstartedbyusingCheatEnginetofindtheaddressthatstoredmyhealth.Usingthemethoddescribedin“CheatEngine’sMemoryScanner”onpage5,Ideterminedtheaddresstobe0x40A000.

Next,IneededanexpressionthattoldOllyDbgtoreturn1whenmyhealthwasbelowmaximumandreturn0otherwise.Knowingthatmyhealthwasstoredat0x40A000andthatthemaximumvaluewas500,Iinitiallydevisedthisexpression:

[0x40A000]<500.

Thisexpressionwouldinvokeabreakwhenmyhealthwasbelow500(remember,decimalnumbersmustbesuffixedwithaperiodintheexpressionengine),butinsteadofwaitingforafunctiontobecalled,thebreakwouldhappenimmediately.Toensurethatitwaiteduntilafunctionwascalled,Iappendedanotherexpressionwiththe&&operator:

[0x40A000]<500.&&[➊BYTEEIP]==0xE8

Onx86processors,theEIPregisterstorestheaddressoftheoperationbeingexecuted,soIdecidedtocheckthefirstbyteatEIP➊toseeifitwasequalto0xE8.Thisvaluetellstheprocessortoexecuteanearfunctioncall,whichisthetypeofcallIwaslookingfor.

Beforestartingmytrace,Ihadtodoonelastthing.Becausethetracefeaturerepeatedlysingle-steps(TraceintousesstepintoandTraceoverusesstepover,asdescribedin“ABriefLookatOllyDbg’sUserInterface”onpage24),Ineededtostartthetraceatalocationscopedatorabovethelevelofanycodethatcouldpossiblyupdatethehealthvalue.

FiguringOutWheretoStarttheTraceTofindagoodlocation,Iopenedthegame’smainmoduleinOllyDbg’s

Page 78: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CPUwindow,right-clickedinthedisassemblerpane,andselectedSearchfor▸Allintermodularcalls.TheReferenceswindowpoppedupanddisplayedalistofexternalAPIfunctionsthatwerecalledbythegame.NearlyallgamingsoftwarepollsfornewmessagesusingtheWindowsUSER32.PeekMessage()function,soIsortedthelistusingtheDestinationcolumnandtypedPEEK(youcansearchthelistbysimplytypinganamewiththewindowinfocus)tolocatethefirstcalltoUSER32.PeekMessage().

ThankstotheDestinationsorting,everycalltothisfunctionwaslistedinacontiguouschunkfollowingthefirst,asshowninFigure2-5.IsetabreakpointoneachbyselectingitandpressingF2.

Figure2-5:OllyDbg’sFoundintermodularcallswindow

ThoughtherewerearoundadozencallstoUSER32.PeekMessage(),onlytwoofthemweresettingoffmybreakpoints.Evenbetter,theactivecallswerebesideoneanotherinanunconditionalloop.Atthebottomofthisloopwereanumberofinternalfunctioncalls.Thislookedexactlylikeamaingameloop.

ActivatingtheTrace

Page 79: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Tofinallysetmytrace,Iremovedallofmypreviousbreakpointsandplacedoneatthetopofthesuspectedmainloop.Iremovedthebreakpointassoonasitwashit.IthenpressedCTRL-TfromtheCPUwindow,whichbroughtupadialogcalledConditiontopauseruntrace,showninFigure2-6.Withinthisnewdialog,IenabledtheConditionisTRUEoption,placedmyexpressionintheboxbesideit,andpressedOK.Then,IwentbacktotheCPUwindowandpressedCTRL-F11tobeginaTraceIntosession.

Figure2-6:Conditiontopauseruntracedialog

Oncethetracebegan,thegameransoslowlyitwasnearlyunplayable.Todecreasemytestcharacter’shealth,Iopenedasecondinstanceofthegame,loggedintoadifferentcharacter,andattackedmytestcharacter.Whentheexecutionofthetracecaughtuptorealtime,OllyDbgsawmyhealthchangeandtriggeredthebreakpointonthefollowingfunctioncall—justasexpected.

Inthisgame,themainpiecesofcodethatwouldmodifythehealthvalueweredirectlyinvokedfromthenetworkcode.Usingthistrace,Iwasabletofindthefunctionthatthenetworkmodulecalleddirectlyafteranetworkpackettoldthegametochangetheplayer’shealth.Here’sthepsuedocodeofwhatthegamewasdoing:

Page 80: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

voidnetwork::check(){while(this->hasPacket()){packet=this->getPacket();if(packet.type==UPDATE_HEALTH){oldHealth=player->health;player->health=packet.getInteger();➊observe(HEALTH_CHANGE,oldHealth,player->health);}}}

Iknewthegamehadcodethatneededtoexecuteonlywhentheplayer’shealthwaschanged,andIneededtoaddcodethatcouldalsorespondtosuchchanges.Withoutknowingtheoverallcodestructure,Iguessedthatthehealth-dependentcodewouldbeexecutedfromsomefunctioncalldirectlyafterhealthwasupdated.Mytraceconditionalbreakpointconfirmedthishunch,asitbrokedirectlyontheobserve()function➊.Fromthere,Iwasabletoplaceahookonthefunction(hooking,awaytointerceptfunctioncalls,isdescribedin“HookingtoRedirectGameExecution”onpage153)andexecutemyowncodewhentheplayer’shealthchanged.

OllyDbgPlug-insforGameHackersOllyDbg’shighlyversatileplug-insystemisperhapsoneofitsmostpowerfulfeatures.ExperiencedgamehackersoftenconfiguretheirOllyDbgenvironmentswithdozensofusefulplug-ins,bothpubliclyavailableandcustom-made.

Youcandownloadpopularplug-insfromtheOpenRCE(http://www.openrce.org/downloads/browse/OllyDbg_Plugins)andtuts4you(http://www.tuts4you.com/download.php?list.9/)plug-inrepositories.Installingthemiseasy:justunziptheplug-infilesandplacetheminsideOllyDbg’sinstallationfolder.

Onceinstalled,someplug-inscanbeaccessedfromtheOllyDbg’sPluginmenuitem.Otherplug-ins,however,mightbefoundonlyinspecificplacesthroughouttheOllyDbginterface.

Youcanfindhundredsofpotentplug-insusingtheseonlinerepositories,butyoushouldbecarefulwhenconstructingyourarsenal.Workinginanenvironmentbloatedbyunusedplug-inscanactuallyimpedeproductivity.Inthissection,I’vecarefullyselectedfourplug-insthatIbelievearenotonly

Page 81: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thissection,I’vecarefullyselectedfourplug-insthatIbelievearenotonlyintegraltoagamehacker’stoolkitbutalsononinvasivetotheenvironment.

CopyingAssemblyCodewithAsm2ClipboardAsm2Clipboardisaminimalisticplug-infromtheOpenRCErepositorythatallowsyoutocopychunksofassemblycodefromthedisassemblerpanetotheclipboard.Thiscanbeusefulforupdatingaddressoffsetsanddevisingcodecaves,twogame-hackingessentialsIcoverdeeplyinChapters5and7.

WithAsm2Clipboardinstalled,youcanhighlightablockofassemblycodeinthedisassembler,right-clickthehighlightedcode,expandtheAsm2Clipboardsubmenu,andselecteitherCopyfixedAsmcodetoclipboardorCopyAsmcodetoclipboard.Thelatterprependsthecodeaddressofeachinstructionasacomment,whiletheformercopiesonlythepurecode.

AddingCheatEnginetoOllyDbgwithCheatUtilityTheCheatUtilityplug-infromtuts4youprovidesahighlyslimmed-downversionofCheatEnginewithinOllyDbg.WhileCheatUtilityonlyallowsyoutodoexact-valuescanswithaverylimitednumberofdatatypes,itcanmakesimplescansmucheasierwhenyoudon’tneedthefullfunctionalityofCheatEnginetofindwhatyou’relookingfor.AfterinstallingCheatUtility,toopenitsinterface(showninFigure2-7),selectPlugins▸Cheatutility▸Start.

Page 82: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure2-7:CheatUtilityinterface

CheatUtility’suserinterfaceandoperationmimicCheatEngineclosely,soreviewChapter1ifyouneedarefresher.

NOTE

GamesInvader,anupdatedversionofCheatUtilityalsofromtuts4you,wascreatedtoprovidemorefunctionality.I’vefounditbuggy,however,andIpreferCheatUtilitysinceIcanalwaysuseCheatEngineforadvancedscans.

ControllingOllyDbgThroughtheCommandLineThecommandlineplug-inenablesyoutocontrolOllyDbgthroughasmallcommandlineinterface.Toaccesstheplug-in,eitherpressALT-F1orselectPlugins▸Commandline▸Commandline.Youshouldthenseeawindow,showninFigure2-8,whichactsasthecommandlineinterface.

Figure2-8:Commandlineinterface

Page 83: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Toexecuteacommand,typeitintotheinputbox➊andpressENTER.Youwillseeasession-levelcommandhistoryinthecenterlist➋,andthebottomlabeldisplaysthecommand’sreturnvalue➌(ifany).

Thoughtherearemanycommandsavailable,Ifindamajorityofthemuseless.Iprimarilyusethistoolasawaytotestthatexpressionsareparsingasexpectedandasahandycalculator,butthereareafewadditionalusecasesthatarealsoworthmentioning.I’vedescribedtheseinTable2-6.

Table2-6:CommandLinePlug-inCommands

Command Function

BCidentifier

Removesanybreakpointspresentonidentifier,whichcanbeacodeaddressorAPIfunctionname.

BPidentifier[,condition]

Placesadebuggerbreakpointonidentifier,whichcanbeacodeaddressorAPIfunctionname.WhenidentifierisanAPIfunctionname,thebreakpointwillbeplacedonthefunctionentrypoint.Theconditionparameterisanoptionalexpressionthat,ifpresent,willbesetasthebreakpointcondition.

BPXlabel Placesadebuggerbreakpointoneveryinstanceoflabelwithinthemodulecurrentlybeingdisassembled.ThislabelwilltypicallybeanAPIfunctionname.

CALCexpression?expression

Evaluatesexpressionanddisplaystheresult.

HDaddress Removesanyhardwarebreakpointspresentonaddress.HEaddress Placesahardwareon-executebreakpointonaddress.HRaddress Placesahardwareon-accessbreakpointonaddress.Onlyfour

hardwarebreakpointscanexistatatime.HWaddress Placesahardwareon-writebreakpointonaddress.MD Removesanyexistingmemorybreakpoint,ifpresent.MRaddress1,address2

Placesamemoryon-accessbreakpointstartingataddress1andspanninguntiladdress2.Willreplaceanyexistingmemorybreakpoint.

Page 84: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MWaddress1,address2

Placesamemoryon-writebreakpointstartingataddress1and

spanninguntiladdress2.Willreplaceanyexistingmemorybreakpoint.

WATCHexpressionWexpression

OpenstheWatcheswindowandaddsexpressiontothewatchlist.Expressionsinthislistwillbereevaluatedeverytimetheprocessreceivesamessageandtheevaluationresultswillbedisplayedbesidethem.

Thecommandlineplug-inwasmadebytheOllyDbgdeveloperandshouldcomepreinstalledwithOllyDbg.

VisualizingControlFlowwithOllyFlowOllyFlow,whichcanbefoundintheOpenRCEplug-indirectory,isapurelyvisualplug-inthatcangeneratecodegraphsliketheoneinFigure2-9anddisplaythemusingWingraph32.

Figure2-9:AnOllyFlowfunctionflowchart

Page 85: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NOTE

Wingraph32isnotprovidedwithOllyFlow,butitisavailablewiththefreeversionofIDAhere:https://www.hex-rays.com/products/ida/.Downloaditanddropthe.exeinyourOllyDbginstallationfolder.

Thoughnotinteractive,thesegraphsallowyoutoeasilyidentifyconstructssuchasloopsandnestedif()statementsingamecode,whichcanbeparamountincontrolflowanalysis.WithOllyFlowinstalled,youcangenerateagraphbygoingtoPlugins▸OllyFlow(alternatively,right-clickinthedisassemblerpaneandexpandtheOllyFlowgraphsubmenu)andselectingoneofthefollowingoptions:

GeneratefunctionflowchartGeneratesagraphofthefunctioncurrentlyinscope,breakingapartdifferentcodeblocksandshowingjumppaths.Figure2-9showsafunctionflowchart.Withoutadoubt,thisisOllyFlow’smostusefulfeature.

GeneratexrefsfromgraphGeneratesagraphofallfunctionscalledbythefunctionthatiscurrentlyinscope.

GeneratexrefstographGeneratesagraphofallfunctionsthatcallthefunctioncurrentlyinscope.

GeneratecallstackgraphGeneratesagraphoftheassumedcallpathfromtheprocessentrypointtothefunctioncurrentlyinscope.

GeneratemodulegraphTheoreticallygeneratesacompletegraphofallfunctioncallsintheentiremodule,butrarelyactuallyworks.

TogetanideaoftheusefulnessofOllyFlow,takealookatthegraphinFigure2-9andcompareittotherelativelysimpleassemblyfunctionthatgeneratedit:

76f86878:➊MOVEAX,DWORDPTRDS:[76FE7E54]TESTAL,1JEntdll.76F8689B76f86881:➋MOVEAX,DWORDPTRFS:[18]MOVEAX,DWORDPTRDS:[EAX+30]ORDWORDPTRDS:[EAX+68],2000000

Page 86: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MOVEAX,DWORDPTRDS:[76FE66E0]ORDWORDPTRDS:[EAX],1JMPntdll.76F868B276f8689b:➌TESTEAX,8000JEntdll.76F868B276f868a2:➍MOVEAX,DWORDPTRFS:[18]MOVEAX,DWORDPTRDS:[EAX+30]ORDWORDPTRDS:[EAX+68],200000076f868b2:➎MOVAL,1RETN

TherearefiveboxesinFigure2-9,andtheymaptothefivepiecesofthisfunction.Thefunctionstartswith➊,anditfallsthroughto➋ifthebranchfailsorjumpsto➌ifitsucceeds.After➋executes,itjumpsdirectlytopiece➎,whichthenreturnsoutofthefunction.After➌executes,iteitherfallsthroughto➍orbranchesto➎toreturndirectly.After➍executes,itunconditionallyfallsthroughto➎.WhatthisfunctiondoesisirrelevanttounderstandingOllyFlow;fornow,justfocusonseeinghowthecodemapstothegraph.

PATCHINGANIF()STATEMENTIfyouthinkyou’rereadytogetyourhandsdirtywithOllyDbg,keepreading.Gotohttps://www.nostarch.com/gamehacking/,downloadthebook’sresourcefiles,grabBasicDebugging.exe,andexecuteit.Atfirstglance,you’llseethatitlooksliketheclassicgamePong.InthisversionofPong,theballisinvisibletoyouwhenitisonyouropponent’sscreen.Yourtaskistodisablethisfeaturesothatyoucanalwaysseetheball.Tomakeiteasierforyou,I’vemadethegameautonomous.Youdon’thavetoplay,onlyhack.

Tostart,attachOllyDbgtothegame.ThenfocustheCPUwindowonthemainmodule(findthe.exeinthemodulelistanddouble-clickit)andusetheReferencedtextstringsfeaturetolocatethestringthatisdisplayedwhentheballishidden.Next,double-clickthestringtobringitupinthecodeandanalyzethesurroundingcode

Page 87: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

untilyoufindtheif()statementthatdetermineswhethertohidetheball.Lastly,usingthecode-patchingfeature,patchtheif()statementsotheballisalwaysdrawn.Asanaddedbonus,youmighttryusingOllyFlowtographthisfunctionsoyoucangetabetterunderstandingofwhatexactlyitisdoing.(Hint:Theif()statementcheckswhethertheball’sx-coordinateislessthan0x140.Ifso,itjumpstocodethatdrawstheball.Ifnot,itdrawsthescenewithouttheball.Ifyoucanchange0x140to,say,0xFFFF,theballwillnevergethidden.)

ClosingThoughtsOllyDbgisamuchmorecomplexbeastthanCheatEngine,butyou’lllearnbestbyusingit,sodiveinandgetyourhandsdirty!Youcanstartbypairingthecontrolstaughtinthischapterwithyourdebuggingskillsandgoingtoworkonsomerealgames.Ifyouarenotyetreadytotamperwithyourvirtualfate,however,trytacklingtheexamplein“Patchinganif()Statement”forapracticeenvironment.Whenyou’redone,readontoChapter3,whereI’llintroduceyoutoProcessMonitorandProcessExplorer,twotoolsyou’llfindinvaluableingame-hackingreconnaissance.

Page 88: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

3RECONNAISSANCEWITHPROCESSMONITORANDPROCESSEXPLORER

CheatEngineandOllyDbgcanhelpyoutearapartagame’smemoryandcode,butyoualsoneedtounderstandhowthegameinteractswithfiles,registryvalues,networkconnections,andotherprocesses.Tolearnhowthoseinteractionswork,youmustusetwotoolsthatexcelatmonitoringtheexternalactionsofprocesses:ProcessMonitorandProcessExplorer.Withthesetools,youcantrackdownthecompletegamemap,locatesavefiles,identifyregistrykeysusedtostoresettings,andenumeratetheInternetProtocol(IP)addressesofremotegameservers.

Inthischapter,I’llteachyouhowtousebothProcessMonitorandProcessExplorertologsystemeventsandinspectthemtoseehowagamewasinvolved.Usefulmainlyforinitialreconnaissance,thesetoolsareamazingatgivingaclear,verbosepictureofexactlyhowagameinteractswithyoursystem.YoucandownloadbothprogramsfromtheWindowsSysinternalswebsite(https://technet.microsoft.com/en-us/sysinternals/).

ProcessMonitorYoucanlearnalotaboutagamesimplybyexploringhowitinteractswiththeregistry,filesystem,andnetwork.ProcessMonitorisapowerfulsystem-monitoringtoolthatlogssucheventsinrealtimeandletsyouseamlessly

Page 89: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

monitoringtoolthatlogssucheventsinrealtimeandletsyouseamlesslyintegratethedataintoadebuggingsession.Thistoolprovidesextensiveamountsofusefuldataregardingagame’sinteractionwiththeexternalenvironment.Withcalculatedreview(andsometimes,spontaneousintuition)onyourpart,thisdatacanrevealdetailsaboutdatafiles,networkconnections,andregistryeventsthatarehelpfultoyourabilitytoseeandmanipulatehowthegamefunctions.

Inthissection,I’llshowyouhowtouseProcessMonitortologdata,navigateit,andmakeeducatedguessesaboutthefilesagameinteractswith.Afterthisinterfacetour,you’llhaveachancetotryoutProcessMonitorforyourselfin“FindingaHighScoreFile”onpage55.

LoggingIn-GameEventsProcessMonitor’slogscanholdallsortsofpotentiallyusefulinformation,buttheirmostpracticaluseistohelpyoufigureoutwheredatafiles,suchasin-gameitemdefinitions,mightbestored.WhenyoustartProcessMonitor,thefirstdialogyouseeistheProcessMonitorFilter,showninFigure3-1.

Figure3-1:ProcessMonitorFilterdialog

Thisdialogallowsyoutoshoworsuppresseventsbasedonanumberofdynamicpropertiestheypossess.Tostartmonitoringprocesses,selectProcessName▸Is▸YourGameFilename.exe▸Includeandthenpress

Page 90: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Add,Apply,andOK.ThistellsProcessMonitortoshoweventsinvokedbyYourGameFilename.exe.Withtheproperfiltersset,youwillbetakentothemainwindowshowninFigure3-2.

Figure3-2:ProcessMonitormainwindow

ToconfigurethecolumnsdisplayedinProcessMonitor’slogarea,right-clickontheheaderandchooseSelectColumns.There’sanimpressivenumberofoptions,butIrecommendseven.

TimeofDayLetsyouseewhenactionsarehappening.

ProcessNameIsusefulifyou’remonitoringmultipleprocesses,butwiththesingle-processfilterthatistypicallyusedforgames;disablingthisoptioncansavepreciousspace.

ProcessIDIslikeProcessName,butitshowstheIDratherthanthename.

OperationShowswhatactionwasperformed;thus,thisoptioniscompulsory.

PathShowsthepathoftheaction’starget;alsocompulsory.

DetailIsusefulonlyinsomecases,butenablingitwon’thurt.

ResultShowswhenactions,suchasloadingfiles,fail.

Asyoushowmorecolumns,thelogcangetverycrowded,butstickingwiththeseoptionsshouldhelpkeeptheoutputsuccinct.

Page 91: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

withtheseoptionsshouldhelpkeeptheoutputsuccinct.Oncethemonitorisrunningandyou’vedefinedthecolumnsyouwishto

see,therearefiveeventclassfilters,outlinedinblackinFigure3-2,thatyoucantoggletocleanupyourlogsevenfurther.Eventclassfiltersletyouchoosewhicheventstoshowinthelog,basedontype.Fromlefttoright,thesefiltersareasfollows:

RegistryShowsallregistryactivity.Therewillbealotofwhitenoiseintheregistryuponprocesscreation,asgamesrarelyusetheregistryandWindowslibrariesalwaysuseit.Leavingthisfilterdisabledcansavealotofspaceinthelog.

FilesystemShowsallfilesystemactivity.Thisisthemostimportanteventclassfilter,sinceknowingwheredatafilesarestoredandhowtheyareaccessedisintegraltowritinganeffectivebot.

NetworkShowsallnetworkactivity.Thecallstackonnetworkeventscanbeusefulinfindingnetwork-relatedcodewithinagame.

ProcessandthreadactivityShowsallprocessandthreadactions.Thecallstackontheseeventscangiveyouinsightintohowagame’scodehandlesthreads.

ProcessprofilingPeriodicallyshowsinformationaboutthememoryandCPUusageofeachrunningprocess;agamehackerwillrarelyuseit.

Ifclass-leveleventfilteringisstillnotpreciseenoughtofilteroutunwantedpollutioninyourlogs,right-clickonspecificeventsforevent-levelfilteringoptions.Onceyouhaveyoureventfilteringconfiguredtologonlywhatyouneed,youcanbeginnavigatingthelog.Table3-1listssomeusefulhotkeysforcontrollingthelog’sbehavior.

Table3-1:ProcessMonitorHotkeys

HotkeyAction

CTRL-E Toggleslogging.

CTRL-A Togglesautomaticscrollingofthelog.

CTRL-X Clearsthelog.

CTRL-L DisplaystheFilterdialog.

CTRL- DisplaystheHighlightdialog.Thisdialoglooksverysimilartothe

Page 92: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CTRL-H

DisplaystheHighlightdialog.ThisdialoglooksverysimilartotheFilterdialog,butitisusedtoindicatewhicheventsshouldbehighlighted.

CTRL-F DisplaystheSearchdialog.

CTRL-P DisplaystheEventPropertiesdialogfortheselectedevent.

Asyounavigatethelog,youcanexaminetheoperationsrecordedtoseethefine-graineddetailsofanevent.

InspectingEventsintheProcessMonitorLogProcessMonitorlogseverydatapointitpossiblycanaboutanevent,enablingyoutolearnmoreabouttheseeventsthanjustthefilestheyactupon.Carefullyinspectingdata-richcolumns,suchasResultandDetail,canyieldsomeveryinterestinginformation.

Forexample,I’vefoundthatgamessometimesreaddatastructures,elementbyelement,directlyfromfiles.Thisbehaviorisapparentwhenalogcontainsalargenumberofreadstothesamefile,whereeachreadhassequentialoffsetsbutdifferinglengths.ConsiderthehypotheticaleventlogshowninTable3-2.

Table3-2:ExampleEventLog

OperationPath Detail

CreateFileC:\file.datDesiredAccess:Read

ReadFile C:\file.datOffset:0Size:4

ReadFile C:\file.datOffset:4Size:2

ReadFile C:\file.datOffset:6Size:2

ReadFile C:\file.datOffset:8Size:4

ReadFile C:\file.datOffset:12Size:4

... ... ...Continuestoreadchunksof4bytesforawhile

Thislogrevealsthatthegameisreadingastructurefromthefilepiecebypiece,disclosingsomehintsaboutwhatthestructurelookslike.Forexample,let’ssaythatthesereadsreflectthefollowingdatafile:

Page 93: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

structmyDataFile{intheader;//4bytes(offset0)shorteffectCount;//2bytes(offset4)shortitemCount;//2bytes(offset6)int*effects;int*items;};

ComparetheloginTable3-2withthisstructure.First,thegamereadsthe4headerbytes.Then,itreadstwo2-bytevalues:effectCountanditemCount.Itthencreatestwointegerarrays,effectsanditems,ofrespectivelengthseffectCountanditemCount.Thegamethenfillsthesearrayswithdatafromthefile,reading4byteseffectCount+itemCounttimes.

NOTE

Developersdefinitelyshouldn’tuseaprocesslikethistoreaddatafromafile,butyou’dbeamazedathowoftenithappens.Fortunatelyforyou,naïvetélikethisjustmakesyouranalysiseasier.

Inthiscase,theeventlogcanidentifysmallpiecesofinformationwithinafile.Butkeepinmindthat,whilecorrelatingthereadswiththeknownstructureiseasy,it’smuchhardertoreverseengineeranunknownstructurefromnothingbutaneventlog.Typically,gamehackerswilluseadebuggertogetmorecontextabouteachinterestingevent,andthedatafromProcessMonitorcanbeseamlesslyintegratedintoadebuggingsession,effectivelytyingtogetherthetwopowerfulreverseengineeringparadigms.

DebuggingaGametoCollectMoreDataLet’sstepawayfromthishypotheticalfilereadandlookathowProcessMonitorletsyoutransitionfromeventloggingtodebugging.ProcessMonitorstoresacompletestacktraceforeachevent,showingthefullexecutionchainthatledtotheeventbeingtriggered.YoucanviewthesestacktracesintheStacktaboftheEventPropertieswindow(double-clicktheeventorpressCTRL-P),asshowninFigure3-3.

Page 94: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure3-3:ProcessMonitoreventcallstack

ThestacktraceisdisplayedinatablestartingwithaFramecolumn➊,whichshowstheexecutionmodeandstackframeindex.ApinkKinthiscolumnmeansthecallhappenedinkernelmode,whileablueUmeansithappenedinusermode.Sincegamehackerstypicallyworkinusermode,kernelmodeoperationsareusuallymeaningless.

TheModulecolumn➋showstheexecutablemodulewherethecallingcodewaslocated.Eachmoduleisjustthenameofthebinarythatmadethecall;thismakesiteasytoidentifywhichcallswereactuallymadefromwithinagamebinary.

TheLocationcolumn➌showsthenameofthefunctionthatmadeeachcall,aswellasthecalloffset.Thesefunctionnamesarededucedfromthe

Page 95: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

exporttableofthemoduleandwillgenerallynotbepresentforthefunctionswithinagamebinary.Whennofunctionnamesarepresent,theLocationcolumninsteadshowsthemodulenameandthecall’soffset(howmanybytespasttheoriginaddressthecallisinmemory)fromthemodule’sbaseaddress.

NOTE

Inthecontextofcode,theoffsetishowmanybytesofassemblycodearebetweenanitemanditsorigin.

TheAddresscolumn➍showsthecodeaddressofthecall,whichisveryusefulbecauseyoucanjumptotheaddressintheOllyDbgdisassembler.Finally,thePathcolumn➎showsthepathtothemodulethatmadethecall.

Inmyopinion,thestacktraceis,byfar,themostpowerfulfeatureinProcessMonitor.Itrevealstheentirecontextthatledtoanevent,whichcanbeimmenselyusefulwhenyouaredebuggingagame.Youcanuseittofindtheexactcodethattriggeredanevent,crawlupthecallchaintoseehowitgotthere,andevendetermineexactlywhatlibrarieswereusedtocompleteeachaction.

ProcessMonitor’ssisterapplication,ProcessExplorer,doesn’thavemanycapabilitiesbeyondthoseinProcessMonitororOllyDbg.Butitdoesexposesomeofthosecapabilitiesmuchmoreeffectively,makingitanidealpickincertainsituations.

FINDINGAHIGHSCOREFILEIfyou’rereadytotestyourProcessMonitorskills,you’vecometotherightplace.OpentheGameHackingExamples/Chapter3_FindingFilesdirectoryandexecuteFindingFiles.exe.You’llseethatitisagameofPong,liketheonein“Patchinganif()Statement”onpage46.UnlikeinChapter2,though,nowthegameisactuallyplayable.Italsodisplaysyourcurrentscoreandyourall-time-highscore.

Nowrestartthegame,firingupProcessMonitorbeforeexecutingitforthesecondtime.Filteringforfilesystemactivityandcreatinganyotherfiltersyouseefit,trytolocatewherethegamestoresthe

Page 96: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

anyotherfiltersyouseefit,trytolocatewherethegamestoresthehigh-scorefile.Forbonuspoints,trytomodifythisfiletomakethegameshowthehighestpossiblescore.

ProcessExplorerProcessExplorerisanadvancedtaskmanager(itevenhasabuttonyoucanpresstomakeityourdefaulttaskmanager),andit’sveryhandywhenyou’restartingtounderstandhowagameoperates.Itprovidescomplexdataaboutrunningprocesses,suchasparentandchildprocesses,CPUusage,memoryusage,loadedmodules,openhandles,andcommandlinearguments,anditcanmanipulatethoseprocesses.Itexceedsatshowingyouhigh-levelinformation,suchasprocesstrees,memoryconsumption,fileaccess,andprocessIDs,allofwhichcanbeveryuseful.

Ofcourse,noneofthisdataisspecificallyusefulinisolation.Butwithakeeneye,youcanmakecorrelationsanddrawsomeusefulconclusionsaboutwhatglobalobjects—includingfiles,mutexes,andsharedmemorysegments—agamehasaccessto.Additionally,thedatashowninProcessExplorercanbeevenmorevaluablewhencross-referencedwithdatagatheredinadebuggingsession.

ThissectionintroducestheProcessExplorerinterface,discussesthepropertiesitshows,anddescribeshowyoucanusethistooltomanipulatehandles(referencestosystemresources).Afterthisintroduction,use“FindingandClosingaMutex”onpage60tohoneyourskills.

ProcessExplorer’sUserInterfaceandControlsWhenyouopenProcessExplorer,youseeawindowthatissplitintothreedistinctsections,asinFigure3-4.

Page 97: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure3-4:ProcessExplorermainwindow

Thosethreesectionsarethetoolbar➊,anupperpane➋,andalowerpane➌.Theupperpaneshowsalistofprocesses,utilizingatreestructuretodisplaytheirparent/childrelationships.Differentprocessesarehighlightedwithdifferentcolors;ifyoudon’tlikethecurrentcolors,clickOptions▸ConfigureColorstodisplayadialogthatallowsyoutoviewandchangethem.

JustasinProcessMonitor,thedisplayforthistableishighlyversatile,andyoucancustomizeitbyright-clickingonthetableheaderandchoosingSelectColumns.Thereareprobablymorethan100customizationoptions,butIfindthatthedefaultswiththeadditionoftheASLREnabledcolumnworkjustfine.

NOTE

AddressSpaceLayoutRandomization(ASLR)isaWindowssecurity

Page 98: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

featurethatallocatesexecutableimagesatunpredictablelocations,andknowingwhetherit’sonisinvaluablewhenyou’retryingtoaltergamestatevaluesinmemory.

Thelowerpanehasthreepossiblestates:Hidden,DLLs,andHandles.TheHiddenoptionhidesthepanefromview,DLLsdisplaysalistofDynamicLinkLibrariesloadedwithinthecurrentprocess,andHandlesshowsalistofhandlesheldbytheprocess(visibleinFigure3-4).YoucanhideorunhidetheentirelowerpanebytogglingView▸ShowLowerPane.Whenitisvisible,youcanchangetheinformationdisplaybyselectingeitherView▸LowerPaneView▸DLLsorView▸LowerPaneView▸Handles.

Youcanalsousehotkeystoquicklychangebetweenlowerpanemodeswithoutaffectingprocessesintheupperpane.ThesehotkeysarelistedinTable3-3.

Table3-3:ProcessExplorerHotkeys

Hotkey Action

CTRL-F Searchthroughlowerpanedatasetsforavalue.

CTRL-L Togglethelowerpanebetweenhiddenandvisible.

CTRL-D TogglethelowerpanetodisplayDLLs.

CTRL-H Togglethelowerpanetodisplayhandles.

spacebar Toggleprocesslistautorefresh.ENTER DisplaythePropertiesdialogfortheselectedprocess.DEL Killtheselectedprocess.

SHIFT-DELKilltheselectedprocessandallchildprocesses.

UsetheGUIorhotkeystopracticechangingmodes.Whenyou’reacquaintedwiththemainwindow,we’lllookatanotherimportantProcessExplorerdialog,calledProperties.

ExaminingProcessPropertiesMuchlikeProcessMonitor,ProcessExplorerhasaverykineticapproachto

Page 99: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

datagathering;theendresultisabroadandverbosespectrumofinformation.Infact,ifyouopenthePropertiesdialog(showninFigure3-5)foraprocess,you’llseeamassivetabbarcontaining10tabs.

TheImagetab,selectedbydefaultandshowninFigure3-5,displaystheexecutablename,version,builddate,andcompletepath.ItalsodisplaysthecurrentworkingdirectoryandtheAddressSpaceLayoutRandomizationstatusoftheexecutable.ASLRstatusisthemostimportantpieceofinformationhere,becauseithasadirecteffectonhowabotcanreadthememoryfromagame.I’lltalkaboutthismoreinChapter6.

Figure3-5:ProcessExplorerPropertiesdialog

ThePerformance,PerformanceGraph,DiskandNetwork,andGPUGraphtabsdisplayamyriadofmetricsabouttheCPU,memory,disk,network,andGPUusageoftheprocess.Ifyoucreateabotthatinjectsintoa

Page 100: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

network,andGPUusageoftheprocess.Ifyoucreateabotthatinjectsintoagame,thisinformationcanbeveryusefultodeterminehowmuchofaperformanceimpactyourbothasonthegame.

TheTCP/IPtabdisplaysalistofactiveTCPconnections,whichyoucanusetofindanygameserverIPaddressesthatagameconnectsto.Ifyou’retryingtotestconnectionspeed,terminateconnections,orresearchagame’snetworkprotocol,thisinformationiscritical.

TheStringstabdisplaysalistofstringsfoundineitherthebinaryorthememoryoftheprocess.UnlikethestringlistinOllyDbg,whichshowsonlystringsreferencedbyassemblycode,thelistincludesanyoccurrencesofthreeormoreconsecutivereadablecharacters,followedbyanullterminator.Whenagamebinaryisupdated,youcanuseadiffingtoolonthislistfromeachgameversiontodeterminewhetherthereareanynewstringsthatyouwanttoinvestigate.

TheThreadstabshowsyoualistofthreadsrunningwithintheprocessandallowsyoutopause,resume,orkilleachthread;theSecuritytabdisplaysthesecurityprivilegesoftheprocess;andtheEnvironmenttabdisplaysanyenvironmentvariablesknowntoorsetbytheprocess.

NOTE

IfyouopenthePropertiesdialogfora.NETprocess,you’llnoticetwoadditionaltabs:.NETAssembliesand.NETPerformance.Thedatainthesetabsisprettyself-explanatory.Pleasekeepinmindthatamajorityofthetechniquesinthisbookwon’tworkwithgameswrittenin.NET.

HandleManipulationOptionsAsyou’veseen,ProcessExplorercanprovideyouwithawealthofinformationaboutaprocess.That’snotallit’sgoodfor,though:itcanalsomanipulatecertainpartsofaprocess.Forexample,youcanviewandmanipulateopenhandlesfromthecomfortofProcessExplorer’slowerpane(seeFigure3-4).ThisalonemakesastrongargumentforaddingProcessExplorertoyourtoolbox.Closingahandleisassimpleasright-clickingonitandselectingCloseHandle.Thiscancomeinhandywhenyouwant,forinstance,toclosemutexes,whichisessentialtocertaintypesofhacks.

Page 101: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NOTE

Youcanright-clickonthelowerpaneheaderandclickSelectColumnstocustomizethedisplay.OnecolumnyoumightfindparticularlyusefulisHandleValue,whichcanhelpwhenyouseeahandlebeingpassedaroundinOllyDbgandwanttoknowwhatitdoes.

ClosingMutexesGamesoftenallowonlyoneclienttorunatatime;thisiscalledsingle-instancelimitation.Youcanimplementsingle-instancelimitationinanumberofways,butusingasystemmutexiscommonbecausemutexesaresessionwideandcanbeaccessedbyasimplename.It’strivialtolimitinstanceswithmutexes,andthankstoProcessExplorer,it’sjustastrivialtoremovethatlimit,allowingyoutorunmultipleinstancesofagameatthesametime.

First,here’showagamemighttacklesingle-instancelimitationwithamutex:

intmain(intargc,char*argv[]){//createthemutexHANDLEmutex=CreateMutex(NULL,FALSE,"onlyoneplease");if(GetLastError()==ERROR_ALREADY_EXISTS){//themutexalreadyexists,soexitErrorBox("Aninstanceisalreadyrunning.");return0;}//themutexdidn'texist;itwasjustcreated,so//letthegamerunRunGame();//thegameisover;closethemutextofreeitup//forfutureinstancesif(mutex)CloseHandle(mutex);return0;}

Thisexamplecodecreatesamutexnamedonlyoneplease.Next,thefunctionchecksGetLastError()toseewhetherthemutexwasalreadycreated,andifso,itclosesthegame.Ifthemutexdoesn’talreadyexist,thegamecreatesthefirstinstance,therebyblockinganyfuturegameclientsfromrunning.Inthisexample,thegamerunsnormally,andonceitfinishes,

Page 102: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CloseHandle()iscalledtoclosethemutexandallowfuturegameinstancestorun.

YoucanuseProcessExplorertocloseinstance-limitingmutexesandrunmanygameinstancessimultaneously.Todoso,choosetheHandlesviewofthelowerpane,lookforallhandleswithatypeofMutant,determinewhichoneislimitinginstancesofthegame,andclosethatmutex.

WARNING

Mutexesarealsousedtosynchronizedataacrossthreadsandprocesses.Closeoneonlyifyou’resurethatitssolepurposeistheoneyou’retryingtosubvert!

Multiclienthacksaregenerallyinhighdemand,sobeingabletoquicklydevelopthemforemerginggamesiscrucialtoyouroverallsuccessasabotdeveloperwithinthatmarket.Sincemutexesareoneofthemostcommonwaystoachievesingle-instancelimitation,ProcessExplorerisanintegraltoolforprototypingthesekindsofhacks.

InspectingFileAccessesUnlikeProcessMonitor,ProcessExplorercan’tshowalistoffilesystemcalls.Ontheotherhand,theHandlesviewofProcessExplorer’slowerpanecanshowallfilehandlesthatagamecurrentlyhasopen,revealingexactlywhatfilesareincontinuoususewithouttheneedtosetupadvancedfilteringcriteriainProcessMonitor.JustlookforhandleswithatypeofFiletoseeallfilesthegameiscurrentlyusing.

Thisfunctionalitycancomeinhandyifyou’retryingtolocatelogfilesorsavefiles.Moreover,youcanlocatenamedpipesthatareusedforinterprocesscommunication(IPC);thesearefilesprefixedwith\Device\NamedPipe\.Seeingoneofthesepipesisoftenahintthatthegameistalkingtoanotherprocess.

FINDINGANDCLOSINGAMUTEXToputyourProcessExplorerskillstouse,gototheGameHackingExamples/Chapter3_CloseMutexdirectoryandexecute

Page 103: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CloseMutex.exe.Thisgameplaysexactlyliketheonein“FindingaHighScoreFile”onpage55,butitpreventsyoufromsimultaneouslyrunningmultipleinstances.Asyoumighthaveguessed,itdoesthisusingasingle-instance-limitationmutex.UsingProcessExplorer’sHandlesviewinthelowerpane,findthemutexresponsibleforthislimitationandcloseit.Ifyousucceed,you’llbeabletoopenasecondinstanceofthegame.

ClosingThoughtsTobeeffectivewhenusingProcessMonitorandProcessExplorer,youneed,aboveallelse,adeepfamiliaritywiththedatathattheseapplicationsdisplayaswellastheinterfacestheyusetodisplayit.Whilethischapter’soverviewisagoodbaseline,theintricaciesoftheseapplicationscanbelearnedonlythroughexperience,soIencourageyoutoplayaroundwiththemonyoursystem.

Youwon’tusethesetoolsonaregularbasis,butatsomepoint,they’llsavetheday:asyoustruggletofigureouthowsomecodeworks,you’llrecallanobscurepieceofinformationthatcaughtyoureyeduringapreviousProcessExplorerorProcessMonitorsession.That’swhyIconsiderthemusefulreconnaissancetools.

Page 104: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PART2GAMEDISSECTION

Page 105: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

4FROMCODETOMEMORY:AGENERAL

PRIMER

Atthelowestlevel,agame’scode,data,input,andoutputarecomplexabstractionsoferraticallychangingbytes.Manyofthesebytesrepresentvariablesormachinecodegeneratedbyacompilerthatwasfedthegame’ssourcecode.Somerepresentimages,models,andsounds.Othersexistonlyforaninstant,postedbythecomputer’shardwareasinputanddestroyedwhenthegamefinishesprocessingthem.Thebytesthatremaininformtheplayerofthegame’sinternalstate.Buthumanscan’tthinkinbytes,sothecomputermusttranslatetheminawaywecanunderstand.

There’sahugedisconnectintheoppositedirectionaswell.Acomputerdoesn’tactuallyunderstandhigh-levelcodeandvisceralgamecontent,sothesemustbetranslatedfromtheabstractintobytes.Somecontent—suchasimages,sounds,andtext—isstoredlosslessly,readytobepresentedtotheplayeratamicrosecond’snotice.Agame’scode,logic,andvariables,ontheotherhand,arestrippedofallhumanreadabilityandcompileddowntomachinedata.

Bymanipulatingagame’sdata,gamehackersobtainhumanlyimprobableadvantageswithinthegame.Todothis,however,theymustunderstandhowadeveloper’scodemanifestsonceithasbeencompiledandexecuted.Essentially,theymustthinklikecomputers.

Togetyouthinkinglikeacomputer,thischapterwillbeginbyteachingyouhownumbers,text,simplestructures,andunionsarerepresentedin

Page 106: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

youhownumbers,text,simplestructures,andunionsarerepresentedinmemoryatthebytelevel.Thenyou’lldivedeepertoexplorehowclassinstancesarestoredinmemoryandhowabstractinstancesknowwhichvirtualfunctionstocallatruntime.Inthelasthalfofthechapter,you’lltakeanx86assemblylanguagecrashcoursethatcoverssyntax,registers,operands,thecallstack,arithmeticoperations,branchingoperations,functioncalls,andcallingconventions.

Thischapterfocusesveryheavilyongeneraltechnicaldetails.Thereisn’talotofjuicyinformationthatimmediatelyrelatestohackinggames,buttheknowledgeyougainherewillbecentralinthecomingchapters,whenwetalkabouttopicslikeprogrammaticallyreadingandwritingmemory,injectingcode,andmanipulatingcontrolflow.

SinceC++isthedefactostandardforbothgameandbotdevelopment,thischapterexplainstherelationshipsbetweenC++codeandthememorythatrepresentsit.Mostnativelanguageshaveverysimilar(sometimesidentical)low-levelstructureandbehavior,however,soyoushouldbeabletoapplywhatyoulearnheretojustaboutanypieceofsoftware.

AlloftheexamplecodeinthischapterisintheGameHackingExamples/Chapter4_CodeToMemorydirectoryofthisbook’ssourcefiles.TheincludedprojectscanbecompiledwithVisualStudio2010butshouldalsoworkwithanyotherC++compiler.Downloadthemathttps://www.nostarch.com/gamehacking/andcompilethemifyouwanttofollowalong.

HowVariablesandOtherDataManifestinMemoryProperlymanipulatingagame’sstatecanbeveryhard,andfindingthedatathatcontrolsitisnotalwaysaseasyasclickingNextScanandhopingCheatEnginewon’tfailyou.Infact,manyhacksmustmanipulatedozensofrelatedvaluesatonce.Findingthesevaluesandtheirrelationshipsoftenrequiresyoutoanalyticallyidentifystructuresandpatterns.Moreover,developinggamehackstypicallymeansre-creatingtheoriginalstructureswithinyourbot’scode.

Todothesethings,youneedanin-depthunderstandingofexactlyhowvariablesanddataarelaidoutinthegame’smemory.Throughexample

Page 107: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

variablesanddataarelaidoutinthegame’smemory.Throughexamplecode,OllyDbgmemorydumps,andsometablestotieeverythingtogether,thissectionwillteachyoueverythingthereistoknowabouthowdifferenttypesofdatamanifestinmemory.

NumericDataMostofthevaluesgamehackersneed(liketheplayer’shealth,mana,location,andlevel)arerepresentedbynumericdatatypes.Becausenumericdatatypesarealsoabuildingblockforallotherdatatypes,understandingthemisextremelyimportant.Luckily,theyhaverelativelystraightforwardrepresentationsinmemory:theyarepredictablyalignedandhaveafixedbitwidth.Table4-1showsthefivemainnumericdatatypesyou’llfindinWindowsgames,alongwiththeirsizesandranges.

Table4-1:NumericDataTypes

Typename(s)

SizeSignedrange Unsignedrange

char,BYTE 8bits

-128to127 0to255

short,WORD,wchar_t

16bits

-32,768to-32,767 0to65535

int,long,DWORD

32bits

-2,147,483,648to2,147,483,647

0to4,294,967,295

longlong 64bits

-9,223,372,036,854,775,808to9,223,372,036,854,775,807

0to18,446,744,073,709,551,615

float 32bits

+/-1.17549*10-38to+/-3.40282*1038

N/A

Thesizesofnumericdatatypescandifferbetweenarchitecturesandevencompilers.Sincethisbookfocusesonhackingx86gamesonWindows,I’musingtypenamesandsizesmadestandardbyMicrosoft.Withtheexceptionoffloat,thedatatypesinTable4-1arestoredwithlittle-endianordering,

Page 108: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

meaningtheleastsignificantbytesofanintegerarestoredinthelowestaddressesoccupiedbythatinteger.Forexample,Figure4-1showsthatDWORD0x0A0B0C0Disrepresentedbythebytes0x0D0x0C0x0B0x0A.

Figure4-1:Little-endianorderingdiagram

Thefloatdatatypecanholdmixednumbers,soitsrepresentationinmemoryisn’tassimpleasthatofotherdatatypes.Forexample,ifyousee0x0D0x0C0x0B0x0Ainmemoryandthatvalueisafloat,youcan’tsimplyconvertitto0x0A0B0C0D.Instead,floatvalueshavethreecomponents:thesign(bit0),exponent(bits1–8),andmantissa(bits9–31).

Thesigndetermineswhetherthenumberisnegativeorpositive,theexponentdetermineshowmanyplacestomovethedecimalpoint(startingbeforethemantissa),andthemantissaholdsanapproximationofthevalue.Youcanretrievethestoredvaluebyevaluatingtheexpressionmantissa×10n

(wherenistheexponent)andmultiplyingtheresultby–1ifthesignisset.Nowlet’slookatsomenumericdatatypesinmemory.Listing4-1

initializesninevariables.

unsignedcharubyteValue=0xFF;charbyteValue=0xFE;unsignedshortuwordValue=0x4142;shortwordValue=0x4344;unsignedintudwordValue=0xDEADBEEF;intdwordValue=0xDEADBEEF;unsignedlonglongulongLongValue=0xEFCDAB8967452301;longlonglongLongValue=0xEFCDAB8967452301;floatfloatValue=1337.7331;

Page 109: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Listing4-1:CreatingvariablesofnumericdatatypesinC++

Startingfromthetop,thisexampleincludesvariablesoftypeschar,short,int,longlong,andfloat.Fouroftheseareunsigned,andfivearesigned.(InC++,afloatcan’tbeunsigned.)Takingintoaccountwhatyou’velearnedsofar,carefullystudytherelationshipbetweenthecodeinListing4-1andthememorydumpinFigure4-2.Assumethatthevariablesaredeclaredinglobalscope.

Figure4-2:OllyDbgmemorydumpofournumericdata

Youmightnoticethatsomevaluesseemarbitrarilyspacedout.Sinceit’smuchfasterforprocessorstoaccessvaluesresidingataddressesthataremultiplesoftheaddresssize(whichis32bitsinx86),compilerspadvalueswithzerosinordertoalignthemonsuchaddresses—hence,paddingisalsocalledalignment.Single-bytevaluesarenotpadded,sinceoperationsthataccessthemperformthesameregardlessofalignment.

Keepingthisinmind,takealookatTable4-2,whichprovidesasortofmemory-to-codecrosswalkbetweenthememorydumpinFigure4-2andthevariablesdeclaredinListing4-1.

Table4-2:Memory-to-CodeCrosswalkforListing4-1andFigure4-2

Address Size Data Object

0x00BB3018 1byte

0xFF ubyteValue

0x00BB3019 1byte

0xFE byteValue

0x00BB301A 2bytes

0x000x00 PaddingbeforeuwordValue

0x00BB301C 2bytes

0x420x41 uwordValue

0x00BB301E 2bytes

0x000x00 PaddingbeforewordValue

Page 110: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

bytes wordValue

0x00BB3020 2bytes

0x440x43 wordValue

0x00BB3022 2bytes

0x000x00 PaddingbeforeudwordValue

0x00BB3024 4bytes

0xEF0xBE0xAD0xDE udwordValue

0x00BB3028 4bytes

0xEF0xBE0xAD0xDE dwordValue

0x00BB302C 4bytes

0x760x370xA70x44 floatValue

0x00BB3030 8bytes

0x010x230x450x670x890xAB0xCD0xEF

ulongLongValue

0x00BB3038 8bytes

0x010x230x450x670x890xAB0xCD0xEF

LongLongValue

TheAddresscolumnlistslocationsinmemory,andtheDatacolumntellsyouexactlywhat’sstoredthere.TheObjectcolumntellsyouwhichvariablefromListing4-1eachpieceofdatarelatesto.NoticethatfloatValueisplacedbeforeulongLongValueinmemory,eventhoughit’sthelastvariabledeclaredinListing4-1.Becausethesevariablesaredeclaredinglobalscope,thecompilercanplacethemwhereveritwants.Thisparticularmoveislikelyaresultofeitheralignmentoroptimization.

StringDataMostdevelopersusethetermstringasifit’ssynonymouswithtext,buttextisonlythemostcommonuseforstrings.Atalowlevel,stringsarejustarraysofarbitrarynumericobjectsthatappearlinearandunalignedinmemory.Listing4-2showsfourtextstringdeclarations.

//charwillbe1bytepercharacterchar*thinStringP="my_thin_terminated_value_pointer";charthinStringA[40]="my_thin_terminated_value_array";

//wchar_twillbe2bytespercharacter

Page 111: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

//wchar_twillbe2bytespercharacterwchar_t*wideStringP=L"my_wide_terminated_value_pointer";wchar_twideStringA[40]=L"my_wide_terminated_value_array";

Listing4-2:DeclaringseveralstringsinC++

Inthecontextoftext,stringsholdcharacterobjects(charfor8-bitencodingorwchar_tfor16-bitencoding),andtheendofeachstringisspecifiedbyanullterminator,acharacterequalto0x0.Let’slookatthememorywherethesevariablesarestored,asshowninthetwomemorydumpsinFigure4-3.

Figure4-3:InthisOllyDbgmemorydumpofstringdata,thehuman-readabletextintheASCIIcolumnisthetextwestoredinListing4-2.

Ifyou’renotusedtoreadingmemory,theOllyDbgdumpmightbeabitdifficulttofollowatthispoint.Table4-3showsadeeperlookatthecorrelationbetweenthecodeinListing4-2andthememoryinFigure4-3.

Table4-3:Memory-to-CodeCrosswalkforListing4-2andFigure4-3

Address Size Data Object

Pane1

0x012420F8 32bytes

0x6D0x790x5F{...}0x740x650x72

thinStringPcharacters

0x01242118 4bytes

0x000x000x000x00 thinStringPterminatorandpadding

0x0124211C 4bytes

0x000x000x000x00 Unrelateddata

Page 112: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

0x01242120 64bytes

0x6D0x000x79{...}0x000x720x00

wideStringPcharacters

0x01242160 4bytes

0x000x000x000x00 wideStringPterminatorandpadding

{...} Unrelateddata

Pane2

0x01243040 4bytes

0xF80x200x240x01 PointertothinStringPat0x012420F8

0x01243044 30bytes

0x6D0x790x5F{...}0x720x610x79

thinStringAcharacters

0x01243062 10bytes

0x00repeated10times thinStringAterminatorandarrayfill

0x0124306C 4bytes

0x200x210x240x01 PointertowideStringPat0x01242120

0x01243070 60bytes

0x6D0x000x79{...}0x000x790x00

wideStringAcharacters

0x012430AC 20bytes

0x00repeated10times wideStringAterminatorandarrayfill

InFigure4-3,pane1showsthatthevaluesstoredwherethinStringP(address0x01243040)andwideStringP(address0x0124306C)belonginmemoryareonly4byteslongandcontainnostringdata.That’sbecausethesevariablesareactuallypointerstothefirstcharactersoftheirrespectivearrays.Forexample,thinStringPcontains0x012420F8,andinpane2inFigure4-3,youcansee"my_thin_terminated_value_pointer"locatedataddress0x012420F8.

Lookatthedatabetweenthesepointersinpane1,andyoucanseethetextbeingstoredbythinStringAandwideStringA.Furthermore,noticethatthinStringAandwideStringAarepaddedbeyondtheirnullterminators;thisisbecausethesevariablesweredeclaredasarrayswithlength40,sotheyarefilledupto40characters.

Page 113: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DataStructuresUnlikethedatatypeswehavepreviouslydiscussed,structuresarecontainersthatholdmultiplepiecesofsimple,relateddata.Gamehackerswhoknowhowtoidentifystructuresinmemorycanmimicthosestructuresintheirowncode.Thiscangreatlyreducethenumberofaddressestheymustfind,astheyneedtofindonlytheaddresstothestartofthestructure,nottheaddressofeveryindividualitem.

NOTE

Thissectiontalksaboutstructuresassimplecontainersthatlackmemberfunctionsandcontainonlysimpledata.Objectsthatexceedtheselimitationswillbediscussedin“ClassesandVFTables”onpage74.

StructureElementOrderandAlignmentSincestructuressimplyrepresentanassortmentofobjects,theydon’tvisiblymanifestinmemorydumps.Instead,amemorydumpofastructureshowstheobjectsthatarecontainedwithinthatstructure.ThedumpwouldlookmuchliketheothersI’veshowninthischapter,butwithimportantdifferencesinbothorderandalignment.

Toseethesedifferences,startbytakingalookatListing4-3.

structMyStruct{unsignedcharubyteValue;charbyteValue;unsignedshortuwordValue;shortwordValue;unsignedintudwordValue;intdwordValue;unsignedlonglongulongLongValue;longlonglongLongValue;floatfloatValue;};MyStruct&m=0;printf("Offsets:%d,%d,%d,%d,%d,%d,%d,%d,%d\n",&m->ubyteValue,&m->byteValue,&m->uwordValue,&m->wordValue,&m->udwordValue,&m->dwordValue,&m->ulongLongValue,&m->longLongValue,&m->floatValue);

Page 114: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Listing4-3:AC++structureandsomecodethatusesit

ThiscodedeclaresastructurenamedMyStructandcreatesavariablenamedmthatsupposedlypointstoaninstanceofthestructureataddress0.There’snotactuallyaninstanceofthestructureataddress0,butthistrickletsmeusetheampersandoperator(&)intheprintf()calltogettheaddressofeachmemberofthestructure.Sincethestructureislocatedataddress0,theaddressprintedforeachmemberisequivalenttoitsoffsetfromthestartofthestructure.

Theultimatepurposeofthisexampleistoseeexactlyhoweachmemberislaidoutinmemory,relativetothestartofthestructure.Ifyouweretorunthecode,you’dseethefollowingoutput:

Offsets:0,1,2,4,8,12,16,24,32

Asyoucansee,thevariablesinMyStructareorderedexactlyastheyweredefinedincode.Thissequentialmemberlayoutisamandatorypropertyofstructures.ComparethistotheexamplefromListing4-1,whenwedeclaredanidenticalsetofvariables;inthememorydumpfromFigure4-2,thecompilerclearlyplacedsomevaluesoutoforderinmemory.

Furthermore,youmayhavenoticedthatthemembersarenotalignedlikethegloballyscopedvariablesinListing4-1;iftheywere,forexample,therewouldbe2paddingbytesbeforeuwordValue.Thisisbecausestructuremembersarealignedonaddressesdivisiblebyeitherthestructmemberalignment(acompileroptionthataccepts1,2,4,8,or16bytes;inthisexample,it’ssetto4)orthesizeofthemember—whicheverissmaller.IarrangedthemembersofMyStructsothatthecompilerdidn’tneedtopadthevalues.

If,however,weputacharimmediatelyafterulongLongValue,theprintf()callwouldgivethefollowingoutput:

Offsets:0,1,2,4,8,12,16,28,36

Now,takealookattheoriginalandthemodifiedoutputstogether:

Original:Offsets:0,1,2,4,8,12,16,24,32Modified:Offsets:0,1,2,4,8,12,16,28,36

Inthemodifiedversion,thelasttwovalues,whicharetheoffsetsfor

Page 115: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

longLongValueandfloatValuefromthestartofthestructure,havechanged.Thankstothestructmemberalignment,thevariablelongLongValuemovesby4bytes(1forthecharvalueand3followingit)toensureitgetsplacedonanaddressdivisibleby4.

HowStructuresWorkUnderstandingstructures—howtheyarealignedandhowtomimicthem—canbeveryuseful.Forinstance,ifyoureplicateagame’sstructuresinyourowncode,youcanreadorwritethoseentirestructuresfrommemoryinasingleoperation.Consideragamethatdeclarestheplayer’scurrentandmaxhealthlikeso:

struct{intcurrent;intmax;}vital;vitalhealth;

Ifaninexperiencedgamehackerwantstoreadthisinformationfrommemory,theymightwritesomethinglikethistofetchthehealthvalues:

intcurrentHealth=readIntegerFromMemory(currentHealthAddress);intmaxHealth=readIntegerFromMemory(maxHealthAddress);

Thisgamehackerdoesn’trealizethatseeingthesevaluesrightnexttoeachotherinmemorycouldbemorethanaluckyhappenstance,sothey’veusedtwoseparatevariables.Butifyoucamealongwithyourknowledgeofstructures,youmightconcludethat,sincethesevaluesarecloselyrelatedandareadjacentinmemory,ourhackercouldhaveusedastructureinstead:

struct{intcurrent;intmax;}_vital;➊_vitalhealth=readTypeFromMemory<_vital>(healthStructureAddress);

Sincethiscodeassumesastructureisbeingusedandcorrectlymimicsit,itcanfetchbothhealthandmaxhealthinjustoneline➊.We’lldivedeeperintohowtowriteyourowncodetoreadmemoryfrominChapter6.

Page 116: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

UnionsUnlikestructures,whichencapsulatemultiplepiecesofrelateddata,unionscontainasinglepieceofdatathatisexposedthroughmultiplevariables.Unionsfollowthreerules:

•Thesizeofaunioninmemoryisequaltothatofitslargestmember.

•Membersofaunionallreferencethesamememory.

•Aunioninheritsthealignmentofitslargestmember.

Theprintf()callinthefollowingcodehelpsillustratethefirsttworules:

union{BYTEbyteValue;struct{WORDfirst;WORDsecond;}words;DWORDvalue;}dwValue;dwValue.value=0xDEADBEEF;printf("Size%d\nAddresses0x%x,0x%x\nValues0x%x,0x%x\n",sizeof(dwValue),&dwValue.value,&dwValue.words,dwValue.words.first,dwValue.words.second);

Thiscalltoprintf()outputsthefollowing:

Size4Addresses0x2efda8,0x2efda8Values0xbeef,0xdead

ThefirstruleisillustratedbytheSizevalue,whichisprintedfirst.EventhoughdwValuehasthreemembersthatoccupyatotalof9bytes,ithasasizeofonly4bytes.Thesizeresultvalidatesthesecondruleaswell,becausedwValue.valueanddwValue.wordsbothpointtoaddress0x2efda8,asshownbythevaluesprintedafterthewordAddresses.ThesecondruleisalsovalidatedbythefactthatdwValue.words.firstanddwValue.words.secondcontain0xbeefand0xdead,printedafterValues,whichmakessenseconsideringthatdwValue.valueis0xdeadbeef.Thethirdruleisn’tdemonstratedinthisexamplebecausewedon’thaveenoughmemorycontext,butifyouweretoputthisunioninsideastructureandsurrounditwithwhatevertypesyoulike,itwouldinfactalwaysalignlikeaDWORD.

Page 117: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ClassesandVFTablesMuchlikestructures,classesarecontainersthatholdandisolatemultiplepiecesofdata,butclassescanalsocontainfunctiondefinitions.

ASimpleClassClasseswithnormalfunctions,suchasbarinListing4-4,conformtothesamememorylayoutsasstructures.

classbar{public:bar():bar1(0x898989),bar2(0x10203040){}voidmyfunction(){bar1++;}intbar1,bar2;};

bar_bar=bar();printf("Size%d;Address0x%x:_bar\n",sizeof(_bar),&_bar);

Listing4-4:AC++class

Theprintf()callinListing4-4wouldoutputthefollowing:

Size8;Address0x2efd80:_bar

Eventhoughbarhastwomemberfunctions,thisoutputshowsthatitspansonlythe8bytesneededtoholdbar1andbar2.Thisisbecausethebarclassdoesn’tincludeabstractionsofthosememberfunctions,sotheprogramcancallthemdirectly.

NOTE

Accesslevelssuchaspublic,private,andprotecteddonotmanifestinmemory.Regardlessofthesemodifiers,membersofclassesarestillorderedastheyaredefined.

AClasswithVirtualFunctionsInclassesthatdoincludeabstractfunctions(oftencalledvirtualfunctions),theprogrammustknowwhichfunctiontocall.ConsidertheclassdefinitionsinListing4-5:

Page 118: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

classfoo{public:foo():myValue1(0xDEADBEEF),myValue2(0xBABABABA){}intmyValue1;staticintmyStaticValue;virtualvoidbar(){printf("callfoo::bar()\n");}virtualvoidbaz(){printf("callfoo::baz()\n");}virtualvoidbarbaz(){}intmyValue2;};

intfoo::myStaticValue=0x12121212;

classfooa:publicfoo{public:fooa():foo(){}virtualvoidbar(){printf("callfooa::bar()\n");}virtualvoidbaz(){printf("callfooa::baz()\n");}};

classfoob:publicfoo{public:foob():foo(){}virtualvoidbar(){printf("callfoob::bar()\n");}virtualvoidbaz(){printf("callfoob::baz()\n");}};

Listing4-5:Thefoo,fooa,andfoobclasses

Theclassfoohasthreevirtualfunctions:bar,baz,andbarbaz.Classesfooaandfoobinheritfromclassfooandoverloadbothbarandbaz.Sincefooaandfoobhaveapublicbaseclassoffoo,afoopointercanpointtothem,buttheprogrammuststillcallthecorrectversionsofbarandbaz.Youcanseethisbyexecutingthefollowingcode:

foo*_testfoo=(foo*)newfooa();_testfoo->bar();//callsfooa::bar()

Andhereistheoutput:

callfooa::bar()

Theoutputshowsthat_testfoo->bar()invokedfooa::bar()eventhough_testfooisafoopointer.Theprogramknewwhichversionofthefunctiontocall,becausethecompilerincludedaVF(virtualfunction)tableinthememoryof_testfoo.VFtablesarearraysoffunctionaddressesthatabstractclassinstancesusetotellaprogramwheretheiroverloadedfunctionsare

Page 119: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

located.

ClassInstancesandVirtualFunctionTablesTounderstandtherelationshipbetweenclassinstancesandVFtables,let’sinspectamemorydumpofthethreeobjectsdeclaredinthislisting:

foo_foo=foo();fooa_fooa=fooa();foob_foob=foob();

TheseobjectsareofthetypesdefinedinListing4-5.YoucanseetheminmemoryinFigure4-4.

Figure4-4:OllyDbgmemorydumpofclassdata

Pane1showsthateachclassinstancestoresitsmembersjustlikeastructure,butitprecedesthemwithaDWORDvaluethatpointstotheclassinstance’sVFtable.Pane2showstheVFtablesforeachofourthreeclassinstances.Thememory-to-codecrosswalkinTable4-4showshowthesepanesandthecodetietogether.

Table4-4:Memory-to-CodeCrosswalkforListing4-5andFigure4-4

Address Size Data Object

Pane1

0x0018FF20 4bytes

0x004022B0 Startof_fooandpointertofooVFtable

0x0018FF24 8bytes

0xDEADBEEF0xBABABABA

_foo.myValue1and_foo.myValue2

Page 120: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

0x0018FF2C 4bytes

0x004022C0 Startof_fooaandpointertofooaVFtable

0x0018FF30 8bytes

0xDEADBEEF0xBABABABA

_fooa.myValue1and_fooa.myValue2

0x0018FF38 4bytes

0x004022D0 Startof_foobandpointertofoobVFtable

0x0018FF3C 8bytes

0xDEADBEEF0xBABABABA

_foob.myValue1and_foob.myValue2

{...} Unrelateddata

Pane2

0x004022B0 4bytes

0x00401060 StartoffooVFtable;addressoffoo::bar

0x004022B4 4bytes

0x00401080 Addressoffoo::baz

0x004022B8 4bytes

0x004010A0 Addressoffoo::barbaz

0x004022BC 4bytes

0x0040243C Unrelateddata

0x004022C0 4bytes

0x004010D0 StartoffooaVFtable;addressoffooa::bar

0x004022C4 4bytes

0x004010F0 Addressoffooa::baz

0x004022C8 4bytes

0x004010A0 Addressoffoo::barbaz

0x004022CC 4bytes

0x004023F0 Unrelateddata

0x004022D0 4bytes

0x00401130 StartoffoobVFtable;addressoffoob::bar

0x004022D4 4bytes

0x00401150 Addressoffoob::baz

Page 121: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

bytes

0x004022D8 4bytes

0x004010A0Addressoffoo::barbaz

ThiscrosswalkshowshowtheVFtablesforthecodeinListing4-5arelaidoutinmemory.EachVFtableisgeneratedbythecompilerwhenthebinaryismade,andthetablesremainconstant.Tosavespace,instancesofthesameclassallpointtothesameVFtable,whichiswhytheVFtablesaren’tplacedinlinewiththeclass.

SincewehavethreeVFtables,youmightwonderhowaclassinstanceknowswhichVFtabletouse.Thecompilerplacescodesimilartothefollowingbitofassemblyineachvirtualclassconstructor:

MOVDWORDPTRDS:[EAX],VFADDR

ThisexampletakesthestaticaddressofaVFtable(VFADDR)andplacesitinmemoryasthefirstmemberoftheclass.

Nowlookataddresses0x004022B0,0x004022C0,and0x004022D0inTable4-4.Theseaddressescontainthebeginningofthefoo,fooa,andfoobVFtables.Noticethatfoo::barbazexistsinallthreeVFtables;thisisbecausethefunctionisnotoverloadedbyeithersubclass,meaninginstancesofeachsubclasswillcalltheoriginalimplementationdirectly.

Notice,too,thatfoo::myStaticValuedoesnotappearinthiscrosswalk.Sincethevalueisstatic,itdoesn’tactuallyneedtoexistasapartofthefooclass;it’splacedinsidethisclassonlyforbettercodeorganization.Inreality,itgetstreatedlikeaglobalvariableandisplacedelsewhere.

VFTABLESANDCHEATENGINERememberCheatEngine’sFirstelementofpointerstructmustpointtomoduleoptionforpointerscansfromFigure1-4onpage14?Nowthatyou’vereadabitaboutVFtables,thatknowledgeshouldhelpyouunderstandhowthisoptionworks:itmakesCheatEngineignoreallheapchunkswherethefirstmemberisnotapointertoavalidVFtable.Itspeedsupscans,butitworksonlyifeverystepinapointerpathispartofanabstractclassinstance.

Page 122: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thememorytourendshere,butifyouhavetroubleidentifyingachunkofdatainthefuture,comebacktothissectionforreference.Next,we’lllookathowacomputercanunderstandagame’shigh-levelsourcecodeinthefirstplace.

x86AssemblyCrashCourseWhenaprogram’ssourcecodeiscompiledintoabinary,itisstrippedofallunnecessaryartifactsandtranslatedintomachinecode.Thismachinecode,madeupofonlybytes(commandbytesarecalledopcodes,buttherearealsobytesrepresentingoperands),getsfeddirectlytotheprocessorandtellsitexactlyhowtobehave.Those1sand0sfliptransistorstocontrolcomputation,andtheycanbeextremelydifficulttounderstand.Tomakecomputersalittleeasiertotalkto,engineersworkingwithsuchcodeuseassemblylanguage,ashorthandthatrepresentsrawmachineopcodeswithabbreviatednames(calledmnemonics)andasimplisticsyntax.

Assemblylanguageisimportantforgamehackerstoknowbecausemanypowerfulhackscanbeachievedonlythroughdirectmanipulationofagame’sassemblycode,viamethodssuchasNOPingorhooking.Inthissection,you’lllearnthebasicsofx86assemblylanguage,aspecificflavorofassemblymadeforspeakingto32-bitprocessors.Assemblylanguageisveryextensive,soforthesakeofbrevitythissectiontalksonlyaboutthesmallsubsetofassemblyconceptsthataremostusefultogamehackers.1

NOTE

Throughoutthissection,manysmallsnippetsofassemblycodeincludecommentssetoffbyasemicolon(;)todescribeeachinstructioningreaterdetail.

CommandSyntaxAssemblylanguageisusedtodescribemachinecode,soitssyntaxisprettysimplistic.Whilethissyntaxmakesitveryeasyforsomeonetounderstandindividualcommands(alsocalledoperations),italsomakesunderstanding

Page 123: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

complexblocksofcodeveryhard.Evenalgorithmsthatareeasilyreadableinhigh-levelcodeseemobfuscatedwhenwritteninassembly.Forexample,thefollowingsnippetofpseudocode:

if(EBX>EAX)ECX=EDXelseECX=0

wouldlooklikeListing4-6inx86assembly.

CMPEBX,EAXJGlabel1MOVECX,0JMPlabel2label1:MOVECX,EDXlabel2:

Listing4-6:Somex86assemblycommands

Therefore,ittakesextensivepracticetounderstandeventhemosttrivialfunctionsinassembly.Understandingindividualcommands,however,isverysimple,andbytheendofthissection,you’llknowhowtoparsethecommandsIjustshowedyou.

InstructionsThefirstpartofanassemblycommandiscalledaninstruction.Ifyouequateanassemblycommandtoaterminalcommand,theinstructionistheprogramtorun.Atthemachinecodelevel,instructionsaretypicallythefirstbyteofacommand;2therearealsosome2-byteinstructions,wherethefirstbyteis0x0F.Regardless,aninstructiontellstheprocessorexactlywhattodo.InListing4-6,CMP,JG,MOV,andJMPareallinstructions.

OperandSyntaxWhilesomeinstructionsarecompletecommands,thevastmajorityareincompleteunlessfollowedbyoperands,orparameters.EverycommandinListing4-6hasatleastoneoperand,likeEBX,EAX,andlabel1.

Assemblyoperandscomeinthreeforms:

Page 124: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ImmediatevalueAnintegervaluethatisdeclaredinline(hexadecimalvalueshaveatrailingh).

RegisterAnamethatreferstoaprocessorregister.

MemoryoffsetAnexpression,placedinbrackets,thatrepresentsthememorylocationofavalue.Theexpressioncanbeanimmediatevalueoraregister.Alternatively,itcanbeeitherthesumordifferenceofaregisterandimmediatevalue(somethinglike[REG+Ah]or[REG-10h]).

Eachinstructioninx86assemblycanhavebetweenzeroandthreeoperands,andcommasareusedtoseparatemultipleoperands.Inmostcases,instructionsthatrequiretwooperandshaveasourceoperandandadestinationoperand.Theorderingoftheseoperandsisdependentontheassemblysyntax.Forexample,Listing4-7showsagroupofpseudocommandswrittenintheIntelsyntax,whichisusedbyWindows(and,thus,byWindowsgamehackers):

MOVR1,1;setR1(register)to1(immediate)➊MOVR1,[BADF00Dh];setR1tovalueat[BADFOODh](memoryoffset)MOVR1,[R2+10h];setR1tovalueat[R2+10h](memoryoffset)MOVR1,[R2-20h];setR1tovalueat[R2+20h](memoryoffset)

Listing4-7:DemonstratingIntelsyntax

IntheIntelsyntax,thedestinationoperandcomesfirst,followedbythesource,soat➊,R1isthedestinationand[BADFOODh]isthesource.Ontheotherhand,compilerslikeGCC(whichcanbeusedtowritebotsonWindows)useasyntaxknownasAT&T,orUNIX,syntax.Thissyntaxdoesthingsalittledifferently,asyoucanseeinthefollowingexample:

MOV$1,%R1;setR1(register)to1(immediate)MOV0xBADF00D,%R1;setR1tovalueat0xBADFOOD(memoryoffset)MOV0x10(%R2),%R1;setR1tovalueat0x10(%R2)(memoryoffset)MOV-0x20(%R2),%R1;setR1tovalueat-0x20(%R2)(memoryoffset)

ThiscodeistheAT&TversionofListing4-7.AT&Tsyntaxnotonlyreversestheoperandorderbutalsorequiresoperandprefixingandhasadifferentformatformemoryoffsetoperands.

AssemblyCommandsOnceyouunderstandassemblyinstructionsandhowtoformattheir

Page 125: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Onceyouunderstandassemblyinstructionsandhowtoformattheiroperands,youcanstartwritingcommands.Thefollowingcodeshowsanassemblyfunction,consistingofsomeverybasiccommands,thatessentiallydoesnothing.

PUSHEBP;putEBP(register)onthestackMOVEBP,ESP;setEBPtovalueofESP(register,topofstack)PUSH-1;put-1(immediate)onthestackADDESP,4;negatethe'PUSH-1'toputESPbackwhereitwas(aPUSH;subtracts4fromESP,sinceitgrowsthestack)MOVESP,EBP;setESPtothevalueofEBP(theywillbethesameanyway,;sincewehavekeptESPinthesameplace)POPEBP;setEBPtothevalueontopofthestack(itwillbewhat;EBPstartedwith,putonthestackbyPUSHEBP)XOREAX,EAX;exclusive-orEAX(register)withitself(sameeffectas;'MOVEAX,0'butmuchfaster)RETN;returnfromthefunctionwithavalueof0(EAXtypically;holdsthereturnvalue)

Thefirsttwolines,aPUSHcommandandaMOVcommand,setupastackframe.Thenextlinepushes–1tothestack,whichisundonewhenthestackissetbacktoitsoriginalpositionbytheADDESP,4command.Followingthat,thestackframeisremoved,thereturnvalue(storedinEAX)issetto0withanXORinstruction,andthefunctionreturns.

You’lllearnmoreaboutstackframesandfunctionsin“TheCallStack”onpage86and“FunctionCalls”onpage94.Fornow,turnyourattentiontotheconstantsinthecode—namelyEBP,ESP,andEAX,whichareusedfrequentlyinthecodeasoperands.Thesevalues,amongothers,arecalledprocessorregisters,andunderstandingthemisessentialtounderstandingthestack,functioncalls,andotherlow-levelaspectsofassemblycode.

ProcessorRegistersUnlikehigh-levelprogramminglanguages,assemblylanguagedoesnothaveuser-definedvariablenames.Instead,itaccessesdatabyreferencingitsmemoryaddress.Duringintensivecomputation,however,itcanbeextremelycostlyfortheprocessortoconstantlydealwiththeoverheadofreadingandwritingdatatoRAM.Tomitigatethishighcost,x86processorsprovideasmallsetoftemporaryvariables,calledprocessorregisters,which

Page 126: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

provideasmallsetoftemporaryvariables,calledprocessorregisters,whicharesmallstoragespaceswithintheprocessoritself.SinceaccessingtheseregistersrequiresfarlessoverheadthanaccessingRAM,assemblyusesthemtodescribeitsinternalstate,passvolatiledataaround,andstorecontext-sensitivevariables.

GeneralRegistersWhenassemblycodeneedstostoreoroperateonarbitrarydata,itusesasubsetofprocessregisterscalledgeneralregisters.Theseregistersareusedexclusivelytostoreprocess-specificdata,suchasafunction’slocalvariables.Eachgeneralregisteris32bitsandthuscanbethoughtofasaDWORDvariable.Generalregistersarealsooptimizedforspecificpurposes:

EAX,theaccumulatorThisregisterisoptimizedformathematicalcomputations.Someoperations,suchasmultiplicationanddivision,canonlyoccurinEAX.

EBX,thebaseregisterThisregisterisusedarbitrarilyforextrastorage.Sinceits16-bitpredecessor,BX,wastheonlyregisterthatoperationscouldusetoreferencememoryaddresses,EBXwasusedasareferencetoRAM.Inx86assembly,however,allregisterscanbeaddressreferences,leavingEBXwithoutatruepurpose.

ECX,thecounterThisregisterisoptimizedtoactasthecountervariable(oftencallediinhigh-levelcode)inaloop.

EDX,thedataregisterThisregisterisoptimizedtoactasahelpertoEAX.In64-bitcomputations,forinstance,EAXactsasbits0–31andEDXactsasbits32–63.

Theseregistersalsohaveasetof8-and16-bitsubregistersthatyoucanusetoaccesspartialdata.Thinkofeverygeneralregisterasaunion,wherearegisternamedescribesthe32-bitmemberandthesubregistersarealternatemembersthatallowaccesstosmallerpiecesoftheregister.ThefollowingcodeshowswhatthisunionmightlooklikeforEAX:

union{DWORDEAX;WORDAX;struct{BYTEL;

Page 127: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

BYTEH;}A;}EAX;

Inthisexample,AXallowsaccesstothelowerWORDofEAX,whileALallowsaccesstothelowerBYTEofAXandAHtoitshigherBYTE.Everygeneralregisterhasthisstructure,andIoutlinetheotherregisters’subregistersinFigure4-5.

Figure4-5:x86registersandsubregisters

EAX,EBC,ECX,andEDXhavehigherwords,too,butthecompilerwillalmostneveraccessthemonitsown,asitcanjustusethelowerwordwhenitneedsword-onlystorage.

IndexRegistersx86assemblyalsohasfourindexregisters,whichareusedtoaccessdatastreams,referencethecallstack,andkeeptrackoflocalinformation.Likethegeneralregisters,indexregistersare32bits,butindexregistershavemorestrictlydefinedpurposes:

EDI,thedestinationindexThisregisterisusedtoindexmemorytargetedbywriteoperations.Iftherearenowriteoperationsinapieceofcode,thecompilercanuseEDIforarbitrarystorageifneeded.

ESI,thesourceindexThisregisterisusedtoindexmemorytargetedby

Page 128: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

readoperations.Itcanalsobeusedarbitrarily.

ESP,thestackpointerThisregisterisusedtoreferencethetopofthecallstack.Allstackoperationsdirectlyaccessthisregister.YoumustuseESPonlywhenworkingwiththestack,anditmustalwayspointtothetopofthestack.

EBP,thestackbasepointerThisregistermarksthebottomofthestackframe.Functionsuseitasareferencetotheirparametersandlocalvariables.Somecodemaybecompiledwithanoptiontoomitthisbehavior,inwhichcaseEBPcanbeusedarbitrarily.

Likethegeneralregisters,eachindexregisterhasa16-bitcounterpart:DI,SI,SP,andBP,respectively.However,theindexregistershaveno8-bitsubregisters.

WHYDOSOMEX86REGISTERSHAVESUBREGISTERS?

Thereisahistoricalreasonwhybothgeneralandindexregistershave16-bitcounterparts.Thex86architecturewasbasedona16-bitarchitecture,fromwhichitextendedtheregistersAX,BX,CX,DX,DI,SI,SP,andBP.Appropriately,theextensionsretainthesamenamesbutareprefixedwithanE,for“extended.”The16-bitversionsremainforbackwardcompatibility.Thisalsoexplainswhyindexregistershaveno8-bitabstractions:theyareintendedtobeusedasmemory-addressoffsets,andthereisnopracticalneedtoknowpartialbytesofsuchvalues.

TheExecutionIndexRegisterTheExecutionIndexregister,referredtoasEIP,hasaveryconcretepurpose:itpointstotheaddressofthecodecurrentlybeingexecutedbytheprocessor.Becauseitcontrolstheflowofexecution,itisdirectlyincrementedbytheprocessorandisoff-limitstoassemblycode.TomodifyEIP,assemblycodemustindirectlyaccessitusingoperationssuchasCALL,

Page 129: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

JMP,andRETN.

TheEFLAGSRegisterUnlikehigh-levelcode,assemblylanguagedoesn’thavebinarycomparisonoperatorslike==,>,and<.Instead,itusestheCMPcommandtocomparetwovalues,storingtheresultinginformationintheEFLAGSregister.Then,thecodechangesitscontrolflowusingspecialoperationsthatdependonthevaluestoredinELFAGS.

Whilecomparisoncommandsaretheonlyuser-modeoperationsthatcanaccessEFLAGS,theyuseonlythisregister’sstatusbits:0,2,4,6,7,and11.Bits8–10actascontrolflags,bits12–14and16–21actassystemflags,andtheremainingbitsarereservedfortheprocessor.Table4-5showsthetype,name,anddescriptionofeachEFLAGSbit.

Table4-5:EFLAGSbits

Bit(s)Type Name Description

0 Status Carry Setifacarryorborrowwasgeneratedfromthemostsignificantbitduringthepreviousinstruction.

2 Status Parity Setiftheleastsignificantbyteresultingfromthepreviousinstructionhasanevennumberofbitsset.

4 Status Adjust Sameasthecarryflag,butconsidersthe4leastsignificantbits.

6 Status Zero Setiftheresultingvaluefromthepreviousinstructionisequalto0.

7 Status Sign Setiftheresultingvaluefromthepreviousinstructionhasitssignbit(mostsignificantbit)set.

8 Control Trap Whenset,theprocessorsendsaninterrupttotheoperatingsystemkernelafterexecutingthenextoperation.

9 Control Interrupt Whennotset,thesystemignoresmaskable

Page 130: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

interrupts.

10 Control Direction Whenset,ESIandEDIaredecrementedbyoperationsthatautomaticallymodifythem.Whennotset,theyareincremented.

11 Status Overflow Setwhenavalueisoverflowedbythepreviousinstruction,suchaswhenADDisperformedonapositivevalueandtheresultisanegativevalue.

TheEFLAGSregisteralsocontainsasystembitandareservedbit,butthoseareirrelevantinuser-modeassemblyandgamehacking,soI’veomittedthemfromthistable.KeepEFLAGSinmindwhenyou’redebugginggamecodetofigureouthowitworks.Forexample,ifyousetabreakpointonaJE(jumpifequal)instruction,youcanlookattheEFLAGS0bittoseewhetherthejumpwillbetaken.

SegmentRegistersFinally,assemblylanguagehasasetof16-bitregisterscalledsegmentregisters.Unlikeotherregisters,segmentregistersarenotusedtostoredata;theyareusedtolocateit.Intheory,theypointtoisolatedsegmentsofmemory,allowingdifferenttypesofdatatobestoredincompletelyseparatememorysegments.Theimplementationofsuchsegmentationisleftuptotheoperatingsystem.Thesearethex86segmentregistersandtheirintendedpurposes:

CS,thecodesegmentThisregisterpointstothememorythatholdsanapplication’scode.

DS,thedatasegmentThisregisterpointstothememorythatholdsanapplication’sdata.

ES,FS,andGS,theextrasegmentsTheseregisterspointtoanyproprietarymemorysegmentsusedbytheoperatingsystem.

SS,thestacksegmentThisregisterpointstomemorythatactsasadedicatedcallstack.

Inassemblycode,segmentregistersareusedasprefixestomemoryoffsetoperands.Whenasegmentregisterisn’tspecified,DSisusedbydefault.

Page 131: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ThismeansthatthecommandPUSH[EBP]iseffectivelythesameasPUSHDS:[EBP].ButthecommandPUSHFS:[EBP]isdifferent:itreadsmemoryfromtheFSsegment,nottheDSsegment.

IfyoulookcloselyattheWindowsx86implementationofmemorysegmentation,youmightnoticethatthesesegmentregisterswerenotexactlyusedasintended.Toseethisinaction,youcanrunthefollowingcommandswiththeOllyDbgcommandlineplug-inwhileOllyDbgisattachedtoapausedprocess:

?CALC(DS==SS&&SS==GS&&GS==ES)?1?CALCDS-CS?8?CALCFS-DS;returnsnonzero(andchangesbetweenthreads)

Thisoutputtellsusthreedistinctthings.First,itshowsthatthereareonlythreesegmentsbeingusedbyWindows:FS,CS,andeverythingelse.ThisisdemonstratedbyDS,SS,GS,andESbeingequal.Forthesamereason,thisoutputshowsthatDS,SS,GS,andEScanallbeusedinterchangeably,astheyallpointtothesamememorysegments.Lastly,sinceFSchangesdependingonthethread,thisoutputshowsthatitisthreaddependent.FSisaninterestingsegmentregister,anditpointstocertainthread-specificdata.In“BypassingASLRinProduction”onpage128,we’llexplorehowthedatainFScanbeusedtobypassASLR—somethingmostbotswillneedtodo.

Infact,inassemblycodegeneratedforWindowsbyacompiler,you’donlyeverseethreesegmentsused:DS,FS,andSS.Interestinglyenough,eventhoughCSseemstoshowaconstantoffsetfromDS,ithasnorealpurposeinuser-modecode.Knowingallofthesethings,youcanfurtherconcludethatthereareonlytwosegmentsbeingusedbyWindows:FSandeverythingelse.

Thesetwosegmentsactuallypointtodifferentlocationsinthesamememory(there’snosimplewaytoverifythis,butitistrue),whichshowsthatWindowsactuallydoesn’tusememorysegmentsatall.Instead,itusesaflatmemorymodelinwhichsegmentregistersarenearlyirrelevant.Whileallsegmentregisterspointtothesamememory,onlyFSandCSpointtodifferentlocations,andCSisnotused.

Inconclusion,thereareonlythreethingsyouneedtoknowabout

Page 132: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Inconclusion,thereareonlythreethingsyouneedtoknowaboutsegmentregisterswhenworkingwithx86assemblyinWindows.First,DS,SS,GS,andESareinterchangeable,butforclarityDSshouldbeusedtoaccessdataandSSshouldbeusedtoaccessthecallstack.Second,CScanbesafelyforgotten.Third,FSistheonlysegmentregisterwithaspecialpurpose;itshouldbeleftalonefornow.

TheCallStackRegistersarepowerful,butunfortunatelytheycomeinverylimitedsupply.Inorderforassemblycodetoeffectivelystoreallofitslocaldata,itmustalsousethecallstack.Thestackisusedtostoremanydifferentvalues,includingfunctionparameters,returnaddresses,andsomelocalvariables.

Understandingtheinsandoutsofthecallstackwillcomeinhandywhenyou’rereverseengineeringagame.Moreover,you’llrelyonthisknowledgeheavilywhenwejumpintocontrolflowmanipulationinChapter8.

StructureYoucanthinkofthecallstackasaFILO(first-in-last-out)listofDWORDvaluesthatcanbedirectlyaccessedandmanipulatedbyassemblycode.Thetermstackisusedbecausethestructureresemblesastackofpaper:objectsarebothaddedtoandremovedfromthetop.DataisaddedtothestackthroughthePUSHoperandcommand,anditisremoved(andplacedinaregister)throughthePOPregistercommand.Figure4-6showshowthisprocessmightlook.

Page 133: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure4-6:Thestructureofastack

InWindows,thestackgrowsfromhighermemoryaddressestolowerones.Itoccupiesafiniteblockofmemory,pilinguptoaddress0x00000000(theabsolutetop)fromaddressn(theabsolutebottom).ThismeansthatESP(thepointertothetopofthestack)decreasesasitemsareaddedandincreasesasitemsareremoved.

TheStackFrameWhenanassemblyfunctionusesthestacktostoredata,itreferencesthedatabycreatingastackframe.ItdoessobystoringESPinEBPandthensubtractingnbytesfromESP,effectivelyopeningann-bytegapthatisframedbetweentheregistersEBPandESP.Tobetterunderstandthis,firstimaginethatthestackinFigure4-7ispassedtoafunctionthatrequires0x0Cbytesoflocalstoragespace.

Page 134: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure4-7:Initialexamplestack(readfrombottomtotop)

Inthisexample,address0x0000istheabsolutetopofthestack.Wehaveunusedmemoryfromaddresses0x0000to0xFF00–4,andatthetimeofthefunctioncall,0xFF00isthetopofthestack.ESPpointstothisaddress.Thestackmemoryafter0xFF00isusedbyprecedingfunctionsinthecallchain(from0xFF04to0xFFFF).Whenthefunctioniscalled,thefirstthingitdoesisexecutethefollowingassemblycode,whichcreatesastackframeof0x0C(12indecimal)bytes:

PUSHEBP;savesthebottomofthelowerstackframeMOVEBP,ESP;storesthebottomofthecurrentstackframe,inEBP;(also4bytesabovethelowerstackframe)SUBESP,0x0C;subtracts0x0CbytesfromESP,movingitupthestack;tomarkthetopofthestackframe

Afterthiscodeexecutes,thestacklooksmoreliketheoneshowninFigure4-8.Aftercreatingthisstack,thefunctioncanworkwiththe0x0Cbytesitallocatedonthestack.

0x0000isstilltheabsolutetopofthestack.Wehaveunusedstackmemoryfromaddresses0x0000to0xFF00–20,andthememoryataddress0xFF00–16containsthefinal4bytesoflocalstorage(referencedby[EBP-Ch]).Thisisalsothetopofthecurrentstackframe,soESPpointshere.0xFF00–12containsthemiddle4bytesoflocalstorage(referencedby[EBP-8h]),and0xFF00–8containsthefirst4bytesoflocalstorage(referencedby[EBP-4h]).EBPpointsto0xFF00–4,whichisthebottomofthecurrentstackframe;thisaddressholdstheoriginalvalueofEBP.0xFF00isthetopofthelowerstackframe,andtheoriginalESPinFigure4-7pointedhere.Finally,youcanstillseethestackmemoryfromprecedingfunctionsinthecallchainfrom0xFF04to0xFFFF.

Page 135: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure4-8:Examplestackwithstackframesetup(readfrombottomtotop)

Withthestackinthisstate,thefunctionisfreetouseitslocaldataasitpleases.Ifthisfunctioncalledanotherfunction,thenewfunctionwouldbuilditsownstackframeusingthesametechnique(thestackframesreallystackup).Onceafunctionfinishesusingastackframe,however,itmustrestorethestacktoitspreviousstate.Inourcase,thatmeansmakingthestacklooklikeitdidinFigure4-7.Whenthesecondfunctionfinishes,ourfirstfunctioncleansthestackusingthefollowingtwocommands:

MOVESP,EBP;demolishesthestackframe,bringingESPto4bytesabove;itsoriginalvalue(0xFF00-4)POPEBP;restoresthebottomoftheoldstackframethatwassavedby;'PUSHEBP'.Alsoadds4bytestoESP,puttingitbackat;itsoriginalvalue

Butifyouwanttochangetheparameterspassedtoafunctioninagame,don’tlookfortheminthatfunction’sstackframe.Afunction’sparametersarestoredinthestackframeofthefunctionthatcalledit,andthey’re

Page 136: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

referencedthrough[EBP+8h],[EBP+Ch],andsoon.Theystartat[EBP+8h]because[EBP+4h]storesthefunction’sreturnaddress.(“FunctionCalls”onpage94explainsthistopicfurther.)

NOTE

Codecanbecompiledwithstackframesdisabled.Whenthisisthecase,you’llnoticethatfunctionsdon’topenwithPUSHEBPandinsteadreferenceeverythingrelativetoESP.Moreoftenthannot,though,stackframesareenabledincompiledgamecode.

Nowthatyouhaveagrasponthefundamentalsofassemblycode,let’sexploresomespecificsthatwillcomeinhandywhenhackinggames.

Importantx86InstructionsforGameHackingWhileassemblylanguagehashundredsofinstructions,manywell-equippedgamehackersunderstandonlyasmallsubsetofthem,whichIcoverindetailhere.Thissubsettypicallyencapsulatesallinstructionsthatareusedtomodifydata,callfunctions,comparevalues,orjumparoundwithincode.

DataModificationDatamodificationoftenhappensoverseveralassemblyoperations,buttheendresulthastobestoredeitherinmemoryorinaregister,typicallywiththeMOVinstruction.TheMOVoperationtakestwooperands:adestinationandasource.Table4-6showsallpossiblesetsofMOVoperandsandtheresultsyoucanexpectfromthosecalls.

Table4-6:OperandstotheMOVInstruction

Instructionsyntax Result

MOVR1,R2 CopiesR2’svaluetoR1.MOVR1,[R2] CopiesthevaluefromthememoryreferencedbyR2to

R1.MOVR1,[R2+Ah] Copiesthevaluefromthememoryreferencedby

R2+0xAtoR1.

Page 137: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MOVR1,[DEADBEEFh] Copiesthevaluefromthememoryat0xDEADBEEFtoR1.

MOVR1,BADF00Dh Copiesthevalue0xBADF00DtoR1.MOV[R1],R2 CopiesR2’svaluetothememoryreferencedbyR1.MOV[R1],BADF00Dh Copiesthevalue0xBADF00Dtothememory

referencedbyR1.MOV[R1+4h],R2 CopiesR2’svaluetothememoryreferencedbyR1+0x4.MOV[R1+4h],BADF00Dh

Copiesthevalue0xBADF00DtothememoryreferencedbyR1+0x4.

MOV[DEADBEEFh],R1 CopiesR1’svaluetothememoryat0xDEADBEEF.MOV[DEADBEEFh],BADF00Dh

Copiesthevalue0xBADF00Dtothememoryat0xDEADBEEF.

TheMOVinstructioncantakealotofoperandcombinations,butsomearen’tallowed.First,thedestinationoperandcan’tbeanimmediatevalue;itmustbearegisterormemoryaddress,becauseimmediatevaluescan’tbemodified.Second,valuescan’tbedirectlycopiedfromonememoryaddresstoanother.Copyingavaluerequirestwoseparateoperations,likeso:

MOVEAX,[EBP+10h];copymemoryfromEBP+0x10toEAXMOV[DEADBEEFh],EAX;MOVthecopiedmemorytomemoryat0xDEADBEEF

TheseinstructionscopywhateverisstoredatEBP+0x10tothememoryat0xDEADBEEF.

ArithmeticLikemanyhigh-levellanguages,assemblylanguagehastwotypesofarithmetic:unaryandbinary.Unaryinstructionstakeasingleoperandthatactsasbothadestinationandasource.Thisoperandcanbearegisteroramemoryaddress.Table4-7showsthecommonunaryarithmeticinstructionsinx86.

Table4-7:UnaryArithmeticInstructions

Page 138: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Instructionsyntax

Result

INCoperand Adds1totheoperandvalue.

DECoperand Subtracts1fromtheoperandvalue.NOToperand Logicallynegatestheoperandvalue(flipsallbits).NEGoperand Performstwo’s-complementnegation(flipsallbitsandadds1;

essentiallymultipliesby-1).

Binaryinstructions(whichmakeupthemajorityofx86arithmetic),ontheotherhand,aresyntacticallysimilartotheMOVinstruction.Theyrequiretwooperandsandhavesimilaroperandlimitations.UnlikeMOV,however,theirdestinationoperandservesasecondpurpose:itisalsotheleft-handvalueinthecalculation.Forexample,theassemblyoperationADDEAX,EBXequatestoEAX=EAX+EBXorEAX+=EBXinC++.Table4-8showsthecommonx86binaryarithmeticinstructions.

Table4-8:BinaryArithmeticInstructions

Instructionsyntax

Function Operandnotes

ADDdestination,source

destination+=source

SUBdestination,source

destination-=source

ANDdestination,source

destination&=source

ORdestination,source

destination|=source

XORdestination,source

destination^=source

SHLdestination,source

destination=destination<<source

sourcemustbeCLoran8-bitimmediatevalue.

Page 139: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

source source

SHRdestination,

source

destination=destination>>

source

sourcemustbeCLoran8-bitimmediatevalue.

IMULdestination,source

destination*=source

destinationmustbearegister;sourcecannotbeanimmediatevalue.

Ofthesearithmeticinstructions,IMULisspecialbecauseyoucanpassitathirdoperand,intheformofanimmediatevalue.Withthisprototype,thedestinationoperandisnolongerinvolvedinthecalculation,whichinsteadtakesplacebetweentheremainingoperands.Forexample,theassemblycommandIMULEAX,EBX,4hequatestoEAX=EBX*0x4inC++.

YoucanalsopassasingleoperandtoIMUL.3Inthiscase,theoperandactsasthesourceandcanbeeitheramemoryaddressoraregister.Dependingonthesizeofthesourceoperand,theinstructionwillusedifferentpartsoftheEAXregisterforinputsandoutput,asshowninTable4-9.

Table4-9:PossibleIMULRegisterOperands

Sourcesize

InputOutput

8bits AL 16bit,storedinAH:AL(whichisAX)

16bits AX 32bit,storedinDX:AX(bits0–15inAXandbits16–31inDX)

32bits EAX 64bit,storedinEDX:EAX(bits0–31inEAXandbits32–64inEDX)

Noticethateventhoughtheinputisonlyoneregister,eachoutputusestworegisters.That’sbecauseinmultiplication,theresultgenerallyislargerthantheinputs.

Let’slookatanexamplecalculationusingIMULwithasingle32-bitoperand:

IMUL[BADFOODh];32-bitoperandisataddress0xBADFOOD

Thiscommandbehaveslikethefollowingpseudocode:

Page 140: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

EDX:EAX=EAX*[BADFOODh]

Similarly,here’sanoperationthatusesIMULwithasingle16-bitoperand:

IMULCX;16-bitoperandisstoredinCX

Anditscorrespondingpseudocode:

DX:AX=AX*CX

Finally,thisisanIMULcommandwithasingle8-bitoperand:

IMULCL;8-bitoperandisstoredinCL

Anditscorrespondingpseudocode:

AX=AL*CL

x86assemblylanguagehasdivisionaswell,throughtheIDIVinstruction.4TheIDIVinstructionacceptsasinglesourceoperandandfollowsregisterrulessimilartothoseforIMUL.AsTable4-10shows,IDIVoperationsrequiretwoinputsandtwooutputs.

Table4-10:PossibleIDIVRegisterOperands

Sourcesize

Input Output

8bit 16bit,storedinAH:AL(whichisAX)

RemainderinAH;quotientinAL

16bit 32bit,storedinDX:AX RemainderinDX;quotientinAX

32bit 64bit,storedinEDX:EAX RemainderinEDX;quotientinEAX

Indivision,theinputsaregenerallylargerthantheoutput,soheretheinputstaketworegisters.Moreover,divisionoperationsmuststorearemainder,whichgetsstoredinthefirstinputregister.Forexample,here’showa32-bitIDIVcalculationwouldlook:

Page 141: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MOVEDX,0;there'snohigh-orderDWORDintheinput,soEDXis0MOVEAX,inputValue;32-bitinputvalueIDIVECX;divideEDX:EAXbyECX

Andhere’ssomepseudocodethatexpresseswhathappensunderthehood:

EAX=EDX:EAX/ECX;quotientEDX=EDX:EAX%ECX;remainder

ThesedetailsofIDIVandIMULareimportanttoremember,asthebehaviorcanotherwisebequiteobfuscatedwhenyou’resimplylookingatthecommands.

BranchingAfterevaluatinganexpression,programscandecidewhattoexecutenextbasedontheresult,typicallyusingconstructssuchasif()statementsorswitch()statements.Thesecontrolflowstatementsdon’texistattheassemblylevel,however.Instead,assemblycodeusestheEFLAGSregistertomakedecisionsandjumpoperationstoexecutedifferentblocks;thisprocessiscalledbranching.

TogetthepropervalueinEFLAGS,assemblycodeusesoneoftwoinstructions:TESTorCMP.Bothcomparetwooperands,setthestatusbitsofEFLAGS,andthendiscardanyresults.TESTcomparestheoperandsusingalogicalAND,whileCMPusessignedsubtractiontosubtractthelatteroperandfromtheformer.

Inordertobranchproperly,thecodehasajumpcommandimmediatelyfollowingthecomparison.Eachtypeofjumpinstructionacceptsasingleoperandthatspecifiestheaddressofthecodetojumpto.HowaparticularjumpinstructionbehavesdependsonthestatusbitsofEFLAGS.Table4-11describessomex86jumpinstructions.

Table4-11:Commonx86JumpInstructions

InstructionName Behavior

JMPdest Unconditionaljump

Jumpstodest(setsEIPtodest).

Page 142: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

JEdest Jumpifequal JumpsifZF(zeroflag)is1.

JNEdest Jumpifnotequal JumpsifZFis0.JGdest Jumpifgreater JumpsifZFis0andSF(signflag)isequalto

OF(overflowflag).JGEdest Jumpifgreater

orequalJumpsifSFisequaltoOF.

JAdest UnsignedJG JumpsifCF(carryflag)is0andZFis0.JAEdest UnsignedJGE JumpsifCFis0.JLdest Jumpifless JumpsifSFisnotequaltoOF.JLEdest Jumpiflessor

equalJumpsifZFis1orSFisnotequaltoOF.

JBdest UnsignedJL JumpsifCFis1.JBEdest UnsignedJLE JumpsifCFis1orZFis1.JOdest Jumpifoverflow JumpsifOFis1.JNOdest Jumpifnot

overflowJumpsifOFis0.

JZdest Jumpifzero JumpsifZFis1(identicaltoJE).JNZdest Jumpifnotzero JumpsifZFis0(identicaltoJNE).

Rememberingwhichflagscontrolwhichjumpinstructionscanbeapain,buttheirpurposeisclearlyexpressedintheirname.AgoodruleofthumbisthatajumpprecededbyaCMPisthesameasitscorrespondingoperator.Forexample,Table4-11listsJEas“jumpifequal,”sowhenJEfollowsaCMPoperation,it’sthesameasthe==operator.Similarly,JGEwouldbe>=,JLEwouldbe>=,andsoon.

Asanexample,considerthehigh-levelcodeshowninListing4-8.

--snip--if(EBX>EAX)ECX=EDX;elseECX=0;

Page 143: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

--snip--

Listing4-8:Asimpleconditionalstatement

Thisif()statementjustcheckswhetherEBXisgreaterthanEAXandsetsECXbasedontheresult.Inassembly,thesamestatementmaylooksomethinglikethis:

--snip--CMPEBX,EAX;if(EBX>EAX)JGlabel1;jumptolabel1ifEBX>EAXMOVECX,0;ECX=0(elseblock)JMPlabel2;jumpovertheifblocklabel1:➊MOVECX,EDX;ECX=EDX(ifblock)label2:--snip--

Theassemblyfortheif()statementinListing4-8beginswithaCMPinstructionandbranchesifEBXisgreaterthanEAX.Ifthebranchistaken,EIPissettotheifblockat➊courtesyoftheJGinstruction.Ifthebranchisnottaken,thecodecontinuesexecutinglinearlyandhitstheelseblockimmediatelyaftertheJGinstruction.Whentheelseblockfinishesexecuting,anunconditionalJMPsetsEIPto0x7,skippingovertheifblock.

FunctionCallsInassemblycode,functionsareisolatedblocksofcommandsexecutedthroughtheCALLinstruction.TheCALLinstruction,whichtakesafunctionaddressastheonlyoperand,pushesareturnaddressontothestackandsetsEIPtoitsoperandvalue.ThefollowingpseudocodeshowsaCALLinaction,withmemoryaddressesontheleftinhex:

0x1:CALLEAX0x2:...

WhenCALLEAXisexecuted,thenextaddressispushedtothestackandEIPissettoEAX,showingthatCALLisessentiallyaPUSHandJMP.Thefollowingpseudocodeunderscoresthispoint:

0x1:PUSH3h0x2:JMPEAX0x3:...

Page 144: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Whilethere’sanextraaddressbetweenthePUSHinstructionandthecodetoexecute,theresultisthesame:beforetheblockofcodeatEAXisexecuted,theaddressofthecodethatfollowsthebranchispushedtothestack.Thishappenssothecallee(thefunctionbeingcalled)knowswheretojumptointhecaller(thefunctiondoingthecall)whenitreturns.

Ifafunctionwithoutparametersiscalled,aCALLcommandisallthat’snecessary.Ifthecalleetakesparameters,however,theparametersmustfirstbepushedontothestackinreverseorder.Thefollowingpseudocodeshowshowafunctioncallwiththreeparametersmightlook:

PUSH300h;arg3PUSH200h;arg2PUSH100h;arg1CALLECX;call

Whenthecalleeisexecuted,thetopofthestackcontainsareturnaddressthatpointstothecodeafterthecall.Thefirstparameter,0x100,isbelowthereturnaddressonthestack.Thesecondparameter,0x200,isbelowthat,followedbythethirdparameter,0x300.Thecalleesetsupitsstackframe,usingmemoryoffsetsfromEBPtoreferenceeachparameter.Oncethecalleehasfinishedexecuting,itrestoresthecaller’sstackframeandexecutestheRETinstruction,whichpopsthereturnaddressoffthestackandjumpstoit.

Sincetheparametersarenotapartofthecallee’sstackframe,theyremainonthestackafterRETisexecuted.Ifthecallerisresponsibleforcleaningthestack,itadds12(3parameters,at4byteseach)toESPimmediatelyafterCALLECXcompletes.Ifthecalleeisresponsible,itcleansupbyexecutingRET12insteadofRET.Thisresponsibilityisdeterminedbythecallee’scallingconvention.

Afunction’scallingconventiontellsthecompilerhowtheassemblycodeshouldpassparameters,storeinstancepointers,communicatethereturnvalue,andcleanthestack.Differentcompilershavedifferentcallingconventions,buttheoneslistedinTable4-12aretheonlyfourthatagamehackerislikelytoencounter.

Table4-12:CallingConventionstoKnowforGameHacking

Directive CleanerNotes__cdecl caller DefaultconventioninVisualStudio.

Page 145: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

__stdcall callee ConventionusedbyWin32APIfunctions.__fastcallcallee FirsttwoDWORD(orsmaller)parametersarepassedin

ECXandEDX.__thiscallcallee Usedformemberfunctions.Thepointertotheclass

instanceispassedinECX.

TheDirectivecolumninTable4-12givesthenameofthecallingconvention,andtheCleanercolumntellsyouwhetherthecallerorcalleeisresponsibleforcleaningthestackgiventhatdirective.Inthecaseofthesefourcallingconventions,parametersarealwayspushedrighttoleft,andreturnvaluesarealwaysstoredinEAX.Thisisastandard,butnotarule;itcandifferacrossothercallingconventions.

ClosingThoughtsMygoalinwritingthischapterwastohelpyouunderstandmemoryandassemblyinageneralsense,beforewedigintogame-hackingspecifics.Withyournewfoundabilitytothinklikeacomputer,youshouldbeadequatelyarmedtostarttacklingmoreadvancedmemoryforensicstasks.Ifyou’reitchingforapeekathowyou’llapplyallofthistosomethingreal,flipto“ApplyingCallHookstoAdobeAIR”onpage169or“ApplyingJumpHooksandVFHookstoDirect3D”onpage175.

Ifyouwantsomehands-ontimewithmemory,compilethischapter’sexamplecodeanduseCheatEngineorOllyDbgtoinspect,tweak,andpokeatthememoryuntilyou’vegotthehangofit.Thisisimportant,asthenextchapterwillbuildontheseskillsbyteachingyouadvancedmemoryforensictechniques.

Page 146: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

5ADVANCEDMEMORYFORENSICS

Whetheryouhackgamesasahobbyorabusiness,you’lleventuallyfindyourselfbetweenarockand...anunintelligiblememorydump.Beitaracewitharivalbotdevelopertoreleaseahighlyrequestedfeature,abattleagainstagamecompany’sconstantbarrageofupdates,orastruggletolocatesomecomplexdatastructureinmemory,you’llneedtop-notchmemoryforensicsskillstoprevail.

Successfulbotdevelopmentisprecariouslybalancedatopspeedandskill,andtenacioushackersmustrisetothechallengebyswiftlyreleasingingeniousfeatures,promptlyrespondingtogameupdates,andreadilysearchingforeventhemostelusivepiecesofdata.Doingthis,however,requiresacomprehensiveunderstandingofcommonmemorypatterns,advanceddatastructures,andthepurposeofdifferentpiecesofdata.

Thosethreeaspectsofmemoryforensicsareperhapsthemosteffectiveweaponsinyourarsenal,andthischapterwillteachyouhowtousethem.First,I’lldiscussadvancedmemory-scanningtechniquesthatfocusonsearchingfordatabyunderstandingitspurposeandusage.Next,I’llteachyouhowtousememorypatternstotacklegameupdatesandtweakyourbotswithouthavingtorelocateallofyouraddressesfromscratch.Towrapup,I’lldissectthefourmostcommoncomplexdatastructuresintheC++standardlibrary(std::string,std::vector,std::list,andstd::map)soyoucanrecognizetheminmemoryandenumeratetheircontents.Bytheendofthechapter,myhopeisthatyou’llhaveadeepunderstandingofmemory

Page 147: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

forensicsandbeabletotakeonanychallengerelatedtomemoryscanning.

AdvancedMemoryScanningWithinagame’ssourcecode,eachpieceofdatahasacold,calculateddefinition.Whenthegameisbeingplayed,however,allofthatdatacomestogethertocreatesomethingnew.Playersonlyexperiencethebeautifulscenery,visceralsounds,andintenseadventures;thedatathatdrivestheseexperiencesisirrelevant.

Withthatinmind,imagineHackerAhasjuststartedtearingintohisfavoritegame,wantingtoautomatesomeoftheboringbitswithabot.Hedoesn’thaveacompleteunderstandingofmemoryyet,andtohim,thedataisnothingbutassumptions.Hethinks,“Ihave500health,soIcanfindthehealthaddressbytellingCheatEnginetolookfora4-byteintegerwithavalueof500.”HackerAhasanaccurateunderstandingofdata:it’sjustinformation(values)storedatparticularlocations(addresses)usingdefinedstructures(types).

NowimagineHackerB,whoalreadyunderstandsthegamebothinsideandout;sheknowshowplayingthegamealtersitsstateinmemory,andthedatanolongerhasanysecrets.Sheknowsthateverydefinedpropertyofthedatacanbedeterminedgivenitspurpose.UnlikeHackerA,HackerBhasanunderstandingofdatathattranscendstheconfinesofasinglevariabledeclaration:sheconsidersthedata’spurposeandusage.Inthissection,we’lldiscussboth.

Eachpieceofdatainagamehasapurpose,andtheassemblycodeofthegamemust,atsomepoint,referencethedatatofulfillthatpurpose.Findingtheuniquecodethatusesapieceofdatameansfindingaversion-agnosticmarkerthatpersistsacrossgameupdatesuntilthedataiseitherremovedoritspurposeischanged.Letmeshowyouwhythisisimportant.

DeducingPurposeSofar,I’veonlyshownyouhowtoblindlysearchmemoryforagivenpieceofdatawithoutconsideringhowit’sbeingused.Thismethodcanbeeffective,butitisnotalwaysefficient.Inmanycases,it’smuchquickertodeducethepurposeofdata,determinewhatcodemightusethatdata,andthenlocatethatcodetoultimatelyfindtheaddressofthedata.

Page 148: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thenlocatethatcodetoultimatelyfindtheaddressofthedata.Thismightnotsoundeasy,butneitherdoes“scanthegame’smemoryfor

aspecificvalueofaspecificdatatype,andthencontinuouslyfiltertheresultlistbasedonchangingcriteria,”whichiswhatyou’velearnedtodothusfar.Solet’slookathowwemightlocatetheaddressforhealthgivenitspurpose.ConsiderthecodeinListing5-1.

structPlayerVital{intcurrent,maximum;};PlayerVitalhealth;--snip--printString("Health:%dof%d\n",health.current,health.maximum);

Listing5-1:Astructurecontainingtheplayer’svitals,andafunctionthatdisplaysthem

IfyoupretendthatprintString()isafancyfunctiontodrawtextonanin-gameinterface,thenthiscodeisprettyclosetowhatyoumightfindinagame.ThePlayerVitalstructurehastwoproperties:thecurrentvalueandamaximumvalue.ThevaluehealthisaPlayerVitalstructure,soithastheseproperties,too.Basedonthenamealone,youcandeducethathealthexiststodisplayinformationabouttheplayer’shealth,andyoucanseethispurposefulfilledwhenprintString()usesthedata.

Evenwithoutthecode,youcanintuitivelydrawsimilarconclusionsbyjustlookingatthehealthtextdisplayedinthegame’sinterface;acomputercan’tdoanythingwithoutcode,afterall.Asidefromtheactualhealthvariable,thereareafewcodeelementsthatneedtoexisttoshowaplayerthistext.First,thereneedstobesomefunctiontodisplaytext.Second,thestringsHealthandofmustbenearby.

NOTE

WhydoIassumethetextissplitintotwoseparatestringsinsteadofone?Thegameinterfaceshowsthatthecurrenthealthvalueisbetweenthesetwostrings,buttherearemanywaysthatcouldhappen,includingformatstrings,strcat(),ortextalignedwithmultipledisplaytextcalls.Whenyou’reanalyzingdata,it’sbesttokeepyourassumptionsbroadtoaccountforallpossibilities.

Tofindhealthwithoutusingamemoryscanner,wecouldutilizethesetwodistinctstrings.Weprobablywouldn’thaveacluewhatthefunctionto

Page 149: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

displaytextlookslike,whereitis,orhowmanytimesit’scalled,though.Realistically,thestringsareallwewouldknowtolookfor,andthat’senough.Let’swalkthroughit.

FindingthePlayer’sHealthwithOllyDbgI’llwalkyouthroughhowtotrackdownthehealthstructureinthissection,butI’vealsoincludedthebinaryIanalyzeinthebook’sresourcefiles.Tofollowalongandgetsomehands-onpractice,usethefileChapter5_AdvancedMemoryForensics_Scanning.exe.

First,openOllyDbgandattachittotheexecutable.Then,openOllyDbg’sExecutablemoduleswindowanddouble-clickthemainmodule;inmyexample,themainmoduleistheonly.exeinthemodule’swindow.TheCPUwindowshouldpopup.Now,right-clickintheDisassemblerpaneandselectSearchfor▸Allreferencedtextstrings.ThisshouldopentheReferenceswindow,showninFigure5-1.

Figure5-1:OllyDbg’sReferenceswindow,showingonlyalistofstrings.Therewouldbealotmorethanfourinarealgame.

Fromthiswindow,right-clickandselectSearchfortext.Asearchdialogappears.Enterthestringyou’relookingfor,asshowninFigure5-2,andmakethesearchasbroadaspossiblebydisablingCasesensitiveandenablingEntirescope.

Page 150: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure5-2:SearchingforstringsinOllyDbg

ClickOKtoexecutethesearch.TheReferenceswindowcomesbackintofocuswiththefirstmatchhighlighted.Double-clickthematchtoseetheassemblycodethatusesthestringinsidetheCPUwindow.TheDisassemblerpanefocusesonthelineofcodeat0x401030,whichpushestheformatstringparametertoprintString().YoucanseethislineinFigure5-3,whereI’vehighlightedtheentirefunctioncallblock.

Figure5-3:ViewingtheprintString()callintheCPUwindow’sDisassemblerpane

Byreadingtheassemblycode,youcangetaveryaccurateunderstandingofexactlywhatthegameisdoing.TheblackbracketontheleftshowsthatthestringHealthisinsideafunctioncall.Noticetheargumentstothatfunction.Inorder,theseareEAX➊,ECX➋,andtheformatstringat0x4020D0➌.EAXisthevalueat0x40301C,ECXisthevalueat0x403018,andtheformatstringcontainsHealth.Sincethestringcontainstwoformatplaceholders,youcanassumethattheremainingtwoparametersaretheargumentsforthoseplaceholders.

Knowingwhattheargumentsareandthattheyarepushedinreverseorder,youcanworkbackwardandconcludethattheoriginalcodelookedsomethinglikeListing5-2.

intcurrentHealth;//valueat0x403018

Page 151: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

intmaxHealth;//valueat0x40301C--snip--someFunction("Health:%dof%d\n",currentHealth,maxHealth);

Listing5-2:HowagamehackermightinterprettheassemblythatFigure5-3compilesto

ThevaluesstoredinEAXandECXareadjacentinmemory,whichmeanstheymaybepartofastructure.Tokeepitsimple,though,thisexamplejustshowsthemasvariabledefinitions.Eitherway,thesearethetwonumbersusedtodisplaytheplayer’shealth.Becausebothoftheseimportantvaluesweredisplayedinthegame’sUI,itwaseasytomakeassumptionsabouttheunderlyingcodethatdisplaysthem.Whenyouknowthepurposeofapieceofdata,youcanquicklyfindthecoderesponsibleforfulfillingit;inthiscase,thatknowledgehelpedusquicklyfindbothaddresses.

Inmanycases,findingaddressescanbethiseasy,butsomepiecesofdatahavesuchcomplexpurposesthatit’shardertoguesswhattolookfor.FiguringouthowtosearchformapdataorcharacterlocationsinOllyDbg,forinstance,canbeprettytricky.

Stringsarefarfromtheonlymarkersthatyoucanusetofindthedatayouwanttochangeinagame,buttheyaredefinitelytheeasiesttoteachwithoutgivingcontrivedexamples.Moreover,somegameshaveloggingorerrorstringsembeddedintheircode,andpokingaroundintheReferencedtextstringswindowofOllyDbgcanbeaquickwaytodeterminewhetherthesestringsarepresent.Ifyoubecomefamiliarwithagame’sloggingpractices,you’llbeabletofindvaluesevenmoreeasily.

DeterminingNewAddressesAfterGameUpdatesWhenapplicationcodeismodifiedandrecompiled,abrand-newbinarythatreflectsthechangesisproduced.Thisbinarymightbeverysimilartothepreviousone,orthebinariesmightbenothingalike;thedifferencebetweenthetwoversionshasadirectcorrelationtothecomplexityofthehigh-levelchanges.Smallchanges,likemodifiedstringsorupdatedconstants,canleavebinariesnearlyidenticalandoftenhavenoeffectontheaddressesofcodeordata.Butmorecomplexchanges—likeaddedfeatures,anewuserinterface,refactoredinternals,ornewin-gamecontent—oftencauseshiftsinthelocationofcrucialmemory.

Page 152: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AUTOMATICALLYFINDCURRENTHEALTHANDMAXHEALTH

In“SearchingforAssemblyPatterns”onpage19and“SearchingforStrings”onpage21,IshowedafewCheatEngineLuascriptsandexplainedhowtheyworked.UsingthefindString()functionintheseexamples,youcanmakeCheatEngineautomaticallylocatetheaddressoftheformatstringthatwejustfoundmanuallyinOllyDbg.Next,youcanwriteasmallfunctiontoscanforthisaddressfollowingbyte0x68(thebyteforthePUSHcommand,asyoucanseebesideitat0x401030inFigure5-3)tolocatetheaddressofthecodethatpushesittothestack.Then,youcanread4bytesfrompushAddress-5andpushAddress-12tolocatecurrentHealthandmaxHealth,respectively.

Thismaynotseemusefulsincewe’vealreadyfoundtheaddresses,butifthiswerearealgame,theseaddresseswouldchangewhenanupdateisreleased.Usingthisknowledgetoautomatefindingthemcanbeveryhelpful.Ifyou’reuptothechallenge,giveitawhirl!

Duetoconstantbugfixes,contentimprovements,andfeatureadditions,onlinegamesareamongthemostrapidlyevolvingtypesofsoftware.Somegamesreleaseupdatesasoftenasonceaweek,andgamehackersoftenspendamajorityoftheirtimereverseengineeringthenewbinariesinordertoaccordinglyupdatetheirbots.

Ifyoucreateadvancedbots,theywillbecomeincreasinglysupportedbyafoundationofmemoryaddresses.Whenanupdatecomes,determiningthenewaddressesforalargenumberofvaluesandfunctionsisthemosttime-consuminginevitabilityyouwillface.Relyingonthe“TipsforWinningtheUpdateRace”canbeverybeneficial,butthetipswon’thelpyoulocatetheupdatedaddresses.YoucanautomaticallylocatesomeaddressesusingCheatEnginescripts,butthatwon’talwaysworkeither.Sometimesyou’llhavetodothedirtyworkbyhand.

Ifyoutrytoreinventthewheelandfindtheseaddressesthesamewayyoudidinitially,you’llbewastingyourtime.Youactuallyhaveabigadvantage,though:theoldbinaryandtheaddressesthemselves.Usingthesetwothings,itispossibletofindeverysingleaddressyouneedtoupdateina

Page 153: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

twothings,itispossibletofindeverysingleaddressyouneedtoupdateinafractionofthetime.

Figure5-4showstwodifferentdisassemblies:anewgamebinaryontheleftandthepreviousversionontheright.Ihavetakenthisimagefromanactualgame(whichwillremainnameless)inordertogiveyouarealisticexample.

Figure5-4:Side-by-sidedisassembliesoftwoversionsofonegame

Mybotmodifiedthecodeat0x047B542(right),andIneededtofindthecorrespondingcodeinthenewversion,whichIdiscoveredat0x047B672(left).Thisfunctioncallinvokesapacket-parsingfunctionwhenapackethasbeenreceived.Inordertofindthisaddressoriginally(andby“originally,”Imeanabout100updatesprevious),Ifiguredouthowthegame’snetworkprotocolworked,setbreakpointsonmanynetwork-relatedAPIcalls,steppedthroughexecution,andinspecteddataonthestackuntilIfoundsomethingthatlookedsimilartowhatIexpectedgivenmyknowledgeoftheprotocol.

TIPSFORWINNINGTHEUPDATERACEInsaturatedmarkets,beingthefirstbotdevelopertoreleaseastableupdateiscriticaltosuccess.Theracestartsthesecondthegameupdates,andhackersdeterminedtobethefastestwillspendhundredsofhourspreparing.Thesearethemostcommonwaystostayontop:

CreateupdatealarmsBywritingsoftwarethatalertsyouassoonasthegamepatches,youcanbeginworkingonyourupdatesassoonaspossible.

AutomatebotinstallsGamesoftenscheduleexpectedupdatesattimeswhenthefewestplayersareonline.Bottershatewakingupand

Page 154: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

downloadingnewsoftwarebeforetheybot,buttheylovewakinguptofinditsilentlyinstalledwhilethegameispatching.

UsefeweraddressesThelessthereistoupdate,thebetter.Consolidatingrelateddataintostructuresandeliminatingunnecessarymemoryaddressusagecansaveabunchoftime.

HavegreattestcasesDatachanges,andhackersmakemistakes.Havingwaystoquicklytesteveryfeaturecanbethedifferencebetweenastablebotandonethatrandomlycrashes,getsuserskilled,orevenleadstotheircharactersbeingbannedfromthegame.

Attackingupdateswiththesepracticeswillgiveyouasizableheadstart,buttheymightnotalwaysbeenoughtoleadyoutovictory.Aboveallelse,strivetounderstandreverseengineeringasmuchaspossibleandusethatunderstandingtoyouradvantage.

Icouldhavefollowedthesamestepsforeachofthe100+updatessincethen,butthatwouldhavebeenunnecessary.Thecodestayedrelativelythesamethroughouttheyears,whichletmeusepatternsfromtheoldcodetofindthatfunctioncall’saddressinthenewcode.

Now,considerthischunkofassemblycode:

PUSHEDIPUSHEAXLEAEAX,DWORDPTRSS:[EBP-C]MOVDWORDPTRFS:[0],EAXMOVDWORDPTRSS:[EBP-10],ESPMOVDWORDPTRSS:[EBP-220],-1MOVDWORDPTRSS:[EBP-4],0

Doesitlookfamiliar?CompareittoFigure5-4,andyou’llseethatthisexactcodeexistsrightabovethehighlightedfunctioncallinbothversionsofthegame.Regardlessofwhatitdoes,thecombinationofoperationslooksprettydistinctive;becauseofthenumberofdifferentoffsetsthecodeisusingrelativetoEBP,it’sunlikelythatanidenticalchunkofcodeexistsinanyotherpartofthebinary.

EverytimeIhavetoupdatethisaddress,IopentheoldbinaryinOllyDbg,highlightthischunkofoperations,right-click,andselect

Page 155: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Asm2Clipboard▸Copyfixedasmtoclipboard.Then,IopenthenewbinaryinOllyDbg,navigatetotheCPUWindow,pressCTRL-S,pastetheassemblycode,andhitFind.In9.5casesoutof10,thisplacesmedirectlyabovethefunctioncallIneedtofindinthenewversion.

Whenanupdatecomes,youcanusethesamemethodtofindnearlyallofyourknownaddresses.Itshouldworkforeveryaddressyoucanfindeasilyinassemblycode.Thereareafewcaveats,though:

•OllyDbglimitssearchtoeightoperations,soyoumustfindcodemarkersofthatsizeorsmaller.

•Theoperationsyouusecannotcontainanyotheraddresses,asthoseaddresseshavelikelychanged.

•Ifpartsofthegamehavechangedthatusetheaddressyou’relookingfor,thecodemightbedifferent.

•Ifthegamechangescompilersorswitchesoptimizationsettings,almostallcodewillbeentirelydifferent.

Asdiscussedin“AutomaticallyFindcurrentHealthandmaxHealth”onpage102,youcanbenefitfromwritingscriptsthatcarryoutthesetasksforyou.Seriousgamehackersworkveryhardtoautomaticallylocateasmanyaddressesaspossible,andsomeofthebestbotsareengineeredtoautomaticallydetecttheiraddressesatruntime,everytime.Itcanbealotofworkinitially,buttheinvestmentcandefinitelypayoff.

IdentifyingComplexStructuresinGameDataChapter4describedhowagamemightstoredatainstaticstructures.Thisknowledgewillsufficewhenyou’retryingtofindsimpledata,butitfallsshortfordatathatisstoredthroughdynamicstructures.Thisisbecausedynamicstructuresmightbescatteredacrossdifferentmemorylocations,followlongpointerchains,orrequirecomplexalgorithmstoactuallyextractthedatafromthem.

Thissectionexplorescommondynamicstructuresyou’llfindinvideogamecode,andhowtoreaddatafromthemoncethey’refound.Tobegin,I’lltalkabouttheunderlyingcompositionofeachdynamicstructure.Next,I’lloutlinethealgorithmsneededtoreadthedatafromthesestructures.(For

Page 156: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

simplicity,eachalgorithmdiscussionassumesyouhaveapointertoaninstanceofthestructureaswellassomewaytoreadfrommemory.)Lastly,I’llcovertipsandtricksthatcanhelpyoudeterminewhenavalueyou’researchingforinmemoryisactuallyencapsulatedinoneofthesestructures,soyou’llknowwhentoapplythisknowledge.I’llfocusonC++,asitsobject-orientednatureandheavilyusedstandardlibraryaretypicallyresponsibleforsuchstructures.

NOTE

Someofthesestructuresmightdifferslightlyfrommachinetomachinebasedoncompilers,optimizationsettings,orstandardlibraryimplementations,butthebasicconceptswillremainthesame.Also,intheinterestofbrevity,Iwillbeomittingirrelevantpartsofthesestructures,suchascustomallocatorsorcomparisonfunctions.Workingexamplecodecanbefoundathttps://www.nostarch.com/gamehacking/intheresourcefilesforChapter5.

Thestd::stringClassInstancesofstd::stringareamongthemostcommonculpritsofdynamicstorage.ThisclassfromtheC++StandardTemplateLibrary(STL)abstractsstringoperationsawayfromthedeveloperwhilepreservingefficiency,makingitwidelyusedinalltypesofsoftware.Avideogamemightusestd::stringstructureforanystringdata,suchascreaturenames.

ExaminingtheStructureofastd::stringWhenyoustripawaythememberfunctionsandothernondatacomponentsofthestd::stringclass,thisisthestructurethatremains:

classstring{union{char*dataP;chardataA[16];};intlength;};

//pointtoastringinmemory

Page 157: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

string*_str=(string*)stringAddress;

Theclassreserves16charactersthatarepresumablyusedtostorethestringinplace.Italso,however,declaresthatthefirst4bytescanbeapointertoacharacter.Thismightseemodd,butit’saresultofoptimization.Atsomepoint,thedevelopersofthisclassdecidedthat15characters(plusanullterminator)wasasuitablelengthformanystrings,andtheychosetosaveonmemoryallocationsandde-allocationsbyreserving16bytesofmemoryinadvance.Toaccommodatelongerstrings,theyallowedthefirst4bytesofthisreservedmemorytobeusedasapointertothecharactersoftheselongerstrings.

NOTE

Ifthecodewerecompiledto64bits,thenitwouldactuallybethefirst8(not4)bytesthatpointtoacharacter.Throughoutthisexample,however,youcanassume32-bitaddressesandthatintisthesizeofanaddress.

Accessingstringdatathiswaytakessomeoverhead.Thefunctiontolocatetherightbufferlookssomethinglikethis:

constchar*c_str(){if(_str->length<=15)return(constchar*)&_str->dataA[0];elsereturn(constchar*)_str->dataP;}

Thefactthatastd::stringcanbeeitheracompletestringorapointertoalongerstringmakesthisparticularstructurequitetrickyfromagame-hackingperspective.Somegamesmayusestd::stringtostorestringsthatonlyrarelyexceed15characters.Whenthisisthecase,youmightimplementbotsthatrelyonthesestrings,neverknowingthattheunderlyingstructureisinfactmorecomplicatedthanasimplestring.

Overlookingastd::stringCanRuinYourFunNotknowingthetruenatureofthestructurecontainingthedatayouneedcanleadyoutowriteabotthatworksonlysomeofthetimeandfailswhenitcounts.Imagine,forexample,thatyou’retryingtofigureouthowagame

Page 158: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

storescreaturedata.Inyourhypotheticalsearch,youfindthatallthecreaturesinthegamearestoredinanarrayofstructuresthatlooksomethinglikeListing5-3.

structcreatureInfo{intuniqueID;charname[16];intnameLength;inthealthPercent;intxPosition;intyPosition;intmodelID;

intcreatureType;};

Listing5-3:Howyoumightinterpretcreaturedatafoundinmemory

Afterscanningthecreaturedatainmemory,sayyounoticethatthefirst4bytesofeachstructureareuniqueforeachcreature,soyoucallthosebytestheuniqueIDandassumetheyformasingleintproperty.Lookingfurtherinthememory,youfindthatthecreature’snameisstoredrightafteruniqueID,andaftersomededuction,youfigureoutthenameis16byteslong.ThenextvalueyouseeinmemoryturnsouttobethenameLength;it’sabitstrangethatanull-terminatedstringhasanassociatedlength,butyouignorethatoddityandcontinueanalyzingthedatainmemory.Afterfurtheranalysis,youdeterminewhattheremainingvaluesarefor,definethestructureshowninListing5-3,andwriteabotthatautomaticallyattackscreatureswithcertainnames.

AfterweeksoftestingyourbotwhilehuntingcreatureswithnameslikeDragon,Cyclops,Giant,andHound,youdecideit’stimetogiveyourbottoyourfriends.Fortheinauguraluse,yougathereveryonetogethertokillabossnamedSuperBossmanSupreme.TheentireteamsetsthebottoattackthebossfirstandtargetlessercreatureslikeaDemonorGrimReaperwhenthebossgoesoutofrange.

Onceyourteamarrivesattheboss’sdungeon...you’reallslowlyobliterated.

Whatwentwronginthisscenario?Yourgamemustbestoringcreaturenameswithstd::string,notjustasimplecharacterarray.ThenameandnameLengthfieldsincreatureInfoare,infact,partofastd::stringfield,andthenamecharacterarrayisaunionofdataAanddataPmembers.Super

Page 159: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

BossmanSupremeislongerthan15characters,andbecausethebotwasnotawareofthestd::stringimplementation,itdidn’trecognizetheboss.Instead,itconstantlyretargetedsummonedDemoncreatures,effectivelykeepingyoufromtargetingthebosswhileheslowlydrainedyourhealthandsupplies.

DeterminingWhetherDataIsStoredinastd::stringWithoutknowinghowthestd::stringclassisstructured,you’dhavetroubletrackingdownbugslikethehypotheticaloneIjustdescribed.Butpairwhatyou’velearnedherewithexperience,andyoucanavoidthesekindsofbugsentirely.Whenyoufindastringlikenameinmemory,don’tjustassumeit’sstoredinasimplearray.Tofigureoutwhetherastringisinfactastd::string,askyourselfthesequestions:

•Whyisthestringlengthpresentforanull-terminatedstring?Ifyoucan’tthinkofagoodreason,thenyoumayhaveastd::stringonyourhands.

•Dosomecreatures(orothergameelements,dependingonwhatyou’relookingfor)havenameslongerthan16letters,butyoufindroomforonly16charactersinmemory?Ifso,thedataisalmostdefinitelystoredinastd::string.

•Isthenamestoredinplace,requiringthedevelopertousestrcpy()tomodifyit?It’sprobablyastd::string,becauseworkingwithrawCstringsinthiswayisconsideredbadpractice.

Finally,keepinmindthatthereisalsoaclasscalledstd::wstringthatisusedtostorewidestrings.Theimplementationisverysimilar,butwchar_tisusedinplaceofeverychar.

Thestd::vectorClassGamesmustkeeptrackofmanydynamicarraysofdata,butmanagingdynamicallysizedarrayscanbeverytricky.Forspeedandflexibility,gamedevelopersoftenstoresuchdatausingatemplatedSTLclasscalledstd::vectorinsteadofasimplearray.

ExaminingtheStructureofastd::vector

Page 160: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AdeclarationofthisclasslookssomethinglikeListing5-4.

template<typenameT>classvector{T*begin;T*end;T*reservationEnd;};

Listing5-4:Anabstractedstd::vectorobject

Thistemplateaddsanextralayerofabstraction,soI’llcontinuethisdescriptionusingastd::vectordeclaredwiththeDWORDtype.Here’showagamemightdeclarethatvector:

std::vector<DWORD>_vec;

Now,let’sdissectwhatastd::vectorofDWORDobjectswouldlooklikeinmemory.Ifyouhadtheaddressof_vecandsharedthesamememoryspace,youcouldre-createtheunderlyingstructureoftheclassandaccess_vecasshowninListing5-5.

classvector{DWORD*begin;DWORD*end;DWORD*tail;};//pointtoavectorinmemoryvector*_vec=(vector*)vectorAddress;

Listing5-5:ADWORDstd::vectorobject

Youcantreatthememberbeginlikearawarray,asitpointstothefirstelementinthestd::vectorobject.Thereisnoarraylengthmember,though,soyoumustcalculatethevector’slengthbasedonbeginandend,whichisanemptyobjectfollowingthefinalobjectinthearray.Thelengthcalculationcodelookslikethis:

intlength(){return((DWORD)_vec->end-(DWORD)_vec->begin)/sizeof(DWORD);}

Thisfunctionsimplysubtractstheaddressstoredinbeginfromtheaddressstoredinendtofindthenumberofbytesbetweenthem.Then,to

Page 161: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

calculatethenumberofobjects,itdividesthenumberofbytesbythenumberofbytesperobject.

Usingbeginandthislength()function,youcansafelyaccesselementsin_vec.Thatcodewouldlooksomethinglikethis:

DWORDat(intindex){if(index>=_vec->length())thrownewstd::out_of_range();return_vec->begin[index];}

Givenanindex,thiscodewillfetchanitemfromthevector.Butiftheindexisgreaterthanthevector’slength,astd::out_of_rangeexceptionwillbethrown.Addingvaluestoastd::vectorwouldbeveryexpensiveiftheclasscouldn’treserveorreusememory,though.Toremedythis,theclassimplementsafunctioncalledreserve()thattellsthevectorhowmanyobjectstoleaveroomfor.

Theabsolutesizeofastd::vector(itscapacity)isdeterminedthroughanadditionalpointer,whichiscalledtailinthevectorclasswe’vere-created.Thecalculationforthecapacityresemblesthelengthcalculation:

intcapacity(){return((DWORD)_vec->tail-(DWORD)_vec->begin)/sizeof(DWORD);}

Tofindthecapacityofastd::vector,insteadofsubtractingthebeginaddressfromtheendaddress,asyouwouldtocalculatelength,thisfunctionsubtractsthebeginaddressfromtail.Additionally,youcanusethiscalculationathirdtimetodeterminethenumberoffreeelementsinthevectorbyusingtailandendinstead:

intfreeSpace(){return((DWORD)_vec->tail-(DWORD)_vec->end)/sizeof(DWORD);}

Givenpropermemoryreadingandwritingfunctions,youcanusethedeclarationinListing5-4andthecalculationsthatfollowtoaccessandmanipulatevectorsinthememoryofagame.Chapter6discussesreadingmemoryindetail,butfornow,let’slookatwaysyoucandeterminewhetherdatayou’reinterestedinisstoredinastd::vector.

Page 162: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DeterminingWhetherDataIsStoredinastd::vectorOnceyou’vefoundanarrayofdatainagame’smemory,thereareafewstepsyoucanfollowtodeterminewhetheritisstoredinastd::vector.First,youcanbesurethatthearrayisnotstoredinastd::vectorifithasastaticaddress,becausestd::vectorobjectsrequirepointerpathstoaccesstheunderlyingarray.Ifthearraydoesrequireapointerpath,havingafinaloffsetof0wouldindicateastd::vector.Toconfirm,youcanchangethefinaloffsetto4andcheckifitpointstothefinalobjectinthearrayinsteadofthefirstone.Ifso,you’realmostdefinitelylookingatavector,asyou’vejustconfirmedthebeginandendpointers.

Thestd::listClassSimilartostd::vector,std::listisaclassthatyoucanusetostoreacollectionofitemsinalinkedlist.Themaindifferencesarethatstd::listdoesn’trequireacontiguousstoragespaceforelements,cannotdirectlyaccesselementsbytheirindex,andcangrowinsizewithoutaffectinganypreviouselements.Duetotheoverheadrequiredtoaccessitems,itisraretoseethisclassusedingames,butitshowsupinsomespecialcases,whichI’lldiscussinthissection.

ExaminingtheStructureofastd::listThestd::listclasslookssomethinglikeListing5-6.

template<typenameT>classlistItem{listItem<T>*next;listItem<T>*prev;Tvalue;};

template<typenameT>classlist{listItem<T>*root;intsize;};

Listing5-6:Anabstractedstd::listobject

Therearetwoclasseshere:listItemandlist.Toavoidextraabstractionwhileexplaininghowstd::listworks,I’lldescribethisobjectasitwould

Page 163: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

lookwhenthetypeisDWORD.Here’showagamewoulddeclareastd::listoftheDWORDtype:

std::list<DWORD>_lst;

Giventhatdeclaration,thestd::listisstructuredlikethecodeinListing5-7.

classlistItem{listItem*next;listItem*prev;DWORDvalue;};classlist{listItem*root;intsize;};//pointtoalistlist*_lst=(list*)listAddress;

Listing5-7:ADWORDstd::listobject

Theclasslistrepresentsthelistheader,whilelistItemrepresentsavaluestoredinthelist.Insteadofbeingstoredcontiguously,theitemsinthelistarestoredindependently.Eachitemcontainsapointertotheitemthatcomesafterit(next)andtheonethatcomesbeforeit(prev),andthesepointersareusedtolocateitemsinthelist.Therootitemactsasamarkerfortheendofthelist;thenextpointerofthelastitempointstoroot,asdoestheprevpointerofthefirstitem.Therootitem’snextandprevpointersalsopointtothefirstitemandthelastitem,respectively.Figure5-5showswhatthislookslike.

Giventhisstructure,youcanusethefollowingcodetoiterateoverastd::listobject:

Page 164: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure5-5:Astd::listflowchart

//iterateforwardlistItem*it=_lst->root->next;for(;it!=_lst->root;it=it->next)printf("Valueis%d\n",it->value);

//iteratebackwardlistItem*it=_lst->root->prev;for(;it!=_lst->root;it=it->prev)printf("Valueis%d\n",it->value);

Thefirstloopstartsatthefirstitem(root->next)anditeratesforward(it=it->next)untilithitstheendmarker(root).Thesecondloopstartsatthelastitem(root->pres)anditeratesbackward(it=it->prev)untilithitstheendmarker(root).Thisiterationreliesonnextandprevbecauseunlikeobjectsinanarray,objectsinastd::listarenotcontiguous.Sincethememoryofeachobjectinastd::listisnotcontiguous,there’snoquick-and-dirtywaytocalculatethesize.Instead,theclassjustdefinesasizemember.Additionally,theconceptofreservingspacefornewobjectsisirrelevantforlists,sothere’snovariableorcalculationtodeterminealist’scapacity.

DeterminingWhetherGameDataIsStoredinastd::listIdentifyingobjectsstoredinthestd::listclasscanbetricky,butthereareafewhintsyoucanwatchfor.First,itemsinastd::listcannothavestaticaddresses,soifthedatayouseekhasastaticaddress,thenyou’reintheclear.Itemsthatareobviouslypartofacollectionmay,however,bepartofastd::listifthey’renotcontiguousinmemory.

Alsoconsiderthatobjectsinastd::listcanhaveinfinitelylongpointerchains(thinkit->prev->next->prev->next->prev...),andpointerscanningfortheminCheatEnginewillshowmanymoreresultswhenNoLoopingPointersisturnedoff.

Youcanalsouseascripttodetectwhenavalueisstoredinalinkedlist.Listing5-8showsaCheatEnginescriptthatdoesjustthis.

function_verifyLinkedList(address)localnextItem=readInteger(address)or0localpreviousItem=readInteger(address+4)or0localnextItemBack=readInteger(nextItem+4)localpreviousItemForward=readInteger(previousItem)

Page 165: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

return(address==nextItemBackandaddress==previousItemForward)end

functionisValueInLinkedList(valueAddress)foraddress=valueAddress-8,valueAddress-48,-4doif(_verifyLinkedList(address))thenreturnaddressendendreturn0end

localnode=isValueInLinkedList(addressOfSomeValue)if(node>0)thenprint(string.format("ValueinLL,topofnodeat0x0%x",node))end

Listing5-8:Determiningwhetherdataisinastd::listusingaCheatEngineLuascript

There’squiteabitofcodehere,butwhatit’sdoingisactuallyprettysimple.TheisValueInLinkedList()functiontakesanaddressofsomevalueandthenlooksbackwardforupto40bytes(10integerobjects,incasethevalueisinsomelargerstructure),starting8bytesabovetheaddress(twopointersmustbepresent,andtheyare4byteseach).Becauseofmemoryalignment,thisloopiteratesinstepsof4bytes.

Oneachiteration,theaddressispassedtothe_verifyLinkedList()function,whichiswherethemagichappens.Ifwelookatitintermsoflinkedliststructureasdefinedinthischapter,thefunctionsimplydoesthis:

return(node->next->prev==node&&node->prev->next==node)

Thatis,thefunctionbasicallyassumesthememoryaddressit’sgivenpointstoalinkedlist,anditmakessurethesupposednodehasvalidnextandpreviousnodes.Ifthenodesarevalid,theassumptionwascorrectandtheaddressisthatofalinkedlistnode.Ifthenodesdon’texistordon’tpointtotherightlocations,theassumptionwaswrongandtheaddressisnotpartofalinkedlist.

Keepinmindthatthisscriptwon’tgiveyoutheaddressofthelist’srootnodebutsimplytheaddressofthenodecontainingthevalueyou’vegivenit.Toproperlytraversealinkedlist,you’llneedtoscanforavalidpointerpathtotherootnode,soyou’llneeditsaddress.

Page 166: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Findingthataddresscanrequiresomesearchingofmemorydumps,alotoftrialanderror,andatonofheadscratching,butit’sdefinitelypossible.Thebestwaytostartistofollowthechainofprevandnextnodesuntilyoufindanodewithdatathatiseitherblank,nonsensical,orfilledwiththevalue0xBAADF00D(some,butnotall,standardlibraryimplementationsusethisvaluetomarkrootnodes).

Thisinvestigationcanalsobemadeeasierifyouknowexactlyhowmanynodesareinthelist.Evenwithoutthelistheader,youcandeterminetheamountofnodesbycontinuouslyfollowingthenextpointeruntilyouendupbackatyourstartingnode,asinListing5-9.

functioncountLinkedListNodes(nodeAddress)localcounter=0localnext=readInteger(nodeAddress)while(next~=nodeAddress)docounter=counter+1next=readInteger(next)endreturncounterend

Listing5-9:Determiningthesizeofanarbitrarystd::listusingaCheatEngineLuascript

First,thisfunctioncreatesacountertostorethenumberofnodesandavariabletostorethenextnode’saddress.Thewhilelooptheniteratesoverthenodesuntilitendsupbackattheinitialnode.Finally,itreturnsthecountervariable,whichwasincrementedoneveryiterationoftheloop.

FINDTHEROOTNODEWITHASCRIPTIt’sactuallypossibletowriteascriptthatcanfindtherootnode,butI’llleaveitasanoptionalexerciseforyou.Howdoesitwork?Well,therootnodemustbeinthechainofnodes,thelistheaderpointstotheroot,andthesizeofthelistwillimmediatelyfollowtherootinmemory.Giventhisinformation,youcanwriteascriptthatwillsearchforanymemorycontainingapointertooneofthelist’snodes,followedbythesizeofthelist.Moreoftenthannot,thispieceofmemoryisthelistheader,andthenodeitpointstoistherootnode.

Page 167: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thestd::mapClassLikeastd::list,astd::mapuseslinksbetweenelementstoformitsstructure.Uniquetostd::map,however,isthefactthateachelementstorestwopiecesofdata(akeyandavalue),andsortingtheelementsisaninherentpropertyoftheunderlyingdatastructure:ared-blacktree.Thefollowingcodeshowsthestructuresthatcomposeastd::map.

template<typenamekeyT,typenamevalT>structmapItem{mapItem<keyT,valT>*left;mapItem<keyT,valT>*parent;mapItem<keyT,valT>*right;keyTkey;valTvalue;};

template<typenamekeyT,typenamevalT>structmap{DWORDirrelevant;mapItem<keyT,valT>*rootNode;intsize;}

Ared-blacktreeisaself-balancingbinarysearchtree,soastd::mapis,too.IntheSTL’sstd::mapimplementation,eachelement(ornode)inthetreehasthreepointers:left,parent,andright.Inadditiontothepointers,eachnodealsohasakeyandavalue.Thenodesarearrangedinthetreebasedonacomparisonbetweentheirkeys.Theleftpointerofanodepointstoanodewithasmallerkey,andtherightpointerpointstoanodewithalargerkey.Theparentpointstotheuppernode.ThefirstnodeinthetreeiscalledtherootNode,andnodesthatlackchildrenpointtoit.

Visualizingastd::mapFigure5-6showsastd::mapthathasthekeys1,6,8,11,13,15,17,22,25,and27.

Page 168: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure5-6:Ared-blacktree

Thetopnode(holdingthevalue13)ispointedtobytheparentofrootNode.Everythingtotheleftofithasasmallerkey,andeverythingtotherighthasagreaterkey.Thisistrueforanynodeinthetree,andthistruthenablesefficientkey-basedsearch.Whilenotrepresentedintheimage,theleftpointeroftherootnodewillpointtotheleftmostnode(1),andtherightpointerwillpointtotherightmostnode(27).

AccessingDatainastd::mapOnceagain,I’lluseastaticstd::mapdefinitionwhendiscussinghowtoextractdatafromthestructure.Sincethetemplatetakestwotypes,I’llalsousesomepseudotypestokeepthingsobvious.Here’sthedeclarationforthestd::mapobjectI’llreferencefortherestofthesection:

typedefintkeyInt;typedefintvalInt;std::map<keyInt,valInt>myMap;

Withthisdeclaration,thestructureofmyMapbecomes:

Page 169: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

structmapItem{mapItem*left;mapItem*parent;mapItem*right;keyIntkey;valIntvalue;};structmap{DWORDirrelevant;mapItem*rootNode;intsize;}map*_map=(map*)mapAddress;

Therearesomeimportantalgorithmsthatyoumightneedtoaccessthedatainastd::mapstructureinagame.First,blindlyiteratingovereveryiteminthemapcanbeusefulifyoujustwanttoseeallofthedata.Todothissequentially,youcouldwriteaniterationfunctionlikethis:

voiditerateMap(mapItem*node){if(node==_map->rootNode)return;iterateMap(node->left);printNode(node);iterateMap(node->right);}

Afunctiontoiterateoveranentiremapwouldfirstreadthecurrentnodeandcheckwhetherit’stherootNode.Ifnot,itwouldrecurseleft,printthenode,andrecurseright.

Tocallthisfunction,you’dhavetopassapointertotherootNodeasfollows:

iterateMap(_map->rootNode->parent);

Thepurposeofastd::map,however,istostorekeyeddatainaquicklysearchableway.Whenyouneedtolocateanodegivenaspecifickey,mimickingtheinternalsearchalgorithmispreferabletoscanningtheentiretree.Thecodeforsearchingastd::maplookssomethinglikethis:

mapItem*findItem(keyIntkey,mapItem*node){if(node!=_map->rootNode){if(key==node->key)returnnode;elseif(key<node->key)returnfindItem(key,node->left);

Page 170: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

elsereturnfindItem(key,node->right);}elsereturnNULL;}

Startingatthetopofthetree,yousimplyrecurseleftifthecurrentkeyisgreaterthanthesearchkeyandrecurserightifitissmaller.Ifthekeysareequal,youreturnthecurrentnode.Ifyoureachthebottomofthetreeanddon’tfindthekey,youreturnNULLbecausethekeyisn’tstoredinthemap.

Here’sonewayyoumightusethisfindItem()function:

mapItem*ret=findItem(someKey,_map->rootNode->parent);if(ret)printNode(ret);

AslongasfindItem()doesn’treturnNULL,thiscodeshouldprintanodefrom_map.

DeterminingWhetherGameDataIsStoredinastd::mapTypically,Idon’tevenconsiderwhetherdatacouldbeinastd::mapuntilIknowthecollectionisnotanarray,astd::vector,orastd::list.Ifyouruleoutallthreeoptions,thenaswithastd::list,youcanlookatthethreeintegervaluesbeforethevalueandcheckiftheypointtomemorythatcouldpossiblybeothermapnodes.

Onceagain,thiscanbedonewithaLuascriptinCheatEngine.ThescriptissimilartotheoneIshowedforlists,loopingbackwardovermemorytoseeifavalidnodestructureisfoundbeforethevalue.Unlikethelistcode,though,thefunctionthatverifiesanodeismuchtrickier.TakealookatthecodeinListing5-10,andthenI’lldissectit.

function_verifyMap(address)localparentItem=readInteger(address+4)or0

localparentLeftItem=readInteger(parentItem+0)or0localparentRightItem=readInteger(parentItem+8)or0

➊localvalidParent=parentLeftItem==addressorparentRightItem==addressif(notvalidParent)thenreturnfalseend

localtries=0

Page 171: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

locallastChecked=parentItemlocalparentsParent=readInteger(parentItem+4)or0➋while(readInteger(parentsParent+4)~=lastCheckedandtries<200)dotries=tries+1lastChecked=parentsParentparentsParent=readInteger(parentsParent+4)or0end

returnreadInteger(parentsParent+4)==lastCheckedend

Listing5-10:Determiningwhetherdataisinastd::mapusingaCheatEngineLuascript

Givenaddress,thisfunctionchecksifaddressisinamapstructure.Itfirstchecksifthere’savalidparentnodeand,ifso,checkswhetherthatparentnodepointstoaddressoneitherside➊.Butthischeckisn’tenough.Ifthecheckpasses,thefunctionwillalsoclimbupthelineofparentnodesuntilitreachesanodethatistheparentofitsownparent➋,trying200timesbeforecallingitquits.Iftheclimbsucceedsinfindinganodethatisitsowngrandparent,thenaddressdefinitelypointstoamapnode.Thisworksbecause,asIoutlinedin“Visualizingastd::map”onpage114,atthetopofeverymapisarootnodewhoseparentpointstothefirstnodeinthetree,andthatnode’sparentpointsbacktotherootnode.

NOTE

Ibetyoudidn’texpecttorunintothegrandfatherparadoxfromtimetravelwhenreadingagame-hackingbook!

UsingthisfunctionandaslightlymodifiedbacktrackingloopfromListing5-8,youcanautomaticallydetectwhenavalueisinsideamap:

functionisValueInMap(valueAddress)foraddress=valueAddress-12,valueAddress-52,-4doif(_verifyMap(address))thenreturnaddressendendreturn0end

localnode=isValueInMap(addressOfSomeValue)if(node>0)then

Page 172: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

print(string.format("Valueinmap,topofnodeat0x0%x",node))end

Asidefromfunctionnames,theonlychangeinthiscodefromListing5-8isthatitstartslooping12bytesbeforethevalueinsteadof8,becauseamaphasthreepointersinsteadofthetwoinalist.Onegoodconsequenceofamap’sstructureisthatit’seasytoobtaintherootnode.Whenthe_verifyMapfunctionreturnstrue,theparentsParentvariablewillcontaintheaddressoftherootnode.Withsomesimplemodifications,youcouldreturnthistothemaincallandhaveeverythingyouneedtoreadthedatafromastd::mapinoneplace.

ClosingThoughtsMemoryforensicsisthemosttime-consumingpartofhackinggames,anditsobstaclescanappearinallshapesandsizes.Usingpurpose,patterns,andadeepunderstandingofcomplexdatastructures,however,youcanquicklyovercometheseobstacles.Ifyou’restillabitconfusedaboutwhat’sgoingon,makesuretodownloadandplaywiththeexamplecodeprovided,asitcontainsproofsofconceptforallofthealgorithmscoveredinthischapter.

InChapter6,we’llstartdivingintothecodeyouneedtoreadfromandwritetoagame’smemoryfromyourownprogramssoyoucantakethefirststepinputtingtoworkallofthisinformationaboutmemorystructures,addresses,anddata.

Page 173: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

6READINGFROMANDWRITINGTOGAME

MEMORY

EarlierchaptersdiscussedhowmemoryisstructuredaswellashowtoscanandmodifymemoryusingCheatEngineandOllyDbg.Workingwithmemorywillbeessentialwhenyoubegintowritebots,andyourcodewillneedtoknowhowtodoso.

Thischapterdigsintothecode-leveldetailsofmemorymanipulation.First,you’lllearnhowtousecodetolocateandobtainhandlestogameprocesses.Next,you’lllearnhowtousethosehandlestoreadfromandwritetomemorybothfromremoteprocessesandfrominjectedcode.Towrapup,you’lllearnbypassesforacertainmemoryprotectiontechnique,completewithasmallexampleofcodeinjection.You’llfindtheexamplecodeforthischapterintheGameHackingExamples/Chapter6_AccessingMemorydirectoryinthisbook’ssourcefiles.

NOTE

WhenItalkaboutAPIfunctionsinthischapter(andinlaterones),I’mreferringtotheWindowsAPIunlessotherwisespecified.IfIdon’tmentionaheaderfileforthelibrary,youcanassumeitisWindows.h.

Page 174: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ObtainingtheGame’sProcessIdentifierToreadfromorwritetoagame’smemory,youneeditsprocessidentifier(PID),anumberthatuniquelyidentifiesanactiveprocess.Ifthegamehasavisiblewindow,youcanobtainthePIDoftheprocessthatcreatedthatwindowbycallingGetWindowThreadProcessId().Thisfunctiontakesthewindow’shandleasthefirstparameterandoutputsthePIDtothesecondparameter.Youcanfindthewindow’shandlebypassingitstitle(thetextonthetaskbar)asthesecondparametertoFindWindow(),asshowninListing6-1.

HWNDmyWindow=FindWindow(NULL,"Titleofthegamewindowhere");DWORDPID;GetWindowThreadProcessId(myWindow,&PID);

Listing6-1:Fetchingawindow’shandletoobtainaPID

Withthewindowhandlesecured,allyouhavetodoiscreateaplacetostorethePIDandcallGetWindowThreadProcessId(),asshowninthisexample.

Ifagameisn’twindowedorthewindownameisn’tpredictable,youcanfindthegame’sPIDbyenumeratingallprocessesandlookingforthenameofthegamebinary.Listing6-2doesthisusingtheAPIfunctionsCreateToolhelp32Snapshot(),Process32First(),andProcess32Next()fromtlhelp32.h.

#include<tlhelp32.h>

PROCESSENTRY32entry;entry.dwSize=sizeof(PROCESSENTRY32);HANDLEsnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);if(Process32First(snapshot,&entry)==TRUE){while(Process32Next(snapshot,&entry)==TRUE){wstringbinPath=entry.szExeFile;if(binPath.find(L"game.exe")!=wstring::npos){printf("gamepidis%d\n",entry.th32ProcessID);break;}}}CloseHandle(snapshot);

Listing6-2:Fetchingagame’sPIDwithoutthewindowname

Page 175: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Listing6-2mightlookabitmorecomplexthanListing6-1,butunderneathallthatcode,thefunctionisactuallylikeacanonicalfor(iterator;comparator;increment)loop.TheCreateToolhelp32Snapshot()functionobtainsalistofprocessesnamedsnapshot,andentryisaniteratoroverthatlist.ThevaluereturnedbyProcess32First()initializestheiterator,whileProcess32Next()incrementsit.Finally,theBooleanreturnvalueofProcess32Next()isthecomparator.Thiscodejustiteratesoverasnapshotofeveryrunningprocess,looksforonewhosebinarypathcontainsthetextgame.exe,andprintsitsPID.

ObtainingProcessHandlesOnceyouknowagame’sPID,youcanobtainahandletotheprocessitselfusinganAPIfunctioncalledOpenProcess().Thisfunctionallowsyoutofetchhandleswiththeaccesslevelsyouneedtoreadfromandwritetomemory.Thisiscrucialtogamehacking,asanyfunctionthatoperatesonaprocesswillrequireahandlewithproperaccess.

Let’stakealookattheprototypeofOpenProcess():

HANDLEOpenProcess(DWORDDesiredAccess,BOOLInheritHandle,DWORDProcessId);

Thefirstparameter,DesiredAccess,expectsoneoramixtureofprocessaccessflagstosetonthehandlethatOpenProcess()returns.Therearemanyflagsyoucanuse,butthesearethemostcommoningamehacking:

PROCESS_VM_OPERATIONThereturnedhandlecanbeusedwithVirtualAllocEx(),VirtualFreeEx(),andVirtualProtectEx()toallocate,free,andprotectchunksofmemory,respectively.

PROCESS_VM_READThereturnedhandlecanbeusedwithReadProcessMemory().

PROCESS_VM_WRITEThereturnedhandlecanbeusedwithWriteProcessMemory(),butitmustalsohavePROCESS_VM_OPERATIONrights.YoucansetbothflagsbypassingPROCESS_VM_OPERATION|PROCESS_VM_WRITEastheDesiredAccessparameter.

PROCESS_CREATE_THREADThereturnedhandlecanbeusedwithCreateRemoteThread().

Page 176: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PROCESS_ALL_ACCESSThereturnedhandlecanbeusedtodoanything.Avoidusingthisflag,asitcanonlybeusedbyprocesseswithdebugprivilegesenabledandhascompatibilityissueswitholderversionsofWindows.

Whenfetchingahandletoagame,youcantypicallyjustsettheOpenProcess()function’ssecondparameter,InheritHandle,tofalse.Thethirdparameter,ProcessId,expectsthePIDoftheprocesstobeopened.

WorkingwithOpenProcess()Nowlet’swalkthroughanexamplecalltoOpenProcess()thatusesahandlewithaccesspermissionsallowingittoreadfromandwritetomemory:

DWORDPID=getGamePID();HANDLEprocess=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,

FALSE,PID);➊if(process==INVALID_HANDLE_VALUE){printf("FailedtoopenPID%d,errorcode%d",PID,GetLastError());}

First,thecalltogetGamePID()fetchesthePIDyou’relookingfor.(Thefunctionissomethingyou’llhavetowriteyourself,thoughitcouldjustbeoneofthesnippetsIshowedinListings6-1and6-2,fleshedoutintoafullblownfunction.)Then,thecodecallsOpenProcess()withthreeflags:thePROCESS_VM_OPERATIONflaggivesthishandlememoryaccesspermissions,andtheothertwocombinedgiveitreadandwritepermissions.Thisexamplealsocontainsanerror-handlingcase➊,butaslongasyouhavethecorrectPID,youhavevalidaccessflags,andyourcodeisrunningunderthesameorhigherpermissionsasthegame(forexample,ifyoustartyourbotusingRunAsAdmin),thecallshouldneverfail.

Onceyou’redoneusingahandle,cleanitupusingCloseHandle()asfollows:

CloseHandle(process);

Page 177: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CloseHandle(process);

Youcanreusehandlesasmuchasyouwant,soyoucanleaveoneopenuntilyou’recompletelydoneusingitoruntilyourbotisexited.

Nowthatyou’veseenhowtoopenaprocesshandleinpreparationformanipulatinggamememory,let’sdigintohowtoactuallyaccessthememoryofthatprocess.

AccessingMemoryTheWindowsAPIexposestwofunctionsthatarecrucialtomemoryaccess:ReadProcessMemory()andWriteProcessMemory().Youcanusethesefunctionstoexternallymanipulateagame’smemory.

WorkingwithReadProcessMemory()andWriteProcessMemory()Theprototypesforthesetwofunctions(showninListing6-3)resembleeachotherclosely,andyou’llfollowalmostexactlythesamestepstousethem.

BOOLReadProcessMemory(HANDLEProcess,LPVOIDAddress,LPVOIDBuffer,DWORDSize,DWORD*NumberOfBytesRead);BOOLWriteProcessMemory(HANDLEProcess,LPVOIDAddress,LPCVOIDBuffer,DWORDSize,

DWORD*NumberOfBytesWritten);

Listing6-3:ReadProcessMemory()andWriteProcessMemory()prototypes

BothfunctionsexpectProcesstobeaprocesshandleandAddresstobethetargetmemoryaddress.Whenthefunctionisreadingfrommemory,Bufferisexpectedtopointtoanobjectthatwillholdthereaddata.Whenthefunctioniswritingtomemory,Bufferisexpectedtopointtothedatatowrite.Inbothcases,SizedefinesthesizeofBuffer,inbytes.Thefinalparametertobothfunctionsisusedtooptionallyreturnthenumberofbytesthatwereaccessed;youcansafelysetittoNULL.Unlessthefunctionfails,the

Page 178: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

valuereturnedinthefinalparametershouldbeequaltoSize.

AccessingaValueinMemorywithReadProcessMemory()andWriteProcessMemory()ThecodeinListing6-4showshowyoumightusethesefunctionstoaccessavalueinmemory.

DWORDval;ReadProcessMemory(proc,adr,&val,sizeof(DWORD),0);printf("Currentmemvalueis%d\n",val);

val++;

WriteProcessMemory(proc,adr,&val,sizeof(DWORD),0);ReadProcessMemory(proc,adr,&val,sizeof(DWORD),0);printf("Newmemvalueisconfirmedas%d\n",val);

Listing6-4:ReadingfromandwritingtoprocessmemoryusingtheWindowsAPI

Beforecodelikethisappearsinaprogram,youneedtofindthePID(proc)asdescribedin“ObtainingtheGame’sProcessIdentifier”onpage120,aswellasthememoryaddress(adr)youwanttoreadfromorwriteto.Withthosevaluesinplace,theReadProcessMemory()functionstoresafetchedvaluefrommemoryinval.Then,thecodeincrementsvalandreplacestheoriginalvaluebycallingWriteProcessMemory().Afterthewritetakesplace,ReadProcessMemory()iscalledonthesameaddresstoconfirmthenewmemoryvalue.Noticethatvalisn’tactuallyabuffer.Passing&valastheBufferparameterworksbecauseitcanbeapointertoanystaticmemorystructure,aslongasSizematches.

WritingTemplatedMemoryAccessFunctionsOfcourse,theexampleinListing6-4assumesyoualreadyknowwhattypeofmemoryyou’redealingwith,andithardcodesthetypeasDWORD.Tobeaversatilegamehacker,it’sbettertohavesomegenericcodeinyourtoolboxtoavoidduplicatingcodefordifferenttypes.GenericmemoryreadingandwritingfunctionsthatsupportdifferenttypesmightlooklikeListing6-5.

template<typenameT>

Page 179: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

TreadMemory(HANDLEproc,LPVOIDadr){Tval;ReadProcessMemory(proc,adr,&val,sizeof(T),NULL);returnval;}

template<typenameT>voidwriteMemory(HANDLEproc,LPVOIDadr,Tval){WriteProcessMemory(proc,adr,&val,sizeof(T),NULL);}

Listing6-5:Genericmemoryfunctions

ThesefunctionsuseC++templatestoacceptarbitrarytypesasarguments.Theyallowyoutoaccessmemorywithwhatevertypesyoulikeinaverycleanway.Forexample,giventhesereadMemory()andwriteMemory()templatesIjustshowed,youcouldmakethecallsinListing6-6.

DWORDvalue=readMemory<DWORD>(proc,adr);//readwriteMemory<DWORD>(proc,adr,value++);//incrementandwrite

Listing6-6:Callingtemplatedmemoryaccessfunctions

ComparethistothecallstoWriteProcessMemory()andReadProcessMemory()inListing6-4.Thiscodestillreadsavalue,incrementsit,andwritesthenewvaluetomemory.Butsincethetemplatedfunctionsletyouspecifythetypewhenyoucallthem,youdon’tneedanewreadMemory()andwriteMemory()functionforeverydatatypeyoumightneedtoworkwith.That’smuchcleaner,sinceyou’lloftenwanttoworkwithallkindsofdata.

MemoryProtectionWhenmemoryisallocatedbyagame(oranyprogram),itisplacedinapage.Inx86Windows,pagesarechunksof4,096bytesthatstoredata.Becauseallmemorymustbewithinapage,theminimalallocationunitis4,096bytes.Theoperatingsystemcanplacememorychunkssmallerthan4,096bytesasasubsetofanexistingpagethathasenoughuncommittedspace,inanewlyallocatedpage,oracrosstwocontiguouspagesthathavethesameattributes.

Memorychunks4,096bytesorlargerspannpages,wherenis

Page 180: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Theoperatingsystemtypicallylooksforroominexistingpageswhenallocatingmemory,butitallocatesnewpagesondemandifnecessary.

NOTE

It’salsopossibleforlargechunkstospann+1pages,asthere’snoguaranteethatachunkbeginsatthestartofapage.

Theimportantthingtounderstandaboutmemorypagesisthateachpagehasasetofspecificattributes.Mostoftheseattributesaretransparentinusermode,butthere’soneyoushouldbeextraconsciousofwhenworkingwithmemory:protection.

Differentiatingx86WindowsMemoryProtectionAttributesThememory-readingtechniquesyou’velearnedsofarareverybasic.Theyassumethatthememoryyou’reaccessingisprotectedwiththePAGE_READWRITEattribute.Whilethisassumptioniscorrectforvariabledata,othertypesofdataexistonpageswithdifferenttypesofprotection.Table6-1describesthedifferenttypesofmemoryprotectioninx86Windows.

Table6-1:MemoryProtectionTypes

Protectiontype Value Readpermission?

Writepermission?

Executepermission?

Specialpermissions?

PAGE_NOACCESS 0x01 No No No PAGE_READONLY 0x02 Yes No No PAGE_READWRITE 0x04 Yes No No PAGE_WRITECOPY 0x08 Yes Yes No Yes,copyon

writePAGE_EXECUTE 0x10 No No Yes PAGE_EXECUTE_READ 0x20 Yes No Yes

Page 181: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PAGE_EXECUTE_READ 0x20 Yes No Yes PAGE_EXECUTE_READWRITE 0x40 Yes Yes Yes

PAGE_EXECUTE_WRITECOPY 0x80 Yes Yes Yes Yes,copyonwrite

PAGE_GUARD 0x100 No No No Yes,guardpage

IfaprotectiontypeinTable6-1hasaYesinanypermissioncolumn,itmeanstheactioninquestioncanbeperformedonthatpageofmemory.Forexample,ifapageisPAGE_READONLY,thenaprogramcanreadthememoryonthatpage,buttheprogramcannotwritetothatmemory.

Constantstrings,forexample,areusuallystoredwithPAGE_READONLYprotection.Otherconstantdata,suchasvirtualfunctiontablesandamodule’sentirePortableExecutable(PE)header(whichcontainsinformationaboutaprogram,suchasthekindofapplicationitis,libraryfunctionsituses,itssize,andsoon),arealsostoredonread-onlypages.Assemblycode,ontheotherhand,isstoredonpagesprotectedwithPAGE_EXECUTE_READ.

Mostprotectiontypesinvolveonlysomecombinationofread,write,andexecuteprotection.Fornow,youcansafelyignorespecialprotectiontypes;Icoverthemin“SpecialProtectionTypes”onpage126ifyou’recurious,butonlyveryadvancedhackswilleverrequireknowledgeofthem.Thebasicprotectiontypes,though,willbeprevalentinyourgame-hackingadventures.

SPECIALPROTECTIONTYPESTwoprotectiontypesinTable6-1includecopy-on-writeprotection.Whenmultipleprocesseshavepagesofmemorythatareidentical(suchaspageswithmappedsystemDLLs),copy-on-writeprotectionisusedtoconservememory.Theactualdataisstoredinonlyonephysicalplace,andtheoperatingsystemvirtuallymapsallmemorypagescontainingthatdatatothephysicallocation.Ifaprocesssharingthememorymakesachangetoit,acopyofthedatawillbemadeinphysicalmemory,thechangewillbeapplied,andthememorypage(s)forthatprocesswillberemappedtothenewphysical

Page 182: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

memory.Whenacopyonwritehappens,theprotectionforallaffectedpageschangesaccordingly;PAGE_WRITECOPYwillbecomePAGE_READWRITE,andPAGE_EXECUTE_WRITECOPYwillbecomePAGE_EXECUTE_READWRITE.I’vefoundnogamehacking–specificusesforcopy-on-writepages,butit’susefultounderstandthem.

Pagescanalsobecreatedwithguardprotection.Guardedpagesmusthaveasecondaryprotection,definedlikePAGE_GUARD|PAGE_READONLY.Whentheprogramtriestoaccessaguardedpage,theoperatingsystemwillthrowaSTATUS_GUARD_PAGE_VIOLATIONexception.Oncetheexceptionishandled,theguardprotectionisremovedfromthepage,leavingonlythesecondaryprotection.Onewayinwhichtheoperatingsystemusesthistypeofprotectionistodynamicallyexpandthecallstackbyplacingaguardedpageatthetopandallocatingmorememorywhenthatguardedpageishit.Somememoryanalysistoolsplaceguardedpagesafterheapmemorytodetectheapcorruptionbugs.Inthecontextofgamehacking,aguardedpagecanbeusedasatripwirethattellsyouwhenagamemightbeattemptingtodetectyourcodewithinitsmemory.

ChangingMemoryProtectionWhenyouwanttohackagame,you’llsometimesneedtoaccessmemoryinawaythatisforbiddenbythememorypage’sprotection,makingitimportanttobeabletochangememoryprotectionatwill.Luckily,theWindowsAPIprovidestheVirtualProtectEx()functionforthispurpose.Thisisthefunction’sprototype:

BOOLVirtualProtectEx(HANDLEProcess,LPVOIDAddress,DWORDSize,DWORDNewProtect,PDWORDOldProtect);

TheparametersProcess,Address,andSizetakethesameinputastheydointheReadProcessMemory()andWriteProcessMemory()functions.NewProtectshouldspecifythenewprotectionflagsforthememory,andOldProtectcanoptionallypointtoaDWORDwheretheoldprotectionflagswillbestored.

Page 183: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Themostgranularscaleformemoryprotectionisperpage,whichmeansVirtualProtectEx()willsetthenewprotectiontoeverypagethatisonorbetweenAddressandAddress+Size-1.

NOTE

TheVirtualProtectEx()functionhasasistercalledVirtualProtect().Theyworkthesameway,butVirtualProtect()operatesonlyontheprocesscallingitand,thus,doesnothaveaprocesshandleparameter.

Whenyou’rewritingyourowncodetochangememoryprotections,Isuggestmakingitflexiblebycreatingatemplate.AgenericwrappedfunctionforVirtualProtectEx()shouldlooksomethinglikeListing6-7.

template<typenameT>DWORDprotectMemory(HANDLEproc,LPVOIDadr,DWORDprot){DWORDoldProt;VirtualProtectEx(proc,adr,sizeof(T),prot,&oldProt);returnoldProt;}

Listing6-7:Agenericfunctiontochangememoryprotection

Withthistemplateinplace,ifyouwantedto,say,writeaDWORDtoamemorypagewithoutwritepermission,youmightdosomethinglikethis:

protectMemory<DWORD>(process,address,PAGE_READWRITE)writeMemory<DWORD>(process,address,newValue)

First,thissetstheprotectiononthememorytochangetoPAGE_READWRITE.Withwritepermissiongranted,thedoorisopentocallwriteMemory()andchangethedataataddress.

Whenyou’rechangingmemoryprotection,it’sbestpracticetoletthechangepersistonlyaslongasneededandrestoretheoriginalprotectionassoonaspossible.Thisislessefficient,butitensuresthatagamedoesn’tdetectyourbot(forexample,bynoticingthatsomeofitsassemblycodepageshavebecomewritable).

Atypicalwriteoperationonread-onlymemoryshouldlooklikethis:

DWORDoldProt=protectMemory<DWORD>(process,address,PAGE_READWRITE);

Page 184: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

writeMemory<DWORD>(process,address,newValue);protectMemory<DWORD>(process,address,oldProt);

ThiscodecallstheprotectMemory()functionfromListing6-7tochangetheprotectiontoPAGE_READWRITE.ItthenwritesnewValuetothememorybeforechangingtheprotectionbacktooldProt,whichwassettothepage’soriginalprotectionbytheinitialcalltoprotectMemory().ThewriteMemory()functionusedhereisthesameonedefinedinListing6-5.

Afinalimportantpointisthatwhenyou’remanipulatingagame’smemory,it’sentirelypossiblethatthegamewillaccessthememoryatthesametimeasyou.Ifthenewprotectionthatyousetisnotcompatiblewiththeoriginalprotection,thegameprocesswillgetanACCESS_VIOLATIONexceptionandcrash.Forinstance,ifyouchangememoryprotectionfromPAGE_EXECUTEtoPAGE_READWRITE,thegamemighttrytoexecutethecodeonthepage(s)whenthememoryisnotmarkedasexecutable.Inthiscase,you’dwanttoinsteadsetthememoryprotectiontoPAGE_EXECUTE_READWRITEtoensurethatyoucanoperateonthememorywhilestillallowingthegametoexecuteit.

AddressSpaceLayoutRandomizationSofar,I’vedescribedmemoryaddressesasstaticintegersthatchangeonlyasthebinarychanges.ThismodeliscorrectonWindowsXPandearlier.OnlaterWindowssystems,however,memoryaddressesareonlystaticrelativetothebaseaddressofthegamebinary,becausethesesystemsenableafeaturecalledaddressspacelayoutrandomization(ASLR)forsupportedbinaries.WhenabinaryiscompiledwithASLRsupport(enabledbydefaultonMSVC++2010andmanyothercompilers),itsbaseaddresscanbedifferenteverytimeitisrun.Conversely,non-ASLRbinarieswillalwayshaveabaseaddressof0x400000.

NOTE

SinceASLRdoesn’tworkonXP,I’llcall0x400000theXP-base.

DisablingASLRtoSimplifyBotDevelopmentTokeepdevelopmentsimple,youcandisableASLRanduseaddresseswith

Page 185: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Tokeepdevelopmentsimple,youcandisableASLRanduseaddresseswiththetransparentXP-base.Todoso,enterasinglecommandintheVisualStudioCommandPrompt:

>editbin/DYNAMICBASE:NO"C:\path\to\game.exe"

Tore-enableit,enter:

>editbin/DYNAMICBASE"C:\path\to\game.exe"

BypassingASLRinProductionDisablingASLRissuitableforbotdevelopment,butitisano-noforproduction;enduserscannotbeexpectedtoturnoffALSR.Instead,youcanwriteafunctiontodynamicallyrebaseaddressesatruntime.IfyouuseaddresseswiththeXP-base,thecodetodoarebasewouldlooklikethis:

DWORDrebase(DWORDaddress,DWORDnewBase){DWORDdiff=address-0x400000;returndiff+newBase;}

Whenyouknowthebaseaddressofthegame(newBase),thisfunctionallowsyoutoessentiallyignoreASLRbyrebasingaddress.

TofindnewBase,however,youneedtousetheGetModuleHandle()function.WhentheparametertoGetModuleHandle()isNULL,italwaysreturnsahandletothemainbinaryinaprocess.Thefunction’sreturnedtypeisHMODULE,butthevalueisactuallyjusttheaddresswherethebinaryismapped.Thisisthebaseaddress,soyoucandirectlycastittoaDWORDtogetnewBase.Sinceyou’relookingforthebaseaddressinanotherprocess,though,youneedawaytoexecutethefunctioninthecontextofthatprocess.

Todothis,callGetModuleHandle()usingtheCreateRemoteThread()APIfunction,whichcanbeusedtospawnthreadsandexecutecodeinaremoteprocess.IthastheprototypeshowninListing6-8.

HANDLECreateRemoteThread(HANDLEProcess,LPSECURITY_ATTRIBUTESThreadAttributes,DWORDStackSize,LPTHREAD_START_ROUTINEStartAddress,LPVOIDParam,

Page 186: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DWORDCreationFlags,LPDWORDThreadId);

Listing6-8:Afunctionthatspawnsathread

ThespawnedthreadwillstartexecutiononStartAddress,treatingitasasingle-parameterfunctionwithParamasinputandsettingthevaluereturnedasthethreadexitcode.Thisisideal,asthethreadcanbestartedwithStartAddresspointingtotheaddressofGetModuleHandle()andParamsettoNULL.YoucanthenusetheAPIfunctionWaitForSingleObject()towaituntilthethreadisdoneexecutingandgetthereturnedbaseaddressusingtheAPIfunctionGetExitCodeThread().

Onceallofthesethingsaretiedtogether,thecodetogetnewBasefromanexternalbotshouldlooklikeListing6-9.

DWORDnewBase;

//gettheaddressofkernel32.dllHMODULEk32=GetModuleHandle("kernel32.dll");

//gettheaddressofGetModuleHandle()LPVOIDfuncAdr=GetProcAddress(k32,"GetModuleHandleA");if(!funcAdr)funcAdr=GetProcAddress(k32,"GetModuleHandleW");

//createthethreadHANDLEthread=CreateRemoteThread(process,NULL,NULL,(LPTHREAD_START_ROUTINE)funcAdr,NULL,NULL,NULL);

//letthethreadfinishWaitForSingleObject(thread,INFINITE);

//gettheexitcodeGetExitCodeThread(thread,&newBase);

//cleanupthethreadhandleCloseHandle(thread);

Listing6-9:FindingthebaseaddressofagamewithAPIfunctions

TheGetModuleHandle()functionispartofkernel32.dll,whichhasthesamebaseaddressineveryprocess,sofirstthiscodegetstheaddressforkernel32.dll.Sincethebaseaddressofkernel32.dllisthesameinevery

Page 187: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

process,theaddressofGetModuleHandle()willbethesameinthegameasitisintheexternalbot.Giventhebaseaddressofkernel32.dll,thiscodefindstheaddressofGetModuleHandle()easilywiththeAPIfunctionGetProcAddress().Fromthere,itcallstheCreateRemoteThread()functionfromListing6-8,letsthethreaddoitsjob,andfetchestheexitcodetoobtainnewBase.

ClosingThoughtsNowthatyou’veseenhowtomanipulatememoryfromyourowncode,I’llshowyouhowtoapplytheskillsfromPartsIandIItogames.Theseskillsareparamounttotheconceptsyou’llexploreinthecomingchapters,somakesureyouhaveafirmgrasponwhat’shappening.Ifyou’rehavingtrouble,playwiththeexamplecodeasyoureviewconcepts,asitprovidesasafesandboxfortestingandtweakinghowthemethodsinthisandearlierchaptersbehave.

ThewayListing6-9tricksthegameintoexecutingGetModuleHandle()isaformofcodeinjection.Butthat’sjustaglimpseintowhatinjectioncando.Ifyou’reexcitedtolearnmoreaboutit,diveintoChapter7,whichexploresthistopicindetail.

Page 188: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PART3PROCESSPUPPETEERING

Page 189: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

7CODEINJECTION

Imaginebeingabletowalkintoagamecompany’soffice,sitdown,andstartaddingcodetotheirgameclient.Imaginethatyoucandothisforanygameyouwant,wheneveryouwant,andforanyfunctionalityyouwant.Almostanygameryoutalktowillhaveideasonhowtoimproveagame,but,asfarastheyknow,it’sjustapipedream.Butyouknowthatdreamsaremeanttobefulfilled,andnowthatyou’velearnedabitabouthowmemoryworks,you’rereadytostartthrowingtherulesoutthewindow.Usingcodeinjection,youcan,forallintentsandpurposes,becomeaspowerfulasanygame’sdevelopers.

Codeinjectionisameansofforcinganyprocesstoexecuteforeigncodewithinitsownmemoryspaceandexecutioncontext.Itouchedonthistopicpreviouslyin“BypassingASLRinProduction”onpage128,whereIshowedyouhowtoremotelysubvertASLRusingCreateRemoteThread(),butthatexampleonlyscratchedthesurface.Inthefirstpartofthischapter,you’lllearnhowtocreatecodecaves,injectnewthreads,andhijackthreadexecutiontoforcegamestoexecutesmallsnippetsofassemblycode.Inthesecondpart,you’lllearnhowtoinjectforeignbinariesdirectlyintogames,forcingthosegamestoexecuteentireprogramsthatyou’vecreated.

InjectingCodeCaveswithThreadInjection

Page 190: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thefirststeptoinjectingcodeintoanotherprocessiswritingposition-agnosticassemblycode,knownasshellcode,intheformofabytearray.Youcanwriteshellcodetoremoteprocessestoformcodecaves,whichactastheentrypointforanewthreadthatyouwantagametoexecute.Onceacodecaveiscreated,youcanexecuteitusingeitherthreadinjectionorthreadhijacking.I’llshowyouanexampleofthreadinjectioninthissection,andI’llillustratethreadhijackingin“HijackingaGame’sMainThreadtoExecuteCodeCaves”onpage138.

You’llfindexamplecodeforthischapterinthisbook’sresourcefilesinthedirectoryGameHackingExamples/Chapter7_CodeInjection.Openmain-codeInjection.cpptofollowalongasIexplainhowtobuildasimplifiedversionofthefunctioninjectCodeUsingThreadInjection()fromthatfile.

CreatinganAssemblyCodeCaveIn“BypassingASLRinProduction”onpage128,IusedthreadinjectiontocallthefunctionGetModuleHandle()bywayofCreateRemoteThread()andobtainaprocesshandle.Inthatcase,GetModuleHandle()actedasthecodecave;ithadthepropercodestructuretoactastheentrypointforanewthread.Threadinjectionisn’talwaysthateasy,though.

Forexample,sayyouwantyourexternalbottoremotelycallafunctionwithinagame,andthefunctionhasthisprototype:

DWORD__cdeclsomeFunction(inttimes,constchar*string);

Afewthingsmakeremotelycallingthisfunctiontricky.First,ithastwoparameters,meaningyouneedtocreateacodecavethatwillbothsetupthestackandproperlymakethecall.CreateRemoteThread()allowsyoutopassoneargumenttothecodecave,andyoucanaccessthatargumentrelativetoESP,buttheotheronewouldstillneedtobehardcodedintothecodecave.Hardcodingthefirstargument,times,iseasiest.Additionally,you’dneedtomakesurethatthecaveproperlycleansthestack.

NOTE

RecallthatwhenbypassingASLRinChapter6,IusedCreateRemoteThread()tostartnewthreadsbyexecutinganyarbitrarycodeatagivenaddressandpassingthatcodeasingleparameter.That’swhytheseexamplescanpassone

Page 191: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

parameterusingthestack.

Ultimately,thecodecavetoinjectthatcalltosomeFunctionintoarunninggameprocesswouldlooksomethinglikethispseudocode:

PUSHDWORDPTR:[ESP+0x4]//getsecondargfromstackPUSHtimesCALLsomeFunctionADDESP,0x8RETN

Thiscodecaveisalmostperfect,butitcouldbelesscomplex.TheCALLoperationexpectsoneoftwooperands:eitheraregisterwithanabsolutefunctionaddressoranimmediateintegerthatholdsanoffsettoafunction,relativetothereturnaddress.Thismeansyou’dhavetodoabunchofoffsetcalculations,whichcanbetedious.

Tokeepthecavepositionagnostic,modifyittousearegisterinstead,asinListing7-1.

PUSHDWORDPTR:[ESP+0x4]//getsecondargfromstackPUSHtimesMOVEAX,someFunctionCALLEAXADDESP,0x8RETN

Listing7-1:AcodecavetocallsomeFunction

SinceacallerknowsthatafunctionitcallswilloverwriteEAXwithitsreturnvalue,thecallershouldensurethatEAXdoesn’tholdanycriticaldata.Knowingthis,youcanuseEAXtoholdtheabsoluteaddressofsomeFunction.

TranslatingtheAssemblytoShellcodeBecausecodecavesneedtobewrittentoanotherprocess’smemory,theycannotbewrittendirectlyinassembly.Instead,you’llneedtowritethembytebybyte.There’snostandardwaytodeterminewhichbytesrepresentwhichassemblycode,butthereareafewhackyapproaches.MypersonalfavoriteistocompileanemptyC++applicationwiththeassemblycodeinafunctionanduseOllyDbgtoinspectthatfunction.Alternatively,youcouldopenOllyDbgonanyarbitraryprocessandscanthroughthedisassemblyuntilyoufindthebytesforalloftheoperationsyouneed.Thismethodis

Page 192: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

untilyoufindthebytesforalloftheoperationsyouneed.Thismethodisactuallyreallygood,asyourcodecavesshouldbewrittenassimplyaspossible,meaningalloftheoperationsshouldbeverycommon.Youcanalsofindchartsofassemblyopcodesonline,butIfindthatthey’reallprettyhardtoread;themethodsIjustdescribedareeasieroverall.

Whenyouknowwhatyourbytesshouldbe,youcanuseC++toeasilygeneratethepropershellcode.Listing7-2showsthefinishedshellcodeskeletonfortheassemblyinListing7-1.

BYTEcodeCave[20]={0xFF,0x74,0x24,0x04,//PUSHDWORDPTR:[ESP+0x4]0x68,0x00,0x00,0x00,0x00,//PUSH00xB8,0x00,0x00,0x00,0x00,//MOVEAX,0x00xFF,0xD0,//CALLEAX0x83,0xC4,0x08,//ADDESP,0x080xC3//RETN};

Listing7-2:Shellcodeskeleton

ThisexamplecreatesaBYTEarraycontainingtheneededbytesofshellcode.Butthetimesargumentneedstobedynamic,andit’simpossibletoknowtheaddressofsomeFunctionatcompiletime,whichiswhythisshellcodeiswrittenasaskeleton.Thetwogroupsoffoursequential0x00bytesareplaceholdersfortimesandtheaddressofsomeFunction,andyoucaninserttherealvaluesintoyourcodecaveatruntimebycallingmemcpy(),asinthesnippetinListing7-3.

memcpy(&codeCave[5],&times,4);memcpy(&codeCave[10],&addressOfSomeFunc,4);

Listing7-3:InsertingtimesandthelocationofsomeFunctionintothecodecave

BothtimesandtheaddressofsomeFunctionare4byteseach(recallthattimesisanintandaddressesare32-bitvalues),andtheybelongatcodeCave[5-8]andcodeCave[10-13],respectively.Thetwocallstomemcpy()passthisinformationasparameterstofilltheblanksinthecodeCavearray.

WritingtheCodeCavetoMemoryWiththepropershellcodecreated,youcanplaceitinsidethetargetprocess

Page 193: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

usingVirtualAllocEx()andWriteProcessMemory().Listing7-4showsonewaytodothis.

intstringlen=strlen(string)+1;//+1toincludenullterminatorintcavelen=sizeof(codeCave);➊intfulllen=stringlen+cavelen;autoremoteString=//allocatethememorywithEXECUTErights➋VirtualAllocEx(process,0,fulllen,MEM_COMMIT,PAGE_EXECUTE);

autoremoteCave=//keepanoteofwherethecodecavewillgo➌(LPVOID)((DWORD)remoteString+stringlen);

//writethestringfirst➍WriteProcessMemory(process,remoteString,string,stringlen,NULL);

//writethecodecavenext➎WriteProcessMemory(process,remoteCave,codeCave,cavelen,NULL);

Listing7-4:Writingthefinalshellcodetoacodecavememory

First,thiscodedeterminesexactlyhowmanybytesofmemoryitwillneedtowritethestringargumentandthecodecaveintothegame’smemory,anditstoresthatvalueinfulllen➊.Then,itcallstheAPIfunctionVirtualAllocEx()toallocatefulllenbytesinsideofprocesswithPAGE_EXECUTEprotection(youcanalwaysuse0andMEM_COMMIT,respectively,forthesecondandfourthparameters),anditstorestheaddressofthememoryinremoteString➋.ItalsoincrementsremoteStringbystringlenbytesandstorestheresultinremoteCave➌,astheshellcodeshouldbewrittendirectlytothememoryfollowingthestringargument.Finally,itusesWriteProcessMemory()tofilltheallocatedbufferwithstring➍andtheassemblybytes➎storedincodeCave.

Table7-1showshowamemorydumpofthecodecavemightlook,assumingthatitisallocatedat0x030000,someFunctionisat0xDEADBEEF,timesissetto5,andstringispointingtotheinjected!text.

Table7-1:CodeCaveMemoryDump

Address Coderepresentation

Rawdata Datameaning

0x030000 remoteString[0-4]

0x690x6E0x6A0x650x63

injec

Page 194: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

4] 0x63

0x030005 remoteString[5-9] 0x740x650x640x0A0x00

ted!\0

0x03000A remoteCave[0-3] 0xFF0x740x240x04 PUSHDWORDPTR[ESP+0x4]

0x03000E remoteCave[4-8] 0x680x050x000x000x00

PUSH0x05

0x030013 remoteCave[9-13] 0xB80xEF0xBE0xAD0xDE

MOVEAX,0xDEADBEEF

0x030018 remoteCave[14-15] 0xFF0xD0 CALLEAX

0x03001A remoteCave[16-18]

0x830xC40x08 ADDESP,0x08

0x03001D remoteCave[19] 0xC3 RETN

TheAddresscolumnshowswhereeachpieceofthecaveislocatedinmemory;theCoderepresentationcolumntellsyouwhichindexesofremoteStringandremoteCavecorrespondtothebytesintheRawdatacolumn;andtheDatameaningcolumnshowswhatthebytesrepresent,inhuman-readableformat.Youcanseetheinjected!stringat0x030000,thevalueoftimesat0x03000E,andtheaddressofsomeFunctionat0x030014.

UsingThreadInjectiontoExecutetheCodeCaveWithacompletecodecavewrittentomemory,theonlythinglefttodoisexecuteit.Inthisexample,youcouldexecutethecaveusingthefollowingcode:

HANDLEthread=CreateRemoteThread(process,NULL,NULL,(LPTHREAD_START_ROUTINE)remoteCave,remoteString,NULL,NULL);

WaitForSingleObject(thread,INFINITE);CloseHandle(thread);VirtualFreeEx(process,remoteString,fulllen,MEM_RELEASE)

ThecallstoCreateRemoteThread(),WaitForSingleObject(),andCloseHandle()worktoinjectandexecutethecodecave,andVirtalFreeEx()

Page 195: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

coversthebot’stracksbyfreeingthememoryallocatedincodelikeListing7-4.Inthesimplestform,that’sallthereistoexecutingacodecaveinjectedintoagame.Inpractice,youshouldalsocheckreturnvaluesaftercallingVirtualAllocEx(),WriteProcessMemory(),andCreateRemoteThread()tomakesurethateverythingwassuccessful.

Forinstance,ifVirtualAllocEx()returns0x00000000,itmeansthatthememoryallocationfailed.Ifyoudon’thandlethefailure,WriteProcessMemory()willalsofailandCreateRemoteThread()willbeginexecutingwithanentrypointof0x00000000,ultimatelycrashingthegame.ThesameistrueforthereturnvaluesofWriteProcessMemory()andCreateRemoteThread().Typically,thesefunctionswillonlyfailwhentheprocesshandleisopenedwithouttherequiredaccessflags.

HijackingaGame’sMainThreadtoExecuteCodeCavesInsomecases,injectedcodecavesneedtobeinsyncwiththemainthreadofthegameprocess.Solvingthisproblemcanbeverytrickybecauseitmeansthatyoumustcontroltheexistingthreadsinanexternalprocess.

Youcouldsimplysuspendthemainthreaduntilthecodecavefinishesexecuting,whichmightwork,butthatwouldproveveryslow.Theoverheadrequiredtowaitforacodecaveandthenresumeathreadisprettyheavy.Afasteralternativeistoforcethethreadtoexecutethecodeforyou,aprocesscalledthreadhijacking.

NOTE

Openthemain-codeInjection.cppfileinthisbook’ssourcecodefilestofollowalongwithbuildingthisthread-hijackingexample,whichisasimplifiedversionofinjectCodeUsingThreadHijacking().

BuildingtheAssemblyCodeCaveAswiththreadinjection,thefirststeptothreadhijackingisknowingwhatyouwanttohappeninyourcodecave.Thistime,however,youdon’tknow

Page 196: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

whatthethreadwillbeexecutingwhenyouhijackit,soyou’llneedtomakesuretosavethethread’sstatewhenthecodecavestartsandrestorethestatewhenyou’redonehijackingit.Thismeansyourshellcodeneedstobewrappedinsomeassembly,asinListing7-5.

PUSHAD//pushgeneralregisterstothestackPUSHFD//pushEFLAGStothestack

//shellcodeshouldbehere

POPFD//popEFLAGSfromthestackPOPAD//popgeneralregisterstothestack

//resumethethreadwithoutusingregistershere

Listing7-5:Aframeworkforthethread-hijackingcodecave

IfyouweretocallthesamesomeFunctionthatyoudidwiththreadinjection,youcoulduseshellcodesimilartothatinListing7-2.Theonlydifferenceisthatyoucouldn’tpassthesecondparametertoyourbotusingthestackbecauseyouwouldn’tbeusingCreateRemoteThread().Butthat’snoproblem;youcouldjustpushitthesamewayyou’dpushthefirstparameter.ThepartofthecodecavethatexecutesthefunctionyouwanttocallwouldneedtolooklikeListing7-6.

PUSHstringPUSHtimesMOVEAX,someFunctionCALLEAXADDESP,0x8

Listing7-6:AssemblyskeletonforcallingsomeFunction

Allthat’schangedherefromListing7-1isthatthisexamplepushesstringexplicitlyandthere’snoRETN.Youdon’tcallRETNinthiscasebecauseyouwantthegamethreadtogobacktowhateveritwasdoingbeforeyouhijackedit.

Toresumetheexecutionofthethreadnormally,thecaveneedstojumpbacktothethread’soriginalEIPwithoutusingregisters.Fortunately,youcanusetheGetThreadContext()functiontofetchEIP,fillingtheshellcodeskeletoninC++.Thenyoucanpushittothestackinsideyourcodecaveanddoareturn.Listing7-7showshowyourcodecavewouldneedtoend.

PUSHoriginalEIP

Page 197: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PUSHoriginalEIPRETN

Listing7-7:JumpingtoEIPindirectly

Areturnjumpstothevalueonthetopofthestack,sodoingthisimmediatelyafterpushingEIPwilldothetrick.Youshouldusethismethodinsteadofajump,becausejumpsrequireoffsetcalculationandmaketheshellcodeabitmorecomplextogenerate.IfyoutieListings7-5through7-7together,youcomeupwiththefollowingcodecave:

//savestatePUSHAD//pushgeneralregisterstothestackPUSHFD//pushEFLAGStothestack

//doworkwithshellcodePUSHstringPUSHtimesMOVEAX,someFunctionCALLEAXADDESP,0x8

//restorestatePOPFD//popEFLAGSfromthestackPOPAD//popgeneralregisterstothestack

//un-hijack:resumethethreadwithoutusingregistersPUSHoriginalEIPRETN

Next,followtheinstructionsin“TranslatingtheAssemblytoShellcode”onpage135andplugthosebytesintoanarrayrepresentingyourcodecave.

GeneratingSkeletonShellcodeandAllocatingMemoryUsingthesamemethodshowninListing7-2,youcouldgeneratetheshellcodeforthiscave,asshowninListing7-8.

BYTEcodeCave[31]={0x60,//PUSHAD0x9C,//PUSHFD0x68,0x00,0x00,0x00,0x00,//PUSH00x68,0x00,0x00,0x00,0x00,//PUSH00xB8,0x00,0x00,0x00,0x00,//MOVEAX,0x00xFF,0xD0,//CALLEAX0x83,0xC4,0x08,//ADDESP,0x080x9D,//POPFD

Page 198: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

0x61,//POPAD0x68,0x00,0x00,0x00,0x00,//PUSH00xC3//RETN};

//we'llneedtoaddsomecodeheretoplace//thethread'sEIPintothreadContext.Eip

memcpy(&codeCave[3],&remoteString,4);memcpy(&codeCave[8],&times,4);memcpy(&codeCave[13],&func,4);memcpy(&codeCave[25],&threadContext.Eip,4);

Listing7-8:Creatingthethread-hijackingshellcodearray

AsinListing7-3,memcpy()isusedtoputthevariablesintotheskeleton.Unlikeinthatlisting,though,therearetwovariablesthatcannotbecopiedrightaway;timesandfuncareknownimmediately,butremoteStringisaresultofallocationandthreadContext.Eipwillbeknownonlyoncethethreadisfrozen.Italsomakessensetoallocatememorybeforefreezingthethread,becauseyoudon’twantthethreadtobefrozenanylongerthanithastobe.Here’showthismightlook:

intstringlen=strlen(string)+1;intcavelen=sizeof(codeCave);intfulllen=stringlen+cavelen;

autoremoteString=VirtualAllocEx(process,0,fulllen,MEM_COMMIT,PAGE_EXECUTE);autoremoteCave=(LPVOID)((DWORD)remoteString+stringlen);

Theallocationcodeisthesameasitwasforthreadinjection,soyoucanreusethesamesnippet.

FindingandFreezingtheMainThreadThecodetofreezethemainthreadisabittrickier.First,yougetthethread’suniqueidentifier.ThisworksmuchlikegettingaPID,andyoucandoitusingCreateToolhelp32Snapshot(),Thread32First(),andThread32Next()fromTlHelp32.h.Asdiscussedin“ObtainingtheGame’sProcessIdentifier”onpage120,thesefunctionsareusedtoessentiallyiterateoveralist.Aprocesscanhavemanythreads,butthefollowingexampleassumesthatthefirstthreadthegameprocesscreatedistheonethatneedstobehijacked:

Page 199: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DWORDGetProcessThreadID(HANDLEProcess){THREADENTRY32entry;entry.dwSize=sizeof(THREADENTRY32);HANDLEsnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);

if(Thread32First(snapshot,&entry)==TRUE){DWORDPID=GetProcessId(Process);while(Thread32Next(snapshot,&entry)==TRUE){if(entry.th32OwnerProcessID==PID){CloseHandle(snapshot);returnentry.th32ThreadID;}}}CloseHandle(snapshot);returnNULL;}

Thiscodesimplyiteratesoverthelistofallthreadsonthesystemandfindsthefirstonethatmatchesthegame’sPID.Thenitgetsthethreadidentifierfromthesnapshotentry.Onceyouknowthethreadidentifier,fetchthethread’scurrentregisterstatelikethis:

HANDLEthread=OpenThread((THREAD_GET_CONTEXT|THREAD_SUSPEND_RESUME|THREAD_SET_CONTEXT),false,threadID);SuspendThread(thread);

CONTEXTthreadContext;threadContext.ContextFlags=CONTEXT_CONTROL;GetThreadContext(thread,&threadContext);

ThiscodeusesOpenThread()togetathreadhandle.ItthensuspendsthethreadusingSuspendThread()andobtainsthevaluesofitsregistersusingGetThreadContext().Afterthis,thememcpy()codeinListing7-8shouldhaveallofthevariablesitneedstofinishgeneratingtheshellcode.

Withtheshellcodegenerated,thecodecavecanbewrittentotheallocatedmemoryinthesamefashionasinListing7-4:

WriteProcessMemory(process,remoteString,string,stringlen,NULL);WriteProcessMemory(process,remoteCave,codeCave,cavelen,NULL);

Oncethecaveisreadyandwaitinginmemory,allyouneedtodoissetthethread’sEIPtotheaddressofthecodecaveandletthethreadresumeexecution,asfollows:

Page 200: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

threadContext.Eip=(DWORD)remoteCave;threadContext.ContextFlags=CONTEXT_CONTROL;SetThreadContext(thread,&threadContext);ResumeThread(thread);

Thiscodecausesthethreadtoresumeexecutionattheaddressofthecodecave.Becauseofthewaythecodecaveiswritten,thethreadhasnocluethatanythinghaschanged.Thecavestoresthethread’soriginalstate,executesthepayload,restoresthethread’soriginalstate,andthenreturnstotheoriginalcodewitheverythingintact.

Whenyou’reusinganyformofcodeinjection,itisalsoimportanttounderstandwhatdatayourcodecavestouch.Forexample,ifyouweretocreateacodecavethatcallsagame’sinternalfunctionstocreateandsendanetworkpacket,you’dneedtomakesurethatanyglobalvariablesthatthefunctionstouch(likeapacketbuffer,packetpositionmarker,andsoon)aresafelyrestoredonceyou’redone.Youneverknowwhatthegameisdoingwhenyourcodecaveisexecuted—itcouldbecallingthesamefunctionasyou!

InjectingDLLsforFullControlCodecavesareverypowerful(youcanmakeagamedoanythingusingassemblyshellcode),buthandcraftingshellcodeisn’tpractical.ItwouldbemuchmoreconvenienttoinjectC++code,wouldn’tit?That’spossible,buttheprocessisfarmorecomplex:thecodemustbecompiledtoassembly,packagedinaposition-agnosticformat,madeawareofanyexternaldependencies,entirelymappedintomemory,andthenexecutedonsomeentrypoint.

Luckily,allofthesethingsarealreadytakencareofinWindows.BychangingaC++projecttocompileasadynamiclibrary,youcancreateaself-contained,position-agnosticbinarycalledadynamiclinklibrary(DLL).ThenyoucanuseamixofthreadinjectionorhijackingandtheLoadLibrary()APIfunctiontomapyourDLLfileintoagame’smemory.

Openmain-codeInjection.cppintheGameHackingExamples/Chapter7_CodeInjectiondirectoryanddllmain.cppunderGameHackingExamples/Chapter7_CodeInjection_DLLtofollowalongwithsomeexamplecodeasyoureadthissection.Inmain-codeInjection.cpp,lookat

Page 201: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

theLoadDLL()functionspecifically.

TrickingaProcessintoLoadingYourDLLUsingacodecave,youcantrickaremoteprocessintoinvokingLoadLibrary()onaDLL,effectivelyloadingforeigncodeintoitsmemoryspace.BecauseLoadLibrary()takesonlyasingleparameter,youcouldcreateacodecavetocallitasfollows:

//writethedllnametomemorywchar_t*dllName="c:\\something.dll";intnamelen=wcslen(dllName)+1;LPVOIDremoteString=VirtualAllocEx(process,NULL,namelen*2,MEM_COMMIT,PAGE_EXECUTE);WriteProcessMemory(process,remoteString,dllName,namelen*2,NULL);

//gettheaddressofLoadLibraryW()HMODULEk32=GetModuleHandleA("kernel32.dll");LPVOIDfuncAdr=GetProcAddress(k32,"LoadLibraryW");

//createathreadtocallLoadLibraryW(dllName)HANDLEthread=CreateRemoteThread(process,NULL,NULL,(LPTHREAD_START_ROUTINE)funcAdr,remoteString,NULL,NULL);

//letthethreadfinishandcleanupWaitForSingleObject(thread,INFINITE);CloseHandle(thread);

Thiscodeissomewhatamixofthethreadinjectioncodefrom“BypassingASLRinProduction”onpage128andthecodecavecreatedtocallsomeFunctioninListings7-2and7-3.Liketheformer,thisexampleusesthebodyofasingle-parameterAPIfunction,namelyLoadLibrary,asthebodyofthecodecave.Likethelatter,though,ithastoinjectastringintomemory,sinceLoadLibraryexpectsastringpointerasitsfirstargument.Oncethethreadisinjected,itforcesLoadLibrarytoloadtheDLLwhosenamewasinjectedintomemory,effectivelyputtingforeigncodeintoagame.

NOTE

GiveanyDLLyouplantoinjectauniquename,like

Page 202: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MySuperBotV2Hook.dll.Simplernames,suchasHook.dllorInjected.dll,aredangerouslygeneric.IfthenameconflictswithaDLLthatisalreadyloaded,LoadLibrary()willassumethatitisthesameDLLandnotloadit!

OncetheLoadLibrary()codecaveloadsyourDLLintoagame,theDLL’sentrypoint—knownasDllMain()—willbeexecutedwithDLL_PROCESS_ATTACHasthereason.WhentheprocessiskilledorFreeLibrary()iscalledontheDLL,itsentrypointwillbecalledwiththeDLL_PROCESS_DETACHreason.Handlingtheseeventsfromtheentrypointmightlooklikethis:

BOOLAPIENTRYDllMain(HMODULEhModule,DWORDul_reason_for_call,LPVOIDlpReserved){switch(ul_reason_for_call){caseDLL_PROCESS_ATTACH:printf("DLLattached!\n");break;caseDLL_PROCESS_DETACH:printf("DLLdetached!\n");break;}returnTRUE;}

ThisexamplefunctionstartsbycheckingwhyDllMain()wascalled.ItthenoutputstextindicatingwhetheritwascalledbecausetheDLLwasattachedordetached,returningTRUEeitherway.

KeepinmindthattheentrypointofaDLLisexecutedinsidealoaderlock,whichisaglobalsynchronizationlockusedbyallfunctionsthatreadormodifythelistofmodulesloadedinaprocess.ThisloaderlockgetsusedbyfunctionslikeGetModuleHandle(),GetModuleFileName(),Module32First(),andModule32Next(),whichmeansthatrunningnontrivialcodefromaDLLentrypointcanleadtodeadlocksandshouldbeavoided.

IfyouneedtoruncodefromaDLLentrypoint,dosofromanewthread,asfollows:

DWORDWINAPIrunBot(LPVOIDlpParam){//runyourbotreturn1;}

Page 203: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

//dothisfromDllMain()forcaseDLL_PROCESS_ATTACHautothread=CreateThread(NULL,0,&runBot,NULL,0,NULL);CloseHandle(thread);

FromDllMain(),thiscodecreatesanewthreadstartingonthefunctionrunBot().Itthenimmediatelyclosesitshandletothethread,asdoinganyfurtheroperationsfromDllMain()canleadtoseriousproblems.FrominsidethisrunBot(),youcanbeginexecutingyourbot’scode.Thecoderunsinsidethegame,meaningyoucandirectlymanipulatememoryusingthetype-castingmethods.Youcanalsodoalotmore,asyou’llseeinChapter8.

WheninjectingDLLs,makesureyouhavenodependencyissues.IfyourDLLreliesonsomenonstandardDLLs,forexample,youhavetoeitherinjectthoseDLLsintothegamefirstorputtheminafolderthatLoadLibrary()willsearch,suchasanyfolderinthePATHenvironmentvariable.TheformerwillworkonlyiftheDLLshavenodependenciesoftheirown,whereasthelatterisabittrickytoimplementandsubjecttonamecollisions.ThebestoptionistolinkallexternallibrariesstaticallysothattheyarecompileddirectlyintoyourDLL.

AccessingMemoryinanInjectedDLLWhenyou’retryingtoaccessagame’smemoryfromaninjectedDLL,processhandlesandAPIfunctionsareahindrance.Becauseagamesharesthesamememoryspaceasallcodeinjectedintoit,youcanaccessagame’smemorydirectlyfrominjectedcode.Forexample,toaccessaDWORDvaluefrominjectedcode,youcouldwritethefollowing:

DWORDvalue=*((DWORD*)adr);//readaDWORDfromadr*((DWORD*)adr)=1234;//write1234toDWORDadr

ThissimplytypecaststhememoryaddressadrtoaDWORD*anddereferencesthatpointertoaDWORD.Doingtypecastsinplacelikethatisfine,butyourmemoryaccesscodewilllookcleanerifthefunctionsareabstractedandmadegeneric,justliketheWindowsAPIwrappers.

Thegenericfunctionsforaccessingmemoryfrominsideinjectedcodelooksomethinglikethis:

template<typenameT>TreadMemory(LPVOIDadr){return*((T*)adr);

Page 204: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}

template<typenameT>voidwriteMemory(LPVOIDadr,Tval){*((T*)adr)=val;}

Usingthesetemplatesisjustlikeusingthefunctionsunder“WritingTemplatedMemoryAccessFunctions”onpage123.Here’sanexample:

DWORDvalue=readMemory<DWORD>(adr);//readwriteMemory<DWORD>(adr,value++);//incrementandwrite

ThesecallsarenearlyidenticaltothecallsinListing6-6onpage124;theyjustdon’tneedtotaketheprocesshandleasanargumentbecausethey’rebeingcalledfrominsidetheprocessitself.YoucanmakethismethodevenmoreflexiblebycreatingathirdtemplatedfunctioncalledpointMemory(),asfollows:

template<typenameT>T*pointMemory(LPVOIDadr){return((T*)adr);}

Thisfunctionskipsthedereferencingstepofamemoryreadandsimplygivesyouthepointertothedata.Fromthere,you’refreetobothreadfromandwritetothememorybydereferencingthatpointeryourself,likethis:

DWORD*pValue=pointMemory<DWORD>(adr);//pointDWORDvalue=*pValue;//'read'(*pValue)++;//incrementand'write'

WithafunctionlikepointMemory()inplace,youcouldeliminatethecallstoreadMemory()andwriteMemory().You’dstillneedtofindadraheadoftime,butfromthere,thecodetoreadavalue,changeit,andwriteitbackwouldbemuchsimplertofollow.

BypassingASLRinanInjectedDLLSimilarly,sincethecodeisinjected,there’snoneedtoinjectathreadintothegametogetthebaseaddress.Instead,youcanjustcallGetModuleHandle()directly,likeso:

DWORDnewBase=(DWORD)GetModuleHandle(NULL);

Page 205: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DWORDnewBase=(DWORD)GetModuleHandle(NULL);

Afasterwaytogetthebaseaddressistoutilizethegame’sFSmemorysegment,whichisanothersuperpoweryougetfrominjectedcode.Thismemorysegmentpointstoastructurecalledthethreadenvironmentblock(TEB),and0x30bytesintotheTEBisapointertotheprocessenvironmentblock(PEB)structure.Thesestructuresareusedbytheoperatingsystemandcontainatonofdataaboutthecurrentthreadandthecurrentprocess,butwe’reinterestedonlyinthebaseaddressofthemainmodule,whichisstored0x8bytesintothePEB.Usinginlineassembly,youcantraversethesestructurestogetnewBase,likethis:

DWORDnewBase;__asm{MOVEAX,DWORDPTRFS:[0x30]MOVEAX,DWORDPTRDS:[EAX+0x8]MOVnewBase,EAX}

ThefirstcommandstoresthePEBaddressinEAX,andthesecondcommandreadsthemainmodule’sbaseaddressandstoresitinEAX.ThefinalcommandthencopiesEAXtonewBase.

ClosingThoughtsInChapter6,IshowedyouhowtoreadfrommemoryremotelyandhowaninjectedDLLcandirectlyaccessagame’smemoryusingpointers.Thischapterdemonstratedhowtoinjectalltypesofcode,frompureassemblybytecodetoentireC++binaries.Inthenextchapter,you’lllearnjusthowmuchpowerbeinginagame’smemoryspaceactuallygivesyou.Ifyouthoughtassemblycodeinjectionwascool,you’lllovewhatyoucandowhenyoumixinjectedC++withcontrolflowmanipulation.

Theexamplecodeforthischaptercontainsproofsofconceptforeverythingwe’vediscussed.Ifyou’restillunclearaboutanyofthetopics,youcanpokeatthecodetolearnexactlywhat’sgoingonandseeallofthetricksinaction.

Page 206: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

8MANIPULATINGCONTROLFLOWINA

GAME

Forcingagametoexecuteforeigncodeisdefinitelypowerful,butwhatifyoucouldalterthewayagameexecutesitsowncode?Whatifyoucouldforcethegametobypassthecodethatdrawsthefogofwar,trickitintomakingenemiesvisiblethroughwalls,ormanipulatetheargumentsitpassestofunctions?Controlflowmanipulationletsyoudoexactlythat,allowingyoutochangewhataprocessdoesbyinterceptingcodeexecutionandmonitoring,modifying,orpreventingit.

Therearemanywaystomanipulatethecontrolflowofaprocess,butalmostallrequireyoutomodifytheprocess’sassemblycode.Dependingonyourgoals,you’llneedtoeithercompletelyremovecodefromtheprocess(calledNOPing)orforcetheprocesstoredirectexecutiontoinjectedfunctions(calledhooking).Inthebeginningofthischapter,you’lllearnaboutNOPing,severaltypesofhooking,andothercontrolflowmanipulationtechniques.OnceI’veexplainedthebasics,I’llshowyouhowI’veappliedtheseprinciplestocommongamelibrarieslikeAdobeAIRandDirect3D.

OpenthedirectoryGameHackingExamples/Chapter8_ControlFlowinthisbook’sresourcefilestoseethecompletesamplecodeforthenextsectionand“HookingtoRedirectGameExecution”onpage153.

Page 207: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NOPingtoRemoveUnwantedCodeChapter7describedhowtoinjectnewcodeintoagame,buttheopposite—removingcodefromagame—canalsobeuseful.Somehacksrequireyoutostopsomeofagame’soriginalcodefrombeingexecuted,andtodothat,you’llhavetogetridofit.OnewaytoeliminatecodefromagameprocessisNOPing,whichinvolvesoverwritingtheoriginalx86assemblycodewithNOPinstructions.

WhentoNOPConsideragamethatwon’tshowthehealthbarsofcloakedenemies.It’sprettyhardtoseecloakedenemiescoming,andyou’dhaveahugeadvantageincombatifyoucouldatleastseetheirhealthbars.ThecodetodrawhealthbarsoftenlookslikeListing8-1.

for(inti=0;i<creatures.size();i++){autoc=creatures[i];if(c.isEnemy&&c.isCloaked)continue;drawHealthBar(c.healthBar);}

Listing8-1:TheloopfromthedrawCreatureHealthBarExample()function

Whendrawinghealthbars,agamewithcloakedcreaturesmightuseaforlooptocheckwhetherthecreatureswithinthescreen’sboundsarecloaked.Ifanenemyisn’tcloaked,theloopcallssomefunction(drawHealthBar()inthisexample)todisplaytheenemy’shealthbar.

Giventhesourcecode,youcouldforcethegametodrawevencloakedenemies’healthbarsbysimplyremovingif(c.isEnemy&&c.isCloaked)continue;fromthecode.Butasagamehacker,youhaveonlytheassemblycode,notthesourcecode.Whensimplified,theassemblythatListing8-1translatesintolookssomethinglikethispseudocode:

startOfLoop:;forMOVi,0;inti=0JMPcondition;firstloop,skipincrementincrement:ADDi,1;i++condition:CMPi,creatures.Size();i<creatures.size()JNBendOfLoop;exitloopifi>=

Page 208: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

creatures.size()body:MOVc,creatures[i];autoc=creatures[i]TESTc.isEnemy,c.isEnemy;ifc.isEnemyJZdrawHealthBar;drawbarifc.isEnemy==falseTESTc.isCloaked,c.isCloaked;&&c.isCloakedJZdrawHealthBar;drawbarifc.isCloaked==false➊JMPincrement;continuedrawHealthBar:CALLdrawHealthBar(c.healthBar);drawHealthBar(c.healthBar)JMPincrement;continueendOfLoop:

Totrickthegameintodrawingallenemyhealthbars,regardlessofcloaking,you’dneedtoremovetheJMPincrementcommand➊thatexecuteswhenc.isEnemy&&c.isCloakedevaluatestotrue.Inassembly,though,replacingunwantedcodewithinstructionsthatdonothingiseasierthandeletingcode.That’swheretheNOPcommandcomesin.SinceNOPisasinglebyte(0x90),youcanoverwritethe2-byteJMPincrementcommandwithtwoNOPcommands.WhentheprocessorreachesthoseNOPcommands,itrollsoverthemandfallsintodrawHealthBar()evenwhenc.isEnemy&&c.isCloakedevaluatestotrue.

HowtoNOPThefirststeptoNOPingachunkofassemblycodeismakingthememorychunkwherethecodeliveswritable.It’spossibleforthecodeonthesamememorypagetobeexecutedwhileyou’rewritingtheNOPcommands,though,soyoualsowanttomakesurethememoryisstillexecutable.Youcanaccomplishbothofthesetasksbysettingthememory’sprotectiontoPAGE_EXECUTE_READWRITE.Oncethememoryisproperlyprotected,youcanwritetheNOPcommandsandbedone.Ittechnicallydoesn’thurttoleavethememorywritable,butit’sgoodpracticetoalsorestoretheoriginalprotectionwhenyou’refinished.

Providedyouhavefacilitiesinplaceforwritingandprotectingmemory(asdescribedinChapter6),youcanwriteafunctionliketheoneshowninListing8-2towriteNOPcommandstogamememory.(Followalongbyopeningtheproject’sNOPExample.cppfile.)

template<intSIZE>

Page 209: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

voidwriteNop(DWORDaddress){autooldProtection=protectMemory<BYTE[SIZE]>(address,PAGE_EXECUTE_READWRITE);

for(inti=0;i<SIZE;i++)writeMemory<BYTE>(address+i,0x90);

protectMemory<BYTE[SIZE]>(address,oldProtection);}

Listing8-2:ProperNOPing,completewithmemoryprotection

Inthisexample,thewriteNop()functionsetstheappropriatememoryprotection,writesanumberofNOPcommandsequaltoSIZE,andreappliestheoriginalmemoryprotectionlevel.

ThewriteNop()functiontakesthenumberofNOPinstructionstoplaceasatemplateparameter,sincethememoryfunctionsrequireacorrectlysizedtypeatcompiletime.PassinganintegerSIZEtellsthememoryfunctionstooperateonatypeofBYTE[SIZE]atcompiletime.Tospecifyadynamicsizeatruntime,simplydroptheloopandinsteadcallprotectMemory<BYTE>andpassaddressandaddress+SIZEasarguments.Aslongasthesizeisn’tlargerthanapage(andreally,youshouldn’tbeNOPingafullpage),thiswillensurethatthememorygetsproperlyprotectedevenifit’sonapageboundary.

CallthisfunctionwiththeaddresswhereyouwanttoplaceyourNOPsandthenumberofNOPcommandstoplace:

writeNop<2>(0xDEADBEEF);

KeepinmindthatthenumberofNOPcommandsshouldmatchthesizeinbytesofthecommandbeingremoved.ThiscalltowriteNop()writestwoNOPcommandstotheaddress0xDEADBEEF.

PRACTICENOPINGIfyouhaven’talready,openNOPExample.cppinthischapter’sexamplecodenowandplayaroundwithitforabit.You’llfindaworkingimplementationofthewriteNop()functionandaninterestingfunctioncalledgetAddressforNOP()thatscanstheexampleprogram’s

Page 210: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

memorytofindwheretheNOPcommandshouldbeplaced.ToseetheNOPcommandinaction,runthecompiled

NOPapplicationinVisualStudio’sdebuggerwithbreakpointsatthestartandendofthewriteNop()function.Whenthefirstbreakpointishit,pressALT-8toopenthedisassemblywindow,enteraddressintheinputbox,andpressENTER.ThisbringsyoutotheNOP’stargetaddress,whereyou’llseetheassemblycodefullyintact.PressF5tocontinueexecution,whichtriggersthesecondbreakpointafterallowingtheapplicationtoplacetheNOPs.Finally,jumpbacktoaddressinthedisassemblytabtoseethatthecodewasreplacedbyNOPs.

Youcanreworkthiscodetodoothercoolstuff.Forexample,youmighttryplacingNOPsonthecomparisonsinsteadofthejumporevenmodifyingthejump’stypeordestination.

Theseandotheralternativeapproachesmaywork,butnotethattheyintroducemoreroomforerrorthanoverwritingthesingleJMPwithNOPcommands.Whenmodifyingforeigncode,makeasfewchangesaspossibletominimizethepotentialforerrors.

HookingtoRedirectGameExecutionSofar,I’veshownyouhowtomanipulategamesbyaddingcodetothem,hijackingtheirthreads,creatingnewthreads,andevenremovingexistingcodefromtheirexecutionflow.Thesemethodsareverypowerfulontheirown,butwhencombined,theyformanevenmorepotentmethodofmanipulationcalledhooking.Hookingallowsyoutointerceptprecisebranchesofexecutionandredirectthemtoinjectedcodethatyou’vewrittentodictatewhatthegameshoulddonext,anditcomesinavarietyofflavors.Inthissection,I’llteachyouaboutfourofthemostpowerfulhookingmethodsforgamehacking:callhooking,virtualfunctiontablehooking,importaddresstablehooking,andjumphooking.

CallHookingAcallhookdirectlymodifiesthetargetofaCALLoperationtopointtoanew

Page 211: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

pieceofcode.ThereareafewvariationsoftheCALLoperationinx86assembly,butcallhooksaregenerallyusedononlyone:thenearcall,whichtakesanimmediateaddressasanoperand.

WorkingwithNearCallsinMemoryInanassemblyprogram,anearcalllookslikethis:

CALL0x0BADF00D

Thisnearcallisrepresentedbythebyte0xE8,soyoumightassumeitisstoredinmemorylikethis:

0xE80x0BADF00D

Or,whensplitintosinglebytesandswappedforendianness,likethis:

0xE80x0D0xF00xAD0x0B

Buttheanatomyofanearcallinmemoryisnotthatsimple.Insteadofstoringthecallee’sabsoluteaddress,anearcallstoresanoffsettothecalleerelativetotheaddressimmediatelyafterthecall.Sinceanearcallis5bytes,theaddressimmediatelyafterthecallis5byteslaterinmemory.Giventhat,theaddressstoredcanbecomputedasfollows:

calleeAddress–(callAddress+5)

IfCALL0x0BADF00Dlivesat0xDEADBEEFinmemory,thenthevalueafter0xE8isthis:

0x0BADF00D–(0xDEADBEEF+5)=0x2D003119

Inmemory,then,thatCALLinstructionlookslikethis:

0xE80x190x310x000x2D

Tohookanearcall,youfirstneedtochangetheoffsetfollowing0xE8(thatis,thelittle-endian0x190x310x000x2D)topointtoyournewcallee.

HookingaNearCall

Page 212: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

FollowingthesamememoryprotectionrulesshowninListing8-2,youhookanearcalllikeso(followalongbyopeningCallHookExample.cpp):

DWORDcallHook(DWORDhookAt,DWORDnewFunc){DWORDnewOffset=newFunc-hookAt-5;

autooldProtection=protectMemory<DWORD>(hookAt+1,PAGE_EXECUTE_READWRITE);

DWORDoriginalOffset=readMemory<DWORD>(➊hookAt+1);writeMemory<DWORD>(hookAt+1,newOffset);protectMemory<DWORD>(hookAt+1,oldProtection);

➋returnoriginalOffset+hookAt+5;}

ThisfunctiontakesasargumentstheaddressoftheCALLtohook(hookAt)andtheaddresstoredirectexecutionto(newFunc),anditusesthemtocalculatetheoffsetrequiredtocallthecodeattheaddressnewFunccontains.Afteryouapplythecorrectmemoryprotections,thecallHook()functionwritesthenewoffsettothememoryathookAt+1➊,appliestheoldmemoryprotections,calculatestheaddressoftheoriginalcall➋,andreturnsthatvaluetothecaller.

Here’showyoumightactuallyuseafunctionlikethisinagamehack:

DWORDorigFunc=callHook(0xDEADBEEF,(DWORD)&someNewFunction);

Thishooksthenearcallto0x0BADF00Dat0xDEADBEEFandredirectsittotheaddressofsomeNewFunction,whichisthecodeyourhackwillexecute.Afterthisiscalled,theorigFuncvaluewillhold0x0BADF00D.

CleaningUptheStackThenewcalleemustalsoproperlyhandlethestack,preserveregisters,andpassproperreturnvalues.Attheleast,thismeansyourreplacementfunctionmustmatchthegame’soriginalfunctioninbothcallingconventionandargumentcount.

Let’ssaythisistheoriginalfullfunctioncall,inassembly:

PUSH1PUSH456PUSH321

Page 213: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PUSH321CALL0x0BADF00DADDESP,0x0C

YoucantellthefunctionhastheC++__cdeclconventionbecausethestackisbeingresetbythecaller.Additionally,the0x0Cbytesbeingcleanedfromthestackshowthattherearethreearguments,whichyoucancalculateasfollows:

Ofcourse,youcanalsoobtainthenumberofargumentsbycheckinghowmanythingsarepushedtothestack:therearethreePUSHcommands,oneforeachargument.

WritingaCallHookInanycase,thenewcallee,someNewFunction,mustfollowthe__cdeclconventionandhavethreearguments.Here’sanexampleskeletonforthenewcallee:

DWORD__cdeclsomeNewFunction(DWORDarg1,DWORDarg2,DWORDarg3){

}

InVisualStudio,C++programsusethe__cdeclconventionbydefault,sotechnicallyyoucouldomititfromyourfunctiondefinition;however,I’vefoundit’sbettertobeverbosesoyougetintothehabitofbeingspecific.Alsokeepinmindthatifthecallerexpectsavaluetobereturned,thereturntypeofyourfunctionshouldmatchaswell.ThisexampleassumesthereturntypeisalwaysaDWORDorsmaller.SincereturntypesinthissizerangewillallbepassedbackonEAX,furtherexampleswillalsouseareturntypeofDWORD.

Inmostcases,ahookfinishesbycallingtheoriginalfunctionandpassingitsreturnvaluebacktothecaller.Here’showallofthatmightfittogether:

typedefDWORD(__cdecl_origFunc)(DWORDarg1,DWORDarg2,DWORDarg3);

_origFunc*originalFunction=(_origFunc*)hookCall(0xDEADBEEF,(DWORD)&someNewFunction);

DWORD__cdeclsomeNewFunction(DWORDarg1,DWORDarg2,DWORDarg3){

Page 214: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

returnoriginalFunction(arg1,arg2,arg3);}

Thisexampleusestypedeftodeclareatyperepresentingtheoriginalfunction’sprototypeandcreatesapointerwiththistypetotheoriginalfunction.ThensomeNewFunction()usesthispointertocalltheoriginalfunctionwiththeoriginalargumentsandpassthereturnedvaluebacktothecaller.

Rightnow,allsomeNewFunction()doesisreturntotheoriginalfunction.ButyoucandowhateveryouwantfrominsidethesomeNewFunction()callfromhere.Youcanmodifytheparametersbeingpassedtotheoriginalfunctionorinterceptandstoreinterestingparametersforlateruse.Ifyouknowthecallerisn’texpectingareturnvalue(orifyouknowhowtospoofthereturnvalue),youcanevenforgetabouttheoriginalfunctionandcompletelyreplace,replicate,orimproveitsfunctionalityinsidethenewcallee.Onceyou’veperfectedthisskill,youcanaddyourownnativeCorC++codetoanypartofagamethatyouwish.

VFTableHookingUnlikecallhooks,virtualfunction(VF)tablehooksdon’tmodifyassemblycode.Instead,theymodifythefunctionaddressesstoredintheVFtablesofclasses.(IfyouneedarefresheronVFtables,see“AClasswithVirtualFunctions”onpage75.)AllinstancesofthesameclasstypeshareastaticVFtable,soVFtablehookswillinterceptallcallsmadetoamemberfunction,regardlessofwhichclassinstancethegameiscallingthefunctionfrom.Thiscanbebothpowerfulandtricky.

THETRUTHABOUTVFTABLESTosimplifytheexplanation,IliedalittlewhenIsaidthatVFtablehookscouldinterceptallcallsmadetoafunction.Inreality,theVFtableistraversedonlywhenavirtualfunctioniscalledinawaythatleavesthecompilerwithsomeplausibletypeambiguity.Forexample,aVFtablewillbetraversedwhenafunctioniscalledthroughtheinst->function()callformat.AVFtablewon’tbetraversedwhena

Page 215: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

virtualfunctionisinvokedinsuchawaythatthecompilerissureaboutthetype,asininst.function()orsimilarcalls,sincethecompilerwillknowthefunction’saddress.Conversely,callinginst.function()fromascopewhereinstispassedinasareferencewouldtriggeraVFtabletraversal.BeforeyoutrytodeployVFtablehooking,makesurethefunctioncallsyouwanttohookhavetypeambiguity.

WritingaVFTableHookBeforewegoanydeeperintohowtoplaceaVFtablehook,weneedtotalkaboutthosepeskycallingconventionsagain.VFtablesareusedbyclassinstancestocallvirtualmemberfunctions,andallmemberfunctionswillhavethe__thiscallconvention.Thename__thiscallisderivedfromthethispointerthatmemberfunctionsusetoreferencetheactiveclassinstance.Thus,memberfunctionsaregiventhisasapseudoparameteronECX.

It’spossibletomatchtheprototypeofa__thiscallbydeclaringaclassthatactsasacontainerforall__thiscallhookcallbacks,butIdon’tpreferthismethod.Instead,Ifinditeasiertocontrolthedatausinginlineassembly.Let’sexplorehowyoucontrolthedatawhenplacingaVFhookonaclassthatlookslikethis:

classsomeBaseClass{public:virtualDWORDsomeFunction(DWORDarg1){}};classsomeClass:publicsomeBaseClass{public:virtualDWORDsomeFunction(DWORDarg1){}};

ThesomeBaseClassclassjusthasonemember(apublicvirtualfunction),andthesomeClassclassinheritsfromsomeBaseClassandoverridesthesomeBaseClass::someFunctionmember.TohooksomeClass::someFunction,youreplicatetheprototypeinyourVFtablehook,asshowninListing8-3(followalongintheVFHookExample.cppfileoftheproject).

DWORD__stdcallsomeNewVFFunction(DWORDarg1){➊staticDWORD_this;

Page 216: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

__asmMOV_this,ECX}

Listing8-3:ThestartofaVFtablehook

Thisfunctionworksasahookbecause__thiscallonlydiffersfrom__stdcallinthattheformerisgiventhisonECX.Toreconcilethissmalldifference,thecallbackfunctionusesinlineassembly(denotedby__asm)tocopythisfromECXtoastaticvariable➊.Sincethestaticvariableisactuallyinitializedasaglobal,theonlycodethatexecutesbeforeMOV_this,ECXisthecodethatsetsupthestackframe—andthatcodenevertouchesECX.ThatensuresthatthepropervalueisinECXwhentheassemblyisexecuted.

NOTE

IfmultiplethreadsstartcallingthesameVFfunction,thesomeNewVFFunction()hookwillbreakbecause_thismightbemodifiedbyonecallwhilestillbeingusedbyanothercall.I’veneverpersonallyrunintothisproblem,asgamesdon’ttypicallythrowaroundmultipleinstancesofcriticalclassesbetweenthreads,butanefficientremedywouldbetostore_thisinthreadlocalstorage,ensuringeachthreadwouldhaveitsowncopy.

Beforereturning,aVFtablecallbackmustalsorestoreECX,tokeepwiththe__thiscallconvention.Here’showthatprocesslooks:

DWORD__stdcallsomeNewVFFunction(DWORDarg1){staticDWORD_this;__asmMOV_this,ECX

//dogamemodifyingstuffhere

__asm➊MOVECX,_this}

Afterexecutingsomegame-hackingcode,thisversionofthefunctionsomeNewVFFunction()restoresECX➊withareversedversionofthefirstMOVinstructionfromListing8-3.

Unlikewith__cdeclfunctions,however,youshouldn’tcallfunctionsthat

Page 217: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

usethe__thiscallconventionfrompureC++usingonlyafunctionpointerandtypedef(asyouwouldforacallhook).WhencallingtheoriginalfunctionfromaVFtablehook,youmustuseinlineassembly—that’stheonlywaytobesureyou’repassingdata(specifically_this)aroundproperly.Forexample,thisishowyoucontinuetobuildthesomeNewVFFunction()hook:

DWORD__stdcallsomeNewVFFunction(DWORDarg1){staticDWORD_this,_ret;__asmMOV_this,ECX

//dopre-callstuffhere

__asm{PUSHarg1MOVECX,_this➊CALL[originalVFFunction]➋MOV_ret,EAX}

//dopost-callstuffhere

➌__asmMOVECX,_thisreturn_ret;}

Now,someNewVFFunction()storesthisinthe_thisvariable,allowssomecodetoexecute,callstheoriginalgamefunction➊that’sbeinghooked,storesthatfunction’sreturnvaluein_ret➋,allowssomemorecodetoexecute,restoresthistoECX➌,andreturnsthevaluestoredin_ret.Thecalleecleansthestackfor__thiscallcalls,sounlikeacallhook,thepushedargumentdoesn’tneedtoberemoved.

NOTE

Ifyouwanttoremoveasinglepushedargumentatanypoint,usetheassemblyinstructionADDESP,0x4becauseasingleargumentis4bytes.

UsingaVFTableHookWiththecallingconventionestablishedandaskeletoncallbackinplace,it’stimetomoveontothefunpart:actuallyusingaVFtablehook.Apointerto

Page 218: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

timetomoveontothefunpart:actuallyusingaVFtablehook.Apointertoaclass’sVFtableisthefirstmemberofeveryclassinstance,soplacingaVFtablehookrequiresonlyaclassinstanceaddressandtheindexofthefunctiontobehooked.Usingthesetwopiecesofinformation,youneedonlyamodestamountofcodetoplaceahook.Here’sanexample:

DWORDhookVF(DWORDclassInst,DWORDfuncIndex,DWORDnewFunc){DWORDVFTable=➊readMemory<DWORD>(classInst);DWORDhookAt=VFTable+funcIndex*sizeof(DWORD);

autooldProtection=protectMemory<DWORD>(hookAt,PAGE_READWRITE);DWORDoriginalFunc=readMemory<DWORD>(hookAt);writeMemory<DWORD>(hookAt,newFunc);protectMemory<DWORD>(hookAt,oldProtection);

returnoriginalFunc;}

ThehookVF()functionfindstheVFtablebyreadingthefirstmemberoftheclassinstance➊andstoringitinVFTable.SincetheVFtableisjustanarrayofDWORD-sizedaddresses,thiscodefindsthefunctionaddressbymultiplyingthefunction’sindexintheVFtable(funcIndexinthisexample)bythesizeofaDWORD,whichis4,andaddingtheresulttotheVFtable’saddress.Fromthere,hookVF()actssimilartoacallhook:itmakessurethememoryisproperlyaccessiblebysettingappropriateprotections,storestheoriginalfunctionaddressforlater,writesthenewfunctionaddress,andfinally,restorestheoriginalmemoryprotection.

You’lltypicallyhooktheVFtableofaclassinstantiatedbythegame,andcallingafunctionlikehookVF()foraVFtablehooklookslikethis:

DWORDorigVFFunction=hookVF(classInstAddr,0,(DWORD)&someNewVFFunction);

Asusual,youneedtofindclassInstAddrandthefuncIndexargumentaheadoftime.

TherearesomeverynichecasesinwhichVFtablehooksareuseful,anditcanbereallyhardtofindtherightclasspointersandfunctions.Giventhat,insteadofshowingcontrivedusecases,I’llcomebacktoVFtablehooksin“ApplyingJumpHooksandVFHookstoDirect3D”onpage175,onceI’vediscussedothertypesofhooking.

Page 219: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

IfyouwanttoplaywithVFhooksbeforereadingmore,addnewvirtualfunctionstotheexampleclassesinthisbook’sresourcefilesandpracticehookingthem.YoumightevencreateasecondclassthatderivesfromsomeBaseClassandplaceahookonitsvirtualtabletodemonstratehowyoucanhavetwocompletelyseparateVFhooksontwoclassesthatinheritthesamebaseclass.

IATHookingIAThooksactuallyreplacefunctionaddressesinaspecifictypeofVFtable,calledtheimportaddresstable(IAT).EachloadedmoduleinaprocesscontainsanIATinitsPEheader.Amodule’sIATholdsalistofalltheothermodulesonwhichthemoduledepends,aswellasalistoffunctionsthatthemoduleusesfromeachdependency.ThinkofanIATasalookuptableforAPIstocalloneanother.

Whenamoduleisloaded,itsdependenciesarealsoloaded.Dependencyloadingisarecursiveprocessthatcontinuesuntilalldependenciesforallmodulesareloaded.Aseachdependencyisloaded,theoperatingsystemfindsallfunctionsusedbythedependentmoduleandfillsanyblankspacesinitsIATwiththefunctionaddresses.Then,whenamodulecallsafunctionfromadependency,itmakesthatcallbyresolvingthefunction’saddressfromtheIAT.

PayingforPortabilityFunctionaddressesarealwaysresolvedfromtheIATinrealtime,sohookingtheIATissimilartohookingVFtables.SincefunctionpointersarestoredintheIATbesidetheiractualnames,there’snoneedtodoanyreverseengineeringormemoryscanning;aslongasyouknowthenameoftheAPIyouwanttohook,youcanhookit!Moreover,IAThookingletsyoueasilyhookWindowsAPIcallsonamodule-specificbasis,allowingyourhookstointerceptonlyAPIcallsfromagame’smainmodule.

Thisportabilityhasacost,though;thecodetoplaceanIAThookismuchmorecomplexthanwhatyou’veseensofar.First,youneedtolocatethePEheaderofthegame’smainmodule.SincethePEheaderisthefirststructureinanybinary,youcanfinditatthebaseaddressofeachmodule,asshowninListing8-4(followalongintheIATHookExample.cppfileofthe

Page 220: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

project).

DWORDbaseAddr=(DWORD)GetModuleHandle(NULL);

Listing8-4:Fetchingthemodule’sbaseaddress

Onceyou’vefoundthebaseaddress,youmustverifythatthePEheaderisvalid.Thisvalidationcanbeveryimportant,assomegamestrytopreventthesetypesofhooksbyscramblingnonessentialpartsoftheirPEheaderaftertheyload.AvalidPEheaderisprefixedbyaDOSheader,whichindicatesthefileisaDOSMZexecutable;theDOSheaderisidentifiedbythemagicvalue0x5A4D.AmemberoftheDOSheadercallede_lfanewthenpointstotheoptionalheader,whichcontainsvalueslikethesizeofthecode,aversionnumber,andsoonandisidentifiedbythemagicvalue0x10B.

TheWindowsAPIhasPEstructurescalledIMAGE_DOS_HEADERandIMAGE_OPTIONAL_HEADERthatcorrespondtotheDOSheaderandoptionalheader,respectively.YoucanusethemtovalidatethePEheaderwithcodelikeListing8-5.

autodosHeader=pointMemory<IMAGE_DOS_HEADER>(baseAddr);if(dosHeader->e_magic!=0x5A4D)return0;

autooptHeader=pointMemory<IMAGE_OPTIONAL_HEADER>(baseAddr+dosHeader->e_lfanew+24);if(optHeader->Magic!=0x10B)return0;

Listing8-5:ConfirmingtheDOSandoptionalheadersarevalid

ThecallstopointMemory()createpointerstothetwoheadersthatneedtobechecked.Ifeitherif()statementreturns0,thenthecorrespondingheaderhasthewrongmagicnumber,meaningthePEheaderisn’tvalid.

ReferencestotheIATfromassemblyarehardcoded,meaningassemblyreferencesdon’ttraversethePEheadertolocatetheIAT.Instead,eachfunctioncallhasastaticlocationindicatingwheretofindthefunctionaddress.ThatmeansoverwritingthePEheadertosaythattherearenoimportsisaviablewaytoprotectagainstIAThooks,andsomegameshavethisprotection.

Toaccountforthat,youalsoneedtomakesurethegame’sIATstill

Page 221: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

exists.Listing8-6showshowtoaddsuchachecktothecodeinListing8-5.

autoIAT=optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];if(IAT.Size==0||IAT.VirtualAddress==0)return0;

Listing8-6:CheckingthattheIATactuallyexists

ThePEheadercontainsmanysectionsthatstoreinformationabouttheapplication’scode,embeddedresources,relocations,andsoon.ThepieceofcodeinListing8-6isparticularlyinterestedinthedatasection,which—asyoumightguess—storesmanydifferenttypesofdata.Eachtypeofdataisstoredinitsowndirectory,andtheDataDirectorymemberofIMAGE_OPTIONAL_HEADERisanarrayofdirectoryheadersthatdescribesthesizeandvirtualaddressofeachdirectoryinthedatasection.TheWindowsAPIdefinesaconstantcalledIMAGE_DIRECTORY_ENTRY_IMPORT,whichhappenstobetheindexoftheIATheaderwithintheDataDirectoryarray.

Thus,thiscodeusesoptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]toresolvetheheaderoftheIATandcheckthattheheader’sSizeandVirtualAddressarenonzero,essentiallyconfirmingitsexistence.

TraversingtheIATOnceyouknowtheIATisstillintact,youcanstarttraversingit,andthisiswhereIAThookingstartstogetugly.TheIATisanarrayofstructurescalledimportdescriptors.Thereisoneimportdescriptorforeachdependency,eachimportdescriptorpointstoanarrayofstructurescalledthunks,andeachthunkrepresentsafunctionimportedfromthedependency.

Luckily,theWindowsAPIexposesboththeimportdescriptorsandthunksthroughtheIMAGE_IMPORT_DESCRIPTORandIMAGE_THUNK_DATAstructures,respectively.Havingthestructurespredefinedsavesyoufromcreatingyourown,butitdoesn’tmakethecodetotraversetheIATanyprettier.ToseewhatImean,lookatListing8-7,whichbuildsonListings8-4through8-6.

autoimpDesc=pointMemory<IMAGE_IMPORT_DESCRIPTOR>(➊baseAddr+IAT.VirtualAddress);

Page 222: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

➋while(impDesc->FirstThunk){➌autothunkData=pointMemory<IMAGE_THUNK_DATA>(baseAddr+impDesc->OriginalFirstThunk);intn=0;➍while(thunkData->u1.Function){//thehookhappensinheren++;thunkData++;}impDesc++;}

Listing8-7:IteratingovertheIATtofindafunction

KeepinginmindthattheimportdescriptorsarestoredrelativetothestartofthePEheader,thiscodeaddsthemodule’sbaseaddresstothevirtualaddressfoundintheIAT’sdirectoryheader➊,creatingapointer,impDesc,thatpointstothemodule’sfirstimportdescriptor.

Importdescriptorsarestoredinasequentialarray,andadescriptorwithaFirstThunkmembersettoNULLsignifiestheendofthearray.Knowingthis,thecodeusesawhileloop➋thatcontinuesuntilimpDesc->FirstThunkisNULL,incrementingthedescriptorbyexecutingimpDesc++eachiteration.

Foreachimportdescriptor,thecodecreatesapointercalledthunkData➌thatpointstothefirstthunkinsidethedescriptor.Usingafamiliarloop,thecodeiteratesoverthunks➍untiloneisfoundwithaFunctionmembersettoNULL.Theloopalsousesaninteger,n,tokeeptrackofthecurrentthunkindex,astheindexisimportantwhenplacingthehook.

PlacingtheIATHookFromhere,placingthehookisjustamatteroffindingtheproperfunctionnameandreplacingthefunctionaddress.Youcanfindthenameinsidethenestedwhileloop,asshowninListing8-8.

char*importFunctionName=pointMemory<char>(baseAddr+(DWORD)thunkData->u1.AddressOfData+2);

Listing8-8:Findingthefunctionname

ThefunctionnameforeachthunkisstoredatthunkData-

Page 223: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

>u1.AddressOfData+2bytesintothemodule,soyoucanaddthatvaluetothemodule’sbaseaddresstolocatethefunctionnameinmemory.

Afterobtainingapointertothefunctionname,usestrcmp()tocheckwhetherit’sthetargetfunction,likeso:

if(strcmp(importFuncName,funcName)==0){//thefinalstephappensinhere}

Onceyou’velocatedthetargetfunctionusingitsname,yousimplyneedtooverwritethefunctionaddresswiththeaddressofyourownfunction.Unlikefunctionnames,functionaddressesarestoredinanarrayatthestartofeachimportdescriptor.Usingnfromthethunkloop,youcanfinallysetthehook,asshowninListing8-9.

autovfTable=pointMemory<DWORD>(baseAddr+impDesc->FirstThunk);DWORDoriginal=vfTable[n];

➊autooldProtection=protectMemory<DWORD>((DWORD)&vfTable[n],PAGE_READWRITE);➋vfTable[n]=newFunc;protectMemory<DWORD>((DWORD)&vfTable[n],oldProtection);

Listing8-9:Findingthefunctionaddress

ThiscodelocatestheVFtableforthecurrentdescriptorbyaddingtheaddressofthefirstthunktothemodulebaseaddress.TheVFtableisanarrayoffunctionaddresses,sothecodeusesthenvariableasanindextolocatethetargetfunctionaddress.

Oncetheaddressisfound,thecodeinListing8-9worksjustlikeatypicalVFhook:itstorestheoriginalfunctionaddress,setstheprotectionofindexnintheVFtabletoPAGE_READWRITE➊,insertsthenewfunctionaddressintotheVFtable➋,andfinallyrestorestheoldprotection.

IfyoustitchtogetherthecodefromListings8-4through8-9,thefinalIAThookingfunctionlookslikeListing8-10.

DWORDhookIAT(constchar*funcName,DWORDnewFunc){DWORDbaseAddr=(DWORD)GetModuleHandle(NULL);autodosHeader=pointMemory<IMAGE_DOS_HEADER>(baseAddr);if(dosHeader->e_magic!=0x5A4D)return0;

Page 224: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

autooptHeader=pointMemory<IMAGE_OPTIONAL_HEADER>(baseAddr+dosHeader->e_lfanew+24);if(optHeader->Magic!=0x10B)return0;

autoIAT=optHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];if(IAT.Size==0||IAT.VirtualAddress==0)return0;

autoimpDesc=pointMemory<IMAGE_IMPORT_DESCRIPTOR>(baseAddr+IAT.VirtualAddress);

while(impDesc->FirstThunk){autothunkData=pointMemory<IMAGE_THUNK_DATA>(baseAddr+impDesc->OriginalFirstThunk);intn=0;while(thunkData->u1.Function){char*importFuncName=pointMemory<char>(baseAddr+(DWORD)thunkData->u1.AddressOfData+2);if(strcmp(importFuncName,funcName)==0){autovfTable=pointMemory<DWORD>(baseAddr+impDesc->FirstThunk);DWORDoriginal=vfTable[n];autooldProtection=protectMemory<DWORD>((DWORD)&vfTable[n],PAGE_READWRITE);vfTable[n]=newFunc;protectMemory<DWORD>((DWORD)&vfTable[n],oldProtection);returnoriginal;}n++;thunkData++;}impDesc++;}}

Listing8-10:ThecompleteIAThookingfunction

Thisisthemostcomplexcodethatwe’veputtogethersofar,andit’sprettyhardtoreadwhensquishedtofitonapage.Ifyouhaven’tyetwrappedyourheadaroundwhatit’sdoing,youmightwanttostudytheexamplecodefromthisbook’sresourcefilesbeforecontinuing.

Page 225: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

UsinganIATHooktoSyncwithaGameThreadWiththecodeinListing8-10,hookinganyWindowsAPIfunctionisassimpleasknowingthefunctionnameandtheproperprototype.TheSleep()APIisacommonAPItohookwhengamehacking,asbotscanuseaSleep()hooktothread-syncwithagame’smainloop.

GETTINGINSYNCWITHTHREADSYNCYourinjectedcodewillinevitablyhavetosyncwithagame’smainloop,oritwon’twork.Whenyou’rereadingorwritingdatalargerthan4bytes,forexample,beingoutofsyncallowsthegametoreadorwritethatdataatthesametimeasyou.You’llbesteppingonthegame’stoes,andviceversa,leadingtoallsortsofraceconditionsanddatacorruptionissues.Similarly,ifyoutrytocallagame’sfunctionfromyourownthread,youruntheriskofcrashingthegameifthefunctionisnotthreadsafe.

SinceIAThooksarethread-safemodificationstothePEheader,theycanbeplacedfromanythread.Byplacingoneonafunctionthat’scalledbeforeorafterthegame’smainloop,youcaneffectivelysyncwiththegame’smainthread.Allyouneedtodoisplacethehookandexecuteanythread-sensitivecodefromyourhookcallback.

Here’sonewaytousehookIAT()tohooktheSleep()API:

VOIDWINAPInewSleepFunction(DWORDms){//dothread-sensitivethingsoriginalSleep(ms);}

typedefVOID(WINAPI_origSleep)(DWORDms);_origSleep*originalSleep=(_origSleep*)hookIAT("Sleep",(DWORD)&newSleepFunction);

Here’swhythisworks.Attheendofagame’smainloop,itmightcallSleep()torestuntilit’sreadytodrawthenextframe.Sinceit’ssleeping,it’ssafeforyoutodoanythingyouwantwithoutworryingabout

Page 226: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

synchronizationissues.Somegamesmightnotdothis,ortheymightcallSleep()frommultiplethreads,andthosegameswillrequireadifferentmethod.

AmoreportablealternativeistohookthePeekMessageA()APIfunction,becausegamesoftencallthatfunctionfromthemainloopwhilewaitingforinput.Then,yourbotcandothread-sensitiveoperationsfromwithinthePeekMessageA()hook,ensuringthatthey’redonefromthegame’smainthread.Youmayalsowantyourbottousethismethodtohookthesend()andrecv()APIfunctions,asinterceptingtheseallowsyoutocreateapacketsnifferrelativelysimply.

JumpHookingJumphookingallowsyoutohookcodeinplaceswherethereisnobranchingcodetomanipulate.Ajumphookreplacesthecodebeinghookedwithanunconditionaljumptoatrampolinefunction.Whenthejumpishit,thetrampolinefunctionstoresallcurrentregisterandflagvalues,callsacallbackfunctionofyourchoice,restorestheregisters,restorestheflags,executesthecodethatwasreplacedbythehook,andfinallyjumpsbacktothecodejustbelowthehook.ThisprocessisshowninFigure8-1.

Figure8-1:Ajumphook

Theoriginalcodeshowsanexampleofsomeunmodifiedassemblyyoumightfindinagame,andthehookedcodeshowshowthatassemblymightlookafterbeinghookedbyajumphook.Thetrampolineboxshowsanexampletrampolinefunction,inassembly,andthecallbackrepresentsthe

Page 227: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

codeyou’retryingtoexecutethroughhooking.Intheoriginalcode,theassemblyexecutesfromtoptobottom.Inthehookedcode,togetfromtheSUBEAX,1instructiontotheRETNinstruction,executionmustfollowthepathshownbythedashedarrows.

NOTE

Ifyourcallbackcodeissimple,itcanbeintegratedintothetrampolineinstead.It’salsonotalwaysnecessarytostoreandrestoretheregistersandflags,butdoingsoisgoodpractice.

PlacingaJumpThebytecodeofanunconditionaljumpresemblesthatofanearcall,butthefirstbyteis0xE9insteadof0xE8.(See“WorkingwithNearCallsinMemory”onpage153forarefresher.)InFigure8-1,theunconditionaljumpJMPtrampolinereplacesthefollowingfouroperations:

POPEAXMOVAL,1POPEDIPOPESI

Inthiscase,youneedtoreplacemultiplesequentialoperationstoaccommodatethe5-bytesizeoftheunconditionaljump.Youmaycomeacrosscaseswherethesizeoftheoperation(oroperations)beingreplacedislargerthan5bytes.Whenthishappens,replacetheremainingbyteswithNOPinstructions.

Now,let’slookathowtoreplacethoseoperations.Listing8-11showsthecodetoplaceajumphook.

DWORDhookWithJump(DWORDhookAt,DWORDnewFunc,intsize){if(size>12)//shouldn'teverhavetoreplace12+bytesreturn0;➊DWORDnewOffset=newFunc-hookAt-5;

autooldProtection=protectMemory<DWORD[3]>(hookAt+1,PAGE_EXECUTE_READWRITE);➋writeMemory<BYTE>(hookAt,0xE9);➌writeMemory<DWORD>(hookAt+1,newOffset);

Page 228: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

for(unsignedinti=5;i<size;i++)writeMemory<BYTE>(hookAt+i,0x90);protectMemory<DWORD[3]>(hookAt+1,oldProtection);

returnhookAt+5;}

Listing8-11:Howtoplaceajumphook

Thisfunctiontakestheaddresstohookat,theaddressofthecallbackfunction,andthesizeofthememorytooverwrite(inbytes)asarguments.First,itcalculatestheoffsetbetweenthehooksiteandthetrampolineandstorestheresultinnewOffset➊.Next,PAGE_EXECUTE_READWRITEpermissionsareappliedtothememorytobechanged.Theunconditionaljump(0xE9)➋andtheaddressofthecallbackfunction➌arethenwrittentomemory,andaforloopwritesNOPinstructions(0x90)toanyabandonedbytes.Aftertheoldprotectionsarereapplied,hookWithJump()returnstotheoriginaladdress.

NoticethatthehookWithJump()functionensuresthatsizeisnotabove12beforeplacingthejump.Thischeckisimportantbecauseajumptakesup5bytes,meaningitcanreplaceuptofivecommandsifthefirstfourareeachasinglebyte.Ifthefirstfourcommandsareeachasinglebyte,thefifthcommandwouldneedtobemorethan8bytestotriggertheif(size>12)clause.Because9-byteoperationsarevery,veryrare,12isasafebutflexiblelimit.Havingthislimitcanstopallsortsofbugsfromhappening,especiallyifyourbotisdynamicallydetectingthesizeparameter.Ifthebotmessesupandpassesasizeof500,000,000,forinstance,thecheckwillstopyoufromNOPingthewholeuniverse.

WritingtheTrampolineFunctionUsingthefunctioninListing8-11,youcanreplicatethehookshowninFigure8-1,butfirstyou’llhavetocreatethetrampolinefunctionasfollows:

DWORDrestoreJumpHook=0;void__declspec(naked)myTrampoline(){__asm{➊PUSHFD➋PUSHAD➌CALLjumpHookCallback➍POPAD

Page 229: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

➎POPFD➏POPEAXMOVAL,1POPEDI➐POPESI➑JMP[restoreJumpHook]}}

JustlikethetrampolinedescribedalongsideFigure8-1,thistrampolinestoresallcurrentflag➊andregistervalues➋,callsacallbackfunction➌,restorestheregisters➍,restorestheflags➎,executesthecodethatwasreplacedbythehookat➏and➐,andfinallyjumpsbacktotheoriginalcodejustbelowthejumpandNOPs➑.

NOTE

Toensurethatthecompilerdoesn’tautogenerateanyextracodewithinthetrampoline,alwaysdeclarethetrampolineusingthe__declspec(naked)convention.

FinishingtheJumpHookOnceyoucreatethetrampoline,definethecallbackandsetthehooklikeso:

voidjumpHookCallback(){//dostuff}restoreJumpHook=hookWithJump(0xDEADBEEF,&myTrampoline,5);

Finally,insidethejumpHookCallback()function,executethecodethatreliesonthehook.Ifyourcodeneedstoreadorwritethevaluesoftheregistersastheywerewhenthehookexecuted,you’reinluck.ThePUSHADcommandpushesthemtothestackintheorderEAX,ECX,EDX,EBX,originalESP,EBP,ESI,andEDI.ThetrampolinecallsPUSHADdirectlybeforethejumpHookCallback()call,soyoucanreferencetheregistervaluesasarguments,likethis:

voidjumpHookCallback(DWORDEDI,DWORDESI,DWORDEBP,DWORDESP,DWORDEBX,DWORDEDX,DWORDECX,DWORDEAX){//dostuff

Page 230: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}restoreJumpHook=hookWithJump(0xDEADBEEF,&myTrampoline,5);

SincethetrampolineusesPOPADtodirectlyrestoretheregistersfromthesevaluesonthestack,anymodificationsyoumaketotheparameterswillbeappliedtotheactualregisterswhentheyarerestoredfromthestack.

LikeVFtablehooks,jumphooksarerarelyneeded,andtheycanbetrickytosimulatewithasimpleexample.Tohelpyouwrapyourheadaroundthem,I’llexploreareal-world,practicalusecasein“ApplyingJumpHooksandVFHookstoDirect3D”onpage175.

PROFESSIONALAPIHOOKINGLIBRARIESThereareprewrittenhookinglibraries,likeMicrosoft’sDetoursandMadCHook,thatuseonlyjumphooks.Theselibrariescanautomaticallydetectandfollowotherhooks,theyknowhowmanyinstructionstoreplace,andtheygeneratetrampolinefunctionsforyou.Thelibrariesareabletodothisbecausetheyunderstandhowtodisassembleandwalkthroughassemblyinstructionstodeterminelengths,jumpdestinations,andsoon.Ifyouneedtousehookswiththatmuchpower,itisarguablybettertouseoneofthoselibrariesthantocreateyourown.

ApplyingCallHookstoAdobeAIRAdobeAIRisadevelopmentframeworkthatcanbeusedtomakecross-platformgamesinanenvironmentsimilartoAbodeFlash.AIRisacommonframeworkforonlinegames,asitallowsdeveloperstowritecross-platformcodeinaversatile,high-levellanguagecalledActionScript.ActionScriptisaninterpretedlanguage,andAIRrunsthecodeinsideavirtualmachine,whichmakesitinfeasibletohookgame-specificcodewithAIR.Instead,itiseasiertohookAIRitself.

TheexamplecodeforthissectioncanbefoundinGameHackingExamples/Chapter8_AdobeAirHookinthisbook’ssourcefiles.

Page 231: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thecodecomesfromanoldprojectofmine,anditworksonanygamerunningAdobeAIR.dllversion3.7.0.1530.I’vegottenitworkingonotherversionsaswell,butIcan’tguaranteeitwillworkwithmuchnewerormucholderversions,sotreatthisasacasestudy.

AccessingtheRTMPGoldmineTheRealTimeMessagingProtocol(RTMP)isatext-basednetworkprotocolthatActionScriptusestoserializeandsendentireobjectsoverthenetwork.RTMPsitsontopoftheHyperTextTransferProtocol(HTTP),andasecureversion,RTMPS,sitsontopofHTTPSecure(HTTPS).RTMPSallowsgamedeveloperstoeasilysendandreceiveentireobjectinstancesoverasecureconnectionwithlittlecomplication,makingitthenetworkprotocolofchoiceforanygamesrunningonAIR.

NOTE

DatasentoverRTMP/RTMPSisserializedthroughActionMessageFormat(AMF),andparsingAMFpacketsisbeyondthescopeofthisbook.Searchonlinefor“AMF3Parser,”andyou’llfindalotofcodethatdoesit.

DatasentoverRTMPandRTMPSisveryrich.Thepacketscontaininformationaboutobjecttypes,names,andvalues.Thisisagoldmine.Ifyoucaninterceptthisdatainrealtime,youcaninstantaneouslyrespondtochangesingamestate,seeawealthofcriticalinformationwithouteverreadingitfrommemory,andfindusefulpiecesofdatathatyoumightnotevenknowexist.

Awhileback,Iwasworkingonatoolthatrequiredatonofinsightintothestateofagame.Obtainingsuchalargeamountofdatadirectlyfrommemorywouldhavebeenextremelyhard,ifnotimpossible.Aftersomeresearch,IrealizedthatthegamewasusingRTMPStocommunicatewiththeserver,andthatpromptedmetostartdiggingintothisgoldmine.

SinceRTMPSisencrypted,IknewIhadtosomehowhookthecryptographicfunctionsusedbyAIRbeforeIcouldgetanyusabledata.Aftersearchingonline,Ifoundsourcecodeforasmalltoolcalledairlog,createdbyanothergamehackerwho,likeme,wastryingtologpacketssentoverRTMPS.AlthoughthetoolhookedtheexactfunctionsIneeded,thecodewasoutdated,messy,and,worstofall,didn’tworkontheversionof

Page 232: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

codewasoutdated,messy,and,worstofall,didn’tworkontheversionofAIRIwastryingtohook.

Butthatdidn’tmeanitwasuseless.NotonlydidairloghookthetwofunctionsIneeded,butitalsolocatedthembyscanningforcertainbytepatternswithintheAdobeAIRlibrary.Thesebytepatternswerethreeyearsold,though,sotheyweren’tworkinganymore.ThenewerversionsofAdobeAIRhadchangedenoughthattheassemblybyteswerenolongerthesame.Thedifferenceinbyteswasaproblemforthecodeinairlog,butnotforme.

Insideaninlineassemblyblock,youcanspecifyrawbyteswiththefollowingfunctioncall:

_emitBYTE

IfyoureplaceBYTEwith,say,0x03,thecodewillbecompiledinawaythattreats0x03asabyteintheassemblycode,regardlessofwhetherthatmakessense.Usingthistrick,Icompiledthebytearraysbacktoassemblycode.Thecodedidn’tdoanything,anditwasn’tmeantto;usingthistricksimplyallowedmetoattachtomydummyapplicationwithOllyDBGandinspectbytes,whichwereconvenientlypresentedasacleandisassembly.

SincethesebytesrepresentedthecodesurroundingthefunctionsIneeded,so,too,didtheirdisassembly.Thecodewasprettystandardanddidn’tseemlikelytochange,soIturnedmyattentiontotheconstants.Thecodehadafewimmediatevaluespassedasoffsetsincommands.Knowinghowcommonlythesecanchange,Irewiredairlog’spattern-matchingalgorithmtosupportwildcards,updatedthepatternstotreatanyconstantsaswildcards,andthenranthematch.Aftersometweakstothepatternsandabitofdiggingthroughduplicatesearchresults,ItrackeddownthefunctionsIwantedtohook.Iappropriatelynamedthemencode()anddecode()andbeganworkingonatoolsimilartoairlog—butbetter.

HookingtheRTMPSencode()FunctionIdiscoveredthattheencode()function,whichisusedtoencryptthedataforoutgoingpackets,isanonvirtual__thiscall,meaningit’scalledbyanearcall.Moreover,thecallhappensinsidealoop.TheentirelooplookslikeListing8-12,takendirectlyfromtheOllyDBGdisassemblypane.

loop:

Page 233: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MOVEAX,[ESI+3C58]SUBEAX,EDIPUSHEAX➊LEAEAX,[ESI+EDI+1C58]PUSHEAXMOVECX,ESI➋CALLencodeCMPEAX,-1➌JESHORTendLoopADDEDI,EAX➍CMPEDI,[ESI+3C58]JLloopendLoop:

Listing8-12:Theencode()loop

Withabitofanalysisandsomeguidancefromairlog,Ideterminedthattheencode()functioncalledat➊takesabytearrayandbufferlength(let’scallthembufferandsize,respectively)asparameters.Thefunctionreturns-1whenitfailsandreturnssizeotherwise.Thefunctionoperatesonchunksof4,096bytes,whichiswhythishappensinaloop.

Turnedintomorereadablepseudocode,theloopcallingencode()lookslikethis(thenumbersrefertotherelevantassemblyinstructionsinListing8-12):

for(EDI=0;EDI<➍[ESI+3C58];){EAX=➋encode(➊&[ESI+EDI+1C58],[ESI+3C58]-EDI);if(EAX==-1)➌break;EDI+=EAX;}

Iwasn’tinterestedinwhatencode()did,butIneededtheentirebufferitwasloopingover,andhookingencode()wasmymeansofgettingthatbuffer.LookingattherealloopinListing8-12,Iknewthatthecallingobjectinstance’sfullbufferwasstoredatESI+0x1C58,thatthefullsizewasstoredatESI+0x3C58,andthatEDIcontainedtheloopcounter.Idevisedthehookwiththesethingsinmind,ultimatelycreatingatwo-parthook.

ThefirstpartofmyhookwasareportEncode()functionthatlogstheentirebufferonthefirstloopiteration.Here’sthereportEncode()functioninfull:

DWORD__stdcallreportEncode(

Page 234: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

constunsignedchar*buffer,unsignedintsize,unsignedintloopCounter){if(loopCounter==0)printBuffer(buffer,size);returnorigEncodeFunc;}

Thisfunctiontakesbuffer,size,andloopCounterasparametersandreturnstheaddressofthefunctionIdubbedencode().Beforefetchingthataddress,however,thesecondpartofmyhook,amyEncode()function,doesallofthedirtyworktoobtainbuffer,size,andloopCounter,asfollows:

void__declspec(naked)myEncode(){__asm{MOVEAX,DWORDPTRSS:[ESP+0x4]//getbufferMOVEDX,DWORDPTRDS:[ESI+0x3C58]//getfullsizePUSHECX//storeecxPUSHEDI//pushcurrentpos(loopcounter)PUSHEDX//pushsizePUSHEAX//pushbufferCALLreportEncode//reporttheencodecallPOPECX//restoreecxJMPEAX//jumptoencode}}

ThemyEncode()functionisapureassemblyfunctionthatreplacestheoriginalencode()functioncallusinganearcallhook.AfterstoringECXonthestack,myEncode()obtainsbuffer,size,andloopCounterandpassesthemtothereportEncode()function.AftercallingthereportEncode()function,themyEncode()functionrestoresECXandjumpsdirectlyintoencode(),causingtheoriginalfunctiontoexecuteandreturngracefullytotheloop.

SincemyEncode()cleanseverythingitusesfromthestack,thestackstillcontainstheoriginalparametersandreturnaddressinthecorrectspotaftermyEncode()runs.That’swhymyEncode()jumpsdirectlyintoencode()insteadofusingafunctioncall:thatstackisalreadysetupwiththeproperreturnaddressandparameters,sotheencode()functionwillthinkeverythinghappenedasnormal.

HookingtheRTMPSdecode()Function

Page 235: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ThefunctionInameddecode(),whichisusedtodecryptincomingdata,wasalsoa__thiscallthatwascalledinaloop.Itworkedonchunksof4,096bytesandtookabufferandsizeasparameters.Theloopwasquiteabitmorecomplex,containingmultiplefunctioncalls,nestedloops,andloopescapes,buthookingworkedmuchthesameashookingtheso-calledencode()function.Thereasonfortheaddedcomplexityisnotrelevanttohookingthefunction,butitmakesthecodedifficulttosummarize,soIwon’tshowtheoriginalfunctionhere.Thebottomlineisthis:onceallthecomplexitywasrubbedaway,thedecode()loopwastheencode()loopinreverse.

Onceagain,Idevisedatwo-partnearcallhook.Thefirstpart,reportDecode(),isshownhere:

void__stdcallreportDecode(constunsignedchar*buffer,unsignedintsize){printBuffer(buffer,size);}

Thefunctionlogseachpacketthatcomesthrough.Ididn’thavealoopindexatthetime,soIdecidedthatitwasokaytologeverysinglepartialpacket.

Thesecondpartofthehook,themyDecode()function,actsasthenewcalleeanddoesallofthedirtywork,asfollows:

void__declspec(naked)myDecode(){__asm{MOVEAX,DWORDPTRSS:[ESP+0x4]//getbufferMOVEDX,DWORDPTRSS:[ESP+0x8]//getsizePUSHEDX//pushsizePUSHEAX//pushbuffer➊CALL[origDecodeFunc]

MOVEDX,DWORDPTRSS:[ESP+0x4]//getthebuffer

PUSHEAX//storeeax(returnvalue)PUSHECX//storeecxPUSHEAX//pushsizePUSHEDX//pushbufferCALLreportDecode//reporttheresultsnowPOPECX//restoreecx➋POPEAX//restoreeax(returnvalue)

Page 236: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

➌RETN8//returnandcleanstack}}

Iknewthebufferwasdecryptedinplace,meaningtheencryptedchunkwouldbeoverwrittenwiththedecryptedoneoncethecalltodecode()wascomplete.ThismeantthatmyDecode()hadtocalltheoriginaldecode()function➊beforecallingthereportDecode()function,whichwouldgivetheresultsofthedecoding.Ultimately,myDecode()alsoneededtoreturnwiththesamevaluethattheoriginaldecode()functionwouldandcleanupthestack,andthefinalPOP➋andRETN➌instructionstookcareofthat.

PlacingtheHooksThenextproblemIranintowasthatthehookswereforcodeinsidethemoduleAdobeAIR.dll,whichwasnotthemainmoduleofthegame.Becauseofthecode’slocation,Ineededtofindthebaseaddressesforthehooksabitdifferently.Additionally,sinceIneededthesehookstoworkacrossafewdifferentversionsofAdobeAIR,Ialsohadtofindtherightaddressesforeachversion.InsteadoftryingtogetmyhandsonallofthedifferentversionsofAdobeAIR,Itookanotherpageoutofairlog’splaybookanddecidedtoprogrammaticallylocatetheaddressesbywritingasmallmemoryscanner.BeforeIcouldwritethememoryscanner,IneededboththebaseaddressandsizeofAdobeAIR.dllsoIcouldlimitmymemorysearchtoonlythatarea.

IfoundthesevaluesusingModule32First()andModule32Next()asfollows:

MODULEENTRY32entry;entry.dwSize=sizeof(MODULEENTRY32);HANDLEsnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,NULL);

DWORDbase,size;if(Module32First(snapshot,&entry)==TRUE){➊while(Module32Next(snapshot,&entry)==TRUE){std::wstringbinaryPath=entry.szModule;➋if(binaryPath.find("AdobeAIR.dll")!=std::wstring::npos){size=(DWORD)entry.modBaseSize;base=(DWORD)entry.modBaseAddr;break;}

Page 237: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}}

CloseHandle(snapshot);

ThiscodeloopsthroughallmodulesintheprocessuntilitfindsAdobeAIR.dll➊.Whenitfindsthecorrectmoduleentry➋,itfetchesthemodBaseSizeandmodBaseAddrpropertiesfromitandbreaksoutimmediately.

ThenextstepwasfindingasequenceofbytesIcouldusetoidentifythefunctions.Idecidedtousethebytecodesurroundingeachcall.Ialsohadtomakesurethateachsequencewasuniquewhileavoidingtheuseofanyconstantsinthepatternstoensurethecode’sportability.Listing8-13showsthebytesequencesIendedupwith.

constcharencodeSeq[16]={0x8B,0xCE,//MOVECX,ESI0xE8,0xA6,0xFF,0xFF,0xFF,//CALLencode0x83,0xF8,0xFF,//CMPEAX,-10x74,0x16,//JESHORTendLoop0x03,0xF8,//ADDEDI,EAX0x3B,0xBE};//partofCMPEDI,[ESI+0x3C58]constchardecodeSeq[12]={0x8B,0xCE,//MOVECX,ESI0xE8,0x7F,0xF7,0xFF,0xFF,//CALLdecode0x83,0xF8,0xFF,//CMPEAX,-10x89,0x86};//partofMOV[ESI+0x1C54],EAX

Listing8-13:Theencode()anddecode()bytesequences

NoticetheCALLinstructionineachpattern;thesearethecallstotheAdobeAIRfunctionsInamedencode()anddecode().Iscannedforthesesequenceswiththefollowingfunction:

DWORDfindSequence(DWORDbase,DWORDsize,constchar*sequence,unsignedintseqLen){for(DWORDadr=base;adr<=base+size–seqLen;adr++){if(memcmp((LPVOID)sequence,(LPVOID)adr,seqLen)==0)returnadr;}return0;}

TreatingthememoryofAdobeAIR.dllasabytearray,thefindSequence()functionlooksforasequenceofbytesasasubsetofthatbytearrayand

Page 238: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

returnstheaddressofthefirstmatchitfinds.WiththefindSequence()functionwritten,findingtheaddressesIneededtohookencode()anddecode()wassimple.Here’showthosecallslooked:

DWORDencodeHookAt=findSequence(base,size,encodeSeq,16)+2;DWORDdecodeHookAt=findSequence(base,size,decodeSeq,12)+2;

Sinceeachtargetcallwas2bytesintoitsreceptivesearchsequence,allIhadtodowaslocateeachsequenceandadd2.Afterthat,thefinalstepwastoplacethehooksusingthemethoddescribedin“CallHooking”onpage153.

Withmyhookfinished,Icouldseeeverysinglepieceofdatathatwentbetweenthegame’sclientandserver.Moreover,sincetheRTMPSprotocolsendsserializedActionScriptobjects,thedatawasbasicallyself-documenting.Everysinglepieceofinformationwasaccompaniedbyavariablename.Everyvariableexistedasamemberofawell-describedobject.Everyobjecthadaconsistentname.LikeIsaid—itwasagoldmine.

ApplyingJumpHooksandVFHookstoDirect3DUnliketheAdobeAIRhookIjustdescribed,hooksforDirect3D(the3DgraphicscomponentofMicrosoft’sDirectXAPI)areverycommonandhighlydocumented.Direct3Disubiquitousintheworldofgaming:amajorityofPCgamesusethelibrary,whichmeansthathookingitgivesyouaverypowerfulmethodforinterceptingdataandmanipulatingthegraphicslayersofmanydifferentgames.YoucanuseaDirect3Dhookforanumberoftasks,suchasdetectinglocationsofhiddenenemyplayers,increasingthelightingofdarkin-gameenvironments,andseamlesslydisplayingadditionalgraphicalinformation.MakingeffectiveuseofaDirect3DhookrequiresyoutolearnabouttheAPI,butthere’smorethanenoughinformationinthisbooktogetyoustarted.

Inthissection,I’llgiveyouahigh-levelintroductiontoagameloopthatusesDirect3DbeforedivingrightintotheimplementationofaDirect3Dhook.RatherthandetailingtheinternalsandgivingyoutheanalyticalbackstoryasIdidwiththeAdobeAIRhook,I’llgooverthemostpopularDirect3Dhookmethod,asitiswelldocumentedandusedbythemajorityof

Page 239: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Direct3Dhookmethod,asitiswelldocumentedandusedbythemajorityofgamehackers.

Theonlineresourcesforthisbookincludetwopiecesofexamplecodeforthissection;findthosefilesnowifyouwanttofollowalong.Thefirstpart,anexampleDirect3D9applicationforyoutohackon,canbefoundunderGameHackingExamples/Chapter8_Direct3DApplication.Thesecondpart,theactualhook,isunderChapter8_Direct3DHook.

TherearemultipleversionsofDirect3Dinuseatanygiventime,andtherearewaystohookeachone.Forthisbook,I’llfocusonhookingDirect3D9,becauseitistheonlycommonlyusedversionthatissupportedbyWindowsXP.

NOTE

EventhoughXPhasreachedendoflife,manypeopleinlessdevelopedcountriesstilluseitasaprimarygamingsystem.Direct3D9worksonallversionsofWindowsandisnearlyaspowerfulasitssuccessors,somanygamecompaniesstillprefertouseitovernewerversionsthatdon’thaveasmuchbackwardcompatibility.

TheDrawingLoopLet’sjumprightinwithacrashcourseonhowDirect3Dworks.InsideaDirect3Dgame’ssourcecode,you’llfindaninfiniteloopthatprocessesinputandrendersgraphics.Eachiterationinthisdrawingloopiscalledaframe.Ifwecutoutalltheextraneouscodeandfocussimplyonabareskeleton,wecanvisualizeagame’smainloopwiththefollowingcode:

intWINAPIWinMain(args){/*SomecodeherewouldbecalledtosetupDirect3Dandinitializethegame.Leavingitoutforbrevity.*/MSGmsg;while(TRUE){/*Somecodewouldbeheretohandleincomingmouseandkeyboardmessages.*/drawFrame();//thisisthefunctionwecareabout}/*Somecodeherewouldbecalledtocleanupeverythingbeforeexiting.*/}

Page 240: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thisfunctionistheentrypointofthegame.Simplyput,itinitializesthegameandthenentersthegame’smainloop.Insidethemainloop,itexecutescoderesponsibleforprocessinguserinputbeforecallingdrawFrame()toredrawthescreenusingDirect3D.(CheckoutthecodeinGameHackingExamples/Chapter8_Direct3DApplicationtoseeafullyfunctionalgameloop.)

Eachtimeitiscalled,thedrawFrame()functionredrawstheentirescreen.Thecodelookssomethinglikethis:

voiddrawFrame(){➊device->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);device->BeginScene();//drawingwillhappenheredevice->EndScene();device->Present(NULL,NULL,NULL,NULL);}

Afterclearingthescreenwithdevice->Clear➊,thedrawFrame()functioncallsdevice->BeginScene()tounlockthescenefordrawing.Itthenexecutessomedrawingcode(whatthatdrawingcodeactuallydoesisn’timportantrightnow)andlocksthescenewithadevice->EndScene()call.Tofinishup,itrendersthescenetothescreenbycallingthedevice->Present()function.

Noticethatallofthesefunctionsarecalledasmembersofsomeinstancecalleddevice.ThisissimplyanobjectinstancerepresentingtheDirect3Ddevice,whichisusedtoinvokeallsortsofdrawingcalls.Also,noticethatthisfunctionisdevoidofanyactualdrawingcode,butthat’sokay.It’sreallyonlyimportantforyoutounderstandthehigh-levelconceptsofdrawingloops,frames,andtheDirect3Ddevice.Torecap,gameshaveamainloopwithtworesponsibilities:

•Handlingincomingmessages

•Drawingthegametothescreen

Eachiterationinthisloopiscalledaframe,andeachframeisdrawnbyadevice.Takingcontrolofthedevicegivesyouaccesstothemostsensitiveanddescriptivedetailsofthegame’sstate;thatis,you’llbeabletopeekintothegame’sstateafterthedatahasbeenparsed,processed,andrenderedtothescreen.Moreover,you’llbeabletomodifytheoutputofthisstate.These

Page 241: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thescreen.Moreover,you’llbeabletomodifytheoutputofthisstate.Thesetwosuperpowersenableyoutopulloffallkindsofawesomehacks.

FindingtheDirect3DDeviceTotakecontrolofaDirect3Ddevice,youhookthememberfunctionsinthedevice’sVFtable.Unfortunately,however,usingtheDirect3DAPItoinstantiateyourowninstanceofthesamedeviceclassfrominjectedcodedoesn’tmeanyou’llshareaVFtablewiththegame’sinstance.Direct3DdevicesuseacustomizedruntimeimplementationofVFtables,andeachdevicegetsitsownuniqueVFtable.Additionally,devicessometimesrewritetheirownVFtables,removinganyhooksandrestoringtheoriginalfunctionaddresses.

BothoftheseDirect3Dquirksleaveyouwithoneinevitableoption:youmustfindtheaddressofthegame’sdeviceandmodifyitsVFtabledirectly.Here’show:

1. CreateaDirect3DdeviceandtraverseitsVFtabletolocatethetrueaddressofEndScene().

2. PlaceatemporaryjumphookonEndScene().

3. Whenthejumphookcallbackisexecuted,storetheaddressofthedevicethatwasusedtocallthefunction,removethehook,andrestoreexecutionnormally.

4. Fromthere,useVFhookstohookanymemberfunctionoftheDirect3Ddevice.

JumpHookingEndScene()SinceeverydevicewillcallEndScene()attheendofeachframe,youcanhookEndScene()usingajumphookandinterceptthegame’sdevicefromyourhookcallback.UniquedevicesmayhavetheirownuniqueVFtables,butthedifferenttablesstillpointtothesamefunctions,soyoucanfindtheaddressofEndScene()intheVFtableofanyarbitrarydevice.UsingstandardDirect3DAPIcalls,youcancreateyourowndevicelikethis:

LPDIRECT3D9pD3D=Direct3DCreate9(D3D_SDK_VERSION);if(!pD3D)return0;

Page 242: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

D3DPRESENT_PARAMETERSd3dpp;ZeroMemory(&d3dpp,sizeof(d3dpp));d3dpp.Windowed=TRUE;d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;d3dpp.hDeviceWindow=hWnd;

LPDIRECT3DDEVICE9device;HRESULTres=pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&device);if(FAILED(res))return0;

ExplaininghoweverythinginDirect3Dworksisoutsidethescopeofthisbook,sojustknowthatyoucancopythiscodetocreateaDirect3DdevicethatcontainstheEndScene()functionasamember.TheEndScene()addressisatindex42intheVFtableofdevice(see“TheMeaningofDevice,Direct3D,andVFHooks”boxtolearnhowtofindthatindex),andyoucanreaditusingasubsetoftheVFtablehookingcodefrom“UsingaVFTableHook”onpage159,asfollows:

DWORDgetVF(DWORDclassInst,DWORDfuncIndex){DWORDVFTable=readMemory<DWORD>(classInst);DWORDhookAddress=VFTable+funcIndex*sizeof(DWORD);returnreadMemory<DWORD>(hookAddress);}DWORDEndSceneAddress=getVF((DWORD)device,42);

Onceyou’veobtainedtheaddress,yourdiscoverydevicehasserveditspurpose,anditcanbedestroyedwithacalltotheRelease()function:

pD3D->Release();device->Release();

WiththeaddressofEndScene()inhand,you’dbereadytostartthinkingabouthowtoplaceyourhookinmemory.Butsinceyoujusthaveafunctionaddress,youronlyoptionistoplaceajumphookatthetopofthefunction.

THEMEANINGOFDEVICE,DIRECT3D,ANDVF

Page 243: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

HOOKSIfyou’rewonderinghowIknowthattheindexoftheEndScene()functionis42,you’vecometotherightbox.SinceDirect3D9isafreelyavailablelibrary,youcanactuallyseequiteabitofwhatgoesonunderthehood.Themainheaderfileforthelibraryisd3d9.h.Ifyouopenthisfileinyoureditorandsearchfor“EndScene,”you’llendupinthemiddleofalargeclassdefinitionthatspecifiesseveralfunctionsusingCmacros.ThisisthebaseclassforallDirect3D9deviceimplementations,anditdefinesthevirtualfunctionsusedbytheclass.

TheVFtableisconstructedinthesameorderasthefunctionsaredefinedincode,soyoucandeterminetheindexofanymemberfunctionbysimplycountingthelines.Youcanscrolltothetopoftheclassdefinition(atline426inmyversionofthelibrary,andprobablyyourstoo),notethelinewherethefirstfunctionisdeclared(line429),andthenscrolltotheEndScene()definitionandnotethatline(line473).Finally,countthenumberofblankorcommentedlines(twoforme)anddosomemath:473–429–2=42.

Presto!TheEndScene()functionisthe43rdfunctiondeclared,soitsitsatthe42ndspotintheVFtable.Anotheradvantagetohavingthisheaderisthatyoucanseethename,argumenttypes,argumentnames,andreturntypeofeverysinglefunctioninthedeviceclass.Sowhenyou’rewritingyourownhooksinthefuture,you’llknowexactlywheretolook.

PlacingandRemovingtheJumpHookSinceyou’rejustusingthehooktofindthedevice,youneedtocallitonlyonce.Afterobtainingthedevice,you’llremovethejumphookandrestoreexecutionbacktothestartofEndScene()sothatthedrawingloopcancarryonitswork.Believeitornot,thismakesyourlifemucheasier.Sincethecodewillberestoredimmediately,there’snoneedforyourtrampolinetoexecutethecommandsthatarereplacedbythejump,andthere’snoneedtopadthejumpwithNOPs.Allyouneedtodoisstoretheoriginalbytesandplacethehook.Todoso,youuseaslightlytweakedversionofthejump-hookingcodefromListing8-11:

Page 244: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

unsignedchar*hookWithJump(DWORDhookAt,DWORDnewFunc){DWORDnewOffset=newFunc-hookAt-5;➊autooldProtection=protectMemory<BYTE[5]>(hookAt,PAGE_EXECUTE_READWRITE);unsignedchar*originals=newunsignedchar[5];for(inti=0;i<5;i++)➋originals[i]=readMemory<unsignedchar>(hookAt+i);➌writeMemory<BYTE>(hookAt,0xE9);writeMemory<DWORD>(hookAt+1,newOffset);protectMemory<BYTE[5]>(hookAt,oldProtection);returnoriginals;}

LikethefunctioninListing8-11,thisfunctionmakesthememorywritable➊,placesthehook➌,andrestoresthememoryprotection.Beforeplacingthehook,itallocatesa5-bytebuffercalledoriginals➋andfillsitwiththeoriginalbytes.Afterthehookisplaced,itreturnsoriginalstothecallingfunction.

Whenit’stimetoremovethehook,passoriginalstothefollowingfunction:

voidunhookWithJump(DWORDhookAt,unsignedchar*originals){autooldProtection=protectMemory<BYTE[5]>(hookAt,PAGE_EXECUTE_READWRITE);for(inti=0;i<5;i++)writeMemory<BYTE>(hookAt+i,originals[i]);protectMemory<BYTE[5]>(hookAt,oldProtection);delete[]originals;}

Thiscodesimplyiteratesoveroriginalsandquietlyplacesthose5bytesbackwheretheywerefoundsothateverythingisasexpectedwhenexecutionreturnstotheEndScene()function.Whenthetimecomes,youcanplaceandremoveyouractualhookusingtwolinesofcode,likethis:

autooriginals=hookWithJump(EndSceneAddress,(DWORD)&endSceneTrampoline);unhookWithJump(EndSceneAddress,originals);

OnceyouhavethehookWithJump()andunhookWithJump()functions,it’stimetopreparethecallbackandfindthedevice.

Page 245: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

WritingtheCallbackandTrampolineEventhoughyoucanobtaintheEndScene()addressfromaVFtable,theEndScene()functiondoesn’tactuallyfollowthe__thiscallconvention.Direct3DclassesaresimplewrappersaroundaCAPI,andallofthememberfunctioncallsareforwardedto__stdcallfunctionsthattakeaclassinstanceasafirstparameter.Thismeansthatyourtrampolineonlyneedstograbthedevicefromthestack,passittothecallback,andthenjumpbacktoEndScene().Thecallbackonlyhastoremovethejumphookbeforereturningtothetrampoline.

Thefinalcodeforthecallbackandtrampolinetothisjumphooklookssomethinglikethis:

LPDIRECT3DDEVICE9discoveredDevice;DWORD__stdcallreportInitEndScene(LPDIRECT3DDEVICE9device){discoveredDevice=device;unhookWithJump(EndSceneAddress,originals);returnEndSceneAddress;}__declspec(naked)voidendSceneTrampoline(){__asm{MOVEAX,DWORDPTRSS:[ESP+0x4]PUSHEAX//givethedevicetothecallback➊CALLreportInitEndSceneJMPEAX//jumptothestartofEndScene}}

UsingthehookWithJump()function,youcanplaceajumphookonEndScene()thatcallstheendSceneTrampoline()function.Whenthegame’sdevicecallstheEndScene()function,thetrampolinefunctioncallsthereportInitEndScene()function➊.ThereportInitEndScene()functionstoresthecaptureddevicepointertoaglobalvariablecalleddiscoveredDevice,removesthehookbycallingunhookWithJump(),andreturnstheaddressofEndScene()tothetrampoline.Tofinishup,thetrampolinejumpsdirectlytoEAX,whichwillbeholdingtheaddressthatwasreturnedfromthereportingfunction.

NOTE

Page 246: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

YoucanusejumphookstocompletelyskiptheVFtablehookingthatI’llshowyou,butit’sveryunreliabletouse“dumb”jumphooksoncommonlyhookedAPIfunctions.Consistentlyobtaininggoodresultswithonlyjumphooksrequiresprofessionalhookinglibraries,andI’dratherteachyouhowtodoitcompletelyonyourown.

Atthispoint,allthat’slefttodoishooktheVFtableofdiscoveredDevicetohackthegame.ThenexttwosectionswillwalkyouthroughhooksontheEndScene()andReset()functions,whicharerequiredifyouwantastablehook.

WritingaHookforEndScene()AhookonEndScene()isusefulbecauseitallowsyoutointerceptacompletedframejustbeforeitisrendered;youcaneffectivelyexecuteyourownrenderingcodeinsidethegameloop.Asyousawwhenlocatingthisfunction’saddressin“JumpHookingEndScene()”onpage178,thisfunctionisatindex42intheVFtable.YoucanhookEndScene()usingaVFhookasfollows:

typedefHRESULT(WINAPI*_endScene)(LPDIRECT3DDEVICE9pDevice);_endSceneorigEndScene=(_endScene)hookVF((DWORD)discoveredDevice,42,(DWORD)&myEndScene);HRESULTWINAPImyEndScene(LPDIRECT3DDEVICE9pDevice){//drawyourownstuffherereturnorigEndScene(pDevice);}

ThiscodeusesthehookVF()functionfrom“UsingaVFTableHook”onpage159tohookEndScene()atindex42ofdiscoveredDevice,usingmyEndScene()asthecallbackfunction.AdirectDirect3DdevicewilloccasionallyrepatchitsownVFtableandrestoretheoriginalfunctionaddresses.ThistypicallyhappensfromwithintheEndScene()function,meaningyoualsohavetorepatchtheVFtableaftercallingtheoriginalEndScene()function.Thereareafewchangesyoucanmaketothishooktohandlethat,asshowninListing8-14.

_endSceneorigEndScene=NULL;voidplaceHooks()

Page 247: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

{autoret=hookVF((DWORD)discoveredDevice,42,(DWORD)&myEndScene);if(ret!=(DWORD)&myEndScene)//don'tpointtoyourhookorigEndScene=(_endScene)ret;}placeHooks();

HRESULTWINAPImyEndScene(LPDIRECT3DDEVICE9pDevice){//drawyourownstuffhereautoret=origEndScene(pDevice);placeHooks();//updatehooksreturnret;}

Listing8-14:FinalcodetohookEndScene()

ThecodetoplacethehookhasbeenmovedintoafunctioncalledplaceHooks()soitcanbecalledmultipletimeswithease.Thecallbackfunctionstillforwardsthecalltotheoriginalfunction,butitmakessuretocallplaceHooks()beforereturning.Thisensuresthatthehookisalwaysactive,eveniftheoriginalEndScene()functionremovesit.

AnotherpointtonoticeisthatplaceHooks()updatestheaddressoforigEndScene()everytimethehookisreplaced,aslongastheaddressreturnedfromhookVF()isn’ttheaddressofthemyEndScene()function.Thisdoestwodistinctthings.First,itallowsotherapplicationstohookEndScene()withoutsteppingontheirtoes,sinceitwillupdateorigEndScene()towhateverisseenintheVFtable.Second,itmakessurethatthevalueoforigEndScene()canneverbetheaddressofourcallback,preventingapotentialinfiniteloop.Aninfiniteloopispossibleotherwise,becauseorigEndScene()doesn’talwaysfixthedevice’sVFtable,meaningplaceHooks()canbecalledwhentheVFtablestillcontainsthemyEndScene()function.

WritingaHookforReset()Whenyou’reusingaDirect3Dhookinproduction,you’llbedoingallkindsoftaskslikedrawingcustomtext,displayingimagesrelatedtoyourbot,andinteractingwithfunctioncallsfromthegame.ThesetaskswillrequireyoutocreateyourownDirect3Dobjectsthataretiedtothegame’sdevice,andthatcanbeaproblem.Fromtimetotime,thegamemaycompletelyresetitsdevicethroughaReset()function.Whenadeviceisreset,you’llneedto

Page 248: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

updateanyobjects(mostcommonlyfontsandsprites)thatyou’vecreatedforthedevice,usingtheirOnLostDevice()memberfunctions.

SinceReset()iscalledfromtheVFtableofthedevice,youcanuseahookonittotellyouwhenthedevicehasbeenreset.Reset()takestwoparametersandisatindex16intheVFtable.YoucanaddthiscodetoplaceHooks()inListing8-14tohooktheReset()function:

autoret=hookVF((DWORD)discoveredDevice,16,(DWORD)&myReset);if(ret!=(DWORD)&myReset)origReset=(_reset)ret;

AndthisisthedeclarationtousefororigReset:

typedefHRESULT(WINAPI*_reset)(LPDIRECT3DDEVICE9pDevice,D3DPRESENT_PARAMETERS*pPresentationParameters);_resetorigReset=NULL;

Whenaresetissuccessful,theoriginalfunctionreturnsD3D_OK.YourhookfunctionrecognizesthisandcallsOnLostDevice()accordingly:

HRESULTWINAPImyReset(LPDIRECT3DDEVICE9pDevice,D3DPRESENT_PARAMETERS*pPresentationParameters){autoresult=origReset(pDevice,pPresentationParameters);if(result==D3D_OK){//callonLostDevice()forallofyourobjects}returnresult;}

Onceyoufillinthecontentsoftheif()statement,allofyourobjectsarereadytouseagain.

What’sNext?NowthatI’veshownyouhowtotakecontrolofagame’sDirect3Ddevice,you’reprobablywonderingwhatyoucandowithit.Unliketheotherexamplesinthebook,thecodeinthissectionandtheexamplecodedon’thaveaone-to-onecorrelation,butthefunctionalityisstillthesame.Here’sahigh-levelviewofthecorrelationbetweenthischapterandthecodeintheChapter8_Direct3DHookexampleproject.

Page 249: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ThefileDirectXHookCallbacks.hcontainsthecallbacksfortheEndScene()andReset()functions,twocallbacksforothercommonfunctions,andthetrampolineandreporterfunctionsforthetemporaryjumphook.Thesefunctionsareallprettymuchasdescribedinthischapter,excepttheycallintoasingletonclassdefinedinDirectXHook.handDirectXHook.cpp.Thissingletonclassisresponsibleforforwardingthecallstotheoriginalfunctions.

Theclassisalsoresponsibleforalloftheheavylifting,anditcontainsthecodetocreatethediscoverydevice,placethehooks,drawtext,handledeviceresets,anddisplayimages.Furthermore,itallowsexternalcodetoaddcustomcallbacksforeachhook,asyoucanseeinmain.cpp.Here,you’llseeanumberofdifferentcallbacksthataredrawingcustomtext,addingnewimagestothescreen,andchangingthetexturesofmodelsthataredrawnbythegame.Irecommendpokingaroundinthecodetogetabetterunderstandingofwhat’sgoingon,butdon’tgettoocarriedaway.We’lldiveintothiscodeinChapter9totalkaboutallthecoolhacksitcando.

OPTIONALFIXESFORSTABILITYTheReset()andEndScene()hooksdescribedinthischaptershouldworkwellforanygamerunningDirect3D9,butitisslightlyunstable.IfthegametriestoexecuteEndScene()whenthejumphookisplaced,itwillcrashbecausethebytesarebeingmodified.Therearetwowaystofixthis.First,youcanplacethejumphookfromwithinanIAThookonPeekMessage().ThiswillworkbecauseplacinganIAThookisathread-safeoperation,butitassumesthatPeekMessage()iscalledonlyfromthesamethreadthatdoestheDirect3Ddrawing.

Asafer,butmorecomplex,alternativeistoiterateovereverythreadinthegame(similartohowitworkedforthreadhijacking)anduseSuspendThread()topauseallthreadsinthegame(exceptfortheoneplacingthehook,ofcourse).Beforepausingathread,youmustmakesureitsEIPisnotexecutingthefirst5bytesofEndScene().Afterthehookisplaced,youmustuseResumeThread()torestoreexecutionwithyourhookinplace.

Page 250: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ClosingThoughtsControlflowmanipulationisaveryimportantskillingamehacking,andalotofthehacksinthisbookrelyonit.Throughoutthenexttwochaptersyou’lllearnhowtocreatecommonhacksusingtheDirect3Dhook,andyou’llgetabetterideaofthegeneralusecasesofhooking.Evenifyoufeelalittleshaky,continuetoChapter9.ThecodeexamplestherecenterontheDirect3Dhookandwillgetyouevenmorefamiliarwithhookingtechniques.

Page 251: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PART4CREATINGBOTS

Page 252: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

9USINGEXTRASENSORYPERCEPTIONTO

WARDOFFFOGOFWAR

Fogofwar(oftenshortenedtojustfog)isamechanismthatgamedeveloperscommonlyusetolimitaplayer’ssituationalawarenessandhideinformationaboutthegameenvironment.Fogisoftenaliterallackofsightinmassiveonlinebattlearena(MOBA)games,buttheconceptalsoincludesanylackorobscurityofpertinentgameplayinformation.Cloakedfigures,darkrooms,andenemieshidingbehindwallsareallformsoffog.

Gamehackerscanreduceorevencompletelyremovefogusinganextrasensoryperception(ESP)hack.AnESPhackuseshooking,memorymanipulation,orbothtoforceagametodisplayhiddeninformation.Thesehackstakeadvantageofthefactthatsometypesoffogareoftenimplementedontheclientside,asopposedtotheserverside,meaningthatthegameclientsstillcontaininformation(partialorcomplete)aboutwhatisbeinghidden.

Inthischapter,youwilllearnhowtoimplementdifferenttypesofESPhacks.First,you’lllearntolightupdarkenvironments.Next,you’llusex-rayvisiontoseethroughwalls.Finally,you’lllearnaboutzoomhacking,tweakingheads-updisplays,andothersimpleESPhacksthatcanrevealallsortsofuseful(butotherwisehidden)informationaboutthegameyou’replaying.

Page 253: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

BackgroundKnowledgeThischapterstartsthetransitionfromhacking,puppeteering,andreverseengineeringtocoding.Fromhereonout,you’llbelearninghowtoactuallycodeyourownhacks.Tokeepontopic,everythingI’vetalkedaboutthusfarwillbetreatedasbackgroundknowledge.Ifyouseeatechniqueusedthatyoudon’tquiteremember,suchasmemoryscanning,settingmemorybreakpoints,hooking,orwritingmemory,flipbacktotherelevantchaptersandstudythemabitmorebeforecontinuing.Throughoutthetext,you’llfindnotestoremindyouwhereyoucanbrushuponcertaintopics.

Specifically,thischapterwilltalkalotaboutDirect3D.In“ApplyingJumpHooksandVFHookstoDirect3D”onpage175,Iexplainedhowtohookintoagame’sDirect3Ddrawingloop.TheexamplecodeforthatchapterincludesafullyfeaturedDirect3DhookingengineinGameHackingExamples/Chapter8_Direct3DHook.Alotofthehacksinthischapterbuildonthathook,andtheirexamplecodecanbefoundinthemain.cppfileoftheDirect3Dhookcode.YoucanrunthecompiledapplicationfromGameHackingExamples/Chapter8_Direct3DApplicationtoseethehacksinactiononatestapplication.

RevealingHiddenDetailswithLighthacksLighthacksincreaselightingindarkenvironments,allowingyoutoclearlyseeenemies,treasurechests,pathways,andanythingelsethatisnormallyobscuredbydarkness.Lightingisoftenacosmeticchangethat’saddedatagame’sgraphicallayer,anditcanusuallybedirectlymodifiedwithahookonthegraphicslayer.

Optimallightingdependsoncameraorientation,environmentlayout,andevenspecifictraitsofagame’sengine,andyoucanmanipulateanyofthesefactorstocreatelighthacks.Buttheeasiestwayissimplytoaddmorelighttoaroom.

AddingaCentralAmbientLightSourceTheonlineresourcesforthisbookincludetwosmalllighthackexamples.ThefirstistheenableLightHackDirectional()functioninmain.cpp,whichis

Page 254: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

showninListing9-1.

voidenableLightHackDirectional(LPDIRECT3DDEVICE9pDevice){D3DLIGHT9light;ZeroMemory(&light,sizeof(light));light.Type=D3DLIGHT_DIRECTIONAL;light.Diffuse=D3DXCOLOR(0.5f,0.5f,0.5f,1.0f);light.Direction=D3DXVECTOR3(-1.0f,-0.5f,-1.0f);

pDevice->SetLight(0,&light);pDevice->LightEnable(0,TRUE);}Whenyouknowhowmuchexperienceyou

Listing9-1:Adirectionallighthack

ThiscodeiscalledfromtheEndScene()hook,anditaddslighttothescenebycreatingalightsourcecalledlight.Thecodesetslight.Typetodirectional,whichmeansthelightsourcewillactlikeaspotlightandprojectlightinaspecificdirection.Thecodethensetsthered,green,andbluevaluesoflight.Diffuseto0.5,0.5,and0.5,givingthelightanoff-whiteshinewhenreflectedfromasurface.Next,itsetslight.Directiontoanarbitrarypointinthethree-dimensionalspace.Finally,thecodeusesthegame’sDirect3Ddevicetosetupthelightatindex0andenablelightingeffects.

NOTE

Intheexampleapplication,thelightshinesupandtotherightfromthebottomleftofthescene.Youmayneedtochangethislocationdependingonhowyourtargetgameisrendered.

Notethatinsertingthelightatindex0worksforthisproofofconcept,butitwon’talwayswork.Gamestypicallyhavemultiplelightsourcesdefined,andsettingyourlightatanindexthegameusesmightoverridecriticallightingeffects.Inpractice,youmighttrysettingtheindextoanarbitrarilyhighnumber.There’sanissuewiththistypeoflighthack,though:directionallightswillbeblockedbyobjectssuchaswalls,creatures,andterrain,meaningshadowscanstillbecast.Directionallightsworkgreatforwide-openspaces,butnotsowellfortightlywoundcorridorsorundergroundcaves.

Page 255: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

IncreasingtheAbsoluteAmbientLightTheotherlighthackmethod,seenintheenableLightHackAmbient()function,isfarmoreaggressivethantheoneinListing9-1.Itaffectsthelightlevelglobally,ratherthanaddinganextralightsource.Here’swhatthecodelookslike:

voidenableLightHackAmbient(LPDIRECT3DDEVICE9pDevice){pDevice->SetRenderState(D3DRS_AMBIENT,D3DCOLOR_XRGB(100,100,100));}

Thislighthacksetstheabsoluteambientlight(whichyouindicatebypassingD3DRS_AMBIENTtotheSetRenderState()function)toamedium-strengthwhite.TheD3DCOLOR_XRGBmacrosetsthatstrength,taking100asitsparametersforthered,green,andbluelevels.Thislightsupobjectsusinganomnidirectionalwhitelight,effectivelyrevealingeverythingatthecostofshadowsandotherlighting-baseddetails.

CreatingOtherTypesofLighthacksTherearemanyotherwaystocreatelighthacks,buttheydifferfromgametogame.OnecreativewaytoaffectthelightinagameistoNOPthecodethatthegameusestocallthedevice->SetRenderState()function.Sincethisfunctionisusedtosetuptheglobalambientlightstrength,disablingcallstoitleavesDirect3Datthedefaultlightsettingsandmakeseverythingvisible.Thisisperhapsthemostpowerfultypeoflighthack,butitrequiresyourbottoknowtheaddressofthelightingcodetoNOP.

Therearealsomemory-basedlighthacks.Insomegames,playersandcreaturesemitlightofdifferentcolorsandstrengths,oftendependingonattributesliketheirequipment,mount,oractivespells.Ifyouunderstandthestructureofthegame’screaturelist,youcandirectlymodifythevaluesthatdetermineacreature’slightlevel.

Forinstance,imagineagameinwhichcharactersemitabluishballoflightwhenunderahealingorstrengtheningspell.Somewhereinthegame’smemoryarevaluesassociatedwitheachcreaturethattellthegamethecolorandintensityoflightthecreatureshouldemit.Ifyoucanlocatethesevaluesinmemory,youcanchangethemsothatthecreatureseffectivelyemitorbsoflight.Thistypeoflighthackiscommonlyusedingameswitha2Dtop-

Page 256: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

oflight.Thistypeoflighthackiscommonlyusedingameswitha2Dtop-downstyle,sincetheorbsaroundindividualcreaturesproduceacoolartisticeffectwhilesheddinglightonimportantpartsofthescreen.In3Dgames,however,thissortofhackjustturnscreaturesintoblobsoflightthatrunaround.

YoucanalsohooktheSetLight()memberfunctionatindex51intheVFtableofthegame’sDirect3Ddevice.Then,wheneveryourhookcallbackisinvoked,youcanmodifythepropertiesoftheinterceptedD3DLIGHT9lightstructurebeforepassingittotheoriginalfunction.Youmight,forinstance,changealllightstotheD3DLIGHT_POINTtype,causinganyexistinglightsourcesinthegametoradiatelightineverydirectionlikealightbulb.Thistypeoflighthackisverypowerfulandaccurate,butitcanproducesomedisturbingvisuals.Italsotendstobreakinanyenvironmentthathasnolighting,andopaqueobstaclesstillblockpointlightsources.

Lighthacksareverypowerful,buttheydon’trevealanything.Ifinformationishiddenbehindanobstacle,ratherthanbydarkness,you’llneedawallhacktorevealit.

RevealingSneakyEnemieswithWallhacksYoucanusewallhackstoshowenemiesthatarehiddenbywalls,floors,andotherobstacles.Thereareafewwaystocreatethesehacks,butthemostcommonmethodtakesadvantageofatypeofrenderingknownasz-buffering.

RenderingwithZ-BufferingMostgraphicsengines,includingDirect3D,supportz-buffering,whichisawaytomakesurethatwhenthereareoverlappingobjectsinascene,onlythetopobjectisdrawn.Z-bufferingworksby“drawing”thescenetoatwo-dimensionalarraythatdescribeshowclosetheobjectateachpixelonthescreenistotheviewer.Thinkofthearray’sindicesasaxes:theycorrespondtothex-axis(rightandleft)andy-axis(upanddown)foreachpixelonthescreen.Eachvaluestoredinthearrayisthez-axisvalueforapixel.

Whenanewobjectappears,whetheritisactuallydrawnonthescreenisdecidedbythez-bufferarray.Ifthespotattheobject’sx-andy-positionisalreadyfilledinthearray,thatmeansthere’sanotherobjectatthatpixelon

Page 257: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

alreadyfilledinthearray,thatmeansthere’sanotherobjectatthatpixelonthescreen.Thenewobjectwillappearonlyifithasalowerz-axisvalue(thatis,ifit’sclosertotheviewer)thanthepixelalreadythere.Whenthesceneisfinishedbeingdrawntothearray,itisflushedtothescreen.

Toillustratethis,imagineathree-dimensionalspacethatneedstobedrawntoatwo-dimensionalcanvasbysomegamewith4×4-pixelviewport.Thez-bufferforthisscenariowouldlooklikeFigure9-1.

Figure9-1:Anemptyz-buffer

Tostart,thegamedrawsabluebackgroundthatcompletelyfillstheviewportandislocatedasfarawayonthez-axisaspossible;let’ssaythehighestz-valueis100.Next,thegamedrawsa2×2-pixelredrectangleatposition(0,0)withaz-positionof5.Finally,thegamedrawsa2×2-pixelgreenrectangleatposition(1,1)withaz-positionof3.Thez-bufferwouldnowlooklikeFigure9-2.

Page 258: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure9-2:Afilledz-buffer

Thez-bufferneatlyhandledoverlappingobjectsbasedontheirz-positions.Thegreensquarethat’sclosestonthez-axisoverlapstheredsquarethat’sabitfartheraway,andbothsquaresoverlapthebluebackground,whichisveryfaraway.

Thisbehaviorallowsagametodrawitsmap,players,creatures,details,andparticleswithoutworryingaboutwhatisactuallyvisibletotheplayer.Thisisahugeoptimizationforgamedevelopers,butitexposesalargeareaofattack.Sinceallgamemodelsarealwaysgiventothegraphicsengine,youcanusehookstodetectobjectsthattheplayercan’tactuallysee.

CreatingaDirect3DWallhackYoucancreatewallhacksthatmanipulatez-bufferinginDirect3DusingahookontheDrawIndexedPrimitive()function,whichiscalledwhenagamedrawsa3Dmodeltothescreen.Whenanenemyplayermodelisdrawn,a

Page 259: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

wallhackofthistypedisablesz-buffering,callstheoriginalfunctiontodrawthemodel,andthenreenablesz-buffering.Thiscausestheenemymodeltobedrawnontopofeverythingelseinthescene,regardlessofwhat’sinfrontofit.Somewallhackscanalsorenderspecificmodelsinasolidcolor,suchasredforenemiesandgreenforallies.

TogglingZ-BufferingTheDirect3Dhookinmain.cppfromGameHackingExamples/Chapter8_Direct3DHookhasthisexamplewallhackintheonDrawIndexedPrimitive()function:

voidonDrawIndexedPrimitive(DirectXHook*hook,LPDIRECT3DDEVICE9device,D3DPRIMITIVETYPEprimType,INTbaseVertexIndex,UINTminVertexIndex,UINTnumVertices,UINTstartIndex,UINTprimCount){if(numVertices==24&&primCount==12){//it'sanenemy,dothewallhack}}

ThisfunctionisusedasacallbackforahookonDrawIndexedPrimitive()atVFindex82ofthegame’sDirect3Ddevice.Everymodelthegamedrawspassesthroughthisfunction,accompaniedbysomemodel-specificproperties.Byinspectingasubsetoftheproperties,namelythenumVerticesandprimCountvalues,thehookdetectswhenanenemymodelisdrawnandcommencesthewallhack.Inthisexample,thevaluesrepresentinganenemymodelare24and12.

Themagichappensinsidetheif()statement.Usingjustafewlinesofcode,thewallhackdrawsthemodelinawaythatignoresz-buffering,likeso:

device->SetRenderState(D3DRS_ZENABLE,false);//disablez-bufferingDirectXHook::origDrawIndexedPrimitive(//drawmodeldevice,primType,baseVertexIndex,minVertexIndex,numVertices,startIndex,primCount);device->SetRenderState(D3DRS_ZENABLE,true);//enablez-buffering

Simplyput,thiscodedisablesz-bufferingwhendrawingtheenemymodelandreenablesitafterward.Withz-bufferingoff,theenemyisdrawninfrontofeverything.

Page 260: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ChanginganEnemyTextureWhenamodelisrenderedonscreen,atextureisusedtoskinthemodel.Texturesare2Dimagesthatarestretchedaround3Dmodelstoapplythecolorsandpatternsthatmakeupthemodel’s3Dartwork.Tochangethewayanenemylookswhenit’sdrawninyourwallhack,youcansetittobedrawnwithadifferenttexture,asinthisexample:

//whenhookinitializesLPDIRECT3DTEXTURE9red;D3DXCreateTextureFromFile(device,"red.png",&red);//justbeforedrawingtheprimitivedevice->SetTexture(0,red);

Thefirstblockofthiscodeloadsthetexturefromafileandisexecutedonlyonce—whenthehookisinitialized.Thefullexamplecodedoesthisinaninitialize()function,whichgetscalledthefirsttimetheEndScene()hookcallbackisinvoked.ThesecondblockofthiscodehappensrightbeforethecalltotheoriginalDrawIndexedPrimitive()functioninthewallhack,anditcausesthemodeltobedrawnwiththecustomtexture.

FingerprintingtheModelYouWanttoRevealThetrickiestparttocreatingagoodwallhackisfindingtherightvaluesfornumVerticesandprimCount.Todothis,youcancreateatoolthatlogseveryuniquecombinationofthetwovariablesandallowsyoutoiterateoverthelistusingyourkeyboard.Workingexamplecodeforthistoolwon’tbeusefulintheexampleapplicationprovidedwiththischapter,butI’llgiveyousomehigh-levelimplementationdetails.

First,intheglobalscope,you’ddeclareastructurethathasmemberstostorethefollowing:

•numVerticesandprimCount

•Astd::setofthisstructure(let’scallitseenParams)

•Aninstanceofthatstructure(let’scallitcurrentParams)

Thestd::setrequiresacomparatorforthisstructure,soyou’dalsodeclareacomparisonfunctorthatcallsmemcmp()tocomparetwoofthestructuresusingmemcmp().EachtimetheDrawIndexedPrimitive()callbackis

Page 261: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

invoked,yourhackcouldcreateastructureinstancewiththeinterceptedvaluesandpassittoaseenParams.insert()function,whichshouldinserttheparameterpairintothelistonlyifthepairisn’talreadythere.

UsingtheGetAsyncKeyState()WindowsAPIfunction,youcouldthendetectwhenthespacebarispressedandexecutesomethingsimilartothispseudocode:

autocurrent=seenParams.find(currentParam);if(current==seenParams.end())current=seenParams.begin();elsecurrent++;currentParams=*current;

ThiswouldsetcurrentParamstothenextpairinseenParamswhenthespacebarispressed.Withthiscodeinplace,youcouldusecodesimilartoawallhacktochangethetextureofmodelsmatchingcurrentParams.numVerticesandcurrentParams.primCount.Thetoolcouldalsodrawthosevaluesonthescreensoyoucouldseethemandwritethemdown.

Withatoollikethis,findingthepropermodelsisaseasyasstartingupagameinamodewhereyourcharacterwon’tdie(againstafriend,inacustomizationmode,andsoon),runningthebot,andpressingthespacebaruntileachmodelyouneedishighlighted.Onceyouhavethevaluesforyourtargetmodels,you’llmodifythenumVerticesandprimCountcheckinyourwallhacksoitknowswhichmodelstohighlight.

NOTE

Charactermodelsarecommonlymadeupofsmallermodelsforindividualbodysegments,andgamesoftenshowdifferentmodelsofacharacteratdifferentdistances.Thatmeansagamemayhave20ormoremodelsforonetypeofcharacter.Eveninthatcase,selectingonlyonemodel(say,theenemy’storso)toshowinyourwallhackmaybeenough.

GettingaWiderFieldofVisionwithZoomhacksManygamesintheMOBAandreal-timestrategy(RTS)genresusea3Dtop-downstylethatmakesthemimmunetowallhacks.Theyalsousedarknessonthemapasatypeoffog,butshowingthedarkareasusinga

Page 262: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

darknessonthemapasatypeoffog,butshowingthedarkareasusingalighthackdoesn’tgiveanyextrainformation;modelshiddeninsidethefogareknownonlytothegameserver,nottotheclient.

ThisstylemakesmosttypesofESPhacksuseless:there’slittleunknowninformationtoreveal,sothesehacksonlyaugmentyourviewoftheinformationyoucanalreadysee.OnetypeofESPhack,however,canstillbehelpful.Zoomhacksletyouzoomoutmuchfartherthanagamenormallyallows,effectivelyrevealinglargeportionsofthemapthatyoucouldn’tseeotherwise—andthusgettingaroundthegame’swallhackandlighthackimmunity.

UsingNOPingZoomhacksMOBAandRTSgamestypicallyallowplayersavariablebutlimitedamountofzoom.Thesimplesttypeofzoomhackfindsthevalueofthezoomfactor(amultiplierthatchangesasthezoomlevelchanges,typicallyafloatordouble)andoverwritesitwithalargervalue.

Tofindthezoomfactor,fireupCheatEngineandsearchforafloatwithanunknowninitialvalue.(TobrushuponCheatEngine,headoverto“CheatEngine’sMemoryScanner”onpage5.)Forrescans,repeatthefollowingprocessuntilthereareonlyafewvalueslefttofindthezoomfactor:

1. Gotothegamewindowandzoomin.

2. SearchforanincreasedvalueinCheatEngine.

3. Gotothegamewindowandzoomout.

4. SearchforadecreasedvalueinCheatEngine.

Trytogetthevaluelistdowntooneoption.Toconfirmthattheremainingvalueisthezoomfactor,freezeitinCheatEngineandseehowzoombehavesin-game;freezingthepropervaluewilldisablezooming.Ifyoufailtofindthezoomfactorusingafloatsearch,retrythesearchusingadouble.Ifbothsearchesfail,trythemagainbutcorrespondzoominginwithdecreasedvaluesandzoomingoutwithincreasedvaluesinstead.Onceyou’vefoundthezoomfactorinmemory,youcanwriteasmallbottooverwriteittothezoomfactorthatbestsuitsyou.

Page 263: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

MoreadvancedzoomhacksNOPthegamecoderesponsibleformakingsurethezoomfactoriswithinasetrange.YoushouldbeabletofindthiscodewithOllyDbg.Setamemoryon-writebreakpointonthezoomfactor,zoomin-gametotriggerthebreakpoint,andinspectthecodeatthebreakpoint.(TohoneyourOllyDbgmemorybreakpointskills,flipto“ControllingOllyDbgThroughtheCommandLine”onpage43.)Youshouldseethecodethatmodifiedthezoomfactor.Zoomlimitationcodeistypicallyeasytospot:constantsthatmatchtheminimumandmaximumzoomvaluesareadeadgiveaway.

Ifyoucan’tfindthelimitationcodeusingthismethod,thenthelimitationmaybeappliedwhenthegraphicsareredrawnatanewzoomlevel,ratherthanwhenthezoomfactorchanges.Inthiscase,switchyourbreakpointtomemoryon-readandlookforthesameclues.

ScratchingtheSurfaceofHookingZoomhacksYoucanalsocreatezoomhacksbyusingaDirect3Dhookonthefunctiondevice->SetTransform(type,matrix),butthisrequiresadeepunderstandingofhowagamesetsuptheplayer’sperspective.Thereareafewdifferentwaystomanageperspective,butyoucontrolzoomlevelusingeitherview(transformtypeD3DTS_VIEW)orprojection(transformtypeD3DTS_PROJECTION).

Properlymanipulatingtransformmatricesthatcontrolviewandprojectionrequiressomeprettyextensiveknowledgeofthemathematicsbehind3Dgraphics,though,soIstayawayfromthismethodatallcosts—andI’veneverhadtroublesimplymanipulatingthezoomfactor.Ifyou’reinterestedinthiskindofhack,though,Irecommendreadinga3Dgameprogrammingbooktolearnmoreabout3Dmathematicsfirst.

Butsometimes,evenazoomhackisn’tenough.Someusefulinformationmayremainhiddenasapartofagame’sinternalstateormaysimplybehardforaplayertodetermineatamoment’sglance.Forthesesituations,aheads-updisplayisthetoolforthejob.

DisplayingHiddenDatawithHUDsAheads-updisplay(HUD)isatypeofESPhackthatdisplayscriticalgameinformationinanoverlay.HUDsoftenresembleagame’sexistinginterface

Page 264: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

fordisplayinginformationlikeyourremainingammunition,amini-map,yourcurrenthealthlevel,anyactiveabilitycooldowns,andsoon.HUDstypicallydisplayeitherhistoricaloraggregatedinformation,andthey’remostlyusedonMMORPGs.Theyareoftentextbased,butsomealsocontainsprites,shapes,andothersmallvisualeffects.

TheHUDsyoucancreatedependonwhatdataisavailableinthegame.Commondatapointsarethese:

•Experiencegainperhour(exp/h)

•Creaturekillsperhour(KPH)

•Damagepersecond(DPS)

•Goldlootedperhour(GPH)

•Healingperminute

•Estimatedtimeuntilnextlevel

•Amountofgoldspentonsupplies

•Overallgoldvalueofitemslooted

MoreadvancedcustomHUDsmaydisplaylargetablescontainingitemslooted,suppliesused,thenumberofkillsforeachtypeofcreature,andthenamesofplayersthathaverecentlybeenseen.

Beyondwhatyou’vealreadylearnedaboutreadingmemory,hookinggraphicsengines,anddisplayingcustomizeddata,there’snotmuchelseIcanteachyouabouthowtocreateaHUD.Mostgameshaveasimpleenougharchitecturethatyoucaneasilyobtainmostoftheinformationyouneedfrommemory.Then,youcanrunsomebasichourly,percentage,orsummationcalculationstogetthedataintoausableformat.

CreatinganExperienceHUDImagineyouwantaHUDthatdisplaysyourcurrentlevel,hourlyexperience,andhowlongyou’llhavetoplaybeforeyourcharacterlevelsup.First,youcoulduseCheatEnginetofindthevariablesthatcontainyourlevelandexperience.Whenyouknowthosevalues,youcanuseeitheragame-specificalgorithmorahardcodedexperiencetabletocalculatetheexperiencerequiredtoreachthenextlevel.

Page 265: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Whenyouknowhowmuchexperienceyouneedtolevelup,youcancalculateyourhourlyexperience.Putintopseudocode,thatprocessmightlooklikethis:

//thisexampleassumesthetimeisstoredinmilliseconds//forseconds,removethe"1000*"timeUnitsPerHour=1000*60*60timePassed=(currentTime-startTime)➊timePassedToHourRatio=timeUnitsPerHour/timePassed➋expGained=(currentExp-startExp)hourlyExp=expGained*timePassedToHourRatio

➌remainingExp=nextExp-currentExp➍hoursToGo=remainingExp/hourlyExp

Tofindyourhourlyexperience,hourlyExp,you’dstoreyourexperienceandthetimewhenyourHUDfirststarts;thesearestartExpandstartTime,respectively.ThisexamplealsoassumescurrentLevelandcurrentExparepreviouslydefined,wherecurrentLevelisthecharacter’slevelandcurrentExpisthecurrentamountofexperience.

Withthesevalues,hourlyExpcanbecalculatedbymultiplyingaratio➊ofthetimeunitsinanhourtothetimethathaspassedbytheexperiencegainedsincestartTime➋.Inthiscase,thetimeunitisamillisecond,sothetimeunitsgetmultipliedby1,000.

Next,currentExpissubtractedfromnextExptodeterminetheremainingexperience➌tolevelup.Tocalculatehowmanyhoursarelefttolevelup,yourremainingexperienceisdividedbyyourhourlyexperience➍.

Whenyouhaveallthisinformation,youcanfinallydisplayitonscreen.UsingtheDirect3Dhookingengineprovidedinthisbook’sexamplecode,you’ddrawthetextusingthiscallinsidetheEndScene()hookcallback:

hook->drawText(10,10,D3DCOLOR_ARGB(255,255,0,0),"Willreachlevel%din%0.20fhours(%dexpperhour)",currentLevel,hoursToGo,hourlyExp);

That’sallyouneedforaworking,experience-trackingHUD.VariationsofthesesameequationscanbeusedtocalculateKPH,DPS,GPH,andotherusefultime-basedmeasures.Furthermore,youcanusethedrawText()

Page 266: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

functionoftheDirect3Dhooktodisplayanyinformationyoucanlocateandnormalize.ThehookalsocontainsaddSpriteImage()anddrawSpriteImage()functionsthatyoucanusetodrawyourowncustomimages,allowingyoutomakeyourHUDsasfancyasyouwant.

UsingHookstoLocateDataMemoryreadingisn’ttheonlywaytogetdataforacustomHUD.YoucanalsogatherinformationbycountingthenumberoftimesaspecificmodelisdrawnbytheDrawIndexedPrimitive()function,hookingthegame’sinternalfunctionsresponsiblefordrawingcertaintypesoftext,oreveninterceptingfunctioncallsresponsibleforprocessingdatapacketsfromthegameserver.Themethodsyouusetodothiswillbedrasticallydifferentforeverygame,andfindingthosemethodswillrequireyoutopaireverythingyou’velearnedfromthisbookwithyourowningenuityandprogramminginstincts.

Forinstance,tocreateaHUDthatdisplayshowmanyenemiesareonthemap,youcouldusethemodel-fingerprintingmethodsusedbywallhackstocountthenumberofenemiesandoutputthatnumbertothescreen.Thismethodisbetterthancreatingawaytoreadthelistofenemiesfrommemory,sinceitdoesn’trequirenewmemoryaddresseseverytimethegamepatches.

Anotherexampleisdisplayingalistofenemycooldowns,whichwouldrequireyoutointerceptincomingpacketsthattelltheclientwhichspelleffectstodisplay.Youcouldthencorrelatecertainspellswithcertainenemiesbasedonspellandenemylocation,spelltype,andsoon,andusethatinformationtotrackspellseachenemyhasused.Ifyoucorrelatethedatawithadatabaseofcooldowntimes,youcandisplayexactlywheneachenemyspellcanbeusedagain.Thisisespeciallypowerfulbecausemostgamesdon’tstoreenemycooldownsinmemory.

AnOverviewofOtherESPHacksInadditiontothehacksdiscussedinthischapter,thereareanumberofESPhacksthatdon’thavecommonnamesandarespecifictocertaingenresorevencertaingames.I’llquicklytakeyouthroughthetheory,background,andarchitectureofsomeofthesehacks.

Page 267: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

RangeHacksRange hacks use a method similar to wallhacks to detect when themodelsfordifferenttypesofchampionsorheroesaredrawn.Thentheydrawcirclesonthegroundaroundeachheromodel.Theradiusofeachcirclecorrespondstothemaximumattackrangeofthechampionorheroitsurrounds,effectivelyshowingyouareaswhereyoucanbedamagedbyeachenemy.

Loading-ScreenHUDsLoading-screen HUDs are common in MOBA and RTS games thatrequireallplayerstositthroughaloadingscreenwhileeveryone’sgameis starting up.These hacks take advantage of the fact that such gamesoftenhavewebsiteswherehistoricalplayerstatisticscanbequeried.Youcanwriteabotthatautomaticallyqueriesthestatisticsofeachplayerinthegameandseamlesslydisplaysthe informationasanoverlayonyourloadingscreen,allowingyoutostudyyourenemiesbeforelaunchingintobattle.

Pick-PhaseHUDsPick-phaseHUDs are similar to their loading-screen cousins, but theyare displayed during the pregame phase when each player is picking achampion or hero to play. Instead of showing enemy statistics, pick-phase HUDs show statistics about allies. This allows you to quicklyassessthestrengthsandweaknessesofyouralliessoyoucanmakebetterdecisionsaboutwhichcharactertoplay.

FloorSpyHacksFloor spy hacks are common in older 2D top-down games that havedifferent distinct floors or platforms. If you’re on the top floor, youmightwanttoknowwhat’sgoingondownstairsbeforeyougochargingin. You can write floor spy hacks that modify the current floor value(typically an unsigned int) to a different floor above or below you,allowingyoutospyonotherfloors.

Gamesoftenrecalculatethecurrentfloorvalueeveryframebasedonplayerposition,soNOPsaresometimesrequiredtokeepthevaluefrombeingreseteverytimeaframeisredrawn.FindingthecurrentfloorvalueandthecodetoNOPwouldbesimilartofindingthezoomfactor,as

Page 268: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

discussedin“UsingNOPingZoomhacks”onpage197.

ClosingThoughtsESPhacksarepowerfulwaystoobtainextrainformationaboutagame.SomeofthemcanbedoneprettyeasilythroughDirect3Dhooksorsimplememoryediting.Othersrequireyoutolearnaboutagame’sinternaldatastructuresandhookproprietaryfunctions,givingyouareasontoemployyourreverseengineeringskills.

IfyouwanttoexperimentwithESPhacks,studyandtweaktheexamplecodeforthischapter.ForpracticewithmorespecificESPhacks,Iencourageyoutogooutandfindsomegamestoplayaroundwith.

Page 269: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

10RESPONSIVEHACKS

Theaveragegamerhasareactiontimeof250milliseconds,oraquarterofasecond.Professionalgamersaverageafifthofasecond,butsomecanreactinasixthofasecond.Thesefiguresarebasedononlineteststhatmeasureplayers’reactiontimestosingular,predictableevents.Inactualgames,though,playersmustreacttodozensofdifferentevents,likehealthloss,incomingskillshots,abilitiescomingoffofcooldown,enemyattacks,andmanyothers.Onlyveryskilledgamerscanmaintainafourth-orfifth-of-a-secondreactiontimeinsuchdynamicenvironments;theonlywaytobefasteristobeacomputer.

Inthischapter,you’lllearnhowtomakebotsthatreactfasterthananyplayer.First,I’llshowyousomecodepatternsyoucanincorporateintoabottodetectwhencertaineventshappenwithinagame.Next,you’lllearnhowtomakeabotthatmovesyourcharacter,heals,orcastsspellsallonitsown.Onceyou’veexploredthosefundamentaltechniques,I’llhelpyoutiethemtogethertoimplementsomeofthemostcommon,andmostpowerful,responsivehacks.

ObservingGameEventsWithinjustafewsecondsofplayingagame,mostpeoplecanmakeessentialobservationsaboutthegameenvironment.Youcanclearlyseewhenmissilesareflyingtowardyourcharacter,whenyourhealthistoolow,andwhen

Page 270: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

areflyingtowardyourcharacter,whenyourhealthistoolow,andwhenabilitiescomeoffofcooldown.Forabot,though,theseseeminglyintuitiveobservationsarenotaseasytomake.Thebotmustdetecteacheventbylookingforchangesinmemory,detectingvisualcues,orinterceptingnetworktraffic.

MonitoringMemoryTodetectsimpleevents,suchasyourhealthbardroppinglow,youcanprogramabottoperiodicallyreadyourhealthfrommemoryandcompareittosomeminimumacceptablevalue,asinListing10-1.

//dothisevery10milliseconds(100timesasecond)autohealth=readMemory<int>(HEALTH_ADDRESS);if(health<=500){//somecodetotellthebothowtoreact}

Listing10-1:Anifstatementthatcheckshealth

Giventheaddressofyourcharacter’shealth,youcancheckthevaluethereasoftenasyouneed;every10millisecondsistypicallyagoodrate.(FlipbacktoChapter1ifyouneedarefresheronlocatingvaluesinmemory.)Oncehealthdropsbelowacertainvalue,you’llwanttorunsomereactioncodetocastahealingspellordrinkapotion.I’lltalkabouthowyoucandothislaterinthechapter.

Ifyouwantyourbottohavemoregranularinformationandthechanceforagreatervarietyofresponses,youcanprogramittoreacttoanychangeinhealth,insteadofonlyafterasetthreshold.Todoso,changethecodeinListing10-1tocompareyourcurrenthealthtotheamountyouhadduringthepreviousexecution,asfollows:

//stilldothisevery10millisecondsstaticintpreviousHealth=0;autohealth=readMemory<int>(HEALTH_ADDRESS);if(health!=previousHealth){if(health>previousHealth){//reacttoincrease}else{//reacttodecrease}previousHealth=health;}

Page 271: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Now,thiscodeusesastaticvariablecalledpreviousHealthtotrackthevalueofhealthonthepreviousiteration.IfpreviousHealthandhealthdiffer,thebotnotonlyreactstothechangeinhealthbutalsoreactsdifferentlytohealthincreasesanddecreases.Thistechniqueisthesimplest,andmostcommon,waytoreacttochangesinagamestate.Withthepropermemoryaddresses,youcanusethiscodepatterntoobservechangesinhealth,mana,abilitycooldowns,andothercriticalinformation.

DetectingVisualCuesHealthisrelativelysimpleforabottocheckbecauseit’sjustanumber,butsomegameelementshavetoberelayedtothebotdifferently.Forexample,whenstatusailmentsorbuffsareaffectingacharacter,theeasiestwayforyoutotellistosimplylookforanonscreenstatusindicator,andthesameistrueforbots.

Whenreadingmemoryisn’tenough,youcandetectcertaineventsbyhookingagame’sgraphicsengineandwaitingforthegametorenderaspecificmodel.(Referbackto“ApplyingJumpHooksandVFHookstoDirect3D”onpage175and“CreatingaDirect3DWallhack”onpage194togetrefreshedonDirect3Dhooks.)Whenthemodelisdrawn,youcanqueueupareactiontobeexecutedaftertheframeisdrawn,likethis:

//belowisthedrawIndexedPrimitivehookvoidonDrawIndexedPrimitive(...){if(numVertices==EVENT_VERT&&primCount==EVENT_PRIM){//react,preferablyafterdrawingisdone}}

Usingthesamemodel-fingerprintingtrickasthewallhackcodeinChapter9,thiscodedetectswhenaspecificmodelisdrawntothescreenandreactsaccordingly.Thiscodereactstotheeventeverysingleframe,though,andthatcanmakeyourgameunplayable.You’llprobablywantsomeinternalcooldowntoavoidspammingareaction.Incaseswheretheindicatormodelispersistentlydrawn(thatis,notblinking),youcanactuallytrackitacrossframestodeterminewhenitappearsanddisappears.

Here’sacodesnippetthatalsohandlestracking:

booleventActive=false;booleventActiveLastFrame=false;

Page 272: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

//belowisthedrawIndexedPrimitivehookvoidonDrawIndexedPrimitive(...){if(numVertices==EVENT_VERT&&primCount==EVENT_PRIM)eventActive=true;}

//belowistheendScenehookvoidonDrawFrame(...){if(eventActive){if(!eventActiveLastFrame){//reacttoeventmodelappear}eventActiveLastFrame=true;}else{if(eventActiveLastFrame){//reacttoeventmodeldisappear}eventActiveLastFrame=false;}eventActive=false;}

TheonDrawIndexedPrimitive()functionstillcheckswhetheracertainmodelwasdrawn,butnow,twoBooleanstrackwhetherthemodelwasdrawnthisframeorthepreviousframe.Then,whentheframeiscompletelydrawn,thebotcancheckthesevariablesandreacttothemodeleitherappearingordisappearing.

Thismethodworksgreatfordetectingvisualstatusindicatorsthatappearonlywhenyourcharacterisaffectedbystuns,movementslows,snares,poisons,andsoon.YoucanalsouseittodetectwhenenemiesappearanddisappearinMOBAandRTSgames,asthesegamesdrawonlyenemiesthatareexplicitlyinthesightrangeofanalliedunitorplayer.

InterceptingNetworkTrafficOneofthemostreliablewaystoobserveeventsisthesamewaythegameclientdoes:bywaitingforthegameservertotellyouthattheyoccurred.Inthistypeofcommunication,thegameserversendsbytearrayscalledpacketsoverthenetworktotheclient,usingsockets.Thepacketsaretypicallyencryptedandcontainblobsofdataserializedthroughaproprietaryformat.

ATypicalPacket-ParsingFunctionToreceiveandprocesspackets,agameclientdoessomethinglikeListing

Page 273: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

10-2beforeitdrawsaframe.

voidparseNextPacket(){if(!network->packetReady())return;

autopacket=network->getPacket();autodata=packet->decrypt();switch(data->getType()){casePACKET_HEALTH_CHANGE:onHealthChange(data->getMessage());break;casePACKET_MANA_CHANGE:onManaChange(data->getMessage());break;//morecasesformorepackettypes}}

Listing10-2:Asimplifiedlookathowagameparsespackets

Theexactcodeforanyparticulargamemightlookdifferent,butthecontrolflowisalwaysthesame:receiveapacket,decryptit,decidewhatkindofmessageitcontains,andcallafunctionthatknowswhattodowithit.Somegamehackersinterceptrawnetworkpacketsandreplicatethisfunctionalityintheirbots.Thistechniqueworks,butitrequiresextensiveknowledgeofencryption,acompleteunderstandingofhowthegamestoresdatainsideapacket,theabilitytoman-in-the-middlethenetworkconnection,andawaytolocatethedecryptionkeysbeingusedbythegameclient.

Hookingthefunctionsresponsibleforhandlingthepacketsaftertheyaredecryptedandparsedisamuchbetterapproach;inListing10-2,thosefunctionsaretheonHealthChange()andonManaChange()functions.Thismethodleveragesthegame’sinherentabilitytoprocesspackets,allowingabottoremainignorantofthevariousnetworkfacilitiesthegameuses.Italsogivesyoudiscretionoverwhichnetworkdatayouintercept,asyouneedtohookonlythehandlersthatmeetyourneeds.

NOTE

Interceptingentirepacketscansometimesbeadvantageous—forexample,inanygamethatusesAdobeAIRandcommunicatesusingRTMPS.SinceRTMPSissoheavilydocumented,there’snoneedtoreverseengineertheformatorencryption.Chapter8explainshowtohookRTMPSindetail.

Page 274: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thereareafewtricksyoucanusetoeasilyfindtheparserfunctionand,ultimately,theswitch()statementthatdispatchespacketstotheirhandlers.ThemostusefulmethodI’vefoundistoplaceabreakpointonthefunctionthegameusestoreceivedatafromthenetwork,andthenanalyzetheflowoftheapplicationwhenthebreakpointishit.

Let’swalkthroughhowyoumightdothiswithOllyDbgattachedtoyourtargetgame.InWindows,recv()istheAPIfunctiontoreceivedatafromasocket.FromtheOllyDbgcommandline,youcansetabreakpointonrecv()byenteringthebprecvcommand.Whenthebreakpointishit,youcanclimbthecallstackusingCTRL-F9,theshortcutforexecuteuntilreturn,andF8,theshortcutforstepover.Thiscombinationessentiallyletstheprogramexecuteuntilthecalleehasreturnedtothecaller,allowingyoutoclimbthecallstackintandemwiththegame.Ateachstacklevel,youcaninspectthecodeofeachcalleruntilyoufindonethathasabigswitch()statement;thisshouldbethepacketparser.

ATrickierParserDependingonthegame’sarchitecture,though,findingtheparserfunctionmaynotbethatsimple.Consideragamewithaparserfunctionthatlookslikethis:

packetHandlers[PACKET_HEALTH_CHANGE]=onHealthChange;packetHandlers[PACKET_MANA_CHANGE]=onManaChange;

voidparseNextPacket(){if(!network->packetReady())return;autopacket=network->getPacket();autodata=packet->decrypt();autohandler=packetHandlers[data->getType()];handler->invoke(data->getMessage());}

SincetheparseNextPacket()functiondoesn’thaveaswitch()statement,there’snoobviouswaytoidentifyitinmemory.Unlessyoupayverycloseattention,you’lllikelyclimbrightpastitonthecallstack.Whenagamehasaparserfunctionlikethis,tryingtofigureoutwhattheparserfunctionlookslikemightbepointless.Ifyoudon’tseeaswitch()statementwhenclimbing

Page 275: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

therecv()callstack,you’llhavetonoteeverycalleeonthecallstackinstead.Insteadofclimbingupthecallstackfromthebreakpoint,you’dgoto

everyaddressmarkedasaRETURNbelowESPintheOllyDbgstackpane.Thesearethereturnaddressesintoeachcallerforeachcallee.Ateachreturnaddress,you’dneedtofindthetopofthecallerinOllyDbg’sdisassemblypaneandnotetheaddress.Asaresult,you’dhavealistofeveryfunctioncallleadinguptotherecv()call.

Next,you’drepeatthesamelist-makingprocessfrombreakpointsplacedonafewofthegame’shandlerfunctions.Youcanfindahandlerfunctionbymonitoringmemorythatitwillinevitablyuse.Thehandlerforahealthchangepacket,forinstance,willupdateyourhealthinmemory.UsingOllyDbg,youcansetamemoryonwritebreakpointtothehealthaddress.Whenthebreakpointgetstriggered,itmeansthegameupdatedthehealthvaluefromahandlerfunction.Thisshouldworkthesamewayformostvaluesthatarecontrolledbytheserver.Theserverwillcontrolanygame-criticalvalues,suchashealth,mana,level,items,andsoon.

Onceyou’verecordedthecallstackfromrecv()andafewhandlerfunctions,youcancorrelatethemtolocatetheparserfunction.Forexample,considerthethreepseudo–callstacksinTable10-1.

Table10-1:Pseudo–CallStacksforThreePacket-RelatedFunctions

recv()stack onHealthChange()stackonManaChange()stack

0x0BADF00D 0x101E1337 0x14141414

0x40404040 0x50505050 0x60606060

0xDEADBEEF0xDEADBEEF 0xDEADBEEF

0x30303030 0x30303030 0x30303030

0x20202020 0x20202020 0x20202020

0x10101010 0x10101010 0x10101010

Thesestacksshowwhatmemorymightlooklikeduringacalltorecv()andtoagame’shypotheticalonHealthChange()andonManaChange()functions.Noticethateachfunctionoriginatesfromachainoffourcommonfunctioncalls(showninboldface).Thedeepestcommonaddress,0xDEADBEEF,istheaddressoftheparser.Forabetterunderstandingofthisstructure,lookat

Page 276: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thecallstackslaidoutinatreeview,asinFigure10-1.

Figure10-1:Treeviewofourthreecallstacks

Eachfunction’scallstackbranchesoutfromthefunctionat0xDEADBEEF,meaningthatfunctionisacommonpointoforiginforallthreecalls.TheexampleparseNextPacket()functionisresponsibleforcallingthesefunctions,soitmustbethemostrecentcommonancestorat0xDEADBEEF.

NOTE

Thesecallstacksarehypothetical,andthey’resimplifiedbeyondwhatyou’lltypicallyencounter.Realcallstackswillprobablyhavequiteafewmorefunctioncalls,andcomparingthemwon’tbeaseasy.

AHybridParsingSystemAthirdvariationoftheparsingloopmightbeahybridoftheprevioustwothatusesaswitch()statementafterafunctioncall.Here’sanotherhypotheticalfunction:

voidprocessNextPacket(){if(!network->packetReady())return;autopacket=network->getPacket();

Page 277: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

autodata=packet->decrypt();dispatchPacket(data);}

voiddispatchPacket(data){switch(data->getType()){casePACKET_HEALTH_CHANGE:processHealthChangePacket(data->getMessage());break;casePACKET_MANA_CHANGE:processManaChangePacket(data->getMessage());break;//morecasesformoredatatypes}}

TheprocessNextPacket()functionfetchesanewpacketandcallsdispatchPacket()tohandlethedata.Inthiscase,thedispatchPacket()functionexistsinthecallstackofeachhandler,butnotintheonefortherecv()function.LookatthehypotheticalstacksinTable10-2,forexample.

Table10-2:Pseudo–CallStacksforThreePacket-RelatedFunctions

recv()stack onHealthChange()stackonManaChange()stack

0x0BADF00D 0x101E1337 0x14141414

0x40404040 0x00ABCDEF 0x00ABCDEF

0xDEADBEEF0xDEADBEEF 0xDEADBEEF

0x30303030 0x30303030 0x30303030

0x20202020 0x20202020 0x20202020

0x10101010 0x10101010 0x10101010

Althoughthesethreefunctionshavethesamefirstfouraddressesintheircallstacks,onlythetwohandlershaveonemoreaddressincommon(againshowninboldface).That’s0x00ABCDEF,andit’stheaddressofthedispatchPacket()function.Onceagain,youcanimaginetheselaidoutinatreeview,asinFigure10-2.

Page 278: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure10-2:Treeviewofourthreecallstacks

AParserHackOnceyou’velocatedthefunctionresponsiblefordispatchingpacketstotheirhandlers,you’llbeabletospoteveryhandlerthatcanbecalled.Youcandeduceahandler’spurposebyplacingabreakpointonitandwatchingwhatvalueschangeinmemorywhenitexecutes.Then,youcanhookanyhandlersthatyourbotneedstoreactto.(FlipbacktoChapter8ifyouneedarefresheronhowyoumighthookthesefunctions.)

Ofcourse,thereareendlesswaystoimplementnetworkbehavior.Ican’tcoverthemall,butseeingthesethreecommontechniquesshouldhelpyouunderstandthemethodology.Nomatterwhatgameyou’redealingwith,abreakpointonrecv()shouldbeastepintherightdirection.

PerformingIn-GameActionsBeforeabotcanreacttoevents,youhavetoteachittoplaythegame.Itneedstobeabletocastspells,movearound,andactivateitems.Onthisfront,botsaren’tmuchdifferentfrompeople:theycanjustbetoldwhichbuttonstopress.Pressingbuttonsissimpleandsufficesinmanycases,butinmoreintricatesituations,abotmayhavetocommunicateonthenetworkandtelltheserverwhatit’stryingtodo.

Tofollowalongwiththeexamplesinthissectionandexploreonyourownafterward,openthefilesintheGameHackingExamples/Chapter10_

Page 279: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ResponsiveHacks/folderinthisbook’sresourcefiles.

EmulatingtheKeyboardThemostcommonbuttonsyou’llpressinagamearekeyboardkeys,andthereareacoupleofwaysyoucanteachyourbottotype.

TheSendInput()FunctionOnecommonwaytoemulatethekeyboardiswiththeSendInput()WindowsAPIfunction.Thisfunction,whichsendskeyboardandmouseinputtothetopmostwindow,hasthefollowingprototype:

UINTSendInput(UINTinputCount,LPINPUTinputs,intsize);

Thefirstparameter,inputCount,isthenumberofinputsbeingsent.Fortheexamplesinthisbook,I’llalwaysuseavalueof1.Thesecondparameter,inputs,isapointertoastructure(oranarrayofstructureswhoselengthmatchestheinputCountvalue)withthepredefinedtypeINPUT.Thefinalparameteristhesizeofinputsinmemory,ascalculatedwiththeformulasize=inputCount×sizeof(INPUT).

TheINPUTstructuretellstheSendInput()functionwhattypeofinputtosend,andthefollowingcodeshowshowyoumightinitializeaninstanceofINPUTtopresstheF1key:

INPUTinput={0};input.type=INPUT_KEYBOARD;input.ki.wVk=VK_F1;

TohaveyourbotactuallypressF1,you’dneedtosendthisinputtwice,likeso:

SendInput(1,&input,sizeof(input));//changeinputtokeyupinput.ki.dwFlags|=KEYEVENTF_KEYUP;SendInput(1,&input,sizeof(input));

ThefirstcalltoSendInput()pressesF1,andthesecondreleasesit.Thereleasehappensnotbecausetheinputwassenttwice,butbecausethesecondcallwasmadewiththeKEYEVENTF_KEYUPflagenabledintheinputparameter’skeyboardflagsfield.Sincesettingupinputforevenasinglekeyisabit

Page 280: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

messy,it’sbesttowrapeverythinginsideafunction.TheresultlookssomethinglikeListing10-3.

voidsendKeyWithSendInput(WORDkey,boolup){INPUTinput={0};input.type=INPUT_KEYBOARD;input.ki.wVk=key;input.ki.dwFlags=0;

if(up)input.ki.dwFlags|=KEYEVENTF_KEYUP;SendInput(1,&input,sizeof(input));}sendKeyWithSendInput(VK_F1,false);//presssendKeyWithSendInput(VK_F1,true);//release

Listing10-3:AwrapperforemulatingkeystrokeswithSendInput()

Thisfunctioninitializesinputwiththegivenkey,enablestheflagKEYEVENTF_KEYUPifupisset,andcallstheSendInput()function.ThismeanssendKeyWithSendInput()mustbecalledasecondtimetosendthekeyrelease,eventhoughthereleaseisalwaysrequired.ThefunctioniswrittenthiswaybecausekeycombinationsthatinvolvemodifierslikeSHIFT,ALT,orCTRL

mustbesentabitdifferently;themodifier’spressmustcomebeforethekey’spress,butitsreleasemustcomeafterthekey’srelease.

Thefollowingcodeshowshowyou’dusethesendKeyWithSendInput()functiontotellabottopressSHIFT-F1:

sendKeyWithSendInput(VK_LSHIFT,false);//pressshiftsendKeyWithSendInput(VK_F1,false);//pressF1sendKeyWithSendInput(VK_F1,true);//releaseF1sendKeyWithSendInput(VK_LSHIFT,true);//releaseshift

You’dhavetocallsendKeyWithSendInput()fourtimes,butthat’sstilleasierthanusingthecodewithoutawrapperfunction.

TheSendMessage()FunctionAnalternativemethodforsendingkeystrokesreliesontheSendMessage()WindowsAPIfunction.Thisfunctionallowsyoutosendinputtoanywindow,evenifit’sminimizedorhidden,bypostingdatadirectlytothetargetwindow’smessagequeue.Thisadvantagemakesitthemethodof

Page 281: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

choiceforgamehackers,becauseitenablesuserstodootherthingswhiletheirbotplaysthegameinthebackground.SendMessage()hasthefollowingprototype:

LRESULTSendMessage(HWNDwindow,UINTmessage,WPARAMwparam,LPARAMlparam);

Thefirstparameter,window,isahandletothewindowthattheinputisbeingsentto.Thesecondparameter,message,isthetypeofinputbeingsent;forkeyboardinput,thisparameterisWM_KEYUP,WM_KEYDOWN,orWM_CHAR.Thethirdparameter,wparam,shouldbethekeycode.Thefinalparameter,lparam,shouldbe0whenthemessageisWM_KEYDOWNand1otherwise.

BeforeyoucanusetheSendMessage()function,youmustobtainahandletothetargetprocess’smainwindow.Giventhetitleofthewindow,youcanobtainahandleusingtheFindWindow()WindowsAPIfunction,asfollows:

autowindow=FindWindowA(NULL,"TitleOfGameWindow");

Withavalidwindowhandle,makingacalltoSendMessage()lookssomethinglikethis:

SendMessageA(window,WM_KEYDOWN,VK_F1,0);SendMessageA(window,WM_KEYUP,VK_F1,0);

ThefirstcallpressestheF1key,andthesecondcallreleasesit.Keepinmind,however,thatthisseriesofcallsworksonlyforkeysthatdon’tinputtext,likeF1,INSERT,orTAB.Tohaveyourbotpresskeysthatinputtext,youmustalsosendaWM_CHARmessagebetweenthedownandupmessages.TotypeW,forinstance,you’ddosomethinglikethis:

DWORDkey=(DWORD)'W';SendMessageA(window,WM_KEYDOWN,key,0);SendMessageA(window,WM_CHAR,key,1);SendMessageA(window,WM_KEYUP,key,1);

Thiscreatesakeyvariablesotheletterkeytopresscanbechangedeasily.ThenitfollowsthesamestepstheF1exampleused,justwithaWM_CHARmessageinbetween.

Page 282: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

NOTE

YoucanactuallysendnothingbuttheWM_CHARmessageandgetthesameresult,butit’sbestpracticetosendallthreemessages.GamedeveloperscaneasilyshutdownbotsbypatchingthegametoignoreWM_CHARmessagesthatdon’tfollowWM_KEYDOWN,andtheycanevenuseitasawaytodetectyourbotandbanyou.

AsIshowedwiththeSendInput()technique,youcancreateawrapperaroundthisfunctionalitytomakeyourbotcodeeasiertoworkwith.Thewrapperlookssomethinglikethis:

voidsendKeyWithSendMessage(HWNDwindow,WORDkey,charletter){SendMessageA(window,WM_KEYDOWN,key,0);if(letter!=0)SendMessageA(window,WM_CHAR,letter,1);SendMessageA(window,WM_KEYUP,key,1);}

UnlikeListing10-3,thiswrapperactuallysendsboththepressandrelease.ThisisbecauseSendMessage()can’tbeusedtosendkeystrokeswithmodifiers,sothere’sneveranyneedtoinsertcodebetweenthetwocalls.

NOTE

Therearemultiplewaysagamemightcheckwhetheramodifierkeyispressed,though.YoumightbeabletosendmodifierkeystocertaingamesbycallingtheSendMessage()function,butitdependsonhowthosegamesdetectmodifiers.

YoucanusethiswrapperinasimilarwayastheoneinListing10-3.Forexample,thiscodesendsF1followedbyW:

sendKeyWithSendMessage(window,VK_F1,0);sendKeyWithSendMessage(window,'W','W');

Thisexample,likealloftheSendMessage()codeI’veshownsofar,simplygetsthejobdone.Itcaninputtext,butitdoesn’texactlysendpropermessages.

Therearealotofsmalldetailsyouhavetogetrightifyouwanttosend100percentvalidmessageswiththeSendMessage()function.Forinstance,

Page 283: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thefirst16bitsoflparamshouldstorethenumberoftimesthekeyhasbeenautomaticallyrepeatedasaresultofbeinghelddown.Thenext8bitsshouldstorethescancode,akeyidentifierthatisspecifictoeachkeyboardmanufacturer.Thenextbit,number24,shouldbesetonlyifthebuttonisonanextendedpartofthekeyboard,suchasthenumberpad.Thefollowing4bitsareundocumented,andthenextbitshouldbesetonlyiftheALTkeywasdownwhenthemessageoriginated.Thelast2bitsarethepreviousstateflagandthetransitionstateflag.Thepreviousstateflagissetonlyifthekeywaspreviouslydown,andthetransitionstateissetonlyifthekeywaspreviouslyinthestateoppositeitscurrentposition(thatis,ifthekeyisnowupandwaspreviouslydown,orviceversa).

Thankfully,theaveragegamedoesn’tconsidermostofthesevalues.Forthatmatter,theaveragepieceofsoftwaredoesn’tcareaboutthemeither.Ifyouhavetofillallofthesevalueswithproperdatatomakeyourbotwork,you’removinginthewrongdirection.Therearemanyotherwaystoperformactions,themajorityofwhicharesimplerthantryingtoemulatetheexactbehavioroftheoperatingsystem’skernel-levelkeyboardinputhandler/dispatcher.Infact,there’salreadyafunctionthatdoesthat,andI’vealreadytalkedaboutit:theSendInput()function.

YoucanalsocontrolthemousewiththeSendInput()andSendMessage()functions,butIhighlyrecommendavoidingit.Anymousecommandsyousendwillaffect,andbeaffectedby,anylegitimatemousemovements,mouseclicks,orkeystrokessentbytheplayer.Thesameistrueforkeyboardinput,butthecomplicationsaremuchrarer.

SendingPacketsBeforeagamedrawsaframe,itchecksforkeyboardandmouseinput.Whenitreceivesinputthatresultsinanaction,suchasmovingaroundorcastingaspell,itcheckstomakesuretheactionispossibleand,ifso,tellsthegameserverthattheactionhasbeenperformed.Thegamecodetocheckforeventsandalerttheserveroftenlookssomethinglikethis:

voidprocessInput(){do{autoinput=getNextInput();if(input.isKeyboard())processKeyboardInput(input);//handleotherinputtypes(e.g.,mouse)

Page 284: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}while(!input.isEmpty());}voidprocessKeyboardInput(input){if(input.isKeyPress()){if(input.getKey()=='W')step(FORWARD);elseif(input.getKey()=='A')step(BACKWARD);//handleotherkeystrokes(e.g.,'S'and'D')}}voidstep(intdirection){if(!map->canWalkOn(player->position))return;playerMovePacketpacket(direction);network->send(packet);}

TheprocessInput()functioniscalledeveryframe.Thefunctioniteratesoverallpendinginputsanddispatchesdifferenttypesofinputstotheirrelevanthandlers.Inthiscase,whenkeyboardinputisreceived,it’sdispatchedtotheprocessKeyboardInput()function.ThishandlerthencheckswhetherthekeyiseitherWorS,and,ifso,callsstep()tomovetheplayerinthecorrespondingdirection.

Sincestep()isusedtoperformanaction,itiscalledanactorfunction.Theinvocationofanactorfunctioniscalledactuation.Youcandirectlycallagame’sactorfunctionsfromyourbottoperformanactionwhilecompletelybypassingtheinputlayer.

Beforeyoucancallanactor,though,youmustfinditsaddress.Todothis,youcanattachOllyDbgtothegame,openthecommandline,andenterbpsend.Thiswillplaceabreakpointonthesend()function,whichisusedtosenddataoverthenetwork.Whenyouplaythegame,everytimeyoutakeastep,castaspell,pickuploot,ordoanythingelse,yourbreakpointshouldtrigger,andyoucannoteeachfunctioninthecallstack.

NOTE

Thegameshouldcallsend()everytimeyoudoanythingwhileplaying.Payattentiontowhatyoudidbeforeeachsend()breakpointishit,asthatwillgiveyouaroughideaofwhatactioneachcalliscommunicatingtotheserver,and,ultimately,whattheactoryoufindisresponsiblefor.

Page 285: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Onceyouhaveafewdifferentcallstacks,youcancomparethemtolocatetheactorfunctions.Toseehowtospottheactorfunctions,let’scomparethetwoannotatedcallstacksinFigure10-3.

Figure10-3:Treeviewofcallstackstotwoactorfunctions

Likethesetwostacks,thecallstacksyoufindshouldbeidenticalatthetop,sharingacoupleofcommonfunctionsresponsibleforgenericnetworktransmission.Theyshouldalsobeidenticalonthebottom,sinceeachcalltosend()shouldhaveoriginatedfromtheprocessInput()function.Eachstackshouldhavesomeuniquefunctionsbetweentheseidenticalregions,though,andthosearetheactorfunctionsyou’relookingfor.Typically,thefunctionofinterestisimmediatelybeneaththecommonnetworkcalls.Inthiscase,thetwoactorsarethestep()andcastSpell()functions.

Afterhackingthesamegameforawhile,you’lllearnhowfarupthestacktheactorfunctionsarefromthesend()call.InFigure10-3,forexample,theactorshappenthreecallsbeforethesend()call.Knowingthis,youcouldjustclimbthestackinOllyDbg(CTRL-F9followedbyF8)threetimeswhenyoursend()breakpointishitandbeinsidetheactorfunctionthatsentthedata.

Onceyou’vefoundanactorfunction,youcancallitfromaninjectedDLL.Here’showyoumightcallstep()ifyoufounditat0xDEADBEEF:

typedefvoid_step(intdirection);autostepActor=(_step*)0xDEADBEEF;

Page 286: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

autostepActor=(_step*)0xDEADBEEF;

stepActor(FORWARD);

Sincethebotwon’tknowtheactualnameforthisgamefunction,thecodeassignsthecontentsofmemoryat0xDEADBEEFtoaconvenientlynamedvariable:stepActor.Then,thecodejustcallsstepActor()likeanyotherfunction.

Ifyou’vegottherightaddress,functionprototype,andparameters,thisshouldworkbeautifully;you’llbeabletoautomateactionsasifyouhaveaccesstothegame’ssourcecode.Justmakesuretocalltheactorfunctionsfrominsidethesamethreadasthegame,oryoucanrunintothreadingissues.ThebestwaytodothisistocalltheactorsfromahookonamajorfunctionlikeDirect3D’sEndScene()ortheWindowsAPI’sPeekMessage()function,asthesefunctionswillusuallybecalledonlyfromthegame’smainthread.

USINGTHISTOCALL__THISCALLIfyoutrytocallanactorfunctionthat’sanonstaticmemberofaclass,thefunctionwillhavea_thiscallcallingconvention,whichmeansyou’llneedtopasstheinstanceoftheclassontheECXregister.(Youcanbrushuponcallingconventionsin“FunctionCalls”onpage94.)Passingtheinstanceisstraightforward,butyou’llhavetolocateapointerchaintotheclassinstancefirst.

Tofindthepointerchain,youcandropabreakpointontheactorfunction,grabtheclassinstancevaluefromECXwhenthebreakpointkicks,andthrowthatvalueintoaCheatEnginepointerscan.Then,tocallthefunction,you’dwalkthepointerchain,obtainthecurrentinstanceaddress,anduseinlineassemblytosetupECXandmaketheactualfunctioncall.ThisprocessworkssimilarlytothewayVFhookcallbackscalltheiroriginalcounterparts,asshownin“WritingaVFTableHook”onpage156.

Page 287: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

TyingthePiecesTogetherAfteryou’vecreatedframeworksforobservingeventsandperformingactions,youcantiethemtogethertocreateresponsivehacks.Responsivehackscomeinmanyflavors,butthereareafewcommonones.

MakingthePerfectHealerAfavoritebotamonggamersisautohealing,ahackthatautomaticallyusesahealingspellwhentheplayer’shealthdecreasesdrasticallyordropsbelowacertainthreshold.Givenawaytodetectchangesinhealthandanactorfunctiontocastspells,anautohealermightlooksomethinglikethis:

voidonHealthDecrease(inthealth,intdelta){if(health<=500)//healthbelow500castHealing();elseif(delta>=400)//largedropinhealthcastHealing();}

Thisautohealingfunctionisprettysimple,butitworkswell.Moreadvancedautohealersmighthavemanymorelevelsofhealingandbeabletolearnastheygo.You’llgetworkingexamplecodeandanin-depthexplanationofadvancedautohealersin“ControlTheoryandGameHacking”onpage222.

ResistingEnemyCrowd-ControlAttacksAnti-crowd-controlhacksdetectincomingcrowd-controlattacksandautomaticallycastspellsthatreducetheireffectsorcompletelynegatethem.Crowd-controlattacksdisableplayersinsomeway,sohavingenemiescastthemonyoucanbeapain.

Givenawaytodetectincomingoractivecrowd-controleffects,suchasbydetectingaDirect3Dmodelorbyinterceptinganincomingpacket,andanactorfunctiontocastspells,youcouldhaveabotreactinstantlytosuchattackslikeso:

voidonIncomingCrowdControl(){//castashieldtoblockthecrowdcontrolcastSpellShield();

Page 288: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}voidonReceiveCrowdControl(){//cleansecrowdcontrolthathasalreadytakeneffectcastCleanse();}

AnonIncomingCrowdControl()functionmighttrytostopthecrowd-controlspellfromeverhittingyou.Failingthat,thebotcouldcallanonReceiveCrowdControl()spelltoremovetheeffects.

AvoidingWastedManaSpelltrainersarealsoquitecommonamongbotters.Spelltrainerswaituntiltheplayerhasfullmanaandthencastspellstoincreasetheplayer’smagiclevelorstats.Thisallowsplayerstoquicklyincreasetheirmagicskills,astheywillneverwastemanaregenerationjustbecausetheyhavefullmana.

Givenawaytodetectchangesinmanaandanactorfunctiontocastspells,abotmightincludethefollowingpseudocodeforaspelltrainer:

voidonManaIncrease(intmana,intdelta){if(delta>=100)//playerisusingmanapotions,return;//theymustneedthemana,abortif(mana>=MAX_MANA-10)//manaisnearlyfull,wastesomecastManaWasteSpell();}

Thisfunctiontakestheplayer’smanaandtheincreaseinthatplayer’smana(delta)asparameters.Iftheincreaseinmanaisaboveacertainamount,itassumestheplayerisusingpotionsorotheritemstoreplenishmana,anditwon’tcastanyextraspells.Otherwise,iftheplayerhasplentyofmana,thefunctionfiresoffanyoldspelltogettheplayersomeexperiencepoints.

Othercommonresponsivehacksareautoreloadtoinstantlyreloadammo,autododgetoevadeincomingprojectiles,andautocombotoinstantlyattackthesametargetasanearbyally.Really,theonlylimittothenumberofresponsivehacksyoucanaddtoabotisthenumberofeventsyourbotcanobserveinthegame,multipliedbythenumberofvalidandhelpfulresponsesitcansendforeachevent.

Page 289: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ClosingThoughtsUsinghooks,memorymanipulation,andkeyboardsimulation,youcanbegincreatingyourfirstresponsivehacks.Thesehacksareyourentrypointintogamingautonomy,butthey’reonlyaglimpseofwhat’spossible.Chapter11willbethepinnacleofyourgame-hackingadventure.Usingeverythingyou’velearnedsofar,andbuildingontheprinciplesofresponsivehacks,you’lllearnhowtoautomateadvancedactionsandcreateatrulyautonomousbot.

Ifyou’renotfeelingquitereadytogodeeper,Istronglyrecommendreviewingtheearliermaterialandthengettingsomepracticeinanisolatedenvironmentonyourownmachine.Implementingbotslikethisisaloteasierthanyoumightthink,andit’sanamazinglysatisfyingexperience.Onceyou’recomfortablemakingautohealersandotherbasicresponsivehacks,you’llbereadytostartcompletelyautomatinggameplay.

Page 290: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

11PUTTINGITALLTOGETHER:WRITING

AUTONOMOUSBOTS

Theendgoalofgamehackingistomakeafull-fledgedautomatedbotcapableofplayingagameforhoursonend.Suchbotscanheal,drinkpotions,farmmonsters,lootcorpses,walkaround,sellloot,buysupplies,andmore.Makingbotsthispowerfulrequiresyoutocombineyourhooksandmemoryreadswithconceptslikecontroltheory,statemachines,andsearchalgorithms,whichareallcoveredinthischapter.

Throughoutthelessonshere,you’llalsolearnaboutcommonautomatedhacksandhowtheyshouldbehaveatahighlevel.Aftercoveringthetheoryandcodebehindautomatedhacks,I’llgiveyouahigh-levellookattwotypesofbotsthatrelyonsuchcode:cavebots,whichcanexplorecavesandbringhometheloot,andwarbots,whichcanfightenemiesforyou.Bytheendofthechapter,youshouldbereadytobustoutyourtools,fireupyourdevelopmentenvironment,andstartmakingsomereallyawesomebots.

ControlTheoryandGameHackingControltheoryisabranchofengineeringthatprovidesawaytocontrolthebehaviorofdynamicsystems.Controltheorydeterminesthestateofasystemusingsensors,afterwhichacontrollerdeterminesthesetofactionsneededto

Page 291: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

bringthesystem’scurrentstatetosomeotherdesiredstate.Afterthecontrollerexecutesthefirstactionintheset,theentireprocess—knownasafeedbackloop—repeats(seeFigure11-1).

Figure11-1:Acontroltheoryfeedbackloop

Let’sapplythisfeedbacklooptogamehacking.Toautomateplaywithinagame(thesystem),abotimplementssomealgorithms(thecontroller)thatunderstandhowtoplaythegameinanystateobservedbythememoryreads,networkhooks,andsoon(thesensors).Thecontrollertypicallyhassomehumaninputs,likethepathtowalk,creaturestoattack,andloottopickup.Thus,toreachthedesiredstate,thecontrollermustperformsomesubsetoftheseinputsthatarepossiblegiventhecurrentstate.

Forinstance,iftherearenocreaturesonscreenandnocorpsestoloot,thedesiredstatemaybefortheplayertoreachthenextlocation(calledawaypoint)inthepredefinedpath.Inthiscase,thecontrollermovestheplayeronestepclosertothewaypointoneachiteration.Iftheplayerencountersacreature,thecontrollermightdecidetoattackthecreatureinthefirstframeand,inthefollowingframes,switchbetweenrunningfromthecreature(knownaskiting)andshootingspellsatit.Oncethecreaturedies,thecontrollerexecutesasetofactionstolootthebodyandcontinuetothenextwaypoint.

Giventhisexampleofhowafeedbackloopmightoperate,itmightseemoverwhelmingtocodesuchasystem.Luckily,thereareafewdesignpatternsthatmakethetaskmucheasierthanitsounds.

StateMachinesStatemachinesaremathematicalmodelsofcomputationthatdescribehowasystembehavesbasedoninput.Figure11-2showsasimplestatemachine

Page 292: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

thatreadsalistofbinarydigits.ThemachinestartswithaninitialstateofS1.Asititeratesoverthedigitsintheinput,itchangesitsstateaccordingly.Inthiscase,statesS1andS2repeatthemselveswhenthemachineencountersa1andactivateoneanotherwhenitencountersa0.Forexample,forthebinarydigits11000111,thestatetransitionswouldbeS1,S1,S2,S1,S2,S2,S2,andfinallyS2.

Figure11-2:Asimplestatemachine

Withasmallspinontheclassicalstatemachinetheory,astatemachinecanbethecontrollerinacontroltheoryfeedbackloop.Thistweakedversionofastatemachinecomprisesalistofstates,theconditionssignifyingeachstate,andtheactionsthatmusthappentoreacheachstate.

STATEMACHINESANDGAMEHACKINGAgame-hackingstatemachinenotonlymustkeepaninternalstatebutalsomustrespondto(oractuate)thegameenvironmentbasedonthatstate.Theoverallgamestatecanchangebasedonyourbot’sactuation,thebehaviorofotherplayers,andotherunpredictableoccurrencesinthegameenvironment.Forthisreason,tryingtopersistentlywalkastatemachinebasedontheobservedgameenvironmentisfutile;it’snearlyimpossibletocreateasetoftransitionsforeachstatetoaccountforeverypossibleobservationthatcanbemadebetweeniterations.Itmakesmoresenseforthestatemachinetoreevaluatethegameenvironmentasafreshslateeachtimeitconsiderstheinput.Todothis,thestatemachinemustusethegameenvironmentitselfasthemechanismfortransitioningbetween

Page 293: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

states—thatis,themachine’sactuationontheenvironmentshouldhaveenoughofaneffectonthenextiterationsthatitactivatesanewstate.Classicalstatemachinescanbedevisedthatarecapableofworkinglikethis,butwe’regoingtoflattenthemoutandusetheminamuchsimpler,yetstillverypowerful,way.

Ifyou’refamiliarwithclassicalstatemachines,thismaynotseemintuitive,butinthecomingsectionsyou’llseehowstatemachinescanbemutatedandpairedwithcontroltheorytoachievewhatwewant.

Themajordifferenceisthatinsteadofonestatemerelyactivatinganother,foreachstateinagameautomationstatemachine,abotwillperformin-gameactionsthatchangetheoverallstateofthegameand,thus,thestatethatisdetectedonthenextiterationofthefeedbackloop.Incode,anobjecttorepresentastateinthismachinemightlooklikethis:

classStateDefinition{public:StateDefinition(){}~StateDefinition(){}boolcondition();voidreach();};

YoucanassembleStateDefinitionobjectsintoastatemachinewithasimplestd::vectordefinition,likethis:

std::vector<StateDefinition>stateMachine;

Andpresto,youhavetheskeletonofastatemachine,readytoreceiveanyStateDefinitionobjectsyoucreate.Inconjunctionwithafeedbackloop,thisstatemachinecanbeusedtodefinetheflowofautomation.

First,youcancreatealistofdefinitionsthatmodelyourbot’sdesiredbehavior,orderedinthevectorbyimportance.EachStateDefinitionobjectcanuseinformationfromyoursensorsasinput,passingthatdatatothecondition()functiontodeterminewhetherornotthestateshouldbeactivated.Then,youcancreateacontrollerthatloopsoverthelistofstates,callingthereach()functionofthefirststatewhosecondition()functionreturnsfalse.Finally,youcanwrapthecontrollerinafeedbackloop.Ifyoudon’tseehowthisfeedbackloopwouldworkyet,don’tworry;I’llshowyou

Page 294: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

howtocodeitnow.

NOTE

Youcanthinkofthestatementinyourcondition()functionasarequirementforthemachinetotransitiontothenextstate.Ifthestatementistrue,itmeansnoactuationmusthappenbeforethenextstateinthelistcanbeevaluatedandtheloopcancontinueiterating.Ifthestatementisfalse,itmeanssomeactuatormustoccurbeforethetransitioncanhappen.

You’llfindalloftheexamplecodeforthefollowingsectionand“ErrorCorrection”onpage230intheGameHackingExamples/Chapter11_StateMachinesdirectoryofthisbook’ssourcefiles.TheincludedprojectscanbecompiledwithVisualStudio2010,buttheyshouldalsoworkwithanyotherC++compiler.Downloadthemathttps://www.nostarch.com/gamehacking/andcompilethemifyouwanttofollowalong.

CombiningControlTheoryandStateMachinesTotiestatestogetherwithafeedbackloop,firstyouhavetoprovideeachStateDefinitionobjectwithagenericwaytoaccessthesensorsandactuatorsthatyou’veimplemented.TheStateDefinitionclassthenbecomesthefollowing:

classStateDefinition{public:StateDefinition(){}~StateDefinition(){}boolcondition(GameSensors*sensors);voidreach(GameSensors*sensors,GameActuators*actuators);};

Thischangesimplymodifiesthecondition()andreach()functionstoacceptinstancesoftheclassesGameSensorsandGameActuatorsasarguments.GameSensorsandGameActuatorsareclassesyouneedtodefine;GameSensorswillcontaintheresultsofmemoryreads,networkhooks,andotherdatasourcesyourbotinterceptsfromthegame,whileGameActuatorswillbea

Page 295: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

collectionofactorfunctionscapableofperformingactionsinsidethegame.Next,youneedagenericwaytodefineeachindividualstate.Youcould

abstractthedefinitionofeachstatetoitsownclassthatinheritsStateDefinitionandimplementscondition()andreach()asvirtualfunctions.Alternatively,ifthesourcecodeneedstofitinasmallspace(likeabook,winkwink),youcouldkeepasingleclasstorepresenteachdefinitionandusestd::functiontoimplementthecondition()andreach()functionsoutsidetheclassdefinition.

Followingthatalternativemethod,thefinalversionofStateDefinitionwouldlooklikethis:

classStateDefinition{public:StateDefinition(){}~StateDefinition(){}std::function<bool(GameSensors*)>condition;std::function<void(GameSensors*,GameActuators*)>reach;};

WiththisversionoftheStateDefinitionclass,youcoulddefineanewstatebycreatinganinstanceoftheclassandassigningcondition()andreach()tofunctionsthatcorrespondwiththeintendedbehavior.

ABasicHealerStateMachineThenextstepisdefiningthebot’sactualbehavior.Tokeeptheexamplecodesimple,let’ssayyou’reimplementinganautomatichealer.Thishealerhastwohealingmethods:itusesstronghealingiftheplayerisatorbelow50percenthealthandweakhealingiftheplayerisbetween51and70percenthealth.

Astatemachinerepresentingthisbehaviorneedstwostates,oneforstronghealingandoneforweakhealing.Tostart,youneedtodefinethestatemachineasavectorwithtwoStateDefinitionobjects:

std::vector<StateDefinition>stateMachine(2);

ThiscodecreatesastatemachinecalledstateMachineandinitializesitwithtwoemptyStateDefinitionobjects.Next,youdefinethecondition()andreach()functionsforthesestatedefinitions.Thestronghealingstateisthemostimportantbecauseitkeepsthecharacterfromdying,soitshould

Page 296: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

comefirstinthevector,asshowninListing11-1.

autocurDef=stateMachine.begin();curDef->condition=[](GameSensors*sensors){➊returnsensors->getHealthPercent()>50;};curDef->reach=[](GameSensors*sensors,GameActuators*actuators){➋actuators->strongHeal();};

Listing11-1:Codeforastronghealingstate

ThiscodefirstcreatesaniteratorcalledcurDefthatpointstothefirstStateDefinitionobjectinthestateMachinevector.Theobject’scondition()functionisthendefined➊;inEnglish,thisdefinitionsays,“Thestateismetiftheplayer’shealthpercentisgreaterthan50.”Ifthestateisn’tmet,thentheobject’sreach()functioncallsthestrongHeal()actorfunction➋sothatstronghealingcanbeperformed.

Withthestronghealingstatedefined,nextyoudefinetheweakhealingstate,asshowninListing11-2.

curDef++;curDef->condition=[](GameSensors*sensors){➊returnsensors->getHealthPercent()>70;};curDef->reach=[](GameSensors*sensors,GameActuators*actuators){➋actuators->weakHeal();};

Listing11-2:Codeforweakhealing

AfterincrementingcurDefsoitpointstothesecondStateDefinitionobjectinthestateMachinevector,thiscodedefinestheobject’scondition()function➊as,“Thestateismetiftheplayer’shealthpercentisgreaterthan70.”Italsodefinestheobject’sreach()functionasanactuators->weakHeal()call➋.

Onceyou’vefinisheddefiningthestatemachine,youmustimplementthecontroller.Sincetheactualbehaviorofthecontrolleriscontainedinthestatemachine,youonlyneedtoaddasimplelooptocompleteit:

for(autostate=stateMachine.begin();state!=stateMachine.end();state++){

Page 297: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

if(➊!state->condition(&sensors)){state->reach(&sensors,&actuators);break;}}

Thiscontrollerloopiteratesoverthestatemachine,executesthereach()functionofthefirststatewhosecondition()functionreturnsfalse➊,andbreaksoutifanyreach()functioniscalled.Thefinalstepistoimplementthefeedbackloopandplopthecontrollerloopinsideit,asshowninListing11-3.

while(true){for(autostate=stateMachine.begin();state!=stateMachine.end();state++){if(!state->condition(&sensors)){state->reach(&sensors,&actuators);break;}Sleep(FEEDBACK_LOOP_TIMEOUT);}

Listing11-3:Finalhealingstatemachineandfeedbackloop

ThisloopcontinuouslyexecutesthecontrollerloopandsleepsforFEEDBACK_LOOP_TIMEOUTmillisecondsbetweeneachexecution.TheSleep()callallowsthegameservertoreceiveandprocessanyactuationfromthepreviousiterationandallowsthegameclienttoreceiveanyresultsoftheactuationfromtheserverbeforeexecutingthenextcontrollerloop.

Ifyou’restillabitconfusedaboutwhatIjustshowedyou,checkoutFigure11-3,whichshowshowtheinfinitelyloopingcodeinListing11-3works.First,itcheckswhetherthestronghealingconditionistrue,andifitis,theweakhealingconditionischecked.Ifthestronghealingconditionisfalse,thentheplayer’shealthmustbeatorbelow50percent,soastronghealingmethodgetscalled.Iftheweakhealingconditioncheckisfalse,thentheplayer’shealthmustbebetween51and70percent,sotheweakhealingmethodisexecuted.

Page 298: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Figure11-3:Flowchartofthehealingstatemachineandfeedbackloop

Aftereithermethod,themachinesleeps.Ifbothconditionchecksaretrue,thentheplayerneedsnohealing.Themachinedoesnothingtochangethestateandsleepsbeforestartingagainatthetopofthewhileloop.

AComplexHypotheticalStateMachineThebehaviorimplementedinthehealingstatemachineissimple,sorollingitintothiskindofcontrolstructuremayseemlikeoverkill,butit’susefulifyouwanttoexpandthecontroller.If,forexample,youwantedtocombinethehealingstatemachinewiththe“walk,attack,loot”behaviorthatI

Page 299: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

discussedin“ControlTheoryandGameHacking”onpage222,thecontrolstructurewouldbemuchmorecomplex.Let’stakeahigh-levellookatthestatesyou’dneed:

StronghealingConditionmetifhealthisover50percent.Reachbycastingstronghealingspell.

WeakhealingConditionmetifhealthisover70percent.Reachbycastingweakhealingspell.

AttackspellConditionmetifnotargetisavailableorifattackspellisoncooldown.Reachbycastingattackspellontarget.

KitemonsterConditionmetifnotargetisavailableorifdistancefromtargetisadequate.(Thedefinitionof“adequate”dependsonhowfarawayyouwanttobefromenemieswhenkiting.)Reachbytakingastepawayfromtarget.

TargetmonsterConditionmetifthere’snocreaturetoattack.Reachbyattackingacreature.

LootitemConditionmetifthere’snocorpseopenorifopencorpsehasnothingtoloot.Reachbytakinganitemfromopencorpse.

ApproachcorpseConditionmetiftherearenocorpsestoopenorifadjacenttoacorpse.Reachbytakingasteptowardacorpsethatwillbeopened.

OpencorpseConditionmetifthecharacterisnotadjacenttoacorpsethatcanbeopened.Reachbyopeningadjacentcorpse.

FollowpathConditionmetifthecharacterisunabletomovetocurrentwaypointorifstandingoncurrentwaypoint.Reachbytakingasteptowardcurrentwaypoint.

AdvancewaypointConditionmetiftherearenowaypointslefttofollow.Reachbyupdatingthecurrentwaypointtothenextwaypointinthelist.Ifthecharactercan’treachthecurrentwaypointforsomereason(say,ifthecharacterisstuck),thentheAdvanceWaypointstatekeepsitfrombeingstuck.Ifthecharacterhasreachedthecurrentwaypoint,AdvanceWaypointselectsthenextwaypointtokeepthingsmovingalong.

Page 300: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thisstatemachineisquiteabitmorecomplexthanthehealing-onlystatemachine.IfIdiagrammedthisstatemachine,therewouldbe23objectsinthediagram,witharrowsgoingover33controlpaths.ComparethattoFigure11-3,whichhasonly7objectsand9controlpaths.

Youcouldcodethehealerbehaviorwithoutusingastatemachineorfeedbackloop,butIcan’timaginehowtoeasilydothesameforthisfull-fledgedbot.Eachofthese10statesreliesonnotonlyitsownconditionbutalsotheconditionofeverystateprecedingit.Moreover,hardcodingthelogicwouldeitherrequireatonofnestedif()statementsorabunchofstackedif()/return()statements—and,eitherway,itwouldjustbehaveexactlylikethestatemachinebutwithnoruntimeflexibility.

Runtimeflexibilityreferstoastatemachine’sabilitytomutate.Unlikehardcodedconditionchecks,statedefinitionsinastatemachinecanbemoved,removed,andaddeddynamically.Thestatemachinemethodallowsyoutoplugandplaydifferentbehaviorsandfeaturesdependingonuserinput.

Totakethisconceptastepfurther,youcouldexposeyoursensorsandactuatorstoaLuaenvironment,createLuafunctionscapableofaddingandremovingstatesfromthestatemachine,andmodifytheStateDefinitionsothatitscondition()andreach()functionscancallLuafunctionsexposedbytheLuaenvironment.Writingacontrolsystemthiswaywouldallowyoutocodethecoreofyourbot(hooks,memoryreading,actuation)inC++whilemakingLua(ahigh-level,dynamiclanguage)availabletoyouforautomation.

NOTE

YoucanembedLuainyourownprogramsbyincludingafewheadersandlinkingagainsttheLualibrary.Thisprocessisnotdifficult,butit’soutsidethescopeofthisbook,soIencourageyoutocheckoutChapter24ofProgramminginLuabyRobertoIerusalimschy(http://www.lua.org/pil/24.html)formoreinformation.

ErrorCorrectionAnotherpieceofcontroltheorythat’susefulforgamehackingiserror

Page 301: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

correction.Anerrorcorrectionmechanisminacontrollerobservestheoutcomeofactuation,comparestheoutcometoanexpectedresult,andadjustsfuturecalculationstobringlateroutcomesclosertotheexpectedone.Errorcorrectioncancomeinhandywhenyou’reworkingwithstochasticsystems,wheretheoutputgeneratedfromagiveninputisnotfullypredictable.

Gamesasawholearestochastic,but,luckilyforgamehackers,theresultsofactionsaremostlydeterministic.Takethehealingcontroller,forexample.Inmostgames,youcancalculateexactlyhowmuchhealthyoucanhealwithagivenspell,and,thus,youknowexactlywhentoheal.Butimagineyou’rewritingahealerforthesmallspectrumofsituationswhereyourhealingisimpossibletocalculate;forinstance,maybethebotissupposedtoworkonavarietyofcharactersspanningmanylevelswithoutuserinput.

Errorcorrectioncouldenableyourbottolearnhowtobesthealtheplayers.Inthisscenario,therearetwowaysyoucanimplementerrorcorrection,eachofwhichdependsonhowthehealingsystemworks.

AdjustingforaConstantRatioIfyouhealforaconstantratioofhealth,you’llonlyneedtoadjustyourcontrollerafterthefirstheal.Assumingthatyoursensorscandetecthowmuchyou’vehealed,thisaddsonlyafewlinesofcode.YoucouldeasilymodifytheweakhealingstateinListing11-2tosomethinglikethis:

curDef->condition=[](GameSensors*sensors)->bool{staticfloathealAt=70;staticboolhasLearned=false;if(!hasLearned&&sensors->detectedWeakHeal()){hasLearned=true;healAt=100-sensors->getWeakHealIncrease();}returnsensors->getHealthPercent()>healAt;};

Insteadofhardcoding70asthethresholdforweakhealing,thiscodemovesthethresholdtoastaticvariablecalledhealAt.ItalsoaddsanotherstaticvariablecalledhasLearnedsothatthecodeknowswhenlearningiscomplete.

Oneachinvocationofthiscondition()function,thecodecheckstwoconditions:whetherhasLearnedisfalseandwhetherthesensorsdetecteda

Page 302: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

weakhealingevent.Whenthischeckpasses,thecodesetshasLearnedtotrueandupdateshealAttohealatorbelowtheperfectpercentage;thatis,ifyourweakhealingmusteredupa20percentincreaseinhealth,healAtwouldbesetto80percenthealthinsteadof70percent,soeachhealwouldbringtheplayerbackupto100percenthealth.

ImplementingAdaptableErrorCorrectionButwhatifyourhealingpowerincreases?Ifacharactercangainlevels,applyskillpoints,orincreasemaximumhealth,theamountofhealthitcanhealmaychangeaccordingly.Forexample,ifyoustartabotonalevel-10characterandletitrununtilthecharacterislevel40,yourhealingcodewillneedtoadapt.Alevel-40characterhealinglikeitdidatlevel10wouldeitherimmenselyoverhealordiequicklyagainston-levelgameenemies.

Tohandlethisscenario,abotneedstoconstantlyupdateitshealingthresholdtoreflecttheobservedhealingamount.Listing11-4showshowyoucanmodifythestronghealingconditionfunctioninListing11-1todothis.

curDef->condition=[](GameSensors*sensors)->bool{staticfloathealAt=50;➊if(sensors->detectedStrongHeal()){autonewHealAt=100-sensors->getStrongHealIncrease();➋healAt=(healAt+newHealAt)/2.00f;➌sensors->clearStrongHealInfo();}returnsensors->getHealthPercent()>healAt;};

Listing11-4:Tweakingthestronghealingconditioncode

Asinthemodifiedweakhealingfunction,thehealingthresholdhasbeenmovedtoastaticvariablecalledhealAt,butthistime,thelogicisabitdifferent.Sincelearningmusthappencontinually,there’snovariabletotrackwhetherthebothasalreadylearneditstruehealingcapacity.Instead,thecodejustcheckswhetherthesensorshaveseenastronghealingeventsinceitslastinvocation➊.Ifso,thecodereplaceshealAtwiththeaverageofhealAtandnewHealAtandcallsafunctiontoclearthesensorsofinformationrelatedtostronghealing➌.

Clearingthesensorsisactuallyveryimportant,becauseitkeepsthecode

Page 303: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

fromconstantlyupdatinghealAtagainstfeedbackfromthesamestronghealingcast.Notice,too,thatthisfunctiondoesn’tupdatehealAttoaperfectvaluebutinsteadslidesittowardtheobservedoptimalvalue.Thisbehaviormakesthenewfunctionidealforsituationswherethereissomeamountofrandomnessinhowmuchyoucanactuallyheal.Ifyourbotneedstoslidetowardthenewvaluefaster,youmightchangethelineat➋tosomethinglikethis:

healAt=(healAt+newHealAt*2)/3.00f;

ThiscodetoupdatehealAtusesanaverageweightedtowardthenewHealAtvalue.Thereareafewpointstoconsiderwhenusingthisapproach,however.First,whathappenswhenyouoverheal?Insomegames,whenyouhealtofullhealth,yoursensorsmightbeabletodetectonlyhowmuchyouactuallyhealed.Inothergames,yoursensorsmaybeabletodetecttheactualamounthealed.Putanotherway,ifyoucasta30percentstronghealfrom85percenthealth,doyoursensorsseeahealof30percentor15percent?Iftheansweris30percent,you’reset.Iftheansweris15percent,yourcodeneedsawaytoadjustdownward.

OnewaytoadjustaccordinglyistodecrementhealAtwhenyoursensorsseeahealthatbringsyoutofullhealth,likethis:

curDef->condition=[](GameSensors*sensors)->bool{staticfloathealAt=50;if(sensors->detectedStrongHeal()){➊if(sensors->getStrongHealMaxed()){healAt--;}else{autonewHealAt=100-sensors->getStrongHealIncrease();healAt=(healAt+newHealAt)/2.00f;}sensors->clearStrongHealInfo();}returnsensors->getHealthPercent()>healAt;};

ThiscodeisalmostthesameasListing11-4,butitaddsanif()clausetodecrementhealAtifamaxhealisdetected➊.Otherwise,thefunctionshouldbehavelikeListing11-4.

Healingisasimplecase,butthiscodeshowsagreatexampleofhowyoucanuseerrorcorrectiontodynamicallyimproveyourbots’behavior.Onemoreadvancedusecaseisadjustingskillshotstoaccountforenemy

Page 304: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

moreadvancedusecaseisadjustingskillshotstoaccountforenemymovementpatterns.Everyplayerhaspatternsinhowtheyavoidskillshots,soifyoursensorsareabletomeasurethedirectionanddistanceanenemymoveswhendodgingaskillshot,yourcontrollercodecanadjustthelocationwherethebotinitiallyshootstheskillshot.Inthissamescenario,learningwouldalsohelpthebotaccountfordifferencesingameserverlatency,charactermovementspeed,andsoon.

Whenusingerrorcorrection,notethatyourcodewillbecleanerandmoreportableifyourstatedefinitionshavesomeformofinternalbookkeepingotherthanstaticvariables.Moreover,toavoidclutteringyourstatedefinitions,Isuggestencapsulatingtheerrorcorrectionlogicinsomeexternalmodulesthatareeasilyinvokedwhenneeded.

PathfindingwithSearchAlgorithmsOnecommonchallengeyou’llfacewhenwritinganautonomousbotiscalculatingapathforacharactertofollowfromonelocationtoanother.Asidefromthesheerreverseengineeringchallengeofcreatingsensorstoreadwhichcoordinatesonthegamemapareblockingforwardmovementornot,there’salsothealgorithmicchallengeofcalculatingapathwithinthatmap.Calculatingapathiscalledpathfinding,andgamehackersoftenuseasearchalgorithmtotackleit.

TwoCommonSearchTechniquesGivenagridoftiles,astartinglocationa,andanendinglocationb,asearchalgorithmcalculatesapathfromatob.Thealgorithmdoesthisbycreatinganodeata,addingnodesadjacenttoatoalistoftilestobeexplored(calledthefrontier),updatingthenodetothebesttileinthefrontier,andrepeatingtheprocessuntilthenodereachesb.Differentsearchalgorithmsselectthebestnodedifferently,usingeitheracost,aheuristic,orboth.

Dijkstra’salgorithm,forexample,calculatesthecostofatilebasedonitsdistancefromtheanodeandselectsthetilewiththelowestcost.Imagineanemptytwo-dimensionalgridwithainthemiddle.InasearchfollowingDijkstra’salgorithm,thefrontierwillexpandinacircularpatternaroundauntilbliesontheedgeofthecircle,asseeninFigure11-4.

Page 305: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thegreedybest-firstsearchalgorithm,insteadofprioritizingnodesbytheirdistancefromthestartingpoint,usesaheuristictoestimatethedistancefromanodeinthefrontiertob.Thealgorithmthenselectsthenodewiththeshortestestimateddistance.Imaginethisalgorithminthesamegridasbefore;thefrontierwouldbealinegoingalmostdirectlyfromatob,asseeninFigure11-5.

Figure11-4:ThefrontierofDijkstra’salgorithm.Lightertilesarehighercost.

Figure11-5:Thefrontierofthegreedybest-firstsearchalgorithm.Lightertilesarehighercost.

HowObstaclesDisruptSearchesThedifferenceinhowthesealgorithmsbehavebecomescleareronceobstaclesareaddedtothegrid.If,forinstance,awallseparatesaandb,Dijkstra’salgorithmwillalwaysfindthequickestpath,butwithahugeconsequence.Theradiusofthecircularfrontieraroundawillbeequaltothe

Page 306: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

lengthofthefinalpath;let’scallthatradiusr.Ifnogridboundariesclipthefrontier,youcanroughlycalculatethenumberofnodesopenedbytakingtheareaofacirclewithradiusr.Ifthepatharoundthewallis50tiles,thealgorithmwillopenroughly7,854tiles,asshowninthisequation:

π×502=7,854

Inthesamescenario,greedybest-firstsearchwillcalculatealess-than-optimalpathbutopensubstantiallyfewertiles.It’snotaseasytovisualizehowthefrontierwillexpand,andit’snotimportantrightnow,soIwon’tgointoithere.Attheendoftheday,neitherofthesealgorithmsreallyfitsthepathfindingproblemwell.Theoptimalpathisslow,andthefastpathisn’toptimal.

Toquicklycalculateanoptimalpath,youneedtofuseDijkstra’salgorithmwithgreedybest-firstsearch.Luckily,someonehasalreadydonethis,andtheresultingalgorithmisamonsterknownasA-starsearch(oftenjustcalledA*).

A*usesthesumofacost,calledg,andaheuristic,calledh,toselectnodes.Theseresultingsumiscalledthescore.Putsimply,score=g+h.LikeDijkstra’salgorithm,A*cancalculatethemostoptimalpathfromatob,andlikegreedybest-firstsearch,itcandosorelativelyquickly.

AnA*SearchAlgorithmNowthatyouknowthefundamentals,let’swritecodetoimplementtheA*algorithm.Thisimplementationwillworkinatwo-dimensionalgrid.Itwon’tallowdiagonalmovementatfirst,butI’lldiscussinabithowyoucanmodifythecodetoworkwithdiagonalmovement,too.

AlloftheexamplecodeforthissectionisintheGameHackingExamples/Chapter11_SearchAlgorithmsdirectoryofthisbook’ssourcefiles.TheincludedprojectscanbecompiledwithVisualStudio2010,buttheyshouldalsoworkwithanyotherC++compiler.Downloadthemathttps://www.nostarch.com/gamehacking/andcompilethemtofollowalong.IfyouexecuteChapter11_SearchAlgorithms.exe,you’llbeabletodefineyourown20×20gridandwatchthealgorithmcalculateasearchpath.

CreatinganA*Node

Page 307: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Tostart,defineanemptyAStarNodeclassasfollows:

typedefstd::shared_ptr<classAStarNode>AStarNodePtr;classAStarNode{public:};

ThiscodedefinestheAStarNodeclassandastd::shared_ptrtypedefinitioncalledAStarNodePtrtomakeiteasiertocreatesafepointerstotheclass.Next,withinthepublicscopeofthisclass,declaremembervariablesforthenode’sx-position,y-position,cost,andnode’sscore:

intx,y;intg,score;

Additionally,youneedapublicmemberoftypeAStarNodePtrthatreferencestheparentnode:

AStarNodePtrparent;

Afterdeclaringallmembervariables,declareapublicconstructorthatinitializesthemuponinstancecreation,asfollows:

AStarNode(intx,inty,intcost,AStarNodePtrp,intscore=0):x(x),y(y),g(cost),score(score),parent(p){}

Now,tomakecreatingsafepointerseasier,addastatichelperfunctionlikethis:

staticAStarNodePtrmakePtr(intx,inty,intcost,AStarNodePtrp,intscore=0){returnAStarNodePtr(newAStarNode(x,y,cost,p,score));}

ThismakePtr()functioncreatesanewinstanceofAStarNodeandreturnstheinstancewrappedinsideofanAstarNodePtr.

Let’srecap.TheAStarNodeclasshasmembervariablesx,y,g,score,andparent.Whentheclassisconstructed,allofthesemembersareinitializedfromvaluespassedtotheconstructor,withtheexceptionofscore,whichis

Page 308: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

optional(becauseyouuseitonlywhenmakingcopiesofanAStarNodeinstance)andsetto0ifnotprovided.

Next,defineapublicmemberfunctiontocalculatetheheuristicwhengiventhedestinationcoordinates:

intheuristic(constintdestx,intdesty)const{intxd=destx-x;intyd=desty-y;➊returnabs(xd)+abs(yd);}

ThisfunctionreturnstheManhattandistanceheuristic➊,adistancecalculationdesignedforgridswherediagonalmovementisnotpossible:

|Δx|+|Δy|Tocalculateapaththatallowsdiagonalmovement,you’dneedtomodify

thisfunctiontousetheEuclideandistanceheuristic,whichlookslikethis:

Theclassalsoneedsafunctiontoupdatescore.Youaddthatfunctiontothepublicscopeasfollows:

#defineTILE_COST1voidupdateScore(intendx,intendy){autoh=this->heuristic(endx,endy)*TILE_COST;this->score=g+h;}

Now,scoreshouldchangetog+hwhengivendestinationcoordinatestocalculateh.

Towrapup,thenodeclassalsoneedsafunctionthatcancalculateallofitschildnodes.Thefunctioncoulddothisbycreatingnewnodesforeachtileadjacenttothecurrentnode.Eachnewnodereferstothecurrentnodeasitsparent,sotheclassneedstobeabletocreateanAStarNodePtrtoacopyofthecurrentnodeaswell.Here’showallthatworks:

AStarNodePtrgetCopy(){returnAStarNode::makePtr(x,y,g,parent,score);

Page 309: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

}std::vector<AStarNodePtr>getChildren(intwidth,intheight){std::vector<AStarNodePtr>ret;autocopy=getCopy();if(x>0)➊ret.push_back(AStarNode::makePtr(x-1,y,g+TILE_COST,copy));if(y>0)➋ret.push_back(AStarNode::makePtr(x,y-1,g+TILE_COST,copy));if(x<width-1)➌ret.push_back(AStarNode::makePtr(x+1,y,g+TILE_COST,copy));if(y<height-1)➍ret.push_back(AStarNode::makePtr(x,y+1,g+TILE_COST,copy));returnret;}

Thisfunctioncreateschildnodesat(x–1,y)➊,(x,y–1)➋,(x+1,y)➌,and(x,y+1)➍.TheirparentisthenodethatcalledgetChildren,andtheirgistheparent’sgplusTILE_COST.

Toallowfordiagonalmovement,thisfunctionneedstoaddchildrenat(x–1,y–1),(x+1,y–1),(x+1,y+1),and(x–1,y+1).Additionally,ifmovingdiagonallywouldcostmore—thatis,ifthecharacterrequiresmoretimetodoit—you’dalsoneedtodothefollowing:

1. ChangeTILE_COSTto10.

2. DefineaconstantDIAG_TILE_COSTasTILE_COSTmultipliedbythetimeincrease.Ifadiagonalsteptakes1.5timesaslong,DIAG_TILE_COSTwouldbe15.

3. Givediagonalchildrenagoftheparent’sgplusDIAG_TILE_COST.

TofinishoffAStarNode,declareoperatorsforcomparingthepriorityandequalityoftwonodes.Youcouldplacethesedeclarationsoutsidetheclassinglobalscopelikethis:

➊booloperator<(constAStarNodePtr&a,constAStarNodePtr&b){returna.score>b.score;}

Page 310: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

➋booloperator==(constAStarNodePtr&a,constAStarNodePtr&b){returna.x==b.x&&a.y==b.y;}

Theseoperatorsallowstd::priority_queuetosortnodesbyscore➊andstd::findtodeterminenodeequalitybylocation➋.

WritingtheA*SearchFunctionNowthatyou’vecompletedtheAStarNodeclass,youcancodetheactualsearchfunction.Startbydefiningthefunctionprototype:

template<intWIDTH,intHEIGHT,intBLOCKING>booldoAStarSearch(intmap[WIDTH][HEIGHT],intstartx,intstarty,intendx,intendy,intpath[WIDTH][HEIGHT]){}

Theprototypeacceptsthegamemap’swidthandheight,aswellasthevaluethatsignifiesablockingtileonthemap,astemplateparameters.ThedoAStarSearch()functionalsotakesthemapitself(map),thestartingcoordinates(startxandstarty),thedestinationcoordinates(endxandendy),andablankmap(path)whereitcanfillthecalculatedpathwhenitfinishes.

NOTE

Thefirstthreeparametersaretemplateparameters,soyoucanpassthemascompiletimeconstants.I’vedonethisfortheexamplecodetoallowexplicitarraysizedeclarationsforthemapandpathparametersandtoallowadefinitevaluetosignifyblockingtilesonthemap.Inpractice,themapyoureadfromagamewillhaveadynamicsize,andyou’llprobablyneedamorerobustwaytopassthisdata.

Next,thedoAStarSearch()functionneedsasortedlisttoholdthefrontierandacontainertotrackallcreatednotessoyoucanupdatethescoreandparentofanexistingnodeifit’sopenedasachildofadifferentparent.Youcancreatetheseasfollows:

std::vector<AStarNodePtr>allNodes;

Page 311: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

std::vector<AStarNodePtr>allNodes;std::priority_queue<AStarNodePtr>frontier;

Thefrontierisdefinedwithstd::priority_queuesinceitcanautomaticallysortthenodesbasedontheirscore.Thenodecontainer,allNodes,isdefinedasastd::vector.

Now,let’screatethefirstnode:

autonode=AStarNode::makePtr(startx,starty,0,nullptr);node->updateScore(endx,endy);allNodes.push_back(node);

Thefirstnodeisano-costorphannodeattheposition(startx,starty).ThenodeisgivenascorebasedonwhattheupdateScore()functionreturns,andthenit’saddedtotheallNodescontainer.

Withanodeinthecontainer,it’stimetowritethemeatoftheA*algorithm,startingwithasimpleloop:

while(true){}

Untilotherwisespecified,therestofthecodeinthissectionwillappearinsideofthisloop,intheordershown.

Fromhere,thefirststepistocheckthegoalstate.Inthiscase,thegoalistofindapathfortheplayertofollowtothenextwaypoint,whichhappenswhenthenodeobject’spositionis(endx,endy).Thus,tocheckthegoalstate,theprogramneedstocheckwhethernodehasreachedthosecoordinatesornot.Here’showthatcheckshouldlook:

if(node->x==endx&&node->y==endy){makeList<WIDTH,HEIGHT>(node,allNodes,path);returntrue;}

Whenthegoalstateismet,theprogramreportstruebacktothecallerandfillspathwiththefinalpath.Fornow,assumeafunctioncalledmakeList()canfillinpathforyou;I’llshowyouthisfunctionshortly.Ifthegoalstateisn’tmet,youneedtoexpandthechildrenofnode,whichisactuallyaprettycomplicatedprocess:

autochildren=node->getChildren(WIDTH,HEIGHT);for(autoc=children.begin();c!=children.end();c++){

Page 312: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

➊if(map[(*c)->x][(*c)->y]==BLOCKING)continue;autofound=std::find(allNodes.rbegin(),allNodes.rend(),*c);➋if(found!=allNodes.rend()){➌if(*found>*c){(*found)->g=(*c)->g;(*found)->parent=(*c)->parent;(*found)->updateScore(endx,endy);}}else{(*c)->updateScore(endx,endy);➍frontier.push(*c);➎allNodes.push_back(*c);}}

Aftercallingnode->getChildrentogeneratealistofnodesthatcanbeaddedtothefrontier,thecodeiteratesovereachchildandignoresanythatareonblockingtiles➊.Next,foreachchild,thecodecheckswhetheranodehasalreadybeenopenedatthesamecoordinates➋.Ifso,andifthescoreoftheexistingnodeisgreaterthanthescoreofthenewchild,theexistingnodeisupdatedtotheparent,cost,andscoreofthenewchildbytheif()statementat➌.Ifthenewchilddoesn’thaveabrother-from-another-mother,itwillbeaddedasistothefrontier➍andthenodelist➎.

Alsonoticethatstd::findusesthereversebeginandreverseenditeratorsofallNodesinsteadoftheregulariterators➊.Theexampledoesthisbecausenewnodesareappendedtotheendofthevectorandduplicatenodeswillbeclosetogether,soduplicateswillusuallybeclosertotheendofthevector.(Thisstepcouldalsobedonedirectlyagainstthefrontier,butstd::priority_queuedoesn’tallowiterationovernodesandwritingthesortinplacewouldmakethecodetoolargeforprint.)

Eventually,thefunctionwillrunoutofnewchildrentoaddtothefrontier;thefollowingif()statementhandlesthatsituation:

if(frontier.size()==0)returnfalse;➊node=frontier.top();➋frontier.pop();

Thiscodepointsnodetothecheapestnodefromthefrontier➊,removesitfromthefrontier➋,andletsthelooprepeat.Ifthefrontierendsup

Page 313: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

empty,thefunctionreportsfalsebacktothecaller,sincethere’snothinglefttosearch.

CreatingthePathListFinally,it’stimetoimplementthemakeList()function:

template<intWIDTH,intHEIGHT>voidmakeList(AStarNodePtrend,std::vector<AStarNodePtr>nodes,intpath[WIDTH][HEIGHT]){for(auton=nodes.begin();n!=nodes.end();n++)➊path[(*n)->x][(*n)->y]=2;autonode=end;while(node.get()!=nullptr){➋path[node->x][node->y]=1;node=node->parent;}}

Thisfunctionupdatespathwithbothalistofclosednodes➊andthecalculatedpath➋.Forthisexample,thevalue2representstheclosednodesand1representsthepathnodes.Theprogramcalculatesnodesinthepathbyfollowingparentnodesfromthegoalnodeuntilitreachesthestartingnode,whichisanorphanwithnullptrasaparent.

WhenA*SearchesAreParticularlyUsefulMakesuretoplaywiththeexamplecodeandexecutablefortheprevioussection,becausethat’stheonlywayyou’llreallygetacquaintedwiththebehaviorofA*searches.Inmostnewergames,youshouldbeabletojustsendapacketwiththedestinationorevenemulateaclickonthemapatthedesiredspot,butwhenyoucomeacrossasituationwhereyouneedtocalculateapath,you’llbegladyoulearnedA*.

Thereareactuallymanysituationswherecalculatingapathcanbeuseful:

SelectingtargetsWhen your bot is selecting targets to attack, you may want to checkwhetheryourcharactercanactuallyreachthem.Otherwise,ifanenemy

Page 314: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

isisolatedinanunreachableroom,youmightgetstuckinplacetryingtotargetthemforever!

SelectingcorpsesAs your looting state(s) determine which corpses to open, you canoptimizebyalwaystryingtoloottheclosestcorpsefirst.

EmulatingmousemovementsVery rarely, some heavily protected games actually correlate in-gameactionswithmousemovementstoensurethatthere’snobotrunning.Inthis case, you might need to emulate the mouse. Using a modifiedversionofA*where the screen is themap, there are no blocking tiles,and node costs are slightly randomized, you can calculate human-likepathsforyourmousetofollowwhenyousimulatemovement.

KitingmonstersIfyoueverneed towritecode tokitemonsters,youcan implementA*withagoalstateofbeingNunitsawayfromallcreatures.Usingthesamecostmechanismshown in thischapter,playwith theheuristic togiveahigher cost to nodes that are closer to creatures.Kiting isn’t exactly aconventionalusecase,andtheheuristicwillrequireabunchoftweaking,butitworksamazinglyonceyou’vegotitgoing.Someimplementationscankiteanynumberofmonstersbetterthanahuman!

PredictingenemymovementsIfyou’rewritingabotthatfightsotherplayers,youcanuseA*topredicttheirmovementsandactaccordingly.Forinstance,ifyourenemystartsrunning away, your bot can assume they are running to their base,calculatetheirroute,anduseaspelltoblocktheirpathoreventeleporttoalocationwhereitexpectsthemtobe.

ThesearejustafewusecasesforA*searches,andyou’lldefinitelyfindmanymoreasyouimproveyourbots.Fortherestofthechapter,I’lldescribesomepopularautomatedhacksthatyoucanimplementusingthetechniquesdescribedinthisbook.

Page 315: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

OTHERUSESFORA*SEARCHA*isn’tjustforcalculatingpaths.WithabstractionsontopoftheAStarNodeclass,youcanadaptthesamealgorithmtoanysearchproblem.Realistically,A*isjustaweightediterationoveramultidimensionaldatasetthatiteratesuntilsomegoalobjectisfound,and,thus,itcansolveanyproblemthatcanberepresentedasamultidimensionaldataset.MoreadvancedapplicationsforA*includeplayingchessandcheckers,and—whenit’spairedwithathree-dimensionalManhattandistanceheuristicandadepth-firstsearchimplementation—evensolvingaRubik’scube.Sadly,I’mnotgoingtogointotheseusecases;ifyouwanttogetreallygoodwithsearchalgorithms,Iencourageyoutoresearchmoreonline.

CommonandCoolAutomatedHacksNowthatyou’veseenthedesignpatternsandalgorithmsneededtocreateefficient,self-teachingbots,it’stimetolearnaboutsomepopularautomatedhacksthatgobeyondsimplehealingandpathfinding.Let’sflyupto10,000feettoexploretwotypesofbotsatahighlevel.

LootingwithCavebotsWhilediscussingcontroltheory,statemachines,andsearchalgorithms,Itouchedontheideaofacavebotthatkillscreatures,grabsloot,andwalksaroundcaves.Theabilitiesofcavebotscanvarygreatly.

DepositingGoldandRestockingSuppliesIfyouwanttoleaveacharacterbottingfordaysonend,you’llneedadepositorandarefiller.Adepositorcandepositlootinyourbankorvault,whilearefillerrefillsyourpotions,runes,andothersupplies.Thesefeaturescanbedescribedwithsixbasicstates:

LeavespawnConditionmetifthecharacterisinthespawnareaorcave,

Page 316: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ifithasnothingtodeposit,andifithasenoughsupplies.Reachthisstatebyexitingthespawnareaorcave.

WalktotownConditionmetifthecharacterisinthespawnareaorcave.Reachthisstatebywalkingfromthespawnorcavetotown.

DepositConditionmetifthecharacterisinthespawnareaorcave,orifthecharacterisintownandhasnothingtodeposit.Reachthisstatebyputtinglootinthebankorvault.

WithdrawcashConditionmetifthecharacterisinthespawnareaorcave,isintownwithnosuppliestopurchase,orhasenoughgoldtopurchasesupplies.Reachthisstatebywithdrawinggoldfromthebankorvault.

PurchasesuppliesConditionmetifthecharacterisinthespawnareaorcaveorifthecharacterhasenoughsuppliestostarthunting.Reachbybuyingsupplies.

EnterspawnConditionmetifthecharacterisinthespawnareaorcave.Reachthisstatebywalkingtothespawnareaorcave.

Thesestateswouldcomebeforethestatesrelatedtofollowingwaypoints(Idescribeacoupleofthosestatesin“AComplexHypotheticalStateMachine”onpage228)inthevectorofStateDefinitionobjects.Placingthemfirstgivesthempriorityoverremaininginthecave,whilestillallowingthecharactertotarget,kill,andlootmonstersonthewaybacktotown.Dependingonwhereyou’rehuntingandhowyouwantthebottobehave,youmayalsotellyourtargetingstatesnottoattackcreaturesifthecharacterisn’tinthespawnareaorcave,andyoumightaddanextrastatebeforewalktotownthatattacksonlycreaturesthatblockthecharacter’spathtotown.Specifyingthatextrastateincreasesthebot’sefficiency,sincetripstoandfromtownwillbemuchquickerifthemonstersonthewayaren’tworthkilling.

UsingtheCharacterasBaitTwoothercavebotfeaturesthatcanmakeyourbotawesomeareluremodeanddynamiclure.Youwouldn’timplementthesetwofeaturesasactualstatesinacomplexbot;rather,you’dhavetheminformthebot’stargetingandwalkingstatestohelpthebotmakedecisions.

Page 317: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Youcancontrolluremodewithspecialwaypointsinyourpath,anditscodewilltellyourtargetingstatestoattackcreaturesonlyifthebotisstuck,similartothemechanismdiscussedforwalkingtoorfromtown.Thedifferenceisthatluremodecanbeswitchedonandoffatdifferentareasinthecave,allowingyoutoluremultiplemobsofmonsterstocertainlocationsbeforeattackingthem.Thiscanmakeyourbotmuchmoreefficient,ascertaintypesofcharactersmayexcelatkillingmanymonstersatonce.

Dynamiclureissimilar,butinsteadofturningitonandoffatdefinitelocationsviawaypoints,youcanautomaticallyturnluremodeonwhentherearen’tenoughmonsters.Forexample,abotwiththedynamiclurefeaturemighttellthetargetingstatesnottoattackanycreatureuntilfivemonstersareonscreen.Thetargetingstateswouldresumeattackingandkitinguntilallfivemonstersaredead,andthebotwouldsnapbackintoluremodeuntilasuitablysizedmobappearsagain.

Ifyourcharacterisquickenoughtooutrunmonsters,though,you’llneedtomodifyyourbot’swalkingstatestowalkslowlywhenluremodeisonandcreaturesarepresent.Otherwise,yourcharacterwillleavemobsbehindwithoutkillingthem.Youcanslowdownacharacterbyaddingastatebeforethefollowpathstateinyourstatemachinedefinitionthatdelaysmovementslightlywhenluremodeisonandanycreaturesaretoofaraway.

AllowingPlayerstoScriptCustomBehaviorsNearlyeverycavebotincludesascriptinginterfacethatallowsplayerstoaddtheirownbehaviors.Youcouldimplementthisinterfaceasawaytospecifycustomwaypointstofollow,spellstouse,oritemstoloot.Inmoreadvancedbots,youmightmakeyourtargeting,looting,walking,andluringsystemsasdynamicaspossiblesoplayerscanadduniquefeatures.IfyouimplementyourautomationinLua,thirdpartiescouldeasilyimproveandexpandyourbot’sabilities.

Makingyourboteasytowritescriptsfortakesalotofworkoffyourshoulders,sinceotherprogrammerswhoplaythegamemightreleasescriptstoaddsupportfornewhuntingspotsandimproveyourautomation.Suchscriptingservicesarecommoninbottingcommunities,andplayersoftencreateandsellprofessional-gradescriptsthatintegratewithbots.

Page 318: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AutomatingCombatwithWarbotsAnotherclassofautomatedbotsisusedforplayerversusplayer(PvP)combat.Thesewarbots,orPvPbots,havemanyfeaturescategorizedasresponsiveorESPhacks,sincethebotsfocusonrespondingtoincomingdamageorspells,revealinghiddenenemies,andgivingtheplayeraninformationadvantage.

Fullyautomatedwarbotsarerare,butI’vealreadylightlydiscussedhowyoucanusesomeautomationtechniquestomakesmarterhealers,teachbotstolandmoreaccurateskillshots,andpredictplayers’pathstostopthemintheirtracks.Let’sexploreafewothercoolhacksthatfallonthefringeofresponsive,ESP,andautomated.

NOTE

IngamesthatarecompletelyPvPbased,suchasbattlegroundsorreal-timestrategygames,someplayersmightalsojustcallthesebots,sincewarorPvPisthebot’sonlypurpose.

AutowallBotsIfyourcharacterhasa spell tocreatea temporarywall,youcancodeabot that automatically blocks enemy players when they enter smallcorridors.Usingerrorcorrection, thebotcould learnhow faraheadoftheenemytoplacethewall.Withsomereallycreativeengineering,thebot could even learn which enemies can jump over walls by checkingwhethereachenemymanagestogetpastthewallbeforeitdisappears.

AutosnipeBotsForcharacterswithalong-rangeskillshotorglobalexecutionspell,youcan use automation to detect when an enemy across themap has lowhealthandcastyourspelltokillthem.Youcanalsouseerrorcorrectiontomoreaccuratelyguesswheretoshootalong-rangeskillshot.Ifyou’reunabletocalculateexactdamageamounts,errorcorrectioncanalsohelpa bot determine howmuch damage a spell does and tweak the castingthresholdaccordingly.

AutokiteBotsIf you’re playing a carry character that does most of its damage by

Page 319: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

attackingatashortdistance,youmightimplementabottoautomaticallykiteenemies.Usingasetofstatessimilartotheonesacavebotmightuseto kite monsters, you can make a bot that automatically kites enemycharacterswhenyouattack them.Whenyou stop targeting theenemy,the bot can stop kiting. Using A* search, you can improve the kitingmechanism to avoidmultiple enemies, or, if you want to escape whileattacking,guidethekitingmechanismbacktoasafeplace,suchasyourteam’sbaseoraneutrallocation.

ClosingThoughtsBythispoint,youshouldbereadytogooutandmakesomeprettyawesomebots.Don’tworryifyou’restillnotcompletelycomfortablewiththetechniquesinthischapter;thebestwaytolearnistojustdiveinandstarthacking.Usethethousandsoflinesofexamplecodeprovidedforthisbooktogetstartedwithoutworkingfromscratch,andmostofall,havefun!

Inthenextchapter,I’lldiscusswaysthatbotscanhidefromanti-cheatmechanisms,whicharepiecesofsoftwarethatgamesusetodetectandstopbotters.

Page 320: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

12STAYINGHIDDEN

Gamehackingisanever-evolvingpractice,agameofcatandmousebetweenhackersandgamedeveloperswhereeachpartyworkstosubverttheother.Aslongaspeoplemakebots,gamecompanieswillfindwaystohinderbotadvancesandbanplayerswhousebots.Ratherthanmakingtheirgamesinherentlyhardertohack,though,gamecompaniesfocusondetection.

Thelargestgamecompanieshaveverysophisticateddetectionsuitescalledanti-cheatsoftware.Inthebeginningofthischapter,I’lldiscussthecapabilitiesofthemostcommonanti-cheatsuites.Afterrevealinghowthesesuitesdetectbots,I’llteachyousomepowerfulwaystoevadethem.

ProminentAnti-CheatSoftwareThebest-knownanti-cheatsuitesusethesamemethodsasmostantivirussoftwaretoscanforbotsandflagthemasthreats.Someanti-cheatsuitesarealsodynamic,meaningtheirinnerworkingsandcapabilitiescanchangebasedonthegamethey’reprotecting.Anti-cheatsoftwaredevelopersalsotrackdownandpatchtheirsuitesagainstbypasssoftware,soalwaysdoyourownin-depthresearchofanyanti-cheatsoftwarethatyoumightface.

Whenthesesuitesdetectabotter,theyflagthebotter’saccountforbanishment.Everyfewweeks,gamecompanyadministratorsbantheflaggedplayersinabanwave.Gamecompaniesusebanwavesinsteadof

Page 321: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

instantaneousbansbecausebanninginwavesismoreprofitable.Ifbottersarebannedafterafewweeksofplaying,theirfamiliaritywiththegamewillmakethemmorelikelytobuyanewaccountthaniftheywerebannedthemomenttheirbotstartedrunning.

Therearedozensofanti-cheatsuites,butI’llfocusonthefivepackagesthatarethemostcommonandthoroughlyunderstood:PunkBuster,ESEAAnti-Cheat,ValveAnti-Cheat(VAC),GameGuard,andWarden.

ThePunkBusterToolkitPunkBuster,madebyEvenBalanceInc.,istheoriginalanti-cheattoolkit.ManygamesusePunkBuster,butit’smostcommoninfirst-personshootergameslikeMedalofHonor,FarCry3,andseveralinstallmentsoftheBattlefieldseries.

Thetoolkitusesamyriadofdetectionmethods,themostformidableofwhicharesignature-baseddetection(SBD),screenshots,andhashvalidation.PunkBusterisalsoknownforimposinghardwarebansthatpermanentlybanacheater’scomputer,ratherthanjusttheirgameaccount,bysavingafingerprintofthehardware’sserialnumbersandblockingloginsfromamachinethatmatchesit.

Signature-BasedDetectionPunkBusterscansthememoryofallprocessesonasystemrunningagamethatemploysit,searchingforbytepatternsuniquetoknowncheatsoftware,calledsignatures.IfPunkBusterdetectsasignature,theplayerisflaggedforaban.PunkBustercarriesoutmemoryscansfromusermodeusingtheNtQueryVirtualMemory()WindowsAPIfunction,anditsometimesrunsscansfrommultiplehiddenprocesses.

Signature-baseddetectionisblindtocontextbydesign,anditultimatelysuffersfromafatalflaw:falsepositives.OnMarch23,2008,ateamofhackerssetouttoprovetheexistenceofthisflawbyspammingpublicchatroomswithatextstringthatPunkBusterwouldidentifyasabotsignature.SinceSBDblindlyscansprocessmemoryformatchingpatterns,anyandalllegitimateplayersinsidethesepublicchatroomswereflaggedasbotters.

Page 322: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thiscausedthousandsoffairplayerstobebannedwithnojustification.AsimilarsituationhappenedagaininNovember2013:PunkBusterfalselybannedthousandsofplayersonBattlefield4.Thattime,noonewastryingtoproveapoint;thecompanyhadjustaddedabadsignaturetoitssoftware.

PunkBusterresolvedbothoftheseissuesbyrestoringtheplayers’accounts,buttheseincidentsshowjusthowaggressiveitsflavorofSBDis.Inthetimesincetheseattacks,though,PunkBuster’sSBDhasreducedthenumberoffalsepositivesbycheckingonlyforsignaturesatpredefinedbinaryoffsets.

ScreenshotsAsanothermethodofbotdetection,PunkBusteralsoperiodicallytakesscreenshotsofaplayer’sscreenandsendsthemtothecentralgameserver.Thisformofdetectionisanuisance,andit’sweakcomparedtoSDB.Game-hackingcommunitiesspeculatethatPunkBusterimplementedthisfeaturetogivegameadminsproofagainstbotterswhodisputebans.

HashValidationInadditiontoemployingSBDandscreenshots,PunkBusterdetectsbotsbycreatingcryptographichashesofagame’sexecutablebinariesonaplayer’ssystemandcomparingthemtohashesstoredonacentralserver.Ifthehashesdonotmatch,theplayerisflaggedforaban.Thischeckiscarriedoutonlyonthebinariesonthefilesystem,notonin-memorybinaries.

TheESEAAnti-CheatToolkitTheESEAAnti-CheattoolkitisusedbytheE-SportsEntertainmentAssociation(ESEA),primarilyforitsCounter-Strike:GlobalOffensiveleague.UnlikePunkBuster,thissuiteisknownforgeneratingveryfewfalsepositivesandbeinghighlyeffectiveatcatchingcheaters.

ESEAAnti-Cheat’sdetectioncapabilitiesresemblethoseofPunkBuster,withonenoteworthydifference.ESEAAnti-Cheat’sSBDalgorithmiscarriedoutfromakernel-modedriverusingthreedifferentWindowsKernelfunctions:theMmGetPhysicalMemoryRanges()function,theZwOpenSection()

Page 323: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

function,andtheZwMapViewOfSection()function.Thisimplementationmakestheanti-cheatsystemnearlyimmunetomemoryspoofing(acommonwaytodefeatSBD),asthefunctionsusedbythescanaremuchhardertohookwhenthey’recalledfromadriver.

TheVACToolkitVACisthetoolkitValveCorporationappliestoitsowngamesandmanyofthethird-partygamesavailableonitsSteamgamingplatform.VACusesSDBandhashvalidationmethodsthatresemblePunkBuster’sdetectiontechniques,anditalsousesDomainNameSystem(DNS)cachescansandbinaryvalidation.

DNSCacheScansDNSisaprotocolthatconvertsbetweendomainnamesandIPaddressessmoothly,andtheDNScacheiswherethatinformationgetsstoredonacomputer.WhenVAC’sSBDalgorithmdetectscheatsoftware,VACscanstheplayer’sDNScacheforanydomainnamesassociatedwithcheatingwebsites.It’snotcertainwhetherapositiveDNScachescanisrequiredforVAC’sSBDalgorithmtoflagaplayerforbanishment,oriftheDNScachescansimplyactsasanothernailinthecoffinforplayerswhoarealreadyflaggedbySBD.

NOTE

ToseeyourDNScache,enteripconfig/displaydnsatacommandprompt.Yes,VAClooksatallofthat.

BinaryValidationVACalsousesbinaryvalidationtopreventin-memorytamperingofexecutablebinaries.ItscansformodificationslikeIAT,jump,andcodehookingbycomparinghashesofin-memorybinarycodetohashesofthesamecodeinthebinariesonthefilesystem.Ifitfindsamismatch,VACflagstheplayerforaban.

Page 324: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Thisdetectionmethodisformidable,butValve’sinitialimplementationofthealgorithmwasflawed.InJuly2010,VAC’sbinaryvalidationfalselybanned12,000CallofDutyplayers.ThebinaryvalidationmodulefailedtoaccountforaSteamupdate,anditbannedtheplayerswhentheirin-memorycodedidnotmatchtheupdatedbinariesonthefilesystem.

FalsePositivesVAChashadotherissueswithfalsepositives.Itsinitialreleaseroutinelybannedfairplayersfor“faultymemory.”ThissameearlyversionbannedplayersforusingCedega,aplatformthatranWindowsgamesonLinux.AndonApril1,2004,Valvefalselybannedacouplethousandplayersduetoaserver-sideglitch.Ontwoseparateoccasions,oneinJune2011andoneinFebruary2014,VACalsofalselybannedthousandsofTeamFortress2andCounter-Strikeplayersduetobugsthatthecompanyrefusestodisclose.AswithPunkBuster,theseincidentsshowthatVACisveryaggressive.

TheGameGuardToolkitGameGuardisananti-cheattoolkitmadebyINCAInternetCo.Ltd.andusedbymanyMMORPGs,includingLineageII,CabalOnline,andRagnarokOnline.InadditiontosomemildlyaggressiveSBD,GameGuardusesrootkitstoproactivelypreventcheatsoftwarefromrunning.

User-ModeRootkitGameGuardutilizesauser-moderootkittodenybotsaccesstotheWindowsAPIfunctionstheyusetooperate.Therootkithooksthefunctionsattheirlowest-levelentrypoint,ofteninsideundocumentedfunctionsinntdll.dll,user32.dll,andkernel32.dll.ThesearethemostnotableAPIfunctionsGameGuardhooks,andhere’swhatGameGuarddoesfrominsideeachhookedfunction:

NtOpenProcess()BlocksanyOpenProcess()attemptsonthegamebeingprotected.

NtProtectVirtualMemory()BlocksanyVirtualProtect()or

Page 325: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

VirtualProtectEx()attemptsonthegame.

NtReadVirtualMemory()andNtWriteVirtualMemory()BlockanyReadProcessMemory()andWriteProcessMemory()attemptsonthegame.

NtSuspendProcess()andNtSuspendThread()BlockanyattemptstosuspendGameGuard.

NtTerminateProcess()andNtTerminateThread()BlockanyattemptstoterminateGameGuard.

PostMessage(),SendMessage(),andSendInput()Blockanyattemptstosendprogrammaticinputtothegame.

SetWindowsHookEx()Preventsbotsfromgloballyinterceptingmouseandkeyboardinput.

CreateProcessInternal()Automaticallydetectsandhooksintonewprocesses.

GetProcAddress(),LoadLibraryEx(),andMapViewOfFileEx()PreventanyattempttoinjectlibrariesintothegameorGameGuard.

Kernel-ModeRootkitGameGuardalsousesadriver-basedrootkittopreventbotsthatworkinthekernel.Thisrootkithasthesameabilitiesasitsuser-modecounterpart,anditworksbyhookingZwProtectVirtualMemory(),ZwReadVirtualMemory(),ZwWriteVirtualMemory(),SendInput(),andsimilarfunctions.

TheWardenToolkitWarden,madeexclusivelyforBlizzard’sgames,isbyfarthemostadvancedanti-bottoolkitI’veencountered.It’shardtosaywhatexactlyWardendoes,becauseitdownloadsdynamiccodeatruntime.Thiscode,deliveredascompiledshellcode,typicallyhastworesponsibilities:

•Detectbots.

•Periodicallysendaheartbeatsignaltothegameserver.Thevaluesentisnotpredefinedbutinsteadisgeneratedbysomesubsetofthedetectioncode.

Page 326: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

code.

IfWardenfailstocompletethesecondtaskorsendsthewrongvalue,thegameserverwillknowthatit’sbeendisabledortamperedwith.Furthermore,abotcan’tdisablethedetectioncodeandleavetheheartbeatcoderunning.

THEHALTINGPROBLEM

AbotthatcoulddisableWarden’sdetectioncodeandstillsendtheheartbeatsignalwouldsolvethehaltingproblem,whichAlanTuringprovedtobeimpossiblein1936.Thehaltingproblemistheproblemofdetermining,withagenericalgorithm,whetheraprogramwillfinishrunningorcontinueforever.BecauseWardendoestwotasksusingthesameshellcode,writingagenericalgorithmthatcandisablejustonetaskisavariationofthehaltingproblem:thealgorithmcan’tbesurewhichpartsofthecodewilldefinitelyexecute,whichpartswon’t,andwhichpartsareresponsibleforeachtask.

Wardenisformidablebecauseyounotonlyhavenowaytoknowwhatyou’rehidingfrombutalsohavenowaytodisablethetoolkit.Evenifyoumanagetoavoiddetectiontoday,anewdetectionmethodmightbeusedtomorrow.

Ifyouplanonpubliclydistributingbots,youwilleventuallymeetoneoftheanti-cheatsolutionsdescribedintheprevioussections—andyou’llhavetobeatit.Dependingonyourbot’sfootprint,thetypeofdetectioninthegameyou’rebotting,andyourimplementation,thedifficultyofevadingoneofthesetoolkitscanrangefromtrivialtoextremelyhard.

CarefullyManagingaBot’sFootprintAbot’sfootprintishowmanyunique,detectablecharacteristicsithas.Forexample,abotthathooks100functionswilltypicallybeeasiertodetectthanabotthathooksonly10functionsbecausetheformermakesanorderofmagnitudemorechangestoagame’scodethanthelatter.Sinceatargeted

Page 327: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

detectionsystemneedstodetectonlyonehook,thedeveloperoftheformerbotneedstospendmuchmoretimemakingsureallofthebot’shooksareasstealthyaspossible.

Anotherfootprintcharacteristicishowdetailedabot’suserinterfaceis.Ifaknownbothasmanydialogboxesthatallhavespecifictitles,agamecompanycanjusthaveitsanti-cheatsoftwaredetectthebotbysearchingforwindowsthathavethosetitles.Thissamebasicreasoningcanbeusedwithprocessnamesandfilenames.

MinimizingaBot’sFootprintDependingonhowyourbotworks,therearemanywaystominimizeitsfootprint.Ifyourbotreliesheavilyonhooks,forinstance,youcanavoiddirectlyhookingagame’scodeandinsteadfocusonhookingWindowsAPIfunctions.WindowsAPIhookingissurprisinglycommon,sodeveloperscan’tassumeaprogramthathookstheWindowsAPIisabot.

Ifyourbothasawell-defineduserinterface,youcanmasktheinterfacebyremovingallstringsfromwindowbars,buttons,andsoon.Instead,displayimagesthatshowtext.Ifyou’reworriedaboutspecificprocessnamesorfilenamesbeingdetectedbytheanti-cheatsoftware,usegenericfilenamesandmakeyourbotcopyitselftoanew,randomizeddirectoryeverytimeitlaunches.

MaskingYourFootprintMinimizingyourfootprintisapreferredwaytoavoiddetection,butit’snotnecessary.Youcanalsoobfuscateyourbot,makingitharderforanyonetofigureouthowitworks.Obfuscationcanpreventbothanti-botdevelopersfromtryingtodetectyourbotandotherbotdevelopersfromanalyzingyourbottostealproprietaryfunctionality.Ifyousellyourbot,obfuscationpreventspeoplefromcrackingittobypassyourpurchaseverification,too.

Onecommontypeofobfuscationiscalledpacking.Packinganexecutableencryptsitandhidesitinsideanotherexecutable.Whenthecontainerexecutableislaunched,thepackedexecutableisdecryptedandexecutedin-memory.Whenabotispacked,analyzingthebinarytolearnwhatthebotdoesisimpossible,anddebuggingthebotprocessismuchharder.SomecommonpackerprogramsareUPX,Armadillo,Themida,andASPack.

Page 328: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

TeachingaBottoDetectDebuggersWhenanti-botdevelopers(orotherbotcreators)candebugabot,theycanfigureouthowitworksandthushowtostopit.Ifsomeoneisactivelytryingtopickapartabot,packingtheexecutablemaynotbeenoughtoevadethem.Toprotectagainstthis,botsoftenemployanti-debuggingtechniques,whichobfuscatecontrolflowbychangingthebot’sbehaviorwhenadebuggerisdetected.Inthissection,I’llquicklycoversomewell-knownmethodsfordetectingwhenadebuggerisattachedtoyourbot,andinthenext,I’llshowyousometricksforobfuscation.

CallingCheckRemoteDebuggerPresent()CheckRemoteDebuggerPresent()isaWindowsAPIfunctionthatcantellyouifadebuggerisattachedtothecurrentprocess.Codetocheckforadebuggermightlooklikethis:

boolIsRemoteDebuggerPresent(){BOOLdbg=false;CheckRemoteDebuggerPresent(GetCurrentProcess(),&dbg);returndbg;}

Thischeckisprettystraightforward—itcallsCheckRemoteDebuggerPresent()withthecurrentprocessandapointertothedbgBoolean.Callingthisfunctionistheeasiestwaytodetectadebugger,butit’salsoveryeasyforadebuggertoevade.

CheckingforInterruptHandlersInterruptsaresignalstheprocessorsendstotriggeracorrespondinghandlerintheWindowskernel.Interruptsaretypicallygeneratedbyhardwareevents,buttheycanalsobegeneratedinsoftwareusingtheINTassemblyinstruction.Thekernelallowssomeinterrupts—namely,interrupts0x2Dand0x03—totriggeruser-modeinterrupthandlersintheformofexceptionhandlers.Youcantakeadvantageoftheseinterruptstodetectdebuggers.

Whenadebuggersetsabreakpointonaninstruction,itreplacesthatinstructionwithabreakpointinstruction,suchasINT0x03.Whentheinterruptisexecuted,thedebuggerisnotifiedviaanexceptionhandler,whereithandlesthebreakpoint,replacestheoriginalcode,andallowstheapplicationtoresumeexecutionseamlessly.Whenfacedwithan

Page 329: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

applicationtoresumeexecutionseamlessly.Whenfacedwithanunrecognizedinterrupt,somedebuggersevensilentlystepoverthatinterruptandallowexecutiontocontinuenormally,withouttriggeringanyotherexceptionhandlers.

Youcandetectthisbehaviorbypurposelygeneratinginterruptswithinexceptionhandlersinyourcode,asshowninListing12-1.

inlineboolHas2DBreakpointHandler(){__try{__asmINT0x2D}__except(EXCEPTION_EXECUTE_HANDLER){returnfalse;}returntrue;}

inlineboolHas03BreakpointHandler(){__try{__asmINT0x03}__except(EXCEPTION_EXECUTE_HANDLER){returnfalse;}returntrue;}

Listing12-1:Detectinginterrupthandlers

Duringnormalexecution,theseinterruptstriggertheexceptionhandlerssurroundingtheminthecode.Duringadebuggingsession,somedebuggersmightintercepttheexceptionsgeneratedbytheseinterruptsandsilentlyignorethem,preventingthesurroundingexceptionhandlersfromexecuting.Thus,iftheinterruptsdon’ttriggeryourexceptionhandler,thenadebuggerispresent.

CheckingforHardwareBreakpointsDebuggerscanalsosetbreakpointsusingtheprocessor’sdebugregisters;thesearecalledhardwarebreakpoints.Adebuggercansetahardwarebreakpointonaninstructionbywritingtheaddressoftheinstructiontooneofthefourdebugregisters.

Whenanaddresspresentonadebugregisterisexecuted,thedebuggerisnotified.Todetecthardwarebreakpoints(andthus,thepresenceofadebugger),youcancheckfornonzerovaluesonanyofthefourdebugregisterslikethis:

boolHasHardwareBreakpoints(){CONTEXTctx={0};ctx.ContextFlags=CONTEXT_DEBUG_REGISTERS;autohThread=GetCurrentThread();

Page 330: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

if(GetThreadContext(hThread,&ctx)==0)returnfalse;return(ctx.Dr0!=0||ctx.Dr1!=0||ctx.Dr2!=0||ctx.Dr3!=0);}

PrintingDebugStringsOutputDebugString()isaWindowsAPIfunctionthatcanbeusedtoprintlogmessagestoadebuggerconsole.Ifnodebuggerispresent,thefunctionwillreturnwithanerrorcode.Ifadebuggerispresent,however,thefunctionwillreturnwithnoerrorcode.Here’showyoucanusethisfunctionasatrivialdebuggercheck:

inlineboolCanCallOutputDebugString(){SetLastError(0);OutputDebugStringA("test");return(GetLastError()==0);}

LiketheCheckRemoteDebuggerPresent()method,thismethodisverystraightforwardbutalsoveryeasyforadebuggertoevade.

CheckingforDBG_RIPEXCEPTIONHandlersDebuggerstypicallyhaveexceptionhandlersthatblindlycatchexceptionswithWindows’DBG_RIPEXCEPTIONexceptioncode,makingthatcodeaclearwaytospotadebugger.YoucandetecttheseexceptionhandlersinmuchthesamewayListing12-1detectsinterrupthandlers:

#defineDBG_RIPEXCEPTION0x40010007inlineboolhasRIPExceptionHandler(){__try{RaiseException(DBG_RIPEXCEPTION,0,0,0);}__except(EXCEPTION_EXECUTE_HANDLER){returnfalse;}returntrue;}

TimingControl-CriticalRoutinesIfananti-botdeveloperisdebuggingyourbot,thedeveloperwilllikelyplacebreakpointsonandsingle-stepthroughpartsofyourcodethatarecriticaltothebot’sbehavior.Youcandetectthisactivitybymeasuringcodeexecutiontimes;whensomeonestepsthroughcode,executiontakesalotlongerthanusual.

Page 331: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

usual.Forexample,ifafunctiononlyplacessomehooks,youcanbesurethat

thecodeshouldn’ttakemorethanatenthofasecondtodothememoryprotection.YoucouldchecktheexecutiontimeformemoryprotectionwithhelpfromtheGetTickCount()WindowsAPIfunction,asfollows:

--snip--autostartTime=GetTickCount();protectMemory<>(...);if(GetTickCount()-startTime>=100)debuggerDetectedGoConfuseIt();--snip--

CheckingforDebugDriversSomedebuggersloadkernel-modedriverstoassisttheiroperation.Youcandetectthesedebuggersbyattemptingtogetahandletotheirkernel-modedrivers,likethis:

boolDebuggerDriversPresent(){//anarrayofcommondebuggerdriverdevicenamesconstchardrivers[9][20]={"\\\\.\\EXTREM","\\\\.\\ICEEXT","\\\\.\\NDBGMSG.VXD","\\\\.\\RING0","\\\\.\\SIWVID","\\\\.\\SYSER","\\\\.\\TRW","\\\\.\\SYSERBOOT","\0"};for(inti=0;drivers[i][0]!='\0';i++){autoh=CreateFileA(drivers[i],0,0,0,OPEN_EXISTING,0,0);if(h!=INVALID_HANDLE_VALUE){CloseHandle(h);returntrue;}}returnfalse;}

Thereareafewcommonkernel-modedriverdevicenamestocheckfor,like\\\\.\\EXTREMandtheothersshowninthedriversarray.Ifthishandle-fetchingcodesucceeds,thenthere’sadebuggerrunningonthesystem.Unlikewiththepreviousmethods,though,obtainingahandletooneofthosedriversdoesn’talwaysmeanthedebuggerisattachedtoyourbot.

Page 332: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Anti-DebuggingTechniquesOnceyoudetectadebugger,therearemultiplewaystoobfuscateyourcontrolflow.Forinstance,youmighttrytocrashthedebugger.ThefollowingcodecrashesOllyDbgv1.10:

OutputDebugString("%s%s%s%s");

Thestring"%s%s%s%s"containsformatspecifiers,andOllyDbgpassesittoprintf()withoutanyextraparameters,whichiswhythedebuggercrashes.Youcouldplacethiscodeinafunctionthatgetscalledinresponsetodetectingadebugger,butthisoptionworksonlyagainstOllyDbg.

CausinganUnavoidableInfiniteLoopAnotherobfuscationmethodtotryisoverloadingthesystemuntilthepersondebuggingyourbotisforcedtoclosethebotanddebugger.Thisfunctiondoesthetrick:

voidSelfDestruct(){std::vector<char*>explosion;while(true)explosion.push_back(newchar[10000]);}

Theinfinitewhileloopjustkeepsaddingelementstoexplosionuntiltheprocessrunsoutofmemoryorsomeonepullstheplug.

OverflowingtheStackIfyouwanttoreallyconfusetheanalyst,youcanmakeachainoffunctionsthateventuallycauseastackoverflow,butinanindirectway:

#include<random>typedefvoid(*_recurse)();voidrecurse1();voidrecurse2();voidrecurse3();voidrecurse4();voidrecurse5();_recurserecfuncs[5]={&recurse1,&recurse2,&recurse3,&recurse4,&recurse5};voidrecurse1(){recfuncs[rand()%5]();}voidrecurse2(){recfuncs[(rand()%3)+2]();}

Page 333: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

voidrecurse3(){if(rand()%100<50)recurse1();elserecfuncs[(rand()%3)+1]();}voidrecurse4(){recfuncs[rand()%2]();}voidrecurse5(){for(inti=0;i<100;i++)if(rand()%50==1)recfuncs[i%5]();recurse5();}//callanyoftheabovefunctionstotriggerastackoverflow

Inanutshell,thesefunctionsrandomlyandinfinitelyrecurseuntilthere’snoroomleftonthecallstack.Causingtheoverflowindirectlymakesithardfortheanalysttopauseandexaminepreviouscallsbeforetheyrealizewhat’shappened.

CausingaBSODIfyou’reseriousaboutobfuscation,youcaneventriggeraBlueScreenofDeath(BSOD)whenyoudetectadebugger.Onewaytodothatistosetyourbot’sprocessascriticalusingtheSetProcessIsCritical()WindowsAPIfunctionandthencallexit(),sinceWindowswilltriggeraBSODwhenacriticalprocessiskilled.Here’showyoumightdothat:

voidBSODBaby(){typedeflong(WINAPI*RtlSetProcessIsCritical)(BOOLEANNew,BOOLEAN*Old,BOOLEANNeedScb);autontdll=LoadLibraryA("ntdll.dll");if(ntdll){autoSetProcessIsCritical=(RtlSetProcessIsCritical)GetProcAddress(ntdll,"RtlSetProcessIsCritical");if(SetProcessIsCritical)SetProcessIsCritical(1,0,0);}}

BSODBaby();exit(1);

Ormaybeyou’reevil,inwhichcaseyoucandothis:

BSODBaby();OutputDebugString("%s%s%s%s");recurse1();exit(1);

Page 334: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Assumingyou’veimplementedallofthetechniquesdescribedinthissection,thiscodewouldcauseaBSOD,crashthedebugger(ifit’sOllyDbgv1.10),overflowthestack,andexittherunningprogram.Ifanyoneofthemethodsfailsorgetspatched,theanalyststillhastodealwiththeremainingonesbeforetheycancontinuedebugging.

DefeatingSignature-BasedDetectionEvenwithamazingobfuscation,youwon’teasilybeatsignaturedetection.Engineerswhoanalyzebotsandwritesignaturesareveryskilled,andobfuscationis,atbest,anuisancethatmakestheirjobmarginallyharder.

TocompletelyevadeSBD,youneedtosubvertthedetectioncode.ThisrequiresknowingexactlyhowtheSBDworks.PunkBuster,forinstance,usesNtQueryVirtualMemory()toscanthememoryofallrunningprocessesforanysignatures.Ifyouwanttobypassthis,youcaninjectcodeintoallPunkBusterprocesseswithahookontheNtQueryVirtualMemory()function.

Whenthefunctiontriestoquerymemoryfromyourbotprocess,youcangiveitwhateverdatayouwant,likethis:

NTSTATUSonNtQueryVirtualMemory(HANDLEprocess,PVOIDbaseAddress,MEMORY_INFORMATION_CLASSmemoryInformationClass,PVOIDbuffer,ULONGnumberOfBytes,PULONGnumberOfBytesRead){

//ifthescanisonthisprocess,makesureitcan'tseethehookDLLif((process==INVALID_HANDLE_VALUE||process==GetCurrentProcess())&&baseAddress>=MY_HOOK_DLL_BASE&&baseAddress<=MY_HOOK_DLL_BASE_PLUS_SIZE)➊returnSTATUS_ACCESS_DENIED;

//ifthescanisonthebot,zerothereturnedmemoryautoret=origNtQueryVirtualMemory(process,baseAddress,memoryInformationClass,buffer,numberOfBytes,numberOfBytesRead);if(GetProcessId(process)==MY_BOT_PROCESS)➋ZeroMemory(buffer,numberOfBytesRead);returnret;}

Page 335: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ThisonNtQueryVirtualMemory()hookreturnsSTATUS_ACCESS_DENIED➊whenNtQueryVirtualMemory()triestoquerythehookDLL’smemory,butitgiveszeroedmemory➋whenNtQueryVirtualMemory()triestoquerythebot’smemory.Thedifferenceisn’tforanyspecificreason;I’mjustshowingtwowaysyoucanhidefromtheNtQueryVirtualMemory()functioncall.Ifyou’rereallyparanoid,youcanevenreplacetheentirebufferwitharandombytesequence.

Ofcourse,thismethodworksonlyforSBDthathappensfromusermode,liketheSBDinPunkBusterorVAC.SBDthathappensfromthedriver,likeESEA’s,orthatisn’tpredictable,likeWarden’s,isn’taseasytobypass.

Inthosecases,youcantakeprecautionstoeliminateuniquesignaturesinyourbot.Ifyou’redistributingthebottomorethanadozenorsopeople,however,removingalldistinguishingpropertiesistricky.Tothrowanalystsoffthescent,eachtimeyougivesomebodyacopyofthebot,youcouldtrysomecombinationofthefollowing:

•Compilingthebotusingadifferentcompiler

•Changingthecompileroptimizationsettings

•Togglingbetweenusing__fastcalland__cdecl

•Packingthebinariesusingadifferentpacker

•Switchingbetweenstaticanddynamiclinkingofruntimelibraries

Varyingtheseelementscreatesadifferentassemblyforeachuser,butthere’salimitonhowmanyuniqueversionsofthebotyoucanproducethatway.Pastsomepoint,thismethoddoesn’tscaletodemand,andeventually,gamecompanieswillhavesignaturesforeveryincarnationofyourbot.

Apartfromobfuscationandcodemutation,therearen’tmanywaystodefeatadvancedSBDmechanisms.Youcouldimplementyourbotinadriverorcreateakernel-moderootkittohideyourbot,buteventhosemethodsaren’tfoolproof.

NOTE

Thisbookdoesn’tcoverimplementingabotinadriverorcreatingarootkitto

Page 336: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

hideabot,asbothtopicsareprettycomplex.Rootkitdevelopmentaloneisasubjectthatdozensofbookshavecoveredalready.I’drecommendBillBlunden’sTheRootkitArsenal:EscapeandEvasioninTheDarkCornersofTheSystem(Jones&BartlettLearning,2009).

Somegamehackerstrytocovereverysinglebase,hookingeverymemory-readingfunctionandtheentirefilesystemAPI,butstillgetcaughtbydeterminedsystemslikeWarden.Infact,IrecommendstayingawayfromWardenandBlizzardatallcosts.

DefeatingScreenshotsIfyouencounteradetectionmechanismthatusesscreenshotsasadditionalprooftonailbotters,you’reinluck.Bypassingscreenshotmechanismsiseasy:don’tletyourbotbeseen.

YoucansubvertthistypeofdetectionbykeepingaminimalUIandmakingnovisiblydistinguishablechangestothegameclient.IfyourbotrequiresaHUDorotherdistinctiveUIdisplays,though,don’tfret—youcanhaveyourcakeandeatit,too.Aslongasyoucaninterceptthescreenshotcode,youcanhideyourfingerprintswhileascreenshotistaken.

InsomeversionsofPunkBuster,forexample,theWindowsAPIfunctionGetSystemTimeAsFileTime()iscalledjustbeforeascreenshotistaken.YoucanuseahookonthisfunctiontoquicklyhideyourUIforafewsecondstoensureit’snotseen:

voidonGetSystemTimeAsFileTime(LPFILETIMEsystemTimeAsFileTime){myBot->hideUI(2000);//hideUIfor2secondsorigGetSystemTimeAsFileTime(systemTimeAsFileTime);}

JusthookGetSystemTimeAsFileTime()usingthetechniquesdescribedin“HookingtoRedirectGameExecution”onpage153,writeahideUI()function,andcallthehideUI()functionbeforeexecutionresumes.

DefeatingBinaryValidationDefeatingbinaryvalidationisassimpleasnotplacinghooksinsidegame-

Page 337: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Defeatingbinaryvalidationisassimpleasnotplacinghooksinsidegame-specificbinaries.JumphooksandIAThooksonWindowsAPIfunctionsareextremelycommon,sowhereveryoucan,trytogetawaywithusingthosemethodsinsteadofusingjumpornear-callhooksinagamebinary.Incaseswhereyoumustdirectlyhookagame’scode,youcantricktheanti-cheatsoftware’sbinaryvalidationroutinesbyinterceptingthebinaryscanandspoofingthedatatomatchwhatthesoftwareexpectstosee.

LikeSBD,binaryvalidationoftenusesNtQueryVirtualMemory()toscanmemory.Totrickthevalidationcode,startwithahookonthatfunction.Then,writeafunctionlikethisonetospoofthedatawhenNtQueryVirtualMemory()iscalled:

NTSTATUSonNtQueryVirtualMemory(HANDLEprocess,PVOIDbaseAddress,MEMORY_INFORMATION_CLASSmemoryInformationClass,PVOIDbuffer,ULONGnumberOfBytes,PULONGnumberOfBytesRead){

autoret=origNtQueryVirtualMemory(process,baseAddress,memoryInformationClass,buffer,numberOfBytes,numberOfBytesRead);//placetrickycodesomewhereinherereturnret;}

Insidethishook,you’llneedtowatchforanymemoryscansovermemorythathasbeenmodifiedbyoneofyourhooks.

NOTE

ThisexampleassumesthebothasonlyonehookandthatvariablesprefixedwithHOOK_alreadyexistanddescribethecodethehookreplaces.

Listing12-2showssomescan-monitoringcode.

//isthescanonthecurrentprocess?boolcurrentProcess=process==INVALID_HANDLE_VALUE||process==GetCurrentProcess();

//isthehookinthememoryrangebeingscanned?autoendAddress=baseAddress+numberOfBytesRead-1;boolcontainsHook=(HOOK_START_ADDRESS>=baseAddress&&

Page 338: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

HOOK_START_ADDRESS<=endAddress)||(HOOK_END_ADDRESS>=baseAddress&&HOOK_END_ADDRESS<=endAddress);➊if(currentProcess&&containsHook){//hidethehook}

Listing12-2:Checkingwhetherhookedmemoryisbeingscanned

Whenamemoryscanoverthehookedcodehappens(whichmakescurrentProcessandcontainsHookbecometrueatthesametime),codeinsidetheif()statement➊updatestheoutputbuffertoreflecttheoriginalcode.Thismeansyoumustknowwherethehookedcodeiswithinthescannedblock,takingintoaccountthefactthattheblockmayspanonlyasubsetofthehookedcode.

SoifbaseAddressmarkstheaddresswherethescanstarts,HOOK_START_ADDRESSmarksthespotwherethemodifiedcodestarts,endAddressmarkstheaddresswherethescanends,andHOOK_END_ADDRESSmarkstheaddresswherethemodifiedcodeends,youcanusesomesimplemathtocalculatewhichpartsofthemodifiedcodearepresentinwhichpartsofthebuffer.Youdosoasfollows,usingwriteStarttostoretheoffsetofthemodifiedcodeinthescanbufferandreadStarttostoretheoffsetofthescanbufferrelativetothemodifiedcode,incasethescanbufferstartsinthemiddleofthemodifiedcode:

intreadStart,writeStart;if(HOOK_START_ADDRESS>=baseAddress){readStart=0;writeStart=HOOK_START_ADDRESS-baseAddress;}else{readStart=baseAddress-HOOK_START_ADDRESS;writeStart=baseAddress;}

intreadEnd;if(HOOK_END_ADDRESS<=endAddress)readEnd=HOOK_LENGTH-readStart-1;elsereadEnd=endAddress–HOOK_START_ADDRESS;

Onceyouknowhowmanybytesyouneedtoreplace,wheretoputthem,andwheretogetthem,youcandothespoofwiththreelinesofcode:

char*replaceBuffer=(char*)buffer;

Page 339: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

for(;readStart<=readEnd;readStart++,writeStart++)replaceBuffer[writeStart]=HOOK_ORIG_DATA[readStart];

Completelyassembled,thecodelookslikethis:

NTSTATUSonNtQueryVirtualMemory(HANDLEprocess,PVOIDbaseAddress,MEMORY_INFORMATION_CLASSmemoryInformationClass,PVOIDbuffer,ULONGnumberOfBytes,PULONGnumberOfBytesRead){autoret=origNtQueryVirtualMemory(process,baseAddress,memoryInformationClass,buffer,numberOfBytes,numberOfBytesRead);boolcurrentProcess=process==INVALID_HANDLE_VALUE||process==GetCurrentProcess();autoendAddress=baseAddress+numberOfBytesRead-1;boolcontainsHook=(HOOK_START_ADDRESS>=baseAddress&&HOOK_START_ADDRESS<=endAddress)||(HOOK_END_ADDRESS>=baseAddress&&HOOK_END_ADDRESS<=endAddress);if(currentProcess&&containsHook){intreadStart,writeStart;if(HOOK_START_ADDRESS>=baseAddress){readStart=0;writeStart=HOOK_START_ADDRESS-baseAddress;}else{readStart=baseAddress-HOOK_START_ADDRESS;writeStart=baseAddress;}

intreadEnd;if(HOOK_END_ADDRESS<=endAddress)readEnd=HOOK_LENGTH-readStart-1;elsereadEnd=endAddress–HOOK_START_ADDRESS;

char*replaceBuffer=(char*)buffer;for(;readStart<=readEnd;readStart++,writeStart++)replaceBuffer[writeStart]=HOOK_ORIG_DATA[readStart];}returnret;}

Ofcourse,ifyouhadmultiplehooksthatyouneededtohidefrombinaryvalidationscans,youwouldneedtoimplementthisfunctionalityinamorerobustwaythatwouldallowittotrackmultiplemodifiedcoderegionsaccordingly.

Page 340: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DefeatinganAnti-CheatRootkitGameGuardandsomeotheranti-cheatsuitescomewithuser-moderootkitsthatnotonlydetectbotsbutalsoproactivelypreventthemfromrunning.Todefeatthistypeofprotection,ratherthanthinkoutsidethebox,youcancompletelycopytheboxandworkinsidethatcopy.

Forexample,ifyouwanttowritememorytoagame,youmustcalltheWriteProcessMemory()function,whichisexportedbykernel32.dll.Whenyoucallthisfunction,itdirectlycallsNtWriteVirtualMemory()fromntdll.dll.GameGuardhooksntdll.NtWriteVirtualMemory()topreventyoufromwritingmemory.ButifNtWriteVirtualMemory()isexportedfrom,say,ntdll_copy.dll,GameGuardwon’thookthatfunction.

Thatmeansyoucancopyntdll.dllanddynamicallyimportallofthefunctionsyouneed,asfollows:

//copyandloadntdllcopyFile("ntdll.dll","ntdll_copy.dll");automodule=LoadLibrary("ntdll_copy.dll");

//dynamicallyimportNtWriteVirtualMemorytypedefNTSTATUS(WINAPI*_NtWriteVirtualMemory)(HANDLE,PVOID,PVOID,ULONG,PULONG);automyWriteVirtualMemory=(_NtWriteVirtualMemory)GetProcAddress(module,"NtWriteVirtualMemory");

//callNtWriteVirtualMemorymyWriteVirtualMemory(process,address,data,length,&writtenlength);

Aftercopyingntdll.dll,thiscodeimportstheNtWriteVirtualMemory()fromthecopywiththenamemyWriteVirtualMemory().Fromthere,thebotcanusethisfunctioninplaceoftheNtWriteVirtualMemory()function.They’reeffectivelythesamecodeinthesamelibrary,justloadedunderdifferentnames.

Copyingafunctionthatanti-cheatsoftwarehooksworksonlyifyoucallthatfunctionatitslowest-levelentrypoint,though.Ifthiscodecopiedkernel32.dllanddynamicallyimportedtheWriteProcessMemory()function,ananti-cheatrootkitwouldstillstopthebot,becausekernel32_copy.dllwouldstillrelyonntdll.NtWriteVirtualMemory()whencallingtheWriteProcessMemory()function.

Page 341: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DefeatingHeuristicsInadditiontoalloftheadvancedclient-sidedetectionmechanismswe’vejustdiscussed,gamecompanieswillemployserver-sideheuristicsthatcandetectbotssimplybymonitoringaplayer’sbehavior.Thesesystemslearntodistinguishbetweenhumanandautonomousplayerbehaviorthroughmachine-learningalgorithms.Theirdecision-makingprocessisofteninternalandincomprehensibletohumans,soit’sdifficulttopinpointexactlywhatfeaturesofgameplayleadtodetection.

Youdon’tneedtoknowhowsuchalgorithmsworktotrickthem;yourbotjustneedstoacthuman.Herearesomecommonbehaviorsthataredistinguishablydifferentbetweenhumansandbots:

IntervalsbetweenactionsManybots perform actions unreasonably fast or at consistent intervals.Bots will seem more human-like if they have a reasonable cooldownperiod between actions. They should also have some form ofrandomization to prevent them from repeating an action at a constantrate.

PathrepetitionBots that farm enemies automatically visit a preprogrammed list oflocations to kill creatures. These waypoint lists are often extremelyaccurate,indicatingeachlocationasanexactpixel.Humans,conversely,moveinlesspredictablewaysandvisitmoreuniquelocationsalongthewaytoafamiliararea.Toreplicatethisbehavior,abotmightwalktoarandomlocationwithinacertainrangeofatargetlocation,ratherthantothetargetlocationitself.Also,ifthebotrandomizestheorderinwhichitvisitstargetlocations,thevarietyofpathsittakeswillincreasefurther.

UnrealisticplaySome botters run their bots in the same location for hundreds ofconsecutivehours, buthumans can’t play a game that long.Encourageyourusers to refrain frombotting formore than eighthours at a timeand warn them that doing the same thing for seven straight days willdefinitelytriggeralarmsinaheuristicsystem.

Page 342: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

PerfectaccuracyBotscanhitathousandheadshotsinarowwithoutfiringasingleextrabullet,andtheycanhiteveryskillshotwithconsistentprecision.Butit’svirtuallyimpossibleforahumantodothesame,soasmartbotshouldbeintentionallyinaccurateattimes.

Thesearejustafewexamples,butingeneral,youcansneakpastheuristicchecksifyoujustusecommonsense.Don’ttrytohaveabotdosomethingahumancan’t,anddon’thavethebotdoanysinglethingfortoolong.

ClosingThoughtsGamehackersandgamedevelopersareengagedinaconstantbattleofwits.Hackerswillkeepfindingwaystosubvertdetection,anddeveloperswillkeepfindingbetterwaystodetectthem.Ifyou’redetermined,however,theknowledgeinthischaptershouldhelpyoudefeatanyanti-cheatsoftwareyouencounter.

Page 343: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

INDEX

AAbouttextfield,Trainergeneratordialog,9accessingmemory

ininjectedDLL,145–146forwritingandreading,122–124

ActionMessageFormat(AMF),169actorfunctions,216actuation,216,223Addresscolumn

EventPropertiesdialog,55OllyDbgdisassemblerpane,27

addresses,memory.SeememoryaddressesAddressSpaceLayoutRandomization(ASLR),128

bypassingininjectedDLL,146–147bypassinginproduction,128–130disablingforbotdevelopment,128inProcessExplorer,56,57

AdobeAIRhooking,169decode()function,172–173,174–175encode()function,171–172,174–175placinghooks,173–175RTMP,assessing,169–170

AdobeAIR.dll,173–175airlogtool,170alignment

innumericdata,68ofvariables,indatastructures,70–71

ambientlight,adding,190–192

Page 344: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AMF(ActionMessageFormat),169anti-cheatsoftware,245–246

anti-cheatrootkit,defeating,261–262binaryvalidation,defeating,259–261botfootprints,managing,250–256ESEAAnti-Cheattoolkit,247GameGuardtoolkit,248–249heuristics,defeating,262–263PunkBustertoolkit,246–247screenshots,defeating,258signature-baseddetection,evading,256–257VACtoolkit,247–248Wardentoolkit,249–250

anti-crowd-controlhacks,218anti-debuggingtechniques,251,255–256arithmeticinstructions,90–92A*searchalgorithm,234

cost,233creatingnode,234–237creatingpathlist,239–240score,234usesfor,240–241writingsearchfunction,237–239

ASLR.SeeAddressSpaceLayoutRandomization(ASLR)Asm2Clipboardplug-in,42assemblycode

copying,42tracing,32–33viewingandnavigatinginOllyDbg,27–29

assemblylanguage,78.Seealsox86assemblylanguageassemblypatterns,searchingfor,19–21AStarNodeclass,234–236AT&Tsyntax,80

Page 345: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

autocombo,219autododge,219autokitebots,244automatichealer,218,225–228,230–232autonomousbots,221–222.Seealsocontroltheory;statemachines

cavebots,241–243complexhypotheticalstatemachine,228–230errorcorrection,230–232healerstatemachine,225–228pathfindingwithsearchalgorithms,232–234warbots,243–244

autoreload,219autosnipebots,244autowallbots,244

Bbanwaves,246BiggerThanscantype,CheatEngine,6binaryarithmeticinstructions,90binaryvalidation,248,259–261bits,EFLAGSregister,84BlueScreenofDeath(BSOD),256bots.Seealsoautonomousbots;extrasensoryperception(ESP)hacks

anti-crowd-controlhacks,218anti-debuggingtechniques,251,255–256automatichealer,218,225–228,230–232detectingdebuggers,251–254detectingvisualcues,205–206disablingASLRfordevelopment,128emulatingkeyboard,211–215footprints,managing,250–256gameupdates,dealingwith,101–104

Page 346: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

interceptingnetworktraffic,206–211monitoringmemory,204–205obfuscation,251,255–256sendingpackets,215–217spelltrainers,219

branching,92–94breakpoints,30,34,38Breakpointswindow,OllyDbg,26BSOD(BlueScreenofDeath),256BYTEdatatype,67bytes,machinecode,78

CC++,66callee,94–95caller,94–95callHook()function,154callhooking,153–156.SeealsoAdobeAIRhookingcallingconventions,95

forcallhooks,155__cdecl,95,155__fastcall,95__stdcall,95__thiscall,95,217fortrampolinefunctions,168forVFtablehooks,156–158

CALLinstruction,94–95callstack

overflow,255–256viewing,30x86assemblylanguage,86–88

Callstackwindow,OllyDbg,26

Page 347: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

capacityofstd::vector,109castingspells.Seespellscavebots,241–243__cdeclconvention,95,155ChangedValuescantype,CheatEngine,7characters.Seealsoenemies

healthbars,monitoringwithbots,204–205pausingexecutionwhenhealthdrops,39–42playerhealth,findingwithOllyDbg,99–101

chardatatype,67CheatEngine,3,5–6

automaticallylocatingstringaddresseswith,102cheattables,7–8correctaddress,determining,7firstscan,running,6installing,4Luascriptingenvironment,18–22memorymodification,8–11nextscan,running,7pointerscanningwith,14–18scantypes,6std::list,determiningwhetherdataisstoredin,112–113std::map,determiningwhetherdataisstoredin,117trainergenerator,9–11VFtables,78zoomfactor,finding,197

cheattables,CheatEngine,7–8CheatUtilityplug-in,42–43CheckRemoteDebuggerPresent()function,251classes,74–78classinstances,76CloseHandle()function,122,138closingmutexes,59–60

Page 348: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

CMPinstruction,92codecaves,134

loadingDLLs,143–146threadhijacking,138–142threadinjection,134–138

codeinjection,133–134bypassingASLRinproduction,128–130DLLs,142–146withthreadhijacking,138–142withthreadinjection,134–138

codepatches,creating,31–32columnconfigurations,ProcessMonitor,51combat,automating,243–244commandlineplug-in,OllyDbg,43–44commandsyntax,x86assemblylanguage,79–81Commentcolumn,OllyDbgdisassemblerpane,28complexhypotheticalstatemachine,228–230conditionalbreakpoints,34,38conditionalstatements,93constantratioofhealth,adjustingfor,230–231control-criticalroutines,timing,254controlflowhacks,31controlflowmanipulation,149–150.SeealsoAdobeAIRhooking;Direct3D

hookingcallhooking,153–156IAThooking,160–165jumphooking,165–169NOPing,150–152VFtablehooking,156–160

controltheory,222combiningwithstatemachines,225complexhypotheticalstatemachine,228–230errorcorrection,230–232

Page 349: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

healerstatemachine,225–228controlwindows,OllyDbg,25–26cooldowns,displayingenemy,200–201copyingassemblycode,42copy-on-writeprotection,126corpses,botbehaviortoward,229,240correctaddress,determininginCheatEngine,7CPUwindow,OllyDbg,26–30,40crashingdebuggers,255CreateRemoteThread()function,129,130,134,138CreateToolhelp32Snapshot()function,120,141creaturedata,knowingstructurebehind,106–107criticalgameinformation,displaying,198–201crowd-controlattacks,218cryptographicfunctions,hooking,170CSregister,85C-styleoperators,OllyDbg,34–35custombehaviorsforcavebots,scripting,243

Ddarkenvironments,lightingup,190–192datamodificationinstructions,89datastructures,71–73datatypes,66

classesandVFtables,74–78numericdata,67–69OllyDbg,36stringdata,69–71unions,73–74

DBG_RIPEXCEPTIONhandlers,checkingfor,253debugging.SeealsoOllyDbg

anti-debuggingtechniques,255–256

Page 350: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

debugdrivers,checkingfor,254debugstrings,printing,253detectingdebuggers,251–254ProcessMonitor,52–53

__declspec(naked)convention,168decode()function,hooking,172–173,174–175DecreasedValueByscantype,CheatEngine,7DecreasedValuescantype,CheatEngine,7dependencies,DLL,145dependencyloading,160depositor,242destinationoperand,80detection,avoiding.Seeanti-cheatsoftwaredevice->SetRenderState()function,192Dijkstra’salgorithm,233–234Direct3D9,176Direct3Dhooking,175–176.Seealsoextrasensoryperception(ESP)hacks

detectingvisualcuesingames,205–206drawingloop,176–177findingdevices,177–181optionalfixesforstability,184writinghookforEndScene(),182–183writinghookforReset(),183–184

directionallighthacks,190–191disablingASLR,128disassemblerpane,OllyDbg,27–29,42Disassemblycolumn,OllyDbgdisassemblerpane,28dispatchPacket()function,210displaybase,27DLL(dynamiclinklibrary),injecting,142–146DllMain()entrypoint,144–145DLLsoption,ProcessExplorerpane,57

Page 351: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

DomainNameSystem(DNS)cachescans,248DOSheader,160–161DrawIndexedPrimitive()function,194,195,196,200drawingloop,Direct3D,176–177DSregister,85dumppane,OllyDbg,29–30DWORDdatatype,67,145–146dynamicallyallocatedmemory,6,11,12dynamiclinklibrary(DLL),injecting,142–146dynamiclure,242–243dynamicstructures,105

std::listclass,110–113std::mapclass,114–118std::stringclass,105–108std::vectorclass,108–110

EEAXregister,81EBPregister,83EBXregister,82ECXregister,82,157EDIregister,83EDXregister,82EFLAGSregister,84,92EIPregister,83,139emulatingkeyboard,211–215enableLightHackDirectional()function,190–191encode()function,hooking,171–172,174–175EndScene()function

jumphooking,178–181stabilityof,184writinghookfor,182–183

Page 352: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

endSceneTrampoline()function,181enemies.Seealsoextrasensoryperception(ESP)hacks

cooldowns,displaying,200–201criticalgameinformation,displaying,198–201predictingmovementsof,241texture,changing,195–196

entropy,5,7Environmenttab,ProcessExplorerPropertiesdialog,58errorcorrection,230–232ESEA(E-SportsEntertainmentAssociation),247ESEAAnti-Cheattoolkit,247ESIregister,83ESPhacks.Seeextrasensoryperception(ESP)hacksESPregister,83ESregister,85Euclideandistanceheuristic,236eventclassfilters,ProcessMonitor,51–52eventlog,ProcessMonitor,52–53EventPropertiesdialog,54–55ExactValuescantype,CheatEngine,6exceptionhandlers,checkingfor,253executeprotection,125–128Executeuntilreturnbutton,OllyDbg,25experience-trackingHUD,200exponent,floatdatatype,68expressions,OllyDbg,36–37

accessingmemorycontentswith,36elementsevaluatedby,35–36expressionengine,33–36pausingexecutionwhenhealthofcharacterdrops,39–42pausingexecutionwhennameofplayerisprinted,37–38supporteddatatypes,36

extrasensoryperception(ESP)hacks,189–190

Page 353: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

backgroundknowledge,190floorspyhacks,201–202HUDs,198–201lighthacks,190–192loading-screenHUDs,201pick-phaseHUDs,201rangehacks,201wallhacks,192–197zoomhacks,197–198

Ffalsepositives,VACtoolkit,248__fastcallconvention,95feedbackloop,222fileaccesses,inspectinginProcessExplorer,60Filesystemeventclassfilter,52FILO(first-in-last-out),86filters,eventclass,51–52findItem()function,116–117findSequence()function,175first-in-last-out(FILO),86first-personshooter(FPS),xxii,246firstscan,runninginCheatEngine,6flags,processaccess,121floatdatatype,67–68floorspyhacks,201–202fogofwar,189.Seealsoextrasensoryperception(ESP)hacksfootprints,managing,250–256Foundintermodularcallswindow,OllyDbg,40FPS(first-personshooter),xxii,246FPUregisters,29Framecolumn,EventPropertieswindow,54

Page 354: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

frames,inDirect3Ddrawingloop,176Freezeinterval,Trainergeneratordialog,9freezing

addresses,8mainthread,141

frontier,233FSregister,85functioncalls,x86assemblylanguage,94–95functionflowchart,OllyFlow,45functionnames,findingforIAThooking,163

GGameActuatorsclass,225gameautomationstatemachine,223–224GameGuardtoolkit,248–249gameupdates,determiningnewaddressesafter,101–104generalregisters,81–82genericmemoryfunctions,123–124getAddressforNOP()function,152GetAsyncKeyState()function,196GetExitCodeThread()function,129GetModuleFileName()function,144GetModuleHandle()function,129–130,134,144,146–147GetSystemTimeAsFileTime()function,258GetThreadContext()function,139,142GetTickCount()function,254GetWindowThreadProcessId()function,120goalstate,238GoTobutton,OllyDbg,25greedybest-firstsearchalgorithm,233–234GSregister,85

Page 355: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

guardprotection,126

Hhaltingproblem,250handlemanipulationoptions,ProcessExplorer,59–60handlerfunctions,208handles,56,121,210–211,252Handlesoption,ProcessExplorerpane,57Handleswindow,OllyDbg,26hardwarebreakpoints,checkingfor,252–253hashvalidation,247heads-updisplay(HUD),198–201healerstatemachine,225–228,230–232healthofcharacters

healthbars,monitoringwithbots,204–205healthbarsofenemies,displaying,150–152pausingexecutionupondropin,39–42

heapdata,16heuristics,233

defeating,262–263Euclideandistance,236Manhattandistance,235

Hexdumpcolumn,OllyDbgdisassemblerpane,27–28hiddendata,displaying,198–201Hiddenoption,ProcessExplorerpane,57hooking,42,149,153.SeealsoAdobeAIRhooking;Direct3Dhooking;

extrasensoryperception(ESP)hackscall,153–156detectingvisualcuesingames,205–206IAT,160–165interceptingnetworktraffic,206–211jump,165–169

Page 356: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

prewrittenlibraries,169signature-baseddetection,evading,257VFtable,156–160zoomhacks,198

hotkeysPatcheswindow,OllyDbg,32ProcessExplorer,57ProcessMonitor,52fortrainer,settingup,10

hourlyexperience,finding,200HTTP(HyperTextTransferProtocol),169HTTPS(HTTPSecure),169HUD(heads-updisplay),198–201

IIAT(importaddresstable)hooking,160–165IDIVinstruction,92IMAGE_DOS_HEADERstructure,161IMAGE_IMPORT_DESCRIPTORstructure,162IMAGE_OPTIONAL_HEADERstructure,161Imagetab,ProcessExplorerPropertiesdialog,57–58IMAGE_THUNK_DATAstructure,162immediatevalue,80importaddresstable(IAT)hooking,160–165importdescriptors,162IMULarithmeticinstruction,90–91IncreasedValueByscantype,CheatEngine,7IncreasedValuescantype,CheatEngine,7indexregisters,83infiniteloops,causingunavoidable,255in-gameactions,botsfor

anti-crowd-controlhacks,218

Page 357: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

automatichealer,218,225–228,230–232emulatingkeyboard,211–215sendingpackets,215–217spelltrainers,219

in-gameevents,logging,50–52instructions,79

arithmetic,90–92branching,92–94datamodification,89functioncalls,94–95jump,92–94

intdatatype,67Intelsyntax,80interrupthandlers,checkingfor,252iterator,120

JjumpHookCallback()function,168jumphooking,165–169,178–181jumpinstructions,x86assemblylanguage,92–94

Kkernel-moderootkit,GameGuardtoolkit,249keyboard,emulating,211–215KEYEVENTF_KEYUPflag,212kiting,222,240–241

Llibraries,hooking,169lighthacks,190–192

Page 358: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

listclass,110–111listItemclass,110–111little-endianordering,67loaderlock,144loading-screenHUDs,201LoadLibrary()function,143–144Locationcolumn,EventPropertieswindow,54loggingevents,ProcessMonitor,50–52Logwindow,OllyDbg,25longdatatype,67longlongdatatype,67looting,229,241–243Luascriptingenvironment,CheatEngine,18–22luremode,242

Mmachinecode,78mainloop

Direct3Ddrawingloop,176–177syncingwith,164–165

mana,avoidingwasted,219Manhattandistanceheuristic,235mantissa,floatdatatype,68massivelymultiplayeronlinerole-playinggames(MMORPGs),xxi–xxii,198,

248massiveonlinebattlearena(MOBA),xxii,189,197,201,206memcpy()function,136memory,65–66

classesandVFtables,74–78datastructures,71–73numericdata,67–69stringdata,69–71

Page 359: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

unions,73–74memoryaccess

ininjectedDLL,145–146forwritingandreading,122–124

memoryaddresses,4accessingwithOllyDbgexpressions,36correct,determininginCheatEngine,7freezing,8new,determiningaftergameupdates,101–104rebasingatruntime,128–129static,6

memory-basedlighthacks,192memorydump

ofclassdata,76ofcodecave,137ofdatastructures,inspecting,70–71ofnumericdata,inspecting,68–69ofstringdata,inspecting,70

memoryforensics,97–98newaddresses,determiningaftergameupdates,101–104playerhealth,findingwithOllyDbg,99–101purposeofdata,deducing,98–99std::listclass,110–113std::mapclass,114–118std::stringclass,105–108std::vectorclass,108–110

memorymanipulation,119accessingmemory,122–124addressspacelayoutrandomization,128–130memoryprotection,124–128processidentifier,obtaining,120–122

Memorymapwindow,OllyDbg,26memorymodification,8–11memorymonitoringwithbots,204–205

Page 360: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

memoryoffset,80memoryonwritebreakpoint,208memorypointer,11memoryprotection,124–128,151memoryscanning,3,98.SeealsoCheatEngine;pointerscanning

basic,4–5importanceof,4memorymodification,8–11newaddresses,determiningaftergameupdates,101–104optimizationofcode,22playerhealth,findingwithOllyDbg,99–101purposeofdata,deducing,98–99

MMORPGs(massivelymultiplayeronlinerole-playinggames),xxi–xxii,198,248

mnemonics,78MOBA(massiveonlinebattlearena),xxii,189,197,201,206modifyingmemoryvalues,8–11Module32First()function,144,174Module32Next()function,144,174Modulecolumn,EventPropertieswindow,54Moduleswindow,OllyDbg,25monitoringmemorywithbots,204–205monsters,kiting,240–241mousemovements,emulating,215,240MOVinstruction,89multiclientpatching,30mutexes,closing,59–60

Nnamedpipes,locating,60nameofspecificplayer,pausingexecutionwhenprinted,37–38Nameswindow,OllyDbg,29

Page 361: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

nearcalls,153–154nearfunctioncall,39.NETprocesses,59Networkeventclassfilter,52newaddresses,determiningaftergameupdates,101–104nextscan,runninginCheatEngine,7nodes,233,234–238no-operation(NOP)commands,31,32NOPing,150–152

lighthacks,192zoomhacks,197–198

NtQueryVirtualMemory()function,246,257,259NtWriteVirtualMemory()function,261–262nullterminator,70numericdatatypes,67–69numericoperators,OllyDbg,34–35

Oobfuscation,251,255–256observinggameevents

detectingvisualcues,205–206interceptingnetworktraffic,206–211monitoringmemory,204–205

obstacles,searchesdisruptedby,233–234offset,54OllyDbg,23–24

assemblycode,27–29,32–33callstack,viewing,30codepatches,creating,31–32commandlinefor,43–44controlwindows,25–26CPUwindow,26–30

Page 362: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

crashingdebuggers,255dealingwithgameupdates,104debuggerbuttonsandfunctions,25expressionengine,33–37memory,viewingandsearching,29–30memorydumpofnumericdata,68–69memorydumpofstringdata,70packetparser,finding,207–208Patcheswindow,31–32patchingif()statements,46–47pausingexecutionwhenhealthofcharacterdrops,39–42pausingexecutionwhennameofplayerisprinted,37–38plug-ins,42–46registercontents,viewingandediting,29Runtracewindow,32–33supporteddatatypes,36translatingcodecaveassemblytoshellcode,135–136userinterface,24–26zoomlimitationcode,finding,198

OllyFlowplug-in,45–46opcodes,78OpenProcess()function,121–122OpenThread()function,142operands

binaryarithmeticinstructions,90IDIVinstruction,92MOVinstruction,89syntax,80–81unaryarithmeticinstructions,90

operations,79operators,usinginOllyDbgexpressionengine,34–35optimizingmemorycode,22ordering,little-endian,67

Page 363: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

orderofvariables,indatastructures,70–71OutputDebugString()function,253

Ppackets

intercepting,206–211sending,215–217

packing,251padding,68pageprotection,125–126pages,124parsingpackets,206–211Patcheswindow,OllyDbg,26,31–32patching,multiclient,30patchingif()statements,46–47Pathcolumn,EventPropertiesdialog,55pathfindingwithsearchalgorithms,232–234.SeealsoA*searchalgorithmpathlist,A*searchalgorithm,239–240Pausebutton,OllyDbg,25pausingexecution,37–38,39–42pausingthreads,184PEB(processenvironmentblock)structure,146PeekMessage()function,184PEheader,160–161pick-phaseHUDs,201PID(processidentifier),120–122pipes,locatingnamed,60Playbutton,OllyDbg,25playerhealth,findingwithOllyDbg,99–101playerversusplayer(PvP)combat,243–244plug-ins,OllyDbg,42–46

Page 364: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

pointerchains,11–12pointerpath,11PointerscannerScanoptionsdialog,CheatEngine,14–16pointerscanning,11

basicsof,12–14withCheatEngine,14–18pointerchains,11–12rescanning,17–18

Pong,46–47Popuptraineronkeypressfield,Trainergeneratordialog,9predictingenemymovements,241prewrittenhookinglibraries,169printf()call,72,73–74,75printingdebugstrings,253Process32First()function,120Process32Next()function,120–121processaccessflags,121PROCESS_ALL_ACCESSflag,121Processandthreadactivityeventclassfilter,52PROCESS_CREATE_THREADflag,121processenvironmentblock(PEB)structure,146ProcessExplorer,49–50,55–56

configuringcolors,56handlemanipulationoptions,59–60hotkeys,57Propertiesdialog,57–59userinterfaceandcontrols,56–57

processhandles,obtaining,121processidentifier(PID),120–122processInput()function,215–216processKeyboardInput()function,216ProcessMonitor,49–50

configuringcolumnsin,51

Page 365: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

debugging,53–55eventclassfilters,51–52high-scorefile,finding,55hotkeys,52inspectingeventsineventlog,52–53loggingin-gameevents,50–52

ProcessMonitorFilterdialog,50Processnamefield,Trainergeneratordialog,9processNextPacket()function,210processorregisters,81–86Processprofilingeventclassfilter,52PROCESS_VM_OPERATIONflag,121,122PROCESS_VM_READflag,121PROCESS_VM_WRITEflag,121Propertiesdialog,ProcessExplorer,57–59protection,memory,124–128,151PunkBustertoolkit,246–247,257purposeofdata,deducing,98–99PvP(playerversusplayer)combat,243–244

Rrangehacks,201readingfromgamememory,119

accessingmemory,122–124addressspacelayoutrandomization,128–130memoryprotection,124–128processidentifier,obtaining,120–122

ReadProcessMemory()function,122–124readprotection,125–128RealTimeMessagingProtocol(RTMP)

assessing,169–170decode()function,hooking,172–173,174–175

Page 366: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

encode()function,hooking,171–172,174–175interceptingpackets,207

real-timestrategy(RTS),xxii,197,201,206,243rebasingaddressesatruntime,128–129reconnaissance,49–50

ProcessExplorer,55–60ProcessMonitor,50–55

recv()function,207–208red-blacktree,114–115Referenceswindow,OllyDbg,26,28–29,40,100refiller,242registers,processor,81–86registerspane,OllyDbg,29Registryeventclassfilter,51Rescanpointerlistwindow,CheatEngine,17–18responsivehacks,203

anti-crowd-controlhacks,218automatichealer,218,225–228,230–232detectingvisualcues,205–206emulatingkeyboard,211–215interceptingnetworktraffic,206–211monitoringmemory,204–205sendingpackets,215–217spelltrainers,219

rootkitsdefeatinganti-cheat,261–262GameGuardtoolkit,248–249

rootnode,113–114RTMP.SeeRealTimeMessagingProtocolRTS(real-timestrategy),xxii,197,201,206,243runtimeflexibility,229Runtracewindow,OllyDbg,26,32–33

Page 367: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

SSBD.Seesignature-baseddetection(SBD)scancode,214scantypes,CheatEngine,6scanvalue,4score,234screenshots,247,258scriptingcustombehaviorsforcavebots,243scriptingengine,CheatEngine,18–22searchalgorithms,232–234.SeealsoA*searchalgorithmSecuritytab,ProcessExplorerPropertiesdialog,58segmentregisters,84–86send()function,216–217sendingpackets,215–217SendInput()function,211–212,215SendMessage()function,213–215sensors,ofasystem,222Set/Changehotkeyscreen,CheatEngine,10SetLight()memberfunction,192SetProcessIsCritical()function,256shellcode,134,135–136,138–141shortdatatype,67sign,floatdatatype,68signature-baseddetection(SBD)

ESEAAnti-Cheattoolkit,247evading,256–257PunkBustertoolkit,246–247

signatures,246single-instancelimitation,59–60skillshots,232Sleep()function,164–165,227

Page 368: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

SmallerThanscantype,CheatEngine,6sourceoperand,80Sourcewindow,OllyDbg,26spawningthreads,129spells

anti-crowd-controlhacks,218complexhypotheticalstatemachine,228–230spelltrainers,219

SSregister,85stackframe,87–89stackoverflow,255–256stackpane,OllyDbg,30stacktrace,ProcessMonitor,54–55statemachines,223–224

automatedhealer,225–228combiningwithcontroltheory,225complexhypothetical,228–230errorcorrection,230–232Luafunctions,adding,229–230runtimeflexibility,229

staticaddresses,6__stdcallconvention,95std::listclass,110–113std::mapclass,114–118std::stringclass,105–108std::vectorclass,108–110Stepintobutton,OllyDbg,25Stepoverbutton,OllyDbg,25stochasticsystems,230stringdata,21,69–71,100–101stringoperators,OllyDbg,35Stringstab,ProcessExplorerPropertiesdialog,58

Page 369: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

structmemberalignment,71structures,data,71–73subregisters,83SuspendThread()function,142,184syncingwithgamethreads,164–165systems,controllingbehaviorof,222

Ttargets,selecting,240TCP/IPtab,ProcessExplorerPropertiesdialog,58TEB(threadenvironmentblock),146templates

forchangingmemoryprotection,127memoryaccessfunctions,123–124,145–146

TESTinstruction,92textstrings,21,69–71,100–101textureofenemies,changing,195–196__thiscallconvention,95,156–158,217Thread32First()function,141Thread32Next()function,141threadenvironmentblock(TEB),146threads

hijacking,138–142injection,134–138spawning,129

Threadstab,ProcessExplorerPropertiesdialog,58Threadswindow,OllyDbg,26thunks,162–163timingcontrol-criticalroutines,254Titlefield,Trainergeneratordialog,9togglingz-buffering,195

Page 370: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Traceintobutton,OllyDbg,25Traceoverbutton,OllyDbg,25tracingwithOllyDbg,32–33,39–42trainergenerator,CheatEngine,9–11trampolinefunctions,165–168,181traversals

IAThooking,162VFtables,156

Uunaryarithmeticinstructions,90unavoidableinfiniteloops,causing,255UnchangedValuescantype,CheatEngine,7unions,73–74Unixsyntax,80UnknownInitialValuescantype,CheatEngine,6updates,determiningnewaddressesafter,101–104userinterface,ProcessExplorer,56–57user-moderootkit,GameGuardtoolkit,248–249

VVACtoolkit,247–248ValueBetweenscantype,CheatEngine,6ValueTypedirective,CheatEngine,6VF(virtualfunction)tables

classinstancesand,76–78findingDirect3Ddevices,177–181hooking,156–160,182–183traversals,156

VirtualAllocEx()function,136–137,138virtualfunctions,classeswith,75–76

Page 371: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

VirtualProtectEx()function,126–128VirtualProtect()function,127

WWaitForSingleObject()function,129,138wallhacks,192

creatingforDirect3D,194–197renderingwithz-buffering,193–194

warbots,243–244Wardentoolkit,249–250waypoints,222,229wchar_tdatatype,67windowhandle,fetching,120Windowswindow,OllyDbg,26WM_CHARmessages,213–214WORDdatatype,67WriteProcessMemory()function,122–124,136–137,138writeprotection,125–128writingtogamememory,119

accessingmemory,122–124addressspacelayoutrandomization,128–130codecaves,136–137memoryprotection,124–128processidentifier,obtaining,120–122

Xx86assemblylanguage,78–79

arithmeticinstructions,90–92branchinginstructions,92–94callstack,86–88commandsyntax,79–81

Page 372: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

datamodificationinstructions,89functioncalls,94–95jumpinstructions,92–94NOPing,150–152processorregisters,81–86

x86Windowsmemoryprotectionattributes,125–126

Zz-buffering,192–195zoomfactor,197zoomhacks,197–198

Page 373: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

Footnotes

Chapter4:FROMCODETOMEMORY:AGENERALPRIMER1.RandallHyde’sTheArtofAssemblyLanguage,2ndedition(NoStarchPress,2010)isawonderfulbookthatcanteachyoueverythingthereistoknowaboutassembly.2.Eachcommandmustfitwithin15bytes.Mostcommandsare6orfewer.3.Thereisalsoanunsignedmultiplicationinstruction,MUL,whichonlyworkswithasingleoperand.4.JustasMUListoIMUL,DIVistheunsignedcounterparttoIDIV.

Page 374: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

RESOURCESVisithttps://www.nostarch.com/gamehacking/forresources,errata,andotherinformation.

Moreno-nonsensebooksfrom NOSTARCHPRESS

BLACKHATPYTHONPythonProgrammingforHackersandPentestersbyJUSTINSEITZ

DEC2014,192PP.,$34.95ISBN978-1-59327-590-7

Page 375: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

THECARHACKER’SHANDBOOKAGuideforthePenetrationTesterbyCRAIGSMITH

MAR2016,304PP.,$49.95ISBN978-1-59327-703-1

THEIDAPROBOOK,2NDEDITIONTheUnofficialGuidetotheWorld’sMostPopularDisassemblerbyCHRISEAGLE

JUL2011,672PP.,$69.95ISBN978-1-59327-289-0

PRACTICALFORENSICIMAGINGSecuringDigitalEvidencewithLinuxToolsbyBRUCENIKKEL

FALL2016,256PP.,$49.95

Page 376: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

ISBN978-1-59327-793-2

IOSAPPLICATIONSECURITYTheDefinitiveGuideforHackersandDevelopersbyDAVIDTHIEL

FEB2016,296PP.,$49.95ISBN978-1-59327-601-0

PRACTICALMALWAREANALYSISTheHands-OnGuidetoDissectingMaliciousSoftwarebyMICHAELSIKORSKIandANDREWHONIG

FEB2012,800PP.,$59.95ISBN978-1-59327-290-6

800.420.7240OR415.863.9900|[email protected]|WWW.NOSTARCH

Page 377: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names
Page 378: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

GetInsidetheGameYoudon’tneedtobeawizardtotransformagameyoulikeintoagameyoulove.ImagineifyoucouldgiveyourfavoritePCgameamoreinformativeheads-updisplayorinstantlycollectallthatlootfromyourlatestepicbattle.

BringyourknowledgeofWindows-baseddevelopmentandmemorymanagement,andGameHackingwillteachyouwhatyouneedtobecomeatruegamehacker.Learnthebasics,likereverseengineering,assemblycodeanalysis,programmaticmemorymanipulation,andcodeinjection,andhoneyournewskillswithhands-onexamplecodeandpracticebinaries.

Levelupasyoulearnhowto:

ScanandmodifymemorywithCheatEngine

ExploreprogramstructureandexecutionflowwithOllyDbg

LogprocessesandpinpointusefuldatafileswithProcessMonitor

ManipulatecontrolflowthroughNOPing,hooking,andmore

Locateanddissectcommongamememorystructures

You’llevendiscoverthesecretsbehindcommongamebots,including:

Extrasensoryperceptionhacks,suchaswallhacksandheads-updisplays

Responsivehacks,suchasautohealersandcombobots

Botswithartificialintelligence,suchascavewalkersandautomaticlooters

Gamehackingmightseemlikeblackmagic,butitdoesn’thavetobe.Onceyouunderstandhowbotsaremade,you’llbebetterpositionedtodefendagainsttheminyourowngames.JourneythroughtheinnerworkingsofPCgameswithGameHacking,andleavewithadeeperunderstandingofbothgamedesignandcomputersecurity.

Page 379: ihatefeds.com · 2020-04-21 · 005.8--dc23 2015036294 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names

AbouttheAuthorNickCanowrotehisfirstscriptsforopensourcegameserverswhenhewas12andhasbeenapartofthegame-hackingcommunityeversince.Hehasyearsofexperienceindetectinganddefendingagainstmalware,andadvisesdevelopersanddesignersonbestpracticestoprotecttheirgamesagainstbots.Nickhasspokenabouthisresearchandtoolsatmanyconferences.

WARNING!Thisbookdoesnotcondonepiracy,violatingtheDMCA,infringingcopyright,orbreakingin-gameTermsofService.Gamehackershavebeenbannedfromgamesforlife,suedformillionsofdollars,andevenjailedfortheirwork.

THEFINESTINGEEKENTERTAINMENT™www.nostarch.com