- PART 1: TOOLS OF THE TRADE
- PART 2: GAME DISSECTION
- PART 3: PROCESS PUPPETEERING
- PART 4: CREATING BOTS
- TOOLS OF THe TRade
- Game diSSecTiOn
- PROceSS PuPPeTeeRinG
- PaRT 4 cReaTinG bOTS
- Prerequisites for the Reader
- a brief Game Hacking History
- How This book is Organized
- about the Online Resources
- How to use This book
- t O O l s O f t H E t r A D E
- D E B u G G I N G G A M E s w I t H O l ly D B G
- G A M E D I s s E C t I
Game HackinG
GAME HACKING
Developing Autonomous Bots for Online Games
by Nick Cano
San Francisco
Game HackinG. Copyright © 2016 by Nick Cano.
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher.
Printed in USA
First printing
20 19 18 17 16 1 2 3 4 5 6 7 8 9
ISBN-10: 1-59327-669-9
ISBN-13: 978-1-59327-669-0
Publisher: William Pollock
Production Editor: Laurel Chun Cover Illustration: Ryan Milner
Interior Design: Octopod Studios
Developmental Editor: Jennifer Griffith-Delgado
Technical Reviewer: Stephen Lawler
Copyeditor: Rachel Monaghan
Compositor: Laurel Chun
Proofreader: Paula L. Fleming Indexer: BIM Creatives, LLC
For information on distribution, translations, or bulk sales, please contact No Starch Press, Inc. directly: No Starch Press, Inc.
245 8th Street, San Francisco, CA 94103 phone: 415.863.9900; info@nostarch.com www.nostarch.com
Library of Congress Cataloging-in-Publication Data
Cano, Nick, author.
Game hacking : developing autonomous bots for online games / by Nick Cano. pages cm Includes index.
Summary: “A hands-on guide to hacking computer games. Shows programmers how to dissect computer games and create bots to alter their gaming environment. Covers the basics of game hacking, including reverse engineering, assembly code analysis, programmatic memory manipulation, persistent hacks, responsive hacks, and code injection.”— Provided by publisher.
ISBN 978-1-59327-669-0 — ISBN 1-59327-669-9
1. Intelligent agents (Computer software) 2. Internet programming. 3. Internet games-Programming. 4. Hacking. I. Title.
QA76.76.I58C36 2016
005.8—dc23
2015036294
No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names mentioned herein may be the trademarks of their respective owners. Rather than use a trademark symbol with every occurrence of a trademarked name, we are using the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.
The information in this book is distributed on an “As Is” basis, without warranty. While every precaution has been taken in the preparation of this work, neither the author nor No Starch Press, Inc. shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly by the information contained in it.
about the author
Nick Cano wrote his first scripts for open source game servers when he was 12 and started a business selling his bots when he was 16. He has been a part of the game-hacking community ever since and advises game developers and designers on best practices to protect their games against bots. Nick also has years of experience in detecting and defending against malware, and he has spoken at many conferences about his research and
tools.
about the Technical Reviewer
Stephen Lawler is the founder and president of a small computer software and security consulting firm. He has been actively working in information security for over 10 years, primarily in reverse engineering, malware analysis, and vulnerability research. He was a member of the Mandiant malware analysis team and assisted with high-profile computer intrusions affecting several Fortune 100 companies. Stephen also developed and teaches the Practical ARM Exploitation class, which has been offered at BlackHat and several other security conferences for the past five years.
B r I E f C O N t E N t s
Foreword by Dr. Jared DeMott. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xvii
Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
PART 1: TOOLS OF THE TRADE
Chapter 1: Scanning Memory Using Cheat Engine. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 2: Debugging Games with OllyDbg. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Chapter 3: Reconnaissance with Process Monitor and Process Explorer . . . . . . . . . . . . . . . 49
PART 2: GAME DISSECTION
Chapter 4: From Code to Memory: A General Primer. . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Chapter 5: Advanced Memory Forensics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Chapter 6: Reading from and Writing to Game Memory . . . . . . . . . . . . . . . . . . . . . . . . 119
PART 3: PROCESS PUPPETEERING
Chapter 7: Code Injection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Chapter 8: Manipulating Control Flow in a Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
PART 4: CREATING BOTS
Chapter 9: Using Extrasensory Perception to Ward Off Fog of War . . . . . . . . . . . . . . . . 189
Chapter 10: Responsive Hacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Chapter 11: Putting It All Together: Writing Autonomous Bots . . . . . . . . . . . . . . . . . . . . . 221
Chapter 12: Staying Hidden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
C O N t E N t s I N D E tA I l
FORewORd by dr. Jared demott xv
acknOwLedGmenTS xvii
inTROducTiOn xix
Prerequisites for the Reader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xx A Brief Game Hacking History. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xx Why Hack Games? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi How This Book Is Organized. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii About the Online Resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xxiv
How to Use This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xxiv
PaRT 1
TOOLS OF THe TRade
1
ScanninG memORy uSinG cHeaT enGine 3
Why Memory Scanners Are Important . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Basic Memory Scanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Cheat Engine’s Memory Scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Scan Types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Running Your First Scan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Next Scans. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 When You Can’t Get a Single Result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Cheat Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Memory Modification in Games. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Manual Modification with Cheat Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Trainer Generator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Pointer Scanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Pointer Chains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Pointer Scanning Basics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Pointer Scanning with Cheat Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Pointer Rescanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Lua Scripting Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Searching for Assembly Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Searching for Strings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2
debuGGinG GameS wiTH OLLydbG 23
A Brief Look at OllyDbg’s User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
OllyDbg’s CPU Window. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Viewing and Navigating a Game’s Assembly Code . . . . . . . . . . . . . . . . . . . 27 Viewing and Editing Register Contents. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Viewing and Searching a Game’s Memory . . . . . . . . . . . . . . . . . . . . . . . . . 29
Viewing a Game’s Call Stack. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Creating Code Patches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Tracing Through Assembly Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 OllyDbg’s Expression Engine. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Using Expressions in Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Using Operators in the Expression Engine . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Working with Basic Expression Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Accessing Memory Contents with Expressions . . . . . . . . . . . . . . . . . . . . . . . 36
OllyDbg Expressions in Action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Pausing Execution When a Specific Player’s Name Is Printed . . . . . . . . . . . . . 37
Pausing Execution When Your Character’s Health Drops . . . . . . . . . . . . . . . 39
OllyDbg Plug-ins for Game Hackers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Copying Assembly Code with Asm2Clipboard . . . . . . . . . . . . . . . . . . . . . . . 42 Adding Cheat Engine to OllyDbg with Cheat Utility. . . . . . . . . . . . . . . . . . . . 42 Controlling OllyDbg Through the Command Line. . . . . . . . . . . . . . . . . . . . . . 43
Visualizing Control Flow with OllyFlow . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3
RecOnnaiSSance wiTH PROceSS mOniTOR
and PROceSS exPLOReR 49
Process Monitor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Logging In-Game Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Inspecting Events in the Process Monitor Log. . . . . . . . . . . . . . . . . . . . . . . . . 52
Debugging a Game to Collect More Data . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Process Explorer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Process Explorer’s User Interface and Controls . . . . . . . . . . . . . . . . . . . . . . . 56 Examining Process Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Handle Manipulation Options. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
PaRT 2
Game diSSecTiOn
4
FROm cOde TO memORy: a GeneRaL PRimeR 65
How Variables and Other Data Manifest in Memory . . . . . . . . . . . . . . . . . . . . . . . . . 66 Numeric Data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 String Data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Contents in Detail
Unions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Classes and VF Tables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 x86 Assembly Crash Course . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Command Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Processor Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 The Call Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Important x86 Instructions for Game Hacking. . . . . . . . . . . . . . . . . . . . . . . . 89 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5
advanced memORy FORenSicS 97
Advanced Memory Scanning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Deducing Purpose. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Finding the Player’s Health with OllyDbg . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Determining New Addresses After Game Updates . . . . . . . . . . . . . . . . . . . 101
Identifying Complex Structures in Game Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 The std::string Class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 The std::vector Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 The std::list Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
The std::map Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
6
ReadinG FROm and wRiTinG TO Game memORy 119
Obtaining the Game’s Process Identifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Obtaining Process Handles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Working with OpenProcess() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Accessing Memory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Working with ReadProcessMemory() and WriteProcessMemory() . . . . . . . . . 122
Accessing a Value in Memory with ReadProcessMemory() and WriteProcessMemory() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Writing Templated Memory Access Functions. . . . . . . . . . . . . . . . . . . . . . . 123
Memory Protection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Differentiating x86 Windows Memory Protection Attributes . . . . . . . . . . . . . 125
Changing Memory Protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Address Space Layout Randomization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Disabling ASLR to Simplify Bot Development. . . . . . . . . . . . . . . . . . . . . . . . 128
Bypassing ASLR in Production. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
PaRT 3
PROceSS PuPPeTeeRinG
7
cOde inJecTiOn 133
Injecting Code Caves with Thread Injection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Creating an Assembly Code Cave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Translating the Assembly to Shellcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Contents in Detail xi
Writing the Code Cave to Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Using Thread Injection to Execute the Code Cave . . . . . . . . . . . . . . . . . . . . 137
Hijacking a Game’s Main Thread to Execute Code Caves . . . . . . . . . . . . . . . . . . . . 138 Building the Assembly Code Cave. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Generating Skeleton Shellcode and Allocating Memory. . . . . . . . . . . . . . . . 140
Finding and Freezing the Main Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Injecting DLLs for Full Control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Tricking a Process into Loading Your DLL . . . . . . . . . . . . . . . . . . . . . . . . . . 143 Accessing Memory in an Injected DLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 Bypassing ASLR in an Injected DLL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
8
maniPuLaTinG cOnTROL FLOw in a Game 149
NOPing to Remove Unwanted Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 When to NOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 How to NOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Hooking to Redirect Game Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Call Hooking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 VF Table Hooking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 IAT Hooking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Jump Hooking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Applying Call Hooks to Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Accessing the RTMP Goldmine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Hooking the RTMPS encode() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Hooking the RTMPS decode() Function. . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Placing the Hooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
Applying Jump Hooks and VF Hooks to Direct3D. . . . . . . . . . . . . . . . . . . . . . . . . . . 175 The Drawing Loop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Finding the Direct3D Device. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Writing a Hook for EndScene(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Writing a Hook for Reset() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
What’s Next?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
PaRT 4 cReaTinG bOTS
9
uSinG exTRaSenSORy PeRcePTiOn TO waRd OFF
FOG OF waR 189
Background Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Revealing Hidden Details with Lighthacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Adding a Central Ambient Light Source . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Increasing the Absolute Ambient Light . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Creating Other Types of Lighthacks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Contents in Detail
Revealing Sneaky Enemies with Wallhacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
Rendering with Z-Buffering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 Creating a Direct3D Wallhack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Fingerprinting the Model You Want to Reveal. . . . . . . . . . . . . . . . . . . . . . . 196
Getting a Wider Field of Vision with Zoomhacks . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Using NOPing Zoomhacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Scratching the Surface of Hooking Zoomhacks . . . . . . . . . . . . . . . . . . . . . . 198
Displaying Hidden Data with HUDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Creating an Experience HUD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Using Hooks to Locate Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 An Overview of Other ESP Hacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
10
ReSPOnSive HackS 203
Observing Game Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 Monitoring Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 Detecting Visual Cues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Intercepting Network Traffic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Performing In-Game Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 Emulating the Keyboard. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Sending Packets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
Tying the Pieces Together . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Making the Perfect Healer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Resisting Enemy Crowd-Control Attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Avoiding Wasted Mana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
11
PuTTinG iT aLL TOGeTHeR:
wRiTinG auTOnOmOuS bOTS 221
Control Theory and Game Hacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Combining Control Theory and State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 A Basic Healer State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 A Complex Hypothetical State Machine. . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Error Correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Pathfinding with Search Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 Two Common Search Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 How Obstacles Disrupt Searches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 An A Search Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
When A Searches Are Particularly Useful. . . . . . . . . . . . . . . . . . . . . . . . . 240
Common and Cool Automated Hacks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Looting with Cavebots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
Automating Combat with Warbots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Closing Thoughts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Contents in Detail xiii
12……………………………………………………………………………………………………………………………………………………………………………..
Prominent Anti-Cheat Software………………………………………………………………………………………………………………………… 246
The PunkBuster Toolkit……………………………………………………………………………………………………………………………………… 246
Signature-Based Detection 246
Screenshots 247
Hash Validation 247
The ESEA Anti-Cheat Toolkit……………………………………………………………………………………………………………………………… 247
The VAC Toolkit…………………………………………………………………………………………………………………………………………………. 247
DNS Cache Scans 248
Binary Validation 248
False Positives 248
The GameGuard Toolkit…………………………………………………………………………………………………………………………………….. 248
User-Mode Rootkit 248
Kernel-Mode Rootkit 249
The Warden Toolkit…………………………………………………………………………………………………………………………………………… 249
Carefully Managing a Bot’s Footprint……………………………………………………………………………………………………………….. 250
Minimizing a Bot’s Footprint 250
Masking Your Footprint 251
Teaching a Bot to Detect Debuggers 251
Anti-Debugging Techniques 255
Defeating Signature-Based Detection……………………………………………………………………………………………………………….. 256
Defeating Screenshots………………………………………………………………………………………………………………………………………. 258
Defeating Binary Validation………………………………………………………………………………………………………………………………. 259
Defeating an Anti-Cheat Rootkit……………………………………………………………………………………………………………………….. 261
Defeating Heuristics…………………………………………………………………………………………………………………………………………… 262
Closing Thoughts……………………………………………………………………………………………………………………………………………….. 263
STayinG Hidden 245
index 265
Contents in Detail
f O r E w O r D
Nick is great. We first hit it off in all the right and wrong ways, as you can imagine. I’ve been in the security field a while; he’s a little younger. I’ve had the schooling, whereas he’s not much for college. I’m a faith guy, and he’s not. The interesting thing is that none of that matters; we’ve had a blast anyway. Age, race, gender, degrees—when it comes to gaming, hacking, and coding, no one cares!
Nick gets it done. He’s fun. He’s brilliant. He’s hard working. And probably most pertinent: he’s one of the rare few who understand the intersection of gaming, hacking, and coding. He’s worked in this niche and created profitable bots.
In this first-of-its-kind book, Nick walks you through what it means to pull apart games. He teaches you the software investigation tools and tricks of the trade. You’ll learn about game internals, how to pull them apart, and how to modify play. For example, Nick teaches how to avoid anti-cheat so that you can automate play. Wouldn’t it be cool to have your own bot that collects experience, gold, items, and more—all while you’re away?
Ever wonder how the cheaters cheat? Ever wanted to patch or protect your game? Grab a coffee, crack open your laptop, and enjoy.
Blessings to you and yours,
Dr. Jared DeMott
Security Expert & Software Builder
A C K N O w l E D G M E N t s
Writing this book was an amazing journey, and I couldn’t have done it alone. No Starch Press has been extremely supportive and worked closely with me to take this book from concept to reality. In particular, I’d like to thank my developmental editor, Jennifer Griffith-Delgado, and my production editor, Laurel Chun. Bill Pollock, Tyler Ortman, Alison Law, and the rest of the team at No Starch are wonderful people, and I’m pleased to have worked with them.
Thanks to copyeditor Rachel Monaghan, proofreader Paula L. Fleming, and technical reviewer Stephen Lawler. Thanks also to my friends Cavitt “synt4x” Glover and Vadim Kotov, who took the time to skim some chapters before submission, and to Jared DeMott for writing the book’s foreword.
I’d like to thank all of the people on TPForums who took me in when I was just a naive kid and helped me learn how to hack games. In particular, I owe my thanks to Joseph “jo3bingham” Bingham, Ian Obermiller, and jeremic, who all had a significant influence on my progression as a hacker, and to TPForums founder Josh “Zyphrus” Hartzell, who helped me find my confidence and skills when my future looked its bleakest.
Thanks also to my entire forum staff and every customer who has ever used my bots. And finally, thanks to my family, friends, and colleagues, who have been fun and supportive and helped shape me into the man I am today.
I N t r O D u C t I O N
A common misconception in the world of online gaming is the idea that the only
game you can play is the one in the title.
In fact, game hackers enjoy playing the game that hides behind the curtain: a cat-and-mouse game of wits between them and the game developers. While
game hackers work to reverse engineer game binaries, automate aspects of game play, and modify gaming environments, game developers combat the hacker-designed tools (normally referred to as bots) using anti-reversing techniques, bot detection algorithms, and heuristic data mining.
As the battle between game hackers and developers has progressed, the technical methods implemented by both parties—many of which resemble techniques utilized by malware developers and antivirus vendors—have evolved, becoming more complex. This book highlights the fight put up by game hackers, and the advanced methods they have engineered to manipulate games while simultaneously eluding game developers in the dark corners of their own software.
Although the book focuses on teaching you to develop tools that would likely be considered a nuisance or even malicious by gaming companies, you’ll find that many of the techniques are useful for development of tools that are perfectly benign and neutral. Furthermore, the knowledge of how these techniques are implemented is key for the game developers working to prevent their use.
Prerequisites for the Reader
This book does not aim to teach you software development, and therefore assumes that you have, at minimum, a solid software development background. This background should include familiarity with native Windowsbased development, as well as light experience with game development and memory management. While these skills will be enough for you to follow this book, experience with x86 assembly and Windows internals will ensure that details of more advanced implementations are not lost on you.
Furthermore, since all the advanced hacks discussed in this book rely on code injection, an ability to write code in a native language like C or C++ is a must. All of the example code in this book is written in C++ and can be compiled with Microsoft Visual C++ Express Edition. (You can download MSVC++ Express Edition from http://www.visualstudio.com/en-US/ products/visual-studio-express-vs.)
NOtE Other languages that compile to native code, such as Delphi, are also capable of injection, but I will not discuss them in this book.
a brief Game Hacking History
Since the dawn of online PC gaming in the early 1980s, an ongoing war of wits between game hackers and game developers has been taking place. This seemingly endless struggle has prompted game developers to devote countless hours toward preventing hackers from taking their games apart and greasing between the gears. These hackers, who fight back with their sophisticated stealth implementations, have many motivations: customized graphics, better performance, ease of use, autonomous play, in-game asset acquisition, and, of course, real-life profit.
The late 1990s and early 2000s were the golden age of game hacking, when online PC games became advanced enough to draw large crowds but were still simple enough to easily reverse engineer and manipulate. Online games that came out during this time, such as Tibia (January 1997), Runescape (January 2001), and Ultima Online (September 1997), were heavily targeted by bot developers. The developers of these games and others like them still struggle today to control the massive communities of bot developers and bot users. The game developers’ lack of action and the hackers’
Introduction
tenacity have not only completely shattered the economies within the games, but have also produced a thriving for-profit industry focused around bot development and bot defense.
In the years since the golden age, more mature game companies started taking bot defense very seriously. These companies now have dedicated teams focused on developing bot prevention systems, and many also view bots as a legal matter and will not hesitate to banish players who use bots and sue the bot developers who provided them. As a result, many game hackers have been forced to develop advanced stealth techniques to keep their users safe.
This war wages on, and the numbers on both sides of the fight will continue to grow as online gaming becomes more prevalent over the coming years. Major game developers are pursuing hackers with endless determination, even slamming some game hacking giants with multimillion-dollar lawsuits. This means that game hackers who are serious about their business must either target smaller gaming companies, or anonymously market their products from the shadows in order to escape prosecution. For the foreseeable future, game hacking and bot development will continue to grow into a larger and more lucrative industry for those game hackers bold enough to take the risks.
why Hack Games?
Aside from its obvious allure and challenging nature, game hacking has some practical and profitable purposes. Every day, thousands of novice programmers experiment with small-scale game hacking as a way to automate monotonous tasks or perform menial actions. These script kiddies will use automation tools like AutoIt for their small, relatively harmless hacks. On the other hand, professional game hackers, backed by their large toolkits and years of programming experience, will devote hundreds of hours to the development of advanced game hacks. These types of game hacks, which are the focus of this book, are often created with the intent of making large amounts of money.
Gaming is a huge industry that generated $22.4 billion in sales in 2014, according to the Entertainment Software Association. Of the tens of millions of players who play games daily, 20 percent play massively multiplayer online role-playing games (MMORPGs). These MMORPGs often have thousands of players who trade virtual goods within thriving in-game economies. Players often have a need for in-game assets and are willing to buy these assets with real-world money. Consequently, MMORPG players end up developing large communities that provide gold-for-cash services. These services often go as far as enforcing exchange rates from in-game gold to real-world currencies.
To take advantage of this, game hackers will create bots that are capable of automatically farming gold and leveling characters. Then, depending on their goal, hackers will either set up massive gold farms and sell their
Introduction xxi
in-game profits, or perfect and sell their software to players who wish to seamlessly obtain levels and gold with minimal interference. Due to the massive communities surrounding popular MMORPGs, these game hackers can make between six and seven figures annually.
While MMORPGs provide the largest attack surface for hackers, they have a relatively small audience overall. About 38 percent of gamers favor real-time strategy (RTS) and massive online battle arena (MOBA) games, and another 6 percent play primarily first-person shooter (FPS) games. These competitive player versus player (PvP) games collectively represent 44 percent of the gaming market and provide great rewards to determined game hackers.
PvP games are often episodic in nature; each match is an isolated game, and there’s typically not much profitable progression for botting away from keyboard (AFK). This means that, instead of running gold farms or creating autonomous bots to level up characters, hackers will create reactive bots that assist players in combat.
These highly competitive games are about skill and tactics, and most players participate to prove their ability to themselves and others. As a consequence, the number of people seeking bots for PvP-type games is substantially lower than you’d find in the grind-heavy world of MMORPGs. Nevertheless, hackers can still make a pretty penny selling their PvP bots, which are often much easier to develop than full-fledged autonomous bots.
How This book is Organized
This book is split into four parts, each of which focuses on a different core aspect of game hacking. In Part 1: Tools of the Trade, you’ll get a box full of tools to help you hack games.
• Chapter 1: Scanning Memory Using Cheat Engine will teach you how to scan a game’s memory for important values using Cheat Engine.
• In Chapter 2: Debugging Games with OllyDbg, you’ll get a crash course in debugging and reverse engineering with OllyDbg. The skills you learn here will be extremely useful when you start making advanced bots and injecting code.
• To wrap up, Chapter 3: Reconnaissance with Process Monitor and Process Explorer, will teach you how to use two reconnaissance tools to inspect how games interact with files, other processes, the network, and the operating system.
The online resources for each chapter in Part 1 include custom binaries I created to give you a safe place to test and hone your newly discovered skills.
Once you’re comfortable with every wrench and hammer, Part 2: Game Dissection, will teach you how to get under the hood and figure out how games work.
Introduction
• In Chapter 4: From Code to Memory: A General Primer, you’ll learn what a game’s source code and data look like once compiled into a game binary.
• Chapter 5: Advanced Memory Forensics builds on the knowledge you’ll gain from Chapter 4. You’ll learn how to scan memory and use debugging to seamlessly locate tricky memory values and dissect complex classes and structures.
• Finally, Chapter 6: Reading from and Writing to Game Memory shows you how to read and modify data within a running game.
These chapters provide lots of in-depth proof-of-concept example code that you can use to verify everything you read.
In Part 3: Process Puppeteering, you’ll become a puppeteer as you learn how to turn any game into a marionette.
• Building on the skills from Parts 1 and 2, Chapter 7: Code Injection describes how to inject and execute your own code in the address space of a game.
• Once you’ve mastered injection, Chapter 8: Manipulating Control Flow in a Game will teach you how to use injection to intercept, modify, or disable any function call made by a game, and will wrap up with some useful real-world examples for the common libraries Adobe AIR and Direct 3D.
To complement your puppeteering classes, these chapters are accompanied by thousands of lines of production-ready code that you can use as a boilerplate library for a future bot.
In Part 4: Creating Bots, you’ll see how to combine your toolbox, dissection abilities, puppeteering skills, and software engineering background to create powerful bots.
• Chapter 9: Using Extrasensory Perception to Ward Off Fog of War explores ways to make a game display useful information that isn’t exposed by default, such as the locations of hidden enemies and the amount of experience you earn per hour.
• Chapter 10: Responsive Hacks shows code patterns you can use to detect in-game events, like decreases in health, and to make bots that react to those events faster than human players.
• Chapter 11: Putting It All Together: Writing Autonomous Bots reveals how bots that play games without human interaction work. Automated bots combine control theory, state machines, search algorithms, and mathematical models, and this chapter is a crash course in those topics.
• In Chapter 12: Staying Hidden, you’ll learn about some of the highlevel techniques you can use to escape and evade any system that would interfere with your bots.
Introduction xxiii
As you’ve probably come to expect, these chapters have lots of example code. Some of the hacks shown in this part are built on example code from previous chapters. Others explore succinct, straightforward design patterns you can use to create your own bots. Once you’ve finished all four parts of this book, you’ll be sent off into the virtual world with your new superpower.
about the Online Resources
You’ll find many additional resources for this book at https://www.nostarch .com/gamehacking/. These resources include compiled binaries to test your skills, a considerable amount of example code, and quite a few snippets of production-ready game hacking code. These resources go hand-in-hand with the book, and it really isn’t complete without them, so make sure to download them before you continue.
How to use This book
This book should be used first and foremost as a guide to get you started in game hacking. The progression is such that the content of each chapter introduces new skills and abilities that build on all previous chapters. As you complete chapters, I encourage you to play with the example code and test your skills on a real game before continuing your reading. This is important, as some covered topics will have use cases that don’t become evident until you’re 10 feet deep in the mud.
Once you’ve finished the book, I hope it can still be useful to you as a field manual. If you come across some data structure you’re unsure of, maybe the details in Chapter 5 can help. If you reverse engineer a game’s map format and are ready to create a pathfinder, you can always flip to Chapter 11, study the content, and use some of the example code as a starting point. Although it’s impossible to anticipate all the problems you might face when you’re hacking away, I’ve tried to ensure you’ll find some answers within these pages.
A NOtE frOM tHE PuBlIsHEr
This book does not condone piracy, violating the DMCA, infringing copyright, or breaking in-game Terms of Service. Game hackers have been banned from games for life, sued for millions of dollars, and even jailed for their work.
Introduction
Part 1
t O O l s O f t H E t r A D E
1
s C A N N I N G M E M O r y
u s I N G C H E At E N G I N E
The best game hackers in the world spend years personalizing expansive arsenals with
custom-built tools. Such potent toolkits
enable these hackers to seamlessly analyze
games, effortlessly prototype hacks, and effectively develop bots. At the core, however, each unique kit is built from the same four-piece powerhouse: a memory scanner, an assembler-level debugger, a process monitor, and a hex editor.
Memory scanning is the gateway to game hacking, and this chapter will teach you about Cheat Engine, a powerful memory scanner that searches a game’s operating memory (which lives in RAM) for values like the player’s level, health, or in-game money. First, I’ll focus on basic memory scanning, memory modification, and pointer scanning. Following that, we’ll dive into Cheat Engine’s powerful embedded Lua scripting engine.
NOtE You can grab Cheat Engine from http://www.cheatengine.org/. Pay attention when running the installer because it will try to install some toolbars and other bloatware. You can disable those options if you wish.
why memory Scanners are important
Knowing a game’s state is paramount to interacting with the game intelligently, but unlike humans, software can’t determine the state of a game simply by looking at what’s on the screen. Fortunately, underneath all of the stimuli produced by a game, a computer’s memory contains a purely numeric representation of that game’s state—and programs can understand numbers easily. Hackers use memory scanners to find those values in memory, and then in their programs, they read the memory in these locations to understand the game’s state.
For example, a program that heals players when they fall below 500 health needs to know how to do two things: track a player’s current health and cast a healing spell. The former requires access to the game’s state, while the latter might only require a button to be pressed. Given the location where a player’s health is stored and the way to read a game’s memory, the program would look something like this pseudocode:
// do this in some loop
health = readMemory(game, HEALTH_LOCATION)
if (health < 500) pressButton(HEAL_BUTTON)
A memory scanner allows you to find HEALTH_LOCATION so that your software can query it for you later.
basic memory Scanning
The memory scanner is the most basic, yet most important, tool for the aspiring game hacker. As in any program, all data in the memory of a game resides at an absolute location called a memory address. If you think of the memory as a very large byte array, a memory address is an index pointing to a value in that array. When a memory scanner is told to find some value x (called a scan value, because it’s the value you’re scanning for) in a game’s memory, the scanner loops through the byte array looking for any value equal to x. Every time it finds a matching value, it adds the index of the match to a result list.
Due to the sheer size of a game’s memory, however, the value of x can appear in hundreds of locations. Imagine that x is the player’s health, which is currently 500. Our x uniquely holds 500, but 500 is not uniquely held by x, so a scan for x returns all variables with a value of 500. Any addresses not related to x are ultimately clutter; they share a value of 500 with x only by chance. To filter out these unwanted values, the memory scanner allows you to rescan the result list, removing addresses that no longer hold the same value as x, whether x is still 500 or has changed.
For these rescans to be effective, the overall state of the game must have significant entropy—a measure of disorder. You increase entropy by changing the in-game environment, often by moving around, killing creatures, or switching characters. As entropy increases, unrelated addresses are less likely to continue to arbitrarily hold the same value, and given enough entropy, a few rescans should filter out all false positives and leave you with the true address of x.
cheat engine’s memory Scanner
This section gives you a tour of Cheat Engine’s memory-scanning options, which will help you track down the addresses of game state values in memory. I’ll give you a chance to try the scanner out in “Basic Memory Editing” on page 11; for now, open Cheat Engine and have a look around. The memory scanner is tightly encapsulated in its main window, as shown in Figure 1-1.
Figure 1-1: Cheat Engine main screen
To begin scanning a game’s memory, click the Attach icon u to attach to a process and then enter the scan value (referred to as x in our conceptual scanner) you want to locate w. By attaching to a process, we’re telling Cheat Engine to prepare to operate on it; in this case, that operation is a scan. It helps to also tell Cheat Engine what kind of scan to run, as I’ll discuss next.
Scan Types
Cheat Engine allows you to select two different scan directives, called Scan Type and Value Type x. Scan Type tells the scanner how to compare your scan value with the memory being scanned using one of the following scan
types:
Exact Value Returns addresses pointing to values equal to the scan value. Choose this option if the value you are looking for won’t change during the scan; health, mana, and level typically fall into this
category.
Bigger Than Returns addresses pointing to values greater than the scan value. This option is useful when the value you’re searching for is steadily increasing, which often happens with timers.
Smaller Than Returns addresses pointing to values smaller than the scan value. Like Bigger Than, this option is useful for finding timers (in this case, ones that count down rather than up).
Value Between Returns addresses pointing to values within a scan value range. This option combines Bigger Than and Smaller Than, displaying a secondary scan value box that allows you to input a much smaller range of values.
Unknown Initial Value Returns all addresses in a program’s memory, allowing rescans to examine the entire address range relative to their initial values. This option is useful for finding item or creature types, since you won’t always know the internal values the game developers used to represent these objects.
The Value Type directive tells the Cheat Engine scanner what type of variable it’s searching for.
Running Your First Scan
Once the two scan directives are set, click First Scan v to run an initial scan for values, and the scanner will populate the results list y. Any green addresses in this list are static, meaning that they should remain persistent across program restarts. Addresses listed in black reside in dynamically allocated memory, memory that is allocated at runtime.
When the results list is first populated, it shows the address and realtime value of each result. Each rescan will also show the value of each result during the previous scan. (Any real-time values displayed are updated at an interval that you can set in Edit4Settings4General Settings4Update interval.)
Next Scans
Once the results list is populated, the scanner enables the Next Scan v button, which offers six new scan types. These additional scan types allow you to compare the addresses in the results list to their values in the previous scan, which will help you narrow down which address holds the game state value you’re scanning for. They are as follows:
Increased Value Returns addresses pointing to values that have increased. This complements the Bigger Than scan type by keeping the same minimum value and removing any address whose value has decreased.
Increased Value By Returns addresses pointing to values that have increased by a defined amount. This scan type usually returns far fewer false positives, but you can use it only when you know exactly how much a value has increased.
Decreased Value This option is the opposite of Increased Value.
Decreased Value By This option is the opposite of Increased Value By. Changed Value Returns addresses pointing to values that have changed. This type is useful when you know a value will mutate, but you’re unsure how.
Unchanged Value Returns addresses pointing to values that haven’t changed. This can help you eliminate false positives, since you can easily create a large amount of entropy while ensuring the desired value stays the same.
You’ll usually need to use multiple scan types in order to narrow down a large result list and find the correct address. Eliminating false positives is often a matter of properly creating entropy (as described in “Basic Memory Scanning” on page 4), tactically changing your scan directives, bravely pressing Next Scan, and then repeating the process until you have a single remaining address.
When You Can’t Get a Single Result
Sometimes it is impossible to pinpoint a single result in Cheat Engine, in which case you must determine the correct address through experimentation. For example, if you’re looking for your character’s health and can’t narrow it down to fewer than five addresses, you could try modifying the value of each address (as discussed in “Manual Modification with Cheat Engine” on page 8) until you see the health display change or the other values automatically change to the one you set.
Cheat Tables
Once you’ve found the correct address, you can double-click it to add it to the cheat table pane z; addresses in the cheat table pane can be modified, watched, and saved to cheat table files for future use.
For each address in the cheat table pane, you can add a description by double-clicking the Description column, and you can add a color by rightclicking and selecting Change Color. You can also display the values of each address in hexadecimal or decimal format by right-clicking and selecting Show as hexadecimal or Show as decimal, respectively. Lastly, you can change the data type of each value by double-clicking the Type column, or you can change the value itself by double-clicking the Value column.
Since the main purpose of the cheat table pane is to allow a game hacker to neatly track addresses, it can be dynamically saved and loaded. Go to File4Save or File4Save As to save the current cheat table pane to a .ct document file containing each address with its value type, description, display color, and display format. To load the saved .ct documents, go to File4Load. (You’ll find many ready-made cheat tables for popular games at http://cheatengine.org/tables.php.)
Now that I’ve described how to scan for a game state value, I’ll discuss how you can change that value when you know where it lives in memory.
memory modification in Games
Bots cheat a game system by modifying memory values in the game’s state in order to give you lots of in-game money, modify your character’s health, change your character’s position, and so on. In most online games, a character’s vitals (such as health, mana, skills, and position) are held in memory but are controlled by the game server and relayed to your local game client over the Internet, so modifying such values during online play is merely cosmetic and doesn’t affect the actual values. (Any useful memory modification to an online game requires a much more advanced hack that’s beyond Cheat Engine’s capabilities.) In local games with no remote server, however, you can manipulate all of these values at will.
Manual Modification with Cheat Engine
We’ll use Cheat Engine to understand how the memory modification magic
works.
To modify memory manually, do the following:
1. Attach Cheat Engine to a game.
2. Either scan for the address you wish to modify or load a cheat table that contains it.
3. Double-click on the Value column for the address to open an input prompt where you can enter a new value.
4. If you want to make sure the new value can’t be overwritten, select the box under the Active column to freeze the address, which will make Cheat Engine keep writing the same value back to it every time it
changes.
This method works wonders for quick-and-dirty hacks, but constantly changing values by hand is cumbersome; an automated solution would be much more appealing.
Trainer Generator
Cheat Engine’s trainer generator allows you to automate the whole memory modification process without writing any code.
To create a trainer (a simple bot that binds memory modification actions to keyboard hotkeys), go to File4Create generic trainer Lua script from table. This opens a Trainer generator dialog similar to the one shown in Figure 1-2.
Figure 1-2: Cheat Engine Trainer generator dialog
There are a number of fields to modify here:
Processname The name of the executable the trainer should attach to. This is the name shown in the process list when you attach with Cheat Engine, and it should be autofilled with the name of the process Cheat Engine is attached to.
Popup trainer on keypress Optionally enables a hotkey—which you set by entering a key combination in the box below the checkbox—to display the trainer’s main window.
Title The name of your trainer, which will be displayed on its interface. This is optional.
About text The description of your trainer, to be displayed on the interface; this is also optional.
Freeze interval (in milliseconds) The interval during which a freeze operation overwrites the value. You should generally leave this at 250, as lower intervals can sap resources and higher values may be too slow.
Once these values are configured, click Add Hotkey to set up a key sequence to activate your trainer. You will be prompted to select a value from your cheat table. Enter a value, and you will be taken to a Set/Change hotkey screen similar to Figure 1-3.
Figure 1-3: Cheat Engine Set/Change hotkey screen
On this screen, place your cursor in the box labeled Type the keys you want to set the hotkey to u and enter the desired key combination. Next, choose the desired action from the drop-down menu v; your options should appear in the following order:
Toggle freeze Toggles the freeze state of the address.
Toggle freeze and allow increase Toggles the freeze state of the address but allows the value to increase. Any time the value decreases, the trainer overwrites it with its previous value. Increased values will not be overwritten.
Toggle freeze and allow decrease Does the opposite of Toggle freeze and allow increase.
Freeze Sets the address to frozen if it’s not frozen already.
Unfreeze Unfreezes the address if it’s frozen.
Set value to Sets the value to whatever you specify in the value box w.
Decrease value with Decreases the value by the amount you specify in the value box w.
Increase value with Does the opposite of Decrease value with.
Finally, you can set a description for the action x. Click Apply, then OK, and your action will appear in the list on the Trainer generator screen. At this point, Cheat Engine runs the trainer in the background, and you can simply press the hotkeys you configured to execute the memory actions.
To save your trainer to a portable executable, click Generate trainer. Running this executable after the game is launched will attach your trainer to the game so you can use it without starting Cheat Engine.
Now that you know your way around Cheat Engine’s memory scanner and trainer generator, try modifying some memory yourself.
BAsIC MEMOry EDItING
Download the files for this book from https://www.nostarch.com/gamehacking/, and run the file BasicMemory.exe. Next, start up Cheat Engine and attach to the binary. Then, using only Cheat Engine, find the addresses for the x- and y-coordinates of the gray ball. (Hint: Use the 4 Bytes value type.)
Once you’ve found the values, modify them to place the ball on top of the black square. The game will let you know once you’ve succeeded by displaying the text “Good job!” (Hint: Each time the ball is moved, its position—stored as a 4-byte integer—in that plane is changed by 1. Also, try to look only for static [green] results.)
Pointer Scanning
As I’ve mentioned, online games often store values in dynamically allocated memory. While addresses that reference dynamic memory are useless to us in and of themselves, some static address will always point to another address, which in turn points to another, and so on, until the tail of the chain points to the dynamic memory we’re interested in. Cheat Engine can locate these chains using a method called pointer scanning.
In this section, I’ll introduce you to pointer chains and then describe how pointer scanning works in Cheat Engine. When you have a good grasp of the user interface, you can get some hands-on experience in “Pointer Scanning” on page 18.
Pointer Chains
The chain of offsets I’ve just described is called a pointer chain and looks like this: list
The first value in this pointer chain (start) is called a memory pointer. It’s an address that starts the chain. The remaining values (offset1, offset2, and so on) make up the route to the desired value, called a pointer path.
This pseudocode shows how a pointer chain might be read:
int readPointerChain(chain) {
u ret = read(chain[0]) for i = 1, chain.len - 1, 1 { offset = chain[i] ret = read(ret + offset)
} return ret }
This code creates the function readPointerPath(), which takes a pointer chain called chain as a parameter. The function readPointerPath() treats the pointer path in chain as a list of memory offsets from the address ret, which is initially set to the memory pointer at u. It then loops through these offsets, updating the value of ret to the result of read(ret + offset) on each iteration and returning ret once it’s finished. This pseudocode shows what readPointerPath() looks like when the loop is unrolled:
list
value = readPointerPath(chain)
// the function call unrolls to this ret = read(0xDEADBEEF) //chain[0]
ret = read(ret + 0xAB) ret = read(ret + 0x10) ret = read(ret + 0xCC) int value = ret
The function ultimately calls read four times, on four different addresses—one for each element in chain.
NOtE Many game hackers prefer to code their chain reads in place, instead of encapsulating them in functions like readPointerPath().
Pointer Scanning Basics
Pointer chains exist because every chunk of dynamically allocated memory must have a corresponding static address that the game’s code can use to reference it. Game hackers can access these chunks by locating the pointer chains that reference them. Because of their multitier structure, however, pointer chains cannot be located through the linear approach that memory scanners use, so game hackers have devised new ways to find them.
From a reverse engineering perspective, you could locate and analyze the assembly code in order to deduce what pointer path it used to access the value, but doing so is very time-consuming and requires advanced tools. Pointer scanners solve this problem by using brute-force to recursively iterate over every possible pointer chain until they find one that resolves to the target memory address.
The Listing 1-1 pseudocode should give you a general idea of how a pointer scanner works.
list
u for address = BASE, 0x7FFFFFF, 4 { ret = rScan(address, target, maxAdd, maxDepth, 1)
if (ret.len > 0) { ret.pushFront(address)
return ret
}
} return {}
}
list
v for offset = 0, maxAdd, 4 { value = read(address + offset)
w if (value == target) return list
} x if (curDepth < maxDepth) { curDepth++
y for offset = 0, maxAdd, 4 { ret = rScan(address + offset, target, maxAdd, maxDepth, curDepth)
z if (ret.len > 0) { ret.pushFront(offset)
{ return ret
}
}
} return {} }
Listing 1-1: Pseudocode for a pointer scanner
This code creates the functions pointerScan() and rScan().
pointerScan()
The pointerScan() function is the entry point to the scan. It takes the parameters target (the dynamic memory address to find), maxAdd (the maximum value of any offset), and maxDepth (the maximum length of the pointer path). It then loops through every 4-byte aligned address u in the game, calling rScan() with the parameters address (the address in the current iteration), target, maxAdd, maxDepth, and curDepth (the depth of the path, which is always 1 in this case).
rScan()
The rScan() function reads memory from every 4-byte aligned offset between
0 and maxAdd v, and returns if a result is equal to target w. If rScan() doesn’t return in the first loop and the recursion is not too deep x, it increments curDepth and again loops over each offset y, calling itself for each iteration.
If a self call returns a partial pointer path z, rScan() will prepend the current offset to the path and return up the recursion chain { until it reaches pointerScan(). When a call to rScan() from pointerScan() returns a pointer path, pointerScan() pushes the current address to the front of the path and returns it as a complete chain.
Pointer Scanning with Cheat Engine
The previous example showed the basic process of pointer scanning, but the implementation I’ve shown is primitive. Aside from being insanely slow to execute, it would generate countless false positives. Cheat Engine’s pointer scanner uses a number of advanced interpolations to speed up the scan and make it more accurate, and in this section, I’ll introduce you to the smorgasbord of available scanning options.
To initiate a pointer scan in Cheat Engine, right-click on a dynamic memory address in your cheat table and click Pointer scan for this address. When you initiate a pointer scan, Cheat Engine will ask you where to store the scan results as a .ptr file. Once you enter a location, a Pointerscanner scanoptions dialog similar to the one shown in Figure 1-4 will appear.
Figure 1-4: Cheat Engine Pointerscanner scanoptions dialog
The Address to find input field at the top displays your dynamic memory address. Now carefully select from among Cheat Engine’s many scan options.
Key Options
Several of Cheat Engine’s scan options typically retain their default values. Those options are as follows:
Addresses must be 32-bits aligned Tells Cheat Engine to scan only addresses that are multiples of 4, which greatly increases the scan speed. As you’ll learn in Chapter 4, compilers align data so that most addresses will be multiples of 4 anyway by default. You’ll rarely need to disable this option.
Only find paths with a static address Speeds up the scan by preventing Cheat Engine from searching paths with a dynamic start pointer. This option should always be enabled because scanning for a path starting at another dynamic address can be counterproductive.
Don’t include pointers with read-only nodes Should also always be enabled. Dynamically allocated memory that stores volatile data should never be read-only.
Stop traversing a path when a static has been found Terminates the scan when it finds a pointer path with a static start address. This should be enabled to reduce false positives and speed up the scan.
Pointer path may only be inside this region Can typically be left as is. The other options available to you compensate for this large range by intelligently narrowing the scope of the scan.
First element of pointerstruct must point to module Tells Cheat Engine not to search heap chunks in which virtual function tables are not found, under the assumption that the game was coded using object orientation. While this setting can immensely speed up scans, it’s highly unreliable and you should almost always leave it disabled.
No looping pointers Invalidates any paths that point to themselves, weeding out inefficient paths but slightly slowing down the scan. This should usually be enabled.
Max level Determines the maximum length of the pointer path. (Remember the maxDepth variable in the example code in Listing 1-1?) This should be kept around 6 or 7.
Of course, there will be times when you’ll need to change these options from the settings described. For example, failing to obtain reliable results with the No looping pointers or Max level settings typically means that the value you’re looking for exists in a dynamic data structure, like a linked list, binary tree, or vector. Another example is the Stop traversing a path when a static has been found option, which in rare cases can prevent you from getting reliable results.
Situational Options
Unlike the previous options, your settings for the remaining ones will depend on your situation. Here’s how to determine the best configuration for each:
Improve pointerscan with gathered heap data Allows Cheat Engine to use the heap allocation record to determine offset limits, effectively speeding up the scan by weeding out many false positives. If you run into a game using a custom memory allocator (which is becoming increasingly common), this option can actually do the exact opposite of what it’s meant to do. You can leave this setting enabled in initial scans, but it should be the first to go when you’re unable to find reliable paths.
Only allow static and heap addresses in the path Invalidates all paths that can’t be optimized with heap data, making this approach even more aggressive.
Max different offsets per node Limits the number of same-value pointers the scanner checks. That is, if n different addresses point to
0x0BADF00D, this option tells Cheat Engine to consider only the first m addresses. This can be extremely helpful when you’re unable to narrow down your result set. In other cases, you may want to disable it, as it will miss many valid paths.
Allow stack addresses of the first thread(s) to be handled as static Scans the call stacks of oldest m threads in the game, considering the first n bytes in each one. This allows Cheat Engine to scan the parameters and local variables of functions in the game’s call chain (the goal being to find variables used by the game’s main loop). The paths found with this option can be both highly volatile and extremely useful; I use it only when I fail to find heap addresses.
Stack addresses as only static address Takes the previous option even further by allowing only stack addresses in pointer paths.
Pointers must end with specific offsets Can be useful if you know the offset(s) at the end of a valid path. This option will allow you to specify those offsets (starting with the last offset at the top), greatly reducing the scope of the scan.
Nr of threads scanning Determines how many threads the scanner will use. A number equal to the number of cores in your processor often works best. A drop-down menu with options allows you to specify the priority for each thread. Idle is best if you want your scan to go very slowly, Normal is what you should use for most scans, and Time critical is useful for lengthy scans but will render your computer useless for the scan duration.
Maximum offset value Determines the maximum value of each offset in the path. (Remember the maxAdd variable in Listing 1-1?) I typically start with a low value, increasing it only if my scan fails; 128 is a good starting value. Keep in mind that this value is mostly ignored if you’re using the heap optimization options.
NOtE What if both Only allow static and heap addresses in the path and Stack addresses as only static address are enabled? Will the scan come up empty? Seems like a fun, albeit useless, experiment.
Once you have defined your scan options, click OK to start a pointer scan. When the scan completes, a results window will appear with the list of pointer chains found. This list often has thousands of results, containing both real chains and false positives.
Pointer Rescanning
The pointer scanner has a rescan feature that can help you eliminate false positives. To begin, press ctrl-R from the results window to open the Rescan pointerlist dialog, as shown in Figure 1-5.
Figure 1-5: Cheat Engine Rescan pointerlist
dialog
There are two main options to consider when you tell Cheat Engine to
rescan:
Only filter out invalid pointers If you check this box u, the rescan will discard only pointer chains that point to invalid memory, which helps if your initial result set is very large. Disable this to filter out paths that don’t resolve to a specific address or value (as shown in the figure). Repeat rescan until stopped If you check this box v, the rescan will execute in a continuous loop. Ideally, you should enable this setting and let rescan run while you create a large amount of memory entropy.
For the initial rescan, enable both Only filter out invalid pointers and Repeat rescan until stopped, and then press OK to initiate the rescan. The rescan window will go away, and a Stop rescan loop button will appear in the results window. The result list will be constantly rescanned until you click Stop rescan loop, but spend a few minutes creating memory entropy before doing so.
In rare cases, rescanning using a rescan loop may still leave you with a large list of possible paths. When this happens, you may need to restart the game, find the address that holds your value (it may have changed!), and use the rescan feature on this address to further narrow results. In this scan, leave Only filter out invalid pointers unchecked and enter the new address in the Address to find field.
NOtE If you had to close the results window, you can reopen it and load the result list by going to the main Cheat Engine window and pressing the Memory View button below the results pane. This should bring up a memory dump window. When the window appears, press ctrl-P to open the pointer scan results list. Then press ctrl-O to open the .ptr file where you saved the pointer scan.
If your results still aren’t narrow enough, try running the same scan across system restarts or even on different systems. If this still yields a large result set, each result can safely be considered static because more than one pointer chain can resolve to the same address.
Once you’ve narrowed down your result set, double-click on a usable pointer chain to add it to your cheat table. If you have a handful of seemingly usable chains, grab the one with the fewest offsets. If you find multiple chains with identical offsets that start with the same pointer but diverge after a certain point, your data may be stored in a dynamic data structure.
That’s all there is to pointer scanning in Cheat Engine. Try it yourself!
POINtEr sCANNING
Go to https://www.nostarch.com/gamehacking/ and download MemoryPointers .exe__. Unlike the last task, which required you to win only once, this one requires that you win 50 times in 10 seconds. Upon each win, the memory addresses for the x- and y-coordinates will change, meaning you will be able to freeze the value only if you have found a proper pointer path. Start this exercise the same way as the previous one, but once you’ve found the addresses, use the Pointer scan feature to locate pointer paths to them. Then, place the ball on top of the black square, freeze the value in place, and press tab to begin the test. Just as before, the game will let you know once you’ve won. (Hint: Try setting the maximum level to 5 and the maximum offset value to 512. Also, play with the options to allow stack addresses, terminate the scan when a static is found, and improve the pointer scan with heap data. See which combination of options gives the best results.)
Lua Scripting environment
Historically, bot developers rarely used Cheat Engine to update their addresses when a game released a patch because it was much easier to do so in OllyDbg. This made Cheat Engine useless to game hackers other than for initial research and development—that is, until a powerful Luabased embedded scripting engine was implemented around Cheat Engine’s robust scanning environment. While this engine was created to enable the development of simple bots within Cheat Engine, professional game hackers found they could also use it to easily write complex scripts to automatically locate addresses across different versions of a game’s binary—a task that might otherwise take hours.
NOtE You’ll find more detail about the Cheat Engine Lua scripting engine on the wiki at http://wiki.cheatengine.org/.
To start using the Lua engine, press ctrl-alt-L from the main Cheat Engine window. Once the window opens, write your script in the text area and click Execute script to run it. Save a script with ctrl-S and open a saved script with ctrl-O.
The scripting engine has hundreds of functions and infinite use cases, so I’ll give you just a glimpse of its abilities by breaking down two scripts. Every game is different and every game hacker writes scripts to accomplish unique goals, so these scripts are only useful for demonstrating concepts.
Searching for Assembly Patterns
This first script locates functions that compose outgoing packets and sends them to the game server. It works by searching a game’s assembly code for functions that contain a certain code sequence.
u BASEADDRESS = getAddress(“Game.exe”) v function LocatePacketCreation(packetType)
w for address = BASEADDRESS, (BASEADDRESS + 0x2ffffff) do local push = readBytes(address, 1, false) local type = readInteger(address + 1) local call = readInteger(address + 5)
x if (push == 0x68 and type == packetType and call == 0xE8) then return address
end end return 0 end
FUNCTIONHEADER = { 0xCC, 0x55, 0x8B, 0xEC, 0x6A } y function LocateFunctionHead(checkAddress) if (checkAddress == 0) then return 0 end
z for address = checkAddress, (checkAddress - 0x1fff), -1 do local match = true
local checkheader = readBytes(address, #FUNCTIONHEADER, true)
{ for i, v in ipairs(FUNCTIONHEADER) do if (v ~= checkheader[i]) then
match = false break end end
| if (match) then return address + 1 end end
return 0 end
} local funcAddress = LocateFunctionHead(LocatePacketCreation(0x64)) if (funcAddress ~= 0) then
print(string.format(“0x%x”,funcAddress))
else
print(“Not found!”) end
The code begins by getting the base address of the module that
Cheat Engine is attached to u. Once it has the base address, the function LocatePacketCreation() is defined v. This function loops through the first 0x2FFFFFF bytes of memory in the game w, searching for a sequence that represents this x86 assembler code:
PUSH type ; Data is: 0x68 [4byte type]
CALL offset ; Data is: 0xE8 [4byte offset]
The function checks that the type is equal to packetType, but it doesn’t care what the function offset is x. Once this sequence is found, the function returns.
Next, the LocateFunctionHead() function is defined y. The function backtracks up to 0x1FFF bytes from a given address z, and at each address, it checks for a stub of assembler code { that looks something like this:
INT3 ; 0xCC
PUSH EBP ; 0x55
MOV EBP, ESP ; 0x8B 0xEC
PUSH [-1] ; 0x6A 0xFF
This stub will be present at the beginning of every function, because it’s part of the function prologue that sets up the function’s stack frame. Once it finds the code, the function will return the address of the stub plus 1 | (the first byte, 0xCC, is padding).
To tie these steps together, the LocatePacketCreation() function is called with the packetType that I’m looking for (arbitrarily 0x64) and the resulting address is passed into the LocateFunctionHead() function }. This effectively locates the first function that pushes packetType into a function call and stores its address in funcAddress. This stub shows the result:
INT3 ; LocateFunctionHead back-tracked to here
PUSH EBP ; and returned this address
MOV EBP, ESP
PUSH [-1]
—snip—
PUSH [0x64] ; LocatePacketCreation returned this address
CALL [something]
This 35-line script can automatically locate 15 different functions in under a minute. Searching for Strings
This next Lua script scans a game’s memory for text strings. It works much as the Cheat Engine’s memory scanner does when you use the string value type.
BASEADDRESS = getAddress(“Game.exe”) u function findString(str) local len = string.len(str)
v local chunkSize = 4096 w local chunkStep = chunkSize - len print(“Found ‘“ .. str .. “‘ at:”)
x for address = BASEADDRESS, (BASEADDRESS + 0x2ffffff), chunkStep do local chunk = readBytes(address, chunkSize, true) if (not chunk) then break end
y for c = 0, chunkSize-len do
z checkForString(address , chunk, c, str, len) end end end
function checkForString(address, chunk, start, str, len)
for i = 1, len do
if (chunk[start+i] ~= string.byte(str, i)) then
return false
end end
{ print(string.format(“\t0x%x”, address + start)) end
| findString(“hello”)
} findString(“world”)
After getting the base address, the findString() function is defined u, which takes a string, str, as a parameter. This function loops through the game’s memory x in 4,096-byte-long chunks v. The chunks are scanned sequentially, each one starting len (the length of str) bytes before the end of the previous one w to prevent missing a string that begins on one chunk and ends on another.
As findString() reads each chunk, it iterates over every byte until the overlap point in the chunk y, passing each subchunk into the checkForString() function z. If checkForString() matches the subchunk to str, it prints the address of that subchunk to the console {.
Lastly, to find all addresses that reference the strings “hello” and “world”, the functions findString(“hello”) | and findString(“world”) } are called. By using this code to search for embedded debug strings and pairing it with the previous code to locate function headers, I’m able to find a large number of internal functions within a game in mere seconds.
OPtIMIzING MEMOry CODE
Due to the high overhead of memory reading, optimization is extremely important when you’re writing code that performs memory reads. In the previous code snippet, notice that the function findString() does not use the Lua engine’s builtin readString() function. Instead, it reads big chunks of memory and searches them for the desired string. Let’s break down the numbers.
A scan using readString() would try to read a string of len bytes at every possible memory address. This means it would read, at most, (0x2FFFFFF len + len) bytes. However, findString() reads chunks of 4,096 bytes and scans them locally for matching strings. This means it would read, at most, (0x2FFFFFF + 4096 + (0x2FFFFFF / (4096 - 10)) len) bytes. When searching for a string with a length of 10, the number of bytes that each method would read is 503,316,480 and 50,458,923, respectively.
Not only does findString() read an order of magnitude less data, it also invokes far fewer memory reads. Reading in chunks of 4,096 bytes would require a total of (0x2FFFFFF / (4096 - len)) reads. Compare that to a scan using readString(), which would need_ _0x2FFFFFF reads. The scan that uses findString() is a huge improvement because invoking a read is much more expensive than increasing the size of data being read. (Note that I chose 4,096 arbitrarily. I keep the chunk relatively small because reading memory
can be time-consuming, and it might be wasteful to read four pages at a time just to find the string in the first.)
closing Thoughts
By this point, you should have a basic understanding of Cheat Engine and how it works. Cheat Engine is a very important tool in your kit, and I encourage you to get some hands-on experience with it by following “Basic Memory Editing” on page 11 and “Pointer Scanning” on page 18 and playing around with it on your own.
D E B u G G I N G G A M E s w I t H O l ly D B G
You can scratch the surface of what happens as a game runs with Cheat Engine,
but with a good debugger, you can dig
deeper until you understand the game’s
structure and execution flow. That makes OllyDbg essential to your game-hacking arsenal. It’s packed
with a myriad of powerful tools like conditional breakpoints, referenced string search, assembly pattern search, and execution tracing, making it a robust assembler-level debugger for 32-bit Windows applications.
I’ll cover low-level code structure in detail in Chapter 4, but for this chapter, I assume you’re at least familiar with modern code-level debuggers, such as the one packaged with Microsoft Visual Studio. OllyDbg is functionally similar to those, with one major difference: it interfaces with the assembly code of an application, working even in the absence of source code and/or debug symbols, making it ideal when you need to dig into the internals of a game. After all, game companies are rarely nice (or dumb) enough to ship their games with debug symbols!
In this chapter, I’ll go over OllyDbg’s user interface, show you how to use its most common debugging features, break down its expression engine, and provide some real-world examples of how you can tie it in to your game hacking endeavors. As a wrap-up, I’ll teach you about some useful plug-ins and send you off with a test game designed to get you started in OllyDbg.
NOtE This chapter focuses on OllyDbg 1.10 and may not be entirely accurate for later versions. I use this version because, at the time of writing, the plug-in interface for OllyDbg 2 is still far less robust than the one for OllyDbg 1.
When you feel like you have a handle on OllyDbg’s interface and features, you can try it on a game yourself with “Patching an if() Statement” on page 46.
a brief Look at Ollydbg’s user interface
Go to the OllyDbg website (http://www.ollydbg.de/), download and install OllyDbg, and open the program. You should see the toolbar shown in Figure 2-1 above a multiple window interface area.
Figure 2-1: OllyDbg main window
This toolbar contains the program controls u, the debug buttons v, the Go to button w, the control window buttons x, and the Settings button y.
The three program controls allow you to open an executable and attach to the process it creates, restart the current process, or terminate execution of the current process, respectively. You can also complete these functions with the hotkeys F3, ctrl-F2, and alt-F2, respectively. To attach to a process that is already running, click File4Attach.
The debug buttons control the debugger actions. Table 2-1 describes what these buttons do, along with their hotkeys and functions. This table also lists three useful debugger actions that don’t have buttons on the debug toolbar.
Table 2-1: Debug Buttons and Other Debugger Functions
Button | Hotkey | Function |
---|---|---|
Play | F9 | Resumes normal execution of the process. |
Pause | F12 | Pauses execution of all threads within the process and brings up the CPU window at the instruction currently being executed. |
Step into | F7 | Single-steps to the next operation to be executed (will dive down into function calls). |
Step over | F8 | Steps to the next operation to be executed within current scope (will skip over function calls). |
Trace into | ctrl-F11 | Runs a deep trace, tracing every operation that is executed. |
Trace over | ctrl-F12 | Runs a passive trace that traces only operations within the current scope. |
Execute until return | ctrl-F9 | Executes until a return operation is hit within the current scope. |
ctrl-F7 | Automatically single-steps on every operation, following execution in the disassembly window. This makes execution appear to be animated. |
|
ctrl-F8 | Also animates execution, but steps over functions instead of stepping into them. | |
esc | Stops animation, pausing execution on the current operation. |
The Go to button opens a dialog asking for a hexadecimal address. Once you enter the address, OllyDbg opens the CPU window and shows the disassembly at the specified address. When the CPU window is in focus, you can also show that information with the hotkey ctrl-G.
The control window buttons open different control windows, which display useful information about the process you’re debugging and expose more debugging functions, like the ability to set breakpoints. OllyDbg has a total of 13 control windows, which can all be open simultaneously within the multiple window interface. Table 2-2 describes these windows, listed in the order in which they appear on the window buttons toolbar.
Table 2-2: OllyDbg’s Control Windows
Window | Hotkey | Function |
---|---|---|
Log | alt-L | Displays a list of log messages, including debug prints, thread events, debugger events, module loads, and much more. |
Modules alt-E Displays a list of all executable modules loaded into the process. Double-click a module to open it in the CPU window.
(continued)
Table 2-2 (continued)
Window | Hotkey | Function |
---|---|---|
Memory map | alt-M | Displays a list of all blocks of memory allocated by the process. Double-click a block in the list to bring up a dump window of that memory block. |
Threads | Displays a list of threads running in the process. For each thread in this list, the process has a structure called a Thread Information Block (TIB). OllyDbg allows you to view each thread’s TIB; simply right-click a thread and select Dump thread data block. | |
Windows | Displays a list of window handles held by the process. Right-click a window in this list to jump to or set a breakpoint on its class procedure (the function that gets called when a message is sent to the window). | |
Handles | Displays a list of handles held by the process. (Note that Process Explorer has a much better handle list than OllyDbg, as I will discuss in Chapter 3.) |
|
CPU | alt-C | Displays the main disassembler interface and controls a majority of the debugger functionality. |
Patches | ctrl-P | Displays a list of any assembly code modifications you have made to modules within the process. |
Call stack | alt-K | Displays the call stack for the active thread. The window updates when the process halts. |
Breakpoints | alt-B | Displays a list of active debugger breakpoints and allows you to toggle them on and off. |
References | Displays the reference list, which typically holds the search results for many different types of searches. It pops up on its own when you run a search. | |
Run trace | Displays a list of operations logged by a debugger trace. | |
Source | Displays the source code of the disassembled module if a program debug database is present. |
Finally, the Settings button opens the OllyDbg settings window. Keep the default settings for now.
Now that you’ve had a tour of the main OllyDbg window, let’s explore the CPU, Patches, and Run trace windows more closely. You’ll use those windows extensively as a game hacker, and knowing your way around them is key.
Ollydbg’s cPu window
The CPU window in Figure 2-2 is where game hackers spend most of their time in OllyDbg because it is the main control window for the debugging
features.
Figure 2-2: OllyDbg CPU window
This window houses four distinct control panes: the disassembler pane u, the registers pane v, the dump pane w, and the stack pane x. These four panes encapsulate OllyDbg’s main debugger functions, so it’s important to know them inside and out. Viewing and Navigating a Game’s Assembly Code
You’ll navigate game code and control most aspects of debugging from OllyDbg’s disassembler pane. This pane displays the assembly code for the current module, and its data is neatly displayed in a table composed of four distinct columns: Address, Hex dump, Disassembly, and Comment.
The Address column displays the memory addresses of each operation in the game process you’re attached to. You can double-click an address in this column to toggle whether it’s the display base. When an address is set as the display base, the Address column displays all other addresses as offsets relative to it.
The Hex dump column displays the byte code for each operation, grouping operation codes and parameters accordingly. Black braces spanning multiple lines on the left side of this column mark known function boundaries. Operations that have jumps going to them are shown with a right-facing arrow on the inside of these braces. Operations that perform jumps are shown with either up-facing or down-facing arrows, depending on the direction in which they jump, on the inside of these braces. For example, in Figure 2-2, the instruction at address 0x779916B1 (highlighted in gray) has an up-facing arrow, indicating it’s an upward jump. You can think of a jump as a goto operator.
The Disassembly column displays the assembly code of each operation the game performs. So, for example, you can confirm that the instruction at 0x779916B1 in Figure 2-2 is a jump by looking at the assembly, which shows a JNZ (jump if nonzero) instruction. Black braces in this column mark the boundaries of loops. Right-facing arrows attached to these braces point to the conditional statements that control whether the loops continue or exit. The three right-facing arrows in this column in Figure 2-2 point to CMP (compare) and TEST instructions, which are used by assembly code to compare values.
The Comment column displays human-readable comments about each operation the game performs. If OllyDbg encounters known API function names, it will automatically insert a comment with the name of the function. Similarly, if it successfully detects arguments being passed to a function, it will label them (for example, Arg1, Arg2, . . . , ArgN). You can double-click in this column to add a customized comment. Black braces in this column mark the assumed boundaries of function call parameters.
NOtE OllyDbg infers function boundaries, jump directions, loop structures, and function parameters during code analysis, so if these columns lack boundary lines or jump arrows, just press ctrl-A to run a code analysis on the binary.
When the disassembler pane is in focus, there are a few hotkeys you can use to quickly navigate code and control the debugger. Use F2 for Toggle breakpoint, shift-F12 for Place conditional breakpoint, - (hyphen) for Go back and + (plus) for Go forward (these two work as you’d expect in a web browser), (asterisk) for Go to EIP (which is the execution pointer in the x86 architecture), ctrl— (hyphen) for Go to previous function, and ctrl-+ for Go to next function.
The disassembler can also populate the References window with different types of search results. When you want to change the References window’s contents, right-click in the disassembler pane, mouse over the Search for menu to expand it, and select one of the following options:
All intermodular calls Searches for all calls to functions in remote modules. This can, for example, allow you to see everywhere that a game calls Sleep(), PeekMessage(), or any other Windows API function, enabling you to inspect or set breakpoints on the calls.
All commands Searches for all occurrences of a given operation written in assembly, where the added operators CONST and R32 will match a constant value or a register value, respectively. One use for this option might be searching for commands like MOV [0xDEADBEEF], CONST; MOV [0xDEADBEEF], R32; and MOV [0xDEADBEEF], [R32+CONST] to list all operations that modify memory at the address 0xDEADBEEF, which could be anything, including the address of your player’s health.
All sequences Searches for all occurrences of a given sequence of operations. This is similar to the previous options, but it allows you to specify multiple commands.
All constants Searches for all instances of a given hexadecimal constant. For instance, if you enter the address of your character’s health, this will list all of the commands that directly access it.
All switches Searches for all switch-case blocks.
*All referenced text strings Searches for all strings referenced in code. You can use this option to search through all referenced strings and see what code accesses them, which can be useful for correlating in-game text displays with the code that displays them. This option is also very useful for locating any debug assertion or logging strings, which can be a tremendous help in determining the purpose of code parts.
The disassembler can also populate the Names window with all labels in the current module (ctrl-N) or all known labels in all modules (Search for4Name in all modules). Known API functions will be automatically labeled with their names, and you can add a label to a command by highlighting it, pressing shift-; and entering the label when prompted. When a labeled command is referenced in code, the label will be shown in place of the address. One way to use this feature is to name functions that you’ve analyzed (just set a label on the first command in a function) so you can see their names when other functions call them.
Viewing and Editing Register Contents
The registers pane displays the contents of the eight processor registers, all eight flag bits, the six segment registers, the last Windows error code, and EIP. Underneath these values, this pane can display either Floating-Point Unit (FPU) registers or debug registers; click on the pane’s header to change which registers are displayed. The values in this pane are populated only if you freeze your process. Values that are displayed in red have been changed since the previous pause. Double-click on values in this pane to edit them.
Viewing and Searching a Game’s Memory
The dump pane displays a dump of the memory at a specific address. To jump to an address and display the memory contents, press ctrl-G and enter the address in the box that appears. You can also jump to the address of an entry in the other CPU window panes by right-clicking on the Address column and selecting Follow in dump.
While there are always three columns in the dump pane, the only one you should always see is the Address column, which behaves much like its cousin within the disassembler pane. The data display type you choose determines the other two columns shown. Right-click the dump pane to change the display type; for the one shown in Figure 2-2, you’d right-click and select Hex4Hex/ASCII (8 bytes).
You can set a memory breakpoint on an address shown in the dump pane by right-clicking that address and expanding the Breakpoint submenu. Select Memory4On access from this menu to break on any code that uses the address at all, or select Memory4On write to break only on code that writes to that space in memory. To remove a memory breakpoint, select Remove memory breakpoint in the same menu; this option appears only when the address you right-click has a breakpoint.
With one or more values selected in the dump, you can press ctrl-R to search the current module’s code for references to addresses of the selected values; results of this search appear in the References window. You can also search for values in this pane using ctrl-B for binary strings and ctrl-N for labels. After you initiate a search, press ctrl-L to jump to the next match. ctrl-E allows you to edit any values you have selected.
NOtE The dump windows that you can open from the Memory window work in the same way as the dump pane. Viewing a Game’s Call Stack
The final CPU pane is the stack pane, and as the name suggests, it shows the call stack. Like the dump and disassembler panes, the stack pane has an Address column. The stack pane also has a Value column, which shows the stack as an array of 32-bit integers, and a Comment column, which shows return addresses, known function names, and other informative labels. The stack pane supports all the same hotkeys as the dump pane, with the exception of ctrl-N.
MultIClIENt PAtCHING
One type of hack, called a multiclient patch, overwrites the single-instance limitation code within a game’s binary with no-operation code, allowing the user to run multiple game clients, even when doing so is normally forbidden. Because the code that performs instance limitation must be executed very early after a game client is launched, it can be nearly impossible for a bot to inject its patch on time. The easiest workaround for this is to make multiclient patches persist by applying them within OllyDbg and saving them directly to the game
binary.
creating code Patches
OllyDbg’s code patches let you make assembly code modifications for a game you want to hack, removing the need to engineer a tool tailored to that specific game. This makes prototyping control flow hacks—which manipulate game behavior through a mix of game design flaws, x86 assembly protocols, and common binary constructs—much easier.
Game hackers typically include perfected patches as optional features in a bot’s tool suite, but in some cases, making those features persistent is actually more convenient for your end user. Luckily, OllyDbg patches provide the complete functionality you need to design, test, and permanently save code modifications to an executable binary using only OllyDbg.
To place a patch, navigate to the line of assembly code you want to patch in the CPU window, double-click the instruction you wish to modify, place a new assembly instruction in the pop-up prompt, and click Assemble, as shown in Figure 2-3.
Figure 2-3: Placing a patch with OllyDbg
Always pay attention to the size of your patch—you can’t just resize and move around assembled code however you’d like. Patches larger than the code you intend to replace will overflow into subsequent operations, potentially removing critical functionality. Patches smaller than the operations you intend to replace are safe, as long as Fill with NOPs is checked. This option fills any abandoned bytes with no-operation (NOP) commands, which are single-byte operations that do nothing when executed.
All patches you place are listed, along with the address, size, state, old code, new code, and comment, in the Patches window. Select a patch in this list to access a small but powerful set of hotkeys, shown in Table 2-3.
Table 2-3: Patches Window Hotkeys
Operator | Function |
---|---|
enter | Jumps to the patch in the disassembler. |
spacebar | Toggles the patch on or off. |
F2 | Places a breakpoint on the patch. |
shift-F2 | Places a conditional breakpoint on the patch. |
shift-F4 | Places a conditional log breakpoint on the patch. |
del | Removes the patch entry from the list only. |
In OllyDbg, you can also save your patches directly to the binary. First, right-click in the disassembler and click Copy to executable4All modifications. If you want to copy only certain patches, highlight them in the disassembly pane and press Copy to executable4Selection instead.
DEtErMINING PAtCH sIzE
There are a few ways to determine whether your patch will be a different size than the original code. For example, in Figure 2-3, you can see the command at 0x7790ED2E being changed from SHR AL, 6 to SHR AL, 7. If you look at the bytes to the left of the command, you see 3 bytes that represent the memory of the command. This means our new command must either be 3 bytes or padded with NOPs if it’s less than 3 bytes. Furthermore, these bytes are arranged in two columns. The first column contains 0xC0 and 0x08, which represent the command SHR and the first operand, AL. The second column contains 0x06, which represents the original operand. Because the second column shows a single byte, any replacement operand must also be 1 byte (between 0x00 and 0xFF). If this column had shown 0x00000006 instead, a replacement operand could be up to 4 bytes in length.
Typical code patches will either use all NOPs to completely remove a command (by leaving the box empty and letting it fill the entire command with NOPs) or just replace a single operand, so this method of checking patch size is almost always effective.
Tracing Through assembly code
When you run a trace on any program, OllyDbg single-steps over every executed operation and stores data about each one. When the trace is complete, the logged data is displayed in the Run trace window, shown in Figure 2-4.
Figure 2-4: The Run trace window
The Run trace window is organized into the following six columns:
Back The number of operations logged between an operation and the current execution state
Thread The thread that executed the operation
Module The module where the operation resides
Address The address of the operation
Command The operation that was executed
Modified registers The registers changed by the operation and their new values
When hacking games, I find OllyDbg’s trace feature very effective at helping me find pointer paths to dynamic memory when Cheat Engine scans prove inconclusive. This works because you can follow the log in the Run trace window backward from the point when the memory is used to the point where it is resolved from a static address.
This potent feature’s usefulness is limited only by the creativity of the hacker using it. Though I typically use it only to find pointer paths, I’ve come across a few other situations where it has proven invaluable. The anecdotes in “OllyDbg Expressions in Action” on page 36 will help to illuminate the functionality and power of tracing.
Ollydbg’s expression engine
OllyDbg is home to a custom expression engine that can compile and evaluate advanced expressions with a simple syntax. The expression engine is surprisingly powerful and, when utilized properly, can be the difference between an average OllyDbg user and an OllyDbg wizard. You can use this engine to specify expressions for many features, such as conditional breakpoints, conditional traces, and the command line plug-in. This section introduces the expression engine and the options it provides.
NOtE Parts of this section are based on the official expressions documentation (http:// www.ollydbg.de/Help/i_Expressions.htm). I have found, however, that a few of the components defined in the documentation don’t seem to work, at least not in OllyDbg v1.10. Two examples are the __INT and ASCII data types, which must be substituted with the aliases LONG and STRING. For this reason, here I include only components that I’ve personally tested and fully understand.
Using Expressions in Breakpoints
When a conditional breakpoint is toggled on, OllyDbg prompts you to enter an expression for the condition; this is where most expressions are used. When that breakpoint is executed, OllyDbg silently pauses execution and evaluates the expression. If the result of the evaluation is nonzero, execution remains paused and you will see the breakpoint get triggered. But if the result of the evaluation is 0, OllyDbg silently resumes execution as if nothing happened.
With the huge number of executions that happen within a game every second, you’ll often find that a piece of code is executed in far too many contexts for a breakpoint to be an effective way of getting the data you are looking for. A conditional breakpoint paired with a good understanding of the code surrounding it is a foolproof way to avoid these situations.
Using Operators in the Expression Engine
For numeric data types, OllyDbg expressions support general C-style operators, as seen in Table 2-4. While there is no clear documentation on the operator precedence, OllyDbg seems to follow C-style precedence and can use parenthesized scoping.
Table 2-4: OllyDbg Numeric Operators
Operator | Function |
---|---|
a == b | Returns 1 if a is equal to b, else returns 0. |
a != b | Returns 1 if a is not equal to b, else returns 0. |
a > b | Returns 1 if a is greater than b, else returns 0. |
a < b | Returns 1 if a is less than b, else returns 0. |
a >= b | Returns 1 if a is greater than or equal to b, else returns 0. |
a <= b | Returns 1 if a is less than or equal to b, else returns 0. |
a && b | Returns 1 if a and b are both nonzero, else returns 0. |
a || b | Returns 1 if either a or b are nonzero, else returns 0. |
a ^ b | Returns the result of XOR(a, b). |
a % b | Returns the result of MODULUS(a, b). |
a & b | Return the result of AND(a, b). |
a | b | Return the result of OR(a, b). |
a << b | Returns the result of a shifted b bits to the left. |
a >> b Returns the result of a shifted b bits to the right.
Operator | Function |
---|---|
a + b | Returns the sum of a plus b. |
a - b | Returns the difference of a minus b. |
a / b | Returns the quotient of a divided by b. |
a * b | Returns the product of a times b. |
+a | Returns the signed representation of a. |
-a | Returns a*-1. |
!a | Returns 1 if a is 0, else returns 0. |
For strings, on the other hand, the only available operators are == and !=, which both adhere to the following set of rules:
• String comparisons are case insensitive.
• If only one of the operands is a string literal, the comparison will terminate after it reaches the length of the literal. As a result, the expression [STRING EAX]==”ABC123”, where EAX is a pointer to the string ABC123XYZ, will evaluate to 1 instead of 0.
• If no type is specified for an operand in a string comparison and the other operand is a string literal (for example, “MyString”!=EAX), the comparison will first assume the nonliteral operand is an ASCII string, and, if that compare would return 0, it will try a second compare assuming the operand is a Unicode string.
Of course, operators aren’t much use without operands. Let’s look at some of the data you can evaluate in expressions.
Working with Basic Expression Elements
Expressions are able to evaluate many different elements, including:
CPU registers EAX, EBX, ECX, EDX, ESP, EBP, ESI, and EDI. You can also use the 1-byte and 2-byte registers (for example, AL for the low byte and AX for the low word of EAX). EIP can also be used.
Segment registers CS, DS, ES, SS, FS, and GS.
FPU registers ST0, ST1, ST2, ST3, ST4, ST5, ST6, and ST7.
Simple labels Can be API function names, such as GetModuleHandle, or user-defined labels.
Windows constants Such as ERRORSUCCESS.
Integers Are written in hexadecimal format or decimal format if followed by a trailing decimal point (for example, FFFF or 65535._). Floating-point numbers Allow exponents in decimal format (for example, 654.123e-5).
String literals Are wrapped in quotation marks (for example, “my string”).
The expressions engine looks for these elements in the order they’re listed here. For example, if you have a label that matches the name of a Windows constant, the engine uses the address of the label instead of the constant’s value. But if you have a label named after a register, such as EAX, the engine uses the register value, not the label value.
Accessing Memory Contents with Expressions
OllyDbg expressions are also powerful enough to incorporate memory reading, which you can do by wrapping a memory address, or an expression that evaluates to one, in square brackets. For example, [EAX+C] and [401000] represent the contents at the addresses EAX+C and 401000. To read the memory as a type other than DWORD, you can specify the desired type either before the brackets, as in BYTE [EAX], or as the first token within them, as in [STRING ESP+C]. Supported types are listed in Table 2-5.
Table 2-5: OllyDbg Data Types
Data type | Interpretation |
---|---|
BYTE | 8-bit integer (unsigned) |
CHAR | 8-bit integer (signed) |
WORD | 16-bit integer (unsigned) |
SHORT | 16-bit integer (signed) |
DWORD | 32-bit integer (unsigned) |
LONG | 32-bit integer (signed) |
FLOAT | 32-bit floating-point number |
DOUBLE | 64-bit floating-point number |
STRING | Pointer to an ASCII string (null-terminated) |
UNICODE | Pointer to a Unicode string (null-terminated) |
Plugging memory contents directly into your OllyDbg expressions is incredibly useful in game hacking, in part because you can tell the debugger to check a character’s health, name, gold, and so on in memory before breaking. You’ll see an example of this in “Pausing Execution When a Specific Player’s Name Is Printed” on page 37.
Ollydbg expressions in action
Expressions in OllyDbg use a syntax similar to that of most programming languages; you can even combine multiple expressions and nest one expression within another. Game hackers (really, all hackers) commonly use them to create conditional breakpoints, as I described in “Using Expressions in Breakpoints” on page 34, but you can use them in many different places in OllyDbg. For instance, OllyDbg’s command line plug-in can evaluate expressions in place and display their results, allowing you to easily read arbitrary memory, inspect values that are being calculated by assembly code, or quickly get the results of mathematical equations. Furthermore, hackers can even create intelligent, position-agnostic breakpoints by coupling expressions with the trace feature.
In this section, I’ll share some anecdotes where the expression engine has come in handy during my work. I will explain my thought process, walk through my entire debugging session, and break each expression down into its component parts so you can see some ways to use OllyDbg expressions in game hacking.
NOtE These examples contain some assembly code, but if you don’t have much experience with assembly, don’t worry. Just ignore the fine details and know that values like ECX,
EAX, and ESP are process registers like the ones discussed in “Viewing and Editing Register Contents” on page 29. From there, I’ll explain everything else.
If you get confused about an operator, element, or data type in an expression as I walk through these anecdotes, just refer to “OllyDbg’s Expression Engine” on page 33.
Pausing Execution When a Specific Player’s Name Is Printed
During one particular debugging session, I needed to figure out exactly what was happening when a game was drawing the names of players on screen. Specifically, I needed to invoke a breakpoint before the game drew the name “Player 1,” ignoring all other names that were drawn.
Figuring Out Where to Pause
As a starting point, I used Cheat Engine to find the address of Player 1’s name in memory. Once I had the address, I used OllyDbg to set a memory breakpoint on the first byte of the string. Every time this breakpoint got hit, I quickly inspected the assembly code to determine how it was using Player 1’s name. Eventually, I found the name being accessed directly above a call to a function that I had previously given the name printText(). I had found the code that was drawing the name.
I removed my memory breakpoint and replaced it with a code breakpoint on the call to printText(). There was a problem, however: because the call to printText() was inside a loop that iterated over every player in the game, my new breakpoint was getting hit every time a name was drawn—and that was much too often. I needed to fix it to hit only on a specific player.
Inspecting the assembly code at my previous memory breakpoint told me that each player’s name was accessed using the following assembly code:
The EAX register contained the address of an array of player data; I’ll call it playerStruct. The size of playerStruct was 0x90 bytes, the ECX register contained the iteration index (the famous variable i), and each player’s name was stored 0x50 bytes after the start of its respective playerStruct. This meant that this PUSH instruction essentially put EAX[ECX].name (the name of the player at index i) on the stack to be passed as an argument to the printText() function call. The loop, then, broke down to something like the following psuedocode:
playerStruct EAX[MAX_PLAYERS]; // this is filled elsewhere for (int uECX = 0; ECX < MAX_PLAYERS; ECX++) { char* name = vEAX[ECX].name;
breakpoint(); // my code breakpoint was basically right here
printText(name); }
Purely through analysis, I determined that the playerStruct() function contained data for all players, and the loop iterated over the total number of players (counting up with ECX u), fetched the character name v for each index, and printed the name.
Crafting the Conditional Breakpoint
Knowing that, to pause execution only when printing “Player 1” all I had to do was check the current player name before executing my breakpoint. In pseudocode, the new breakpoint would look like this:
Once I figured out the form of my new breakpoint, I needed to access EAX[ECX].name from within the loop. That’s where OllyDbg’s expression engine came in: I could achieve my goal by making slight modifications to the expression that the assembly code used, leaving me with this expression:
I removed the code breakpoint on printText() and replaced it with a conditional breakpoint that used this expression, which told OllyDbg to break only if the string value stored at EAX + ECX*0x90 + 0x50 matched Player 1’s name. This breakpoint hit only when “Player 1” was being drawn, allowing me to continue my analysis.
The amount of work it took to engineer this breakpoint might seem extensive, but with practice, the entire process becomes as intuitive as writing code. Experienced hackers can do this in a matter of seconds.
In practice, this breakpoint enabled me to inspect certain values in the playerStruct() function for “Player 1” as soon as he appeared on screen. Doing it this way was important, as the states of these values were relevant to my analysis only in the first few frames after the player entered the screen. Creatively using breakpoints like this can enable you to analyze all sorts of complex game behavior.
Pausing Execution When Your Character’s Health Drops
During another debugging session, I needed to find the first function called after my character’s health dropped below the maximum. I knew two ways to approach this problem:
• Find every piece of code that accesses the health value and place a conditional breakpoint that checks the health on each one. Then, once one of these breakpoints is hit, single-step through the code until the next function call.
• Use OllyDbg’s trace function to create a dynamic breakpoint that can stop exactly where I need.
The first method required more setup and was not easily repeatable, mostly due to the sheer number of breakpoints needed and the fact that I’d have to single-step by hand. In contrast, the latter method had a quick setup, and since it did everything automatically, it was easily repeatable. Though using the trace function would slow the game down considerably (every single operation was captured by the trace), I chose the latter method.
Writing an Expression to Check Health
Once again, I started by using Cheat Engine to find the address that stored my health. Using the method described in “Cheat Engine’s Memory Scanner” on page 5, I determined the address to be 0x40A000.
Next, I needed an expression that told OllyDbg to return 1 when my health was below maximum and return 0 otherwise. Knowing that my health was stored at 0x40A000 and that the maximum value was 500, I initially devised this expression:
This expression would invoke a break when my health was below 500 (remember, decimal numbers must be suffixed with a period in the expression engine), but instead of waiting for a function to be called, the break would happen immediately. To ensure that it waited until a function was called, I appended another expression with the && operator:
On x86 processors, the EIP register stores the address of the operation being executed, so I decided to check the first byte at EIP u to see if it was equal to 0xE8. This value tells the processor to execute a near function call, which is the type of call I was looking for.
Before starting my trace, I had to do one last thing. Because the trace feature repeatedly single-steps (Trace into uses step into and Trace over uses step over, as described in “A Brief Look at OllyDbg’s User Interface” on page 24), I needed to start the trace at a location scoped at or above the level of any code that could possibly update the health value.
Figuring Out Where to Start the trace
To find a good location, I opened the game’s main module in OllyDbg’s CPU window, right-clicked in the disassembler pane, and selected Search for4All intermodular calls. The References window popped up and displayed a list of external API functions that were called by the game. Nearly all gaming software polls for new messages using the Windows
USER32.PeekMessage() function, so I sorted the list using the Destination column and typed PEEK (you can search the list by simply typing a name with the window in focus) to locate the first call to USER32.PeekMessage().
Thanks to the Destination sorting, every call to this function was listed in a contiguous chunk following the first, as shown in Figure 2-5. I set a breakpoint on each by selecting it and pressing F2.
Figure 2-5: OllyDbg’s Found intermodular calls window
Though there were around a dozen calls to USER32.PeekMessage(), only two of them were setting off my breakpoints. Even better, the active calls were beside one another in an unconditional loop. At the bottom of this loop were a number of internal function calls. This looked exactly like a main game loop.
activating the trace
To finally set my trace, I removed all of my previous breakpoints and placed one at the top of the suspected main loop. I removed the breakpoint as soon as it was hit. I then pressed ctrl-T from the CPU window, which brought up a dialog called Condition to pause run trace, shown in Figure 2-6. Within this new dialog, I enabled the Condition is TRUE option, placed my expression in the box beside it, and pressed OK. Then, I went back to the CPU window and pressed ctrl-F11 to begin a Trace Into session.
Figure 2-6: Condition to pause run trace dialog
Once the trace began, the game ran so slowly it was nearly unplayable. To decrease my test character’s health, I opened a second instance of the game, logged into a different character, and attacked my test character. When the execution of the trace caught up to real time, OllyDbg saw my health change and triggered the breakpoint on the following function call—just as expected.
In this game, the main pieces of code that would modify the health value were directly invoked from the network code. Using this trace, I was able to find the function that the network module called directly after a network packet told the game to change the player’s health. Here’s the psuedocode of what the game was doing:
void network::check() { while (this->hasPacket()) { packet = this->getPacket(); if (packet.type == UPDATEHEALTH) { oldHealth = player->health; player->health = packet.getInteger();
u observe(HEALTH_CHANGE, oldHealth, player->health);
}
}
}
I knew the game had code that needed to execute only when the player’s health was changed, and I needed to add code that could also respond to such changes. Without knowing the overall code structure, I guessed that the health-dependent code would be executed from some function call directly after health was updated. My trace conditional breakpoint confirmed this hunch, as it broke directly on the observe() function u. From there, I was able to place a _hook on the function (hooking, a way to intercept function calls, is described in “Hooking to Redirect Game Execution” on page 153) and execute my own code when the player’s health changed.
Ollydbg Plug-ins for Game Hackers
OllyDbg’s highly versatile plug-in system is perhaps one of its most powerful features. Experienced game hackers often configure their OllyDbg environments with dozens of useful plug-ins, both publicly available and custom-made.
You can download popular plug-ins from the OpenRCE (http://www
.openrce.org/downloads/browse/OllyDbg_Plugins) and tuts4you (http://www .tuts4you.com/download.php?list.9/) plug-in repositories. Installing them is easy: just unzip the plug-in files and place them inside OllyDbg’s installation folder.
Once installed, some plug-ins can be accessed from the OllyDbg’s Plugin menu item. Other plug-ins, however, might be found only in specific places throughout the OllyDbg interface.
You can find hundreds of potent plug-ins using these online repositories, but you should be careful when constructing your arsenal. Working in an environment bloated by unused plug-ins can actually impede productivity. In this section, I’ve carefully selected four plug-ins that I believe are not only integral to a game hacker’s toolkit but also noninvasive to the environment.
Copying Assembly Code with Asm2Clipboard
Asm2Clipboard is a minimalistic plug-in from the OpenRCE repository that allows you to copy chunks of assembly code from the disassembler pane to the clipboard. This can be useful for updating address offsets and devising code caves, two game-hacking essentials I cover deeply in Chapters 5 and 7.
With Asm2Clipboard installed, you can highlight a block of assembly code in the disassembler, right-click the highlighted code, expand the Asm2Clipboard submenu, and select either Copy fixed Asm code to clipboard or Copy Asm code to clipboard. The latter prepends the code address of each instruction as a comment, while the former copies only the pure code.
Adding Cheat Engine to OllyDbg with Cheat Utility
The Cheat Utility plug-in from tuts4you provides a highly slimmed-down version of Cheat Engine within OllyDbg. While Cheat Utility only allows you to do exact-value scans with a very limited number of data types, it can make simple scans much easier when you don’t need the full functionality of Cheat Engine to find what you’re looking for. After installing Cheat Utility, to open its interface (shown in Figure 2-7), select Plugins4Cheat
utility4Start.
Figure 2-7: Cheat Utility interface
Cheat Utility’s user interface and operation mimic Cheat Engine closely, so review Chapter 1 if you need a refresher.
NOtE Games Invader, an updated version of Cheat Utility also from tuts4you, was created to provide more functionality. I’ve found it buggy, however, and I prefer Cheat Utility since I can always use Cheat Engine for advanced scans.
Controlling OllyDbg Through the Command Line
The command line plug-in enables you to control OllyDbg through a small command line interface. To access the plug-in, either press alt-F1 or select Plugins4Command line4Command line. You should then see a window, shown in Figure 2-8, which acts as the command line interface.
Figure 2-8: Command line interface
To execute a command, type it into the input box u and press enter. You will see a session-level command history in the center list v, and the bottom label displays the command’s return value w (if any).
Though there are many commands available, I find a majority of them useless. I primarily use this tool as a way to test that expressions are parsing as expected and as a handy calculator, but there are a few additional use cases that are also worth mentioning. I’ve described these in Table 2-6.
Table 2-6: Command Line Plug-in Commands
Command | Function |
---|---|
BC identifier | Removes any breakpoints present on identifier, which can be a code address or API function name. |
BP identifier [,condition] Places a debugger breakpoint on identifier,<br />which can be a code address or API function name. When identifier is an API function name, the breakpoint will be placed on the function entry point. The condition parameter is an optional expression that, if present, will be set as the breakpoint condition.
BPX label | Places a debugger breakpoint on every instance of label within the module currently being disassembled. This label will typically be an API function name. |
---|---|
CALC expression ? expression |
Evaluates expression and displays the result. |
HD address | Removes any hardware breakpoints present on address. |
HE address | Places a hardware on-execute breakpoint on address. |
HR address | Places a hardware on-access breakpoint on address. Only four hardware breakpoints can exist at a time. |
HW address | Places a hardware on-write breakpoint on address. |
MD | Removes any existing memory breakpoint, if present. |
MR address1, address2 | Places a memory on-access breakpoint starting at address1 and spanning until address2. Will replace any existing memory breakpoint. |
MW address1, address2 | Places a memory on-write breakpoint starting at address1 and spanning until address2. Will replace any existing memory breakpoint. |
WATCH expression W expression |
Opens the Watches window and adds expression to the watch list. Expressions in this list will be reevaluated every time the process receives a message and the evaluation results will be displayed beside them. |
The command line plug-in was made by the OllyDbg developer and should come preinstalled with OllyDbg.
Visualizing Control Flow with OllyFlow
OllyFlow, which can be found in the OpenRCE plug-in directory, is a purely visual plug-in that can generate code graphs like the one in Figure 2-9 and display them using Wingraph32.
Figure 2-9: An OllyFlow function flowchart
NOtE Wingraph32 is not provided with OllyFlow, but it is available with the free version of IDA here: https://www.hex-rays.com/products/ida/. Download it and drop the .exe in your OllyDbg installation folder.
Though not interactive, these graphs allow you to easily identify constructs such as loops and nested if() statements in game code, which can be paramount in control flow analysis. With OllyFlow installed, you can generate a graph by going to Plugins4OllyFlow (alternatively, right-click in the disassembler pane and expand the OllyFlow graph submenu) and selecting one of the following options:
Generate function flowchart Generates a graph of the function currently in scope, breaking apart different code blocks and showing jump paths. Figure 2-9 shows a function flowchart. Without a doubt, this is OllyFlow’s most useful feature.
Generate xrefs from graph Generates a graph of all functions called by the function that is currently in scope.
Generate xrefs to graph Generates a graph of all functions that call the function currently in scope.
Generate call stack graph Generates a graph of the assumed call path from the process entry point to the function currently in scope. Generate module graph Theoretically generates a complete graph of all function calls in the entire module, but rarely actually works.
To get an idea of the usefulness of OllyFlow, take a look at the graph in Figure 2-9 and compare it to the relatively simple assembly function that generated it:
76f86878:
u MOV EAX,DWORD PTR DS:[76FE7E54]
TEST AL,1
JE ntdll.76F8689B
76f86881: v MOV EAX,DWORD PTR FS:[18]
MOV EAX,DWORD PTR DS:[EAX+30]
OR DWORD PTR DS:[EAX+68],2000000
MOV EAX,DWORD PTR DS:[76FE66E0]
OR DWORD PTR DS:[EAX],1
JMP ntdll.76F868B2
76f8689b: w TEST EAX,8000 JE ntdll.76F868B2
76f868a2: x MOV EAX,DWORD PTR FS:[18]
MOV EAX,DWORD PTR DS:[EAX+30]
OR DWORD PTR DS:[EAX+68],2000000
76f868b2:
y MOV AL,1
RETN
There are five boxes in Figure 2-9, and they map to the five pieces of this function. The function starts with u, and it falls through to v if the branch fails or jumps to w if it succeeds. After v executes, it jumps directly to piece y, which then returns out of the function. After w executes, it either falls through to x or branches to y to return directly. After x executes, it unconditionally falls through to y. What this function does is irrelevant to understanding OllyFlow; for now, just focus on seeing how the code maps to the graph.
PAtCHING AN If( ) stAtEMENt
If you think you’re ready to get your hands dirty with OllyDbg, keep reading. Go to https://www.nostarch.com/gamehacking/, download the book’s resource files, grab BasicDebugging.exe, and execute it. At first glance, you’ll see that it looks like the classic game Pong. In this version of Pong, the ball is invisible to you when it is on your opponent’s screen. Your task is to disable this feature so that you can always see the ball. To make it easier for you, I’ve made the game autonomous. You don’t have to play, only hack.
To start, attach OllyDbg to the game. Then focus the CPU window on the main module (find the .exe in the module list and double-click it) and use the Referenced text strings feature to locate the string that is displayed when the ball is hidden. Next, double-click the string to bring it up in the code and analyze the surrounding code until you find the if() statement that determines whether to hide the ball. Lastly, using the code-patching feature, patch the if() statement so the ball is always drawn. As an added bonus, you might try using OllyFlow to graph this function so you can get a better understanding of what exactly it is doing. (Hint: The if() statement checks whether the ball’s x-coordinate is less than 0x140. If so, it jumps to code that draws the ball. If not, it draws the scene without the ball. If you can change 0x140 to, say, 0xFFFF, the ball will never get hidden.)
closing Thoughts
OllyDbg is a much more complex beast than Cheat Engine, but you’ll learn best by using it, so dive in and get your hands dirty! You can start by pairing the controls taught in this chapter with your debugging skills and going to work on some real games. If you are not yet ready to tamper with your virtual fate, however, try tackling the example in “Patching an if() Statement” for a practice environment. When you’re done, read on to Chapter 3, where I’ll introduce you to Process Monitor and Process Explorer, two tools you’ll find invaluable in game-hacking reconnaissance.
3
r E C O N N A I s s A N C E
w I t H P r O C E s s M O N I t O r
A N D P r O C E s s E x P l O r E r
Cheat Engine and OllyDbg can help you tear apart a game’s memory and code, but
you also need to understand how the game
interacts with files, registry values, network
connections, and other processes. To learn how those interactions work, you must use two tools that excel at
monitoring the external actions of processes: Process Monitor and Process Explorer. With these tools, you can track down the complete game map, locate save files, identify registry keys used to store settings, and enumerate the Internet Protocol (IP) addresses of remote game servers.
In this chapter, I’ll teach you how to use both Process Monitor and Process Explorer to log system events and inspect them to see how a game was involved. Useful mainly for initial reconnaissance, these tools are amazing at giving a clear, verbose picture of exactly how a game interacts with your system. You can download both programs from the Windows Sysinternals website (https://technet.microsoft.com/en-us/sysinternals/).
Process monitor
You can learn a lot about a game simply by exploring how it interacts with the registry, filesystem, and network. Process Monitor is a powerful systemmonitoring tool that logs such events in real time and lets you seamlessly integrate the data into a debugging session. This tool provides extensive amounts of useful data regarding a game’s interaction with the external environment. With calculated review (and sometimes, spontaneous intuition) on your part, this data can reveal details about data files, network connections, and registry events that are helpful to your ability to see and manipulate how the game functions.
In this section, I’ll show you how to use Process Monitor to log data, navigate it, and make educated guesses about the files a game interacts with. After this interface tour, you’ll have a chance to try out Process Monitor for yourself in “Finding a High Score File” on page 55.
Logging In-Game Events
Process Monitor’s logs can hold all sorts of potentially useful information, but their most practical use is to help you figure out where data files, such as in-game item definitions, might be stored. When you start Process Monitor, the first dialog you see is the Process Monitor Filter, shown in Figure 3-1.
Figure 3-1: Process Monitor Filter dialog
This dialog allows you to show or suppress events based on a number of dynamic properties they possess. To start monitoring processes, select Process Name4Is4YourGameFilename.exe4Include and then press Add, Apply, and OK. This tells Process Monitor to show events invoked by YourGameFilename.exe. With the proper filters set, you will be taken to the main window shown in Figure 3-2.
To configure the columns displayed in Process Monitor’s log area, rightclick on the header and choose Select Columns. There’s an impressive number of options, but I recommend seven.
Time of Day Lets you see when actions are happening.
Process Name Is useful if you’re monitoring multiple processes, but with the single-process filter that is typically used for games; disabling this option can save precious space.
Process ID Is like Process Name, but it shows the ID rather than the name.
Operation Shows what action was performed; thus, this option is compulsory.
Path Shows the path of the action’s target; also compulsory.
Detail Is useful only in some cases, but enabling it won’t hurt. Result Shows when actions, such as loading files, fail.
As you show more columns, the log can get very crowded, but sticking with these options should help keep the output succinct.
Once the monitor is running and you’ve defined the columns you wish to see, there are five event class filters, outlined in black in Figure 3-2, that you can toggle to clean up your logs even further. Event class filters let you choose which events to show in the log, based on type. From left to right, these filters are as follows:
Registry Shows all registry activity. There will be a lot of white noise in the registry upon process creation, as games rarely use the registry and Windows libraries always use it. Leaving this filter disabled can save a lot of space in the log.
Filesystem Shows all filesystem activity. This is the most important event class filter, since knowing where data files are stored and how they are accessed is integral to writing an effective bot.
Network Shows all network activity. The call stack on network events can be useful in finding network-related code within a game.
Process and thread activity Shows all process and thread actions. The call stack on these events can give you insight into how a game’s code handles threads.
Process profiling Periodically shows information about the memory and CPU usage of each running process; a game hacker will rarely use it.
If class-level event filtering is still not precise enough to filter out unwanted pollution in your logs, right-click on specific events for eventlevel filtering options. Once you have your event filtering configured to log only what you need, you can begin navigating the log. Table 3-1 lists some useful hotkeys for controlling the log’s behavior.
Table 3-1: Process Monitor Hotkeys
Hotkey | Action |
---|---|
ctrl-E | Toggles logging. |
ctrl-A | Toggles automatic scrolling of the log. |
ctrl-X | Clears the log. |
ctrl-L | Displays the Filter dialog. |
ctrl-H | Displays the Highlight dialog. This dialog looks very similar to the Filter dialog, but it is used to indicate which events should be highlighted. |
ctrl-F | Displays the Search dialog. |
ctrl-P | Displays the Event Properties dialog for the selected event. |
As you navigate the log, you can examine the operations recorded to see the fine-grained details of an event. Inspecting Events in the Process Monitor Log
Process Monitor logs every data point it possibly can about an event, enabling you to learn more about these events than just the files they act upon. Carefully inspecting data-rich columns, such as Result and Detail, can yield some very interesting information.
For example, I’ve found that games sometimes read data structures, element by element, directly from files. This behavior is apparent when a log contains a large number of reads to the same file, where each read has sequential offsets but differing lengths. Consider the hypothetical event log shown in Table 3-2.
Table 3-2: Example Event Log
Operation | Path | Detail |
---|---|---|
Create File | C:\file.dat | Desired Access: Read |
Read File | C:\file.dat | Offset: 0 Size: 4 |
Read File | C:\file.dat | Offset: 4 Size: 2 |
Read File | C:\file.dat | Offset: 6 Size: 2 |
Read File | C:\file.dat | Offset: 8 Size: 4 |
Read File | C:\file.dat | Offset: 12 Size: 4 |
… | … | …Continues to read chunks of 4 bytes for a while |
This log reveals that the game is reading a structure from the file piece by piece, disclosing some hints about what the structure looks like. For example, let’s say that these reads reflect the following data file:
struct myDataFile
{
int header; // 4 bytes (offset 0) short effectCount; // 2 bytes (offset 4) short itemCount; // 2 bytes (offset 6)
int effects; int items; };
Compare the log in Table 3-2 with this structure. First, the game reads the 4 header bytes. Then, it reads two 2-byte values: effectCount and itemCount. It then creates two integer arrays, effects and items, of respective lengths effectCount and itemCount. The game then fills these arrays with data from the file, reading 4 bytes effectCount + itemCount times.
NOtE Developers definitely shouldn’t use a process like this to read data from a file, but you’d be amazed at how often it happens. Fortunately for you, naïveté like this just makes your analysis easier.
In this case, the event log can identify small pieces of information within a file. But keep in mind that, while correlating the reads with the known structure is easy, it’s much harder to reverse engineer an unknown structure from nothing but an event log. Typically, game hackers will use a debugger to get more context about each interesting event, and the data from Process Monitor can be seamlessly integrated into a debugging session, effectively tying together the two powerful reverse engineering
paradigms.
Debugging a Game to Collect More Data
Let’s step away from this hypothetical file read and look at how Process Monitor lets you transition from event logging to debugging. Process Monitor stores a complete stack trace for each event, showing the full execution chain that led to the event being triggered. You can view these stack traces in the Stack tab of the Event Properties window (double-click the event or press ctrl-P), as shown in Figure 3-3.
Figure 3-3: Process Monitor event call stack
The stack trace is displayed in a table starting with a Frame column u, which shows the execution mode and stack frame index. A pink K in this column means the call happened in kernel mode, while a blue U means it happened in user mode. Since game hackers typically work in user mode, kernel mode operations are usually meaningless.
The Module column v shows the executable module where the calling code was located. Each module is just the name of the binary that made the call; this makes it easy to identify which calls were actually made from within a game binary.
The Location column w shows the name of the function that made each call, as well as the call offset. These function names are deduced from the export table of the module and will generally not be present for the functions within a game binary. When no function names are present, the Location column instead shows the module name and the call’s offset (how many bytes past the origin address the call is in memory) from the module’s base address.
In the context of code, the offset is how many bytes of assembly code are between an item and its origin.
The Address column x shows the code address of the call, which is very useful because you can jump to the address in the OllyDbg disassembler. Finally, the Path column y shows the path to the module that made the call. In my opinion, the stack trace is, by far, the most powerful feature in Process Monitor. It reveals the entire context that led to an event, which can be immensely useful when you are debugging a game. You can use it to find the exact code that triggered an event, crawl up the call chain to see how it got there, and even determine exactly what libraries were used to complete each action.
Process Monitor’s sister application, Process Explorer, doesn’t have many capabilities beyond those in Process Monitor or OllyDbg. But it does expose some of those capabilities much more effectively, making it an ideal pick in certain situations.
fINDING A HIGH sCOrE fIlE
If you’re ready to test your Process Monitor skills, you’ve come to the right place. Open the GameHackingExamples/Chapter3_FindingFiles directory and execute FindingFiles .exe. You’ll see that it is a game of Pong, like the one in “Patching an if() Statement” on page 46. Unlike in Chapter 2, though, now the game is actually playable. It also displays your current score and your all-time-high score.
Now restart the game, firing up Process Monitor before executing it for the second time. Filtering for filesystem activity and creating any other filters you see fit, try to locate where the game stores the high-score file. For bonus points, try to modify this file to make the game show the highest possible score.
Process explorer
Process Explorer is an advanced task manager (it even has a button you can press to make it your default task manager), and it’s very handy when you’re starting to understand how a game operates. It provides complex data about running processes, such as parent and child processes, CPU usage, memory usage, loaded modules, open handles, and command line arguments, and it can manipulate those processes. It exceeds at showing you high-level information, such as process trees, memory consumption, file access, and process IDs, all of which can be very useful.
Of course, none of this data is specifically useful in isolation. But with a keen eye, you can make correlations and draw some useful conclusions about what global objects—including files, mutexes, and shared memory segments—a game has access to. Additionally, the data shown in Process Explorer can be even more valuable when cross-referenced with data gathered in a debugging session.
This section introduces the Process Explorer interface, discusses the properties it shows, and describes how you can use this tool to manipulate handles (references to system resources). After this introduction, use “Finding and Closing a Mutex” on page 60 to hone your skills.
Process Explorer’s User Interface and Controls
When you open Process Explorer, you see a window that is split into three distinct sections, as in Figure 3-4.
Figure 3-4: Process Explorer main window
Those three sections are the toolbar u, an upper pane v, and a lower pane w. The upper pane shows a list of processes, utilizing a tree structure to display their parent/child relationships. Different processes are highlighted with different colors; if you don’t like the current colors, click Options4Configure Colors to display a dialog that allows you to view and change them.
Just as in Process Monitor, the display for this table is highly versatile, and you can customize it by right-clicking on the table header and choosing Select Columns. There are probably more than 100 customization options, but I find that the defaults with the addition of the ASLR Enabled column work just fine.
Address Space Layout Randomization (ASLR) is a Windows security feature that allocates executable images at unpredictable locations, and knowing whether it’s on is invaluable when you’re trying to alter game state values in memory.
The lower pane has three possible states: Hidden, DLLs, and Handles. The Hidden option hides the pane from view, DLLs displays a list of Dynamic Link Libraries loaded within the current process, and Handles shows a list of handles held by the process (visible in Figure 3-4). You can hide or unhide the entire lower pane by toggling View4Show Lower Pane. When it is visible, you can change the information display by selecting either View4Lower Pane View4DLLs or View4Lower Pane
View4Handles.
You can also use hotkeys to quickly change between lower pane modes without affecting processes in the upper pane. These hotkeys are listed in Table 3-3.
Table 3-3: Process Explorer Hotkeys
Hotkey | Action |
---|---|
ctrl-F | Search through lower pane data sets for a value. |
ctrl-L | Toggle the lower pane between hidden and visible. |
ctrl-D | Toggle the lower pane to display DLLs. |
ctrl-H | Toggle the lower pane to display handles. |
spacebar | Toggle process list autorefresh. |
enter | Display the Properties dialog for the selected process. |
del | Kill the selected process. |
shift-del | Kill the selected process and all child processes. |
Use the GUI or hotkeys to practice changing modes. When you’re acquainted with the main window, we’ll look at another important Process Explorer dialog, called Properties.
Examining Process Properties
Much like Process Monitor, Process Explorer has a very kinetic approach to data gathering; the end result is a broad and verbose spectrum of information. In fact, if you open the Properties dialog (shown in Figure 3-5) for a process, you’ll see a massive tab bar containing 10 tabs.
The Image tab, selected by default and shown in Figure 3-5, displays the executable name, version, build date, and complete path. It also displays the current working directory and the Address Space Layout Randomization status of the executable. ASLR status is the most important piece of information here, because it has a direct effect on how a bot can read the memory from a game. I’ll talk about this more in Chapter 6.
Figure 3-5: Process Explorer Properties dialog
The Performance, Performance Graph, Disk and Network, and GPU Graph tabs display a myriad of metrics about the CPU, memory, disk, network, and GPU usage of the process. If you create a bot that injects into a game, this information can be very useful to determine how much of a performance impact your bot has on the game.
The TCP/IP tab displays a list of active TCP connections, which you can use to find any game server IP addresses that a game connects to. If you’re trying to test connection speed, terminate connections, or research a game’s network protocol, this information is critical.
The Strings tab displays a list of strings found in either the binary or the memory of the process. Unlike the string list in OllyDbg, which shows only strings referenced by assembly code, the list includes any occurrences of three or more consecutive readable characters, followed by a null terminator. When a game binary is updated, you can use a diffing tool on this list from each game version to determine whether there are any new strings that you want to investigate.
The Threads tab shows you a list of threads running within the process and allows you to pause, resume, or kill each thread; the Security tab displays the security privileges of the process; and the Environment tab displays any environment variables known to or set by the process.
If you open the Properties dialog for a .NET process, you’ll notice two additional tabs: .NET Assemblies and .NET Performance. The data in these tabs is pretty selfexplanatory. Please keep in mind that a majority of the techniques in this book won’t work with games written in .NET.
Handle Manipulation Options
As you’ve seen, Process Explorer can provide you with a wealth of information about a process. That’s not all it’s good for, though: it can also manipulate certain parts of a process. For example, you can view and manipulate open handles from the comfort of Process Explorer’s lower pane (see Figure 3-4). This alone makes a strong argument for adding Process Explorer to your toolbox. Closing a handle is as simple as right-clicking on it and selecting Close Handle. This can come in handy when you want, for instance, to close mutexes, which is essential to certain types of hacks.
NOtE You can right-click on the lower pane header and click Select Columns to customize the display. One column you might find particularly useful is Handle Value, which can help when you see a handle being passed around in OllyDbg and want to know what it does.
Closing Mutexes
Games often allow only one client to run at a time; this is called singleinstance limitation. You can implement single-instance limitation in a number of ways, but using a system mutex is common because mutexes are sessionwide and can be accessed by a simple name. It’s trivial to limit instances with mutexes, and thanks to Process Explorer, it’s just as trivial to remove that limit, allowing you to run multiple instances of a game at the same time.
First, here’s how a game might tackle single-instance limitation with a mutex:
int main(int argc, char argv[]) {
// create the mutex
HANDLE mutex = CreateMutex(NULL, FALSE, “onlyoneplease”);
if (GetLastError() == ERRORALREADY_EXISTS) {
// the mutex already exists, so exit
ErrorBox(“An instance is already running.”);
return 0;
}
// the mutex didn’t exist; it was just created, so
// let the game run
RunGame();
// the game is over; close the mutex to free it up
// for future instances
if (mutex)
CloseHandle(mutex);
return 0;
}
This example code creates a mutex named onlyoneplease. Next, the function checks GetLastError() to see whether the mutex was already created, and if so, it closes the game. If the mutex doesn’t already exist, the game creates the first instance, thereby blocking any future game clients from running. In this example, the game runs normally, and once it finishes, CloseHandle() is called to close the mutex and allow future game instances to run.
You can use Process Explorer to close instance-limiting mutexes and run many game instances simultaneously. To do so, choose the Handles view of the lower pane, look for all handles with a type of Mutant, determine which one is limiting instances of the game, and close that mutex.
wA rNING Mutexes are also used to synchronize data across threads and processes. Close one only if you’re sure that its sole purpose is the one you’re trying to subvert!
Multiclient hacks are generally in high demand, so being able to quickly develop them for emerging games is crucial to your overall success as a bot developer within that market. Since mutexes are one of the most common ways to achieve single-instance limitation, Process Explorer is an integral tool for prototyping these kinds of hacks.
Inspecting File accesses
Unlike Process Monitor, Process Explorer can’t show a list of filesystem calls. On the other hand, the Handles view of Process Explorer’s lower pane can show all file handles that a game currently has open, revealing exactly what files are in continuous use without the need to set up advanced filtering criteria in Process Monitor. Just look for handles with a type of File to see all files the game is currently using.
This functionality can come in handy if you’re trying to locate logfiles or save files. Moreover, you can locate named pipes that are used for interprocess communication (IPC); these are files prefixed with \Device\ NamedPipe_. Seeing one of these pipes is often a hint that the game is talking to another process.
*fINDING AND ClOsING A MutE x
To put your Process Explorer skills to use, go to the GameHackingExamples/ Chapter3_CloseMutex directory and execute CloseMutex .exe. This game plays exactly like the one in “Finding a High Score File” on page 55, but it prevents you from simultaneously running multiple instances. As you might have guessed, it does this using a single-instance-limitation mutex. Using Process Explorer’s Handles view in the lower pane, find the mutex responsible for this limitation and close it. If you succeed, you’ll be able to open a second instance of the game.
closing Thoughts
To be effective when using Process Monitor and Process Explorer, you need, above all else, a deep familiarity with the data that these applications display as well as the interfaces they use to display it. While this chapter’s overview is a good baseline, the intricacies of these applications can be learned only through experience, so I encourage you to play around with them on your system.
You won’t use these tools on a regular basis, but at some point, they’ll save the day: as you struggle to figure out how some code works, you’ll recall an obscure piece of information that caught your eye during a previous Process Explorer or Process Monitor session. That’s why I consider them useful reconnaissance tools.
G A M E D I s s E C t I
**