I've decided to start a series of almost tutorial-like posts with information on retro-style raycasting.
More specifically, this series of posts will cover my previous, current and future work with writing Wolfenstein-3D-like 2D array based raycasting engines with various optimizations.
There have been little to no major optimizations in the area of 2D array based raycasting, presumably because all modern hardware is too powerful to need it.
I've spent the last couple of years on and off building and improving raycasting engines.
Most of my early work was in AS2.
Here's a brief overview of my history with the pseudo-3D:
Ye Olde AS2 engines:
I originally started off by porting the code from this tutorial to AS2.
My initial port had graphical errors and a lot of bugs, but worked as a proof-of-concept, which I did about two years ago.
This was my V1 engine.
The V2 engine started off as a complete re-port of the code.
The V2 engine was bug-free, and started off as a texture-less raycaster.
The first improvement I made to the V2 engine was the addition of "fog" which was used as a basic way to implement basic pseudo-lighting.
The second improvement was to draw each wall face as a gradient-filled square instead of a crap-ton of vertical lines, which greatly decreased the time it took to draw the frame.
The V2 engine was also the first engine to support textures, for which I made two drawing algorithms, neither of which were particularly effective.
V3 was my first attempt at implementing my "extra trig" raycasting engine. I'll go into more detail on extra trig raycasting in another post.
The V3 engine, although not a complete failure, required an incredibly buggy piece of code to run: my "edge fix". to put it simply, the edge fix works by using the height of the previous raycasted wall to work out how high the current wall-face edge height is. the edge fix is effectively an interpolation algorithm for the raycaster, it gives a better looking image for many less rays, however, it was unfinished and had many bugs.
The V3 engine was discontinued very early on.
With the partial failure of the V3 engine, I started development on the V3-2 engine, which was built off the V2 engine because the V3 engine was deemed too unstable and bugged.
The V3-2 engine got to be quite powerful after several optimizations.
The V3-2 engine was the first engine to support sprites and have working z-sorting (z-sorting was done per-wall instead of per-pixel, which later gave me the idea of my Left-Right z-sorting algorithm which I may cover in a later post)
Also included in V3-2 was an incredibly snazzy minimap and basic multiplayer support.
V3-2 did not support textures, but was as bug-free and stable as V2.
V4 was a second, more advanced attempt at implementing my "extra-trig" raycasting method, built off of V3-2.
It was filled with bugs and hack-y fixes, but was beginning to show promise before I stopped development.
I stopped development on V4 a little over a year ago.
This was my last iteration of my AS2 raycaster.
About three or four months after the discontinuation of V4, I wrote a full, working AS3 Maze War prototype with a full server running on Adobe Air.
After that, I wrote a quick-and-dirty pseudo-3d engines that used vector-based maps and worked by calculating line intersections and trigonometry, it worked to an extent however there were visual bugs with it.
I dabbled with some experiments and wrote my own basic pseudo-3D engine in C++ that used vector-based maps, A similar "rasterization" technique to my "extra trig" raycasting method and was drawn using SDL late last year in preparation for writing an implementation of my Flood-Fill Raycaster-Like engine, which hasn't been started yet.
So far, I've come up with 3 Wolfenstein-like algorithms for raycasting that are faster than the conventional methods:
Extra-Trig Raycasting:
typically would use less than 50 rays to calculate any scene likely to exist in a game, resolution of display has no effect on rays used or calculation time, however amount of walls on the screen does. uses significantly more maths than regular raycasting but many major operations can be done using precalculation and look-up tables.
Estimated speed VS traditional method:
Depends on resolution, at 640x480, estimated 2-10 times faster.
Binary Raycaster:
Hard to estimate how many rays it would use - however it would definitely use significantly less. at a screen width of 640, maybe around 50-200 rays would be likely. More processing would have to be done per ray, but most likely not much. increased resolution means more calculation, more walls on screen means more calculation. significantly easier to implement than extra-trig
Estimated speed VS traditional method:
estimated 2-10 times faster
Flood-Fill Raycaster
Technically not a raycaster as it doesn't use rays. FFRC is one step on from Extra-Trig. Each tile in view is only checked once, trigonometry is used to do almost everything. heavy use of precalc and look-up tables can greatly increase efficiency. Calculation needed to do is proportional to tiles in view, both empty and filled. Screen resolution has no effect on processing needed.
Estimated speed VS traditional method:
estimated 5-100 times faster.
I have also been working on another perspective-based rasterizer which I believe would be limited to maze-war-like maps, but would allow players to look in all directions and possibly have free movement while still being more efficient than any other method above.
And that concludes a rough overview of my work on pseudo-3D engines. at least all the interesting stuff.
Monday, February 4, 2013
Retro-style Raycasting #1
Labels:
3D,
actionscript,
as2,
AS3,
c++,
casting,
flash,
optimization,
pseudo,
rasterizer,
ray,
raycasting,
SDL,
wolfenstein
Tuesday, January 29, 2013
BPE Pre-Alpha V1.2
With this release comes good news and bad news.
The bad news is my prehook system doesn't work, so I'm going to have to find a new way of adding IP hooks. I've looked at several alternatives and found that I could quite easily make a cross-platform hook for Linux/Mac, but Windows doesn't like letting anyone do any low-ish level network hacks.
The good news is that PEW support has been added, which is a pretty big thing.
I've actually fixed the multiple server hook bug this time - connections now go to where they're meant to go.
I've also done a little more work on the GUI, adding the ability to actually remove port hooks and plugins.
It also no longer saves which hooks you were using. Now that Workspaces are implemented, it no longer needs to.
I'll update the Wiki with some documentation on Workspace files since to load plugins you have to edit the Workspace file via text editor.
I'd also like to point out that now Workspace files have been implemented, BPE is much more friendly towards having complete game hacks released on it since all an end-user needs to do to use a properly set up plugin-based hack is double click a Workspace file.
Feel free to spread this around.
People should use this.
DOWNLOAD
Changelog:
*BPE Pre-Alpha V1.2 (PEPAPI V1.1) (PEWVer 1.0)
- added PEW/Workspace support
- added "resetWorkspace", "hookServer", "hookPort" and "loadPlugin" Workspace commands
- added save & load workspace buttons
- save function saves server hooks and plugin hooks but not plugin configuration
- GUI improvements
- added ability to unload plugins via "Plugin Options" menu
- added ability to unhook ports via "Port Options" menu
- fixed bug where BPE would sometimes not close properly and hang in memory
- BPE now removes server hooks on close, use workspaces to save them
- made BPE the default file opener for .pew files (secretly done in V1.1)
- fixed bug where if more than one server was hooked all connections were routed to the first server in the list
- cleaned up shit tons of code
The bad news is my prehook system doesn't work, so I'm going to have to find a new way of adding IP hooks. I've looked at several alternatives and found that I could quite easily make a cross-platform hook for Linux/Mac, but Windows doesn't like letting anyone do any low-ish level network hacks.
The good news is that PEW support has been added, which is a pretty big thing.
I've actually fixed the multiple server hook bug this time - connections now go to where they're meant to go.
I've also done a little more work on the GUI, adding the ability to actually remove port hooks and plugins.
It also no longer saves which hooks you were using. Now that Workspaces are implemented, it no longer needs to.
I'll update the Wiki with some documentation on Workspace files since to load plugins you have to edit the Workspace file via text editor.
I'd also like to point out that now Workspace files have been implemented, BPE is much more friendly towards having complete game hacks released on it since all an end-user needs to do to use a properly set up plugin-based hack is double click a Workspace file.
Feel free to spread this around.
People should use this.
DOWNLOAD
Changelog:
*BPE Pre-Alpha V1.2 (PEPAPI V1.1) (PEWVer 1.0)
- added PEW/Workspace support
- added "resetWorkspace", "hookServer", "hookPort" and "loadPlugin" Workspace commands
- added save & load workspace buttons
- save function saves server hooks and plugin hooks but not plugin configuration
- GUI improvements
- added ability to unload plugins via "Plugin Options" menu
- added ability to unhook ports via "Port Options" menu
- fixed bug where BPE would sometimes not close properly and hang in memory
- BPE now removes server hooks on close, use workspaces to save them
- made BPE the default file opener for .pew files (secretly done in V1.1)
- fixed bug where if more than one server was hooked all connections were routed to the first server in the list
- cleaned up shit tons of code
Monday, January 28, 2013
Packet Editor Progress #7
It's been a while since I gave a progress update on BPE.
IP hooks (in the form of PreHook) are being added next release. unfortunately, for both hooks to work simultaneously, I have to re-design the entire hook system, which is why this release has been taking quite some time.
Since BPE was originally designed to only have one hook system, it makes things difficult because the server hooks and the port hooks were effectively the same body of code, and now need to be completely separated and mostly re-written (I'm splitting one class into about five to make it work).
There will be a "Server Manager" class that acts as an interface for the different hooks (including plugin interaction, which is controlled by the "Plugin Manager"), and a "Master Server" class that will organize the serversockets and pass connections through the different hooks as they come.
So, next release should fix the two most significant limitations of BPE: the multiple server hook bugs and not being able to hook IPs.
PEW files will probably start being implemented in the release after this next one. I'm focusing on fixing major bugs/limitations before adding new features.
And yes, I still need a Mac tester.
I'd also appreciate a Linux tester.
IP hooks (in the form of PreHook) are being added next release. unfortunately, for both hooks to work simultaneously, I have to re-design the entire hook system, which is why this release has been taking quite some time.
Since BPE was originally designed to only have one hook system, it makes things difficult because the server hooks and the port hooks were effectively the same body of code, and now need to be completely separated and mostly re-written (I'm splitting one class into about five to make it work).
There will be a "Server Manager" class that acts as an interface for the different hooks (including plugin interaction, which is controlled by the "Plugin Manager"), and a "Master Server" class that will organize the serversockets and pass connections through the different hooks as they come.
So, next release should fix the two most significant limitations of BPE: the multiple server hook bugs and not being able to hook IPs.
PEW files will probably start being implemented in the release after this next one. I'm focusing on fixing major bugs/limitations before adding new features.
And yes, I still need a Mac tester.
I'd also appreciate a Linux tester.
Thursday, December 20, 2012
Flash AS3 Class overriding template and tutorial
The biggest problem with class overriding I have found so far is that large classes can take a lot of work to "fix" to work with class overriding. So, I have created a template for class overriding that can make this process a vast amount easier.
It certainly has it's limitations, but where it works, it works well.
To be able to use it properly, you need to have a pretty good understanding of how it works.
I'll start with a quick overview of how it works, don't worry too much if you don't understand it properly yet:
A custom loader dynamically generates a SWF containing a single "nullified" class that has no methods or properties and uses class overriding to nullify the document class in an instance of the game SWF (this instance is used solely for accessing the original, unmodified classes in the game).
Template classes use the proxy extends hack to pretend to "extend" the original class in the game. e.g. if you were overriding the class "Money", the template does this by using the proxy hack to pretend to extend the original "Money" class held in the nullified instance of the SWF loaded by the custom loader.
Classes are overridden by extending the BasicOverrider class that is included in the template. This class and the custom loader do all the hard work for you. Any public methods and variables can now be modified, without having to "fix" any code you're not working with.
Here's a nice little visual explanation for the loader:
With any luck, you now have a decent understanding of how the loader works.
so, onto how the template extender works:
If you need more information, you can take a peek at it's source.
Now, hopefully you understand it's limitations. It cannot access private/protected vars and requires a little work to fix type casting problems (Note: a lot of the time this isn't a problem) due to the nature of how it functions.
Now, here's the mini-tutorial and template download link:
You'll need this SWF and the OverriderLoader template for this tutorial.
I will assume you know everything covered in this tutorial.
Setting up the template is really easy.
The SWF name is "Unhackable.swf" and if you open it up with a decompiler, it'll tell you the document class is "Unhackable".
open up the Overrider class and change:
to:
Next, we need to fix the stage access problem. Unfortunately, template overriding doesn't work on the document class (because it gets nullified so you can load the other classes without running code), so we'll need to use the old method. We'll use the same code we wrote up in the last tutorial. Chuck this code in a new class called "Unhackable":
Now that that problem's solved, we can get on to using the template for something useful.
We'll make each money pickup give you 100 score.
Now, if you remember, the actual score variable is private, which means that template overriding can't touch it. however, the static "addMoney" method is public and can thus be edited.
So, let's start with a basic overrider template class, then.
Create a new class in the package "UnhackableEngine" called "ScoreKeeper" and give it this code:
This is just a basic overrider template class with a wrapper function for the addMoney static method (as all static methods need wrapper functions when using the template). Our goal right now is to get it to compile with this.
So, lets add the line
to our Overrider class to make it all compile together and see what errors we get.
You'll get an error telling you it doesn't want to be added as a child. We've been here before, haven't we? last tutorial?
Change:
to:
in your Overrider class to make it quit it's bitching. Compile, and it should be happy.
Now all we need to do to make money add 100 score is go to our ScoreKeeper class and change:
to:
Compile, and you're done!
Here's the finished source code for the tutorial.
Oh, and if you're wondering how to fix static variables, you do something like this:
Where varName is the name of the variable.
The pros of using the template:
- no need to fix any non-static functions
- static functions only need to be redirected, so fixing is much simpler compared to the old method
The cons of using the template
- doesn't work on the document class
- doesn't work on private/protected vars/methods
- type casting is still a problem
It certainly has it's limitations, but where it works, it works well.
To be able to use it properly, you need to have a pretty good understanding of how it works.
I'll start with a quick overview of how it works, don't worry too much if you don't understand it properly yet:
A custom loader dynamically generates a SWF containing a single "nullified" class that has no methods or properties and uses class overriding to nullify the document class in an instance of the game SWF (this instance is used solely for accessing the original, unmodified classes in the game).
Template classes use the proxy extends hack to pretend to "extend" the original class in the game. e.g. if you were overriding the class "Money", the template does this by using the proxy hack to pretend to extend the original "Money" class held in the nullified instance of the SWF loaded by the custom loader.
Classes are overridden by extending the BasicOverrider class that is included in the template. This class and the custom loader do all the hard work for you. Any public methods and variables can now be modified, without having to "fix" any code you're not working with.
Here's a nice little visual explanation for the loader:
With any luck, you now have a decent understanding of how the loader works.
so, onto how the template extender works:
If you need more information, you can take a peek at it's source.
Now, hopefully you understand it's limitations. It cannot access private/protected vars and requires a little work to fix type casting problems (Note: a lot of the time this isn't a problem) due to the nature of how it functions.
Now, here's the mini-tutorial and template download link:
You'll need this SWF and the OverriderLoader template for this tutorial.
I will assume you know everything covered in this tutorial.
Setting up the template is really easy.
The SWF name is "Unhackable.swf" and if you open it up with a decompiler, it'll tell you the document class is "Unhackable".
open up the Overrider class and change:
loader.load("SWF NAME HERE.swf","DocumentClassNameHere");
to:
loader.load("unhackable.swf","Unhackable");
Next, we need to fix the stage access problem. Unfortunately, template overriding doesn't work on the document class (because it gets nullified so you can load the other classes without running code), so we'll need to use the old method. We'll use the same code we wrote up in the last tutorial. Chuck this code in a new class called "Unhackable":
package
{
import flash.utils.*;
import flash.display.*;
import flash.events.*;
public class Unhackable extends MovieClip
{
private var Player:Class = getDefinitionByName("UnhackableEngine.Player") as Class;
private var Money:Class = getDefinitionByName("UnhackableEngine.Money") as Class;
private var ScoreKeeper:Class = getDefinitionByName("UnhackableEngine.ScoreKeeper") as Class;
private var player:Object;
private var money:Object;
private var score:Object;
public function Unhackable()
{
this.addEventListener(Event.ADDED_TO_STAGE,addToStage);
return;
}
private function addToStage(e:Event)
{
this.player = new Player(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.money = new Money(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.score = new ScoreKeeper();
addChild(this.score as DisplayObject);
addChild(this.money as DisplayObject);
addChild(this.player as DisplayObject);
stage.addEventListener(Event.ENTER_FRAME, this.gameLoop);
}// end function
private function gameLoop(event:Event)
{
this.money.dealWithPlayer(this.player.playerX, this.player.playerY);
this.player.doMove();
return;
}// end function
}
}
Now that that problem's solved, we can get on to using the template for something useful.
We'll make each money pickup give you 100 score.
Now, if you remember, the actual score variable is private, which means that template overriding can't touch it. however, the static "addMoney" method is public and can thus be edited.
So, let's start with a basic overrider template class, then.
Create a new class in the package "UnhackableEngine" called "ScoreKeeper" and give it this code:
package UnhackableEngine {
import OverriderLoaderUtils.BasicOverrider;
import flash.utils.*;
public class ScoreKeeper extends BasicOverrider {
public function ScoreKeeper() {
super(getQualifiedClassName(this));
origObject = new origClass();
}
static function addMoney()
{
origClass.addMoney();
}
}
}
This is just a basic overrider template class with a wrapper function for the addMoney static method (as all static methods need wrapper functions when using the template). Our goal right now is to get it to compile with this.
So, lets add the line
var scoreKeeper:ScoreKeeper;
to our Overrider class to make it all compile together and see what errors we get.
You'll get an error telling you it doesn't want to be added as a child. We've been here before, haven't we? last tutorial?
Change:
addChild(this.score as DisplayObject);
to:
addChild(this.score.origObject as DisplayObject);
in your Overrider class to make it quit it's bitching. Compile, and it should be happy.
Now all we need to do to make money add 100 score is go to our ScoreKeeper class and change:
static function addMoney()
{
origClass.addMoney();
}
to:
static function addMoney()
{
for(var i:int = 0;i<100;i++){
origClass.addMoney();
}
}
Compile, and you're done!
Here's the finished source code for the tutorial.
Oh, and if you're wondering how to fix static variables, you do something like this:
static function get varName():Object
{
return origClass.varName();
}
static function set varName(value:Object):Void
{
origClass.varName = value;
}
Where varName is the name of the variable.
The pros of using the template:
- no need to fix any non-static functions
- static functions only need to be redirected, so fixing is much simpler compared to the old method
The cons of using the template
- doesn't work on the document class
- doesn't work on private/protected vars/methods
- type casting is still a problem
Monday, December 3, 2012
Flash AS3 Class injection via Loader
I discovered a new technique for hacking flash games a month or so ago. I've been referring to it as class overriding (simply because class injection could be used to refer to injecting bytecode into a SWF).
It's a fairly simple technique that allows you to have extreme control over a loaded SWF.
I was going to do this tutorial on an actual game, but unfortunately there weren't any games that were good examples, so instead I modified my Unhackable Engine base (designed to be the simplest game possible for testing new security measures/ect in a semi-real environment and easy to port to other languages, the original AS3 version is under 90 lines of code, and the AS2 version is less than 60).
I'm going to assume you have some experience with AS3 and flash. If you don't, the source for this tutorial will be available.
Be warned, this SWF was botched together as fast as possible, and modified to function in weird ways specifically for the tutorial. Don't judge me on the quality of it's code.
Download the "game" used in this tutorial here.
Anyways, to the tutorial:
The first thing we do is we start with a basic loader template that will load the SWF.
This will load the SWF into our SWFs ApplicationDomain, meaning that classes will be loaded into the same space, and when flash player tries to load a class that already exists in the current ApplicationDomain, the new class is dropped, and the old one remains (which is how this hack works).
Now, compile and run that, and you will get an error.
let's open unhackable.swf with a decompiler, and see what the problem is.
We know from the error that the error is within Unhackable(), so let's look at the code:
Ah, there's our problem. Let me explain for those of us who are unfamiliar with the bugs in the Loader class...
When A SWF is loaded normally (without the Loader class), the document class's constructor is called after it has been added to the stage and therefore has the stage property set. When a SWF is loaded with the Loader class, the document class's constructor is called before it has had it's stage property set, so that refference to the stage:
will throw an error, because the stage variable is still a null object reference (it's null), and as the error states, you cannot access a method of a null object reference.
Luckily, we can fix this quite easily with class overriding.
Create a new class in your default package called Unhackable and copy and paste the code the decompiler generated for that class over.
Now, when you compile that, you'll get about a half-dozen errors. this is ok, and completely normal in class overriding. You see, that class imports other classes (Player, Money, ScoreKeeper) that we don't have in our project. The first solution you probably think if would be to decompile and add every class in the SWF, but that would be a pain in the ass and counterproductive, so we're gonna hack our way through this. the question we need to answer is: How do we access a class we can't import? The solution is simple: using the getDefinitionByName function in flash.utils.*.
so, replace:
with:
getDefintionByName will dynamically find the class for us whenever we need it. so, with a little modification we can fix this class.
replace:
with:
Also, since there are no references to this new class you've added, by default it won't compile into your SWF, so go back to your document class, and under the class variable definitions, add:
When you try and compile, you'll get some more errors now, but that's OK, cause we're gonna have to replace the function they're in anyway.
So, onto replacing the function, fixing the stage reference problems and adding the needed type casting.
First, we're gonna move all the code in the constructor to another function, and make that function be called when the object has been added to the stage (using the ADDED_TO_STAGE listener).
replace:
with:
And now we add some type casting to fix the last 3 errors.
replace:
with:
and compile. with any luck, you have no errors, it compiles, loads the SWF and runs perfectly!
If not, try download the source of the finished code and try and figure out what went wrong.
Congratulations! you've successfully overrided your first class!
Now, onto doing something useful.
We'll double player speed and make it so that each "money" pickup gives us 1,000 points.
First, we'll start with the money hack, because the player speed hack is a little more complicated (If you're feeling confident/bored, you can skip to the player speed hack, as it teaches more important stuff).
This one is simple and straightforward.
you'll need a new package (class locations need to be mirrored) called UnhackableEngine, and in there a new class called ScoreKeeper.
Copy and paste the ScoreKeeper code from the decompiler, add this line of code to your document classes variable definitions to make sure it gets compiled in:
and compile.
You'll get an error.
Don't worry, it's easy to fix.
Our problem is that variables are not being casted from int/whatever to string, so the compiler is getting shitty with us.
replace the two occurrences of:
with:
and compile.
It should compile and work without errors.
Now, let's take a look at the addMoney function:
seems easy enough to modify. Let's chuck some 0s in there
and boom, money pickups now give us 1000 score.
Onto player movement, and advanced class overriding!
I'm sure you know the drill by now.
Create a new class in the UnhackableEngine package named Player.
C+P the code from the decompiler, add a reference to the class in your document class, try to compile and see what errors you get.
Ooh, we get a new, nasty one.
The definition of base class Thing was not found.
We have two options here, overriding the Thing class will solve this problem, but imagine if Thing extended another custom class, which extended another custom class, which ended up being a class chain 20 classes long? it would be impractical to override them all.
But how can you possibly get around it? you can't just dynamically extend classes. That goes directly against AS3s standards. Luckily, in AS3 there's this nasty little thing called the Proxy class that goes against all of AS3s conventions, and makes this possible.
Although we cannot actually dynamically extend classes, we can pretend we do using the Proxy class to dynamically pretend we have properties of classes which we actually don't.
I'm going to warn you now, everything's about to get messy. Which is why I'm stalling.
I guess I'll explain the Proxy class a little, seems like it's the best way to teach this.
The Proxy class allows you to dynamically change the behavior of an object. When set up, you can make it so that if a property is accessed and doesn't exist in an object, a proxy function is called that can deal with it. we use this functionality to make an object act as if it has the properties of another object by making any attempt to access a property that doesn't exist on the object go to the object it is pretending to extend.
Hopefully, the code will help explain what I mean for those who are still confused...
First thing we need to do is make the Player class extend the Proxy class.
replace:
with:
now, add these variables to the Player classes variable definitions:
add these functions to the class:
these functions are the backbone of our Proxy hack. We don't actually need most (or any) of them. in most situations, you'll need them, though. There are more Proxy functions you may need in other circumstances, but these are the main ones.
We're gonna have to do quite a bit of modifying to make this class work with us.
Any internal references in the player class to the class it extends need to be changed.
replace:
with:
and
with:
and
with:
As you can tell, the Proxy hack can be a bit messy. sometimes, it's better to just override the class it extends as well. cause now where up to the next problem: type casting.
A Proxy object can't be casted to anything the object it's pretending to extend can. And the addChild function which the player object is given as a parameter to expects a DisplayObject. luckily, we're already overriding the class that calls the function, so go back to the Unhackable class and
replace:
with:
compile that and it should work error-free.
The Player class is FINALLY set up for modification (again, the proxy hack isn't really made for this situation, but it's useful to know how to do it).
One quick modification and we'll have double player speed.
change
to
And we're done!
Download the source for this tutorial here.
It's a fairly simple technique that allows you to have extreme control over a loaded SWF.
I was going to do this tutorial on an actual game, but unfortunately there weren't any games that were good examples, so instead I modified my Unhackable Engine base (designed to be the simplest game possible for testing new security measures/ect in a semi-real environment and easy to port to other languages, the original AS3 version is under 90 lines of code, and the AS2 version is less than 60).
I'm going to assume you have some experience with AS3 and flash. If you don't, the source for this tutorial will be available.
Be warned, this SWF was botched together as fast as possible, and modified to function in weird ways specifically for the tutorial. Don't judge me on the quality of it's code.
Download the "game" used in this tutorial here.
Anyways, to the tutorial:
The first thing we do is we start with a basic loader template that will load the SWF.
Create a new document class (I called mine Overrider), and
put this code in it:
package {
import flash.display.MovieClip;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
public class Overrider extends MovieClip {
private var ldr:Loader = new Loader();
public function Overrider() {
this.addChild(ldr);
var urlReq:URLRequest = new URLRequest("unhackable.swf");
ldr.load(urlReq,new LoaderContext(false,ApplicationDomain.currentDomain));
}
}
}
Now, compile and run that, and you will get an error.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Unhackable()
let's open unhackable.swf with a decompiler, and see what the problem is.
We know from the error that the error is within Unhackable(), so let's look at the code:
public class Unhackable extends MovieClip
{
...
public function Unhackable()
{
this.player = new Player(int(Math.random() * 300) + 50, int(Math.random() * 200) + 50);
this.money = new Money(int(Math.random() * 300) + 50, int(Math.random() * 200) + 50);
this.score = new ScoreKeeper();
addChild(this.score);
addChild(this.money);
addChild(this.player);
stage.addEventListener(Event.ENTER_FRAME, this.gameLoop);
return;
}
...
}
Ah, there's our problem. Let me explain for those of us who are unfamiliar with the bugs in the Loader class...
When A SWF is loaded normally (without the Loader class), the document class's constructor is called after it has been added to the stage and therefore has the stage property set. When a SWF is loaded with the Loader class, the document class's constructor is called before it has had it's stage property set, so that refference to the stage:
stage.addEventListener(Event.ENTER_FRAME, this.gameLoop);
will throw an error, because the stage variable is still a null object reference (it's null), and as the error states, you cannot access a method of a null object reference.
Luckily, we can fix this quite easily with class overriding.
Create a new class in your default package called Unhackable and copy and paste the code the decompiler generated for that class over.
Now, when you compile that, you'll get about a half-dozen errors. this is ok, and completely normal in class overriding. You see, that class imports other classes (Player, Money, ScoreKeeper) that we don't have in our project. The first solution you probably think if would be to decompile and add every class in the SWF, but that would be a pain in the ass and counterproductive, so we're gonna hack our way through this. the question we need to answer is: How do we access a class we can't import? The solution is simple: using the getDefinitionByName function in flash.utils.*.
so, replace:
import UnhackableEngine.*;
with:
import flash.utils.*;
getDefintionByName will dynamically find the class for us whenever we need it. so, with a little modification we can fix this class.
replace:
private var player:Player;
private var money:Money;
private var score:ScoreKeeper;
with:
private var Player:Class = getDefinitionByName("UnhackableEngine.Player") as Class;
private var Money:Class = getDefinitionByName("UnhackableEngine.Money") as Class;
private var ScoreKeeper:Class = getDefinitionByName("UnhackableEngine.ScoreKeeper") as Class;
private var player:Object;
private var money:Object;
private var score:Object;
Also, since there are no references to this new class you've added, by default it won't compile into your SWF, so go back to your document class, and under the class variable definitions, add:
private var unhackable:Unhackable;
When you try and compile, you'll get some more errors now, but that's OK, cause we're gonna have to replace the function they're in anyway.
So, onto replacing the function, fixing the stage reference problems and adding the needed type casting.
First, we're gonna move all the code in the constructor to another function, and make that function be called when the object has been added to the stage (using the ADDED_TO_STAGE listener).
replace:
public function Unhackable()
{
this.player = new Player(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.money = new Money(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.score = new ScoreKeeper();
addChild(this.score as DisplayObject);
addChild(this.money as DisplayObject);
addChild(this.player as DisplayObject);
stage.addEventListener(Event.ENTER_FRAME, this.gameLoop);
return;
}
with:
public function Unhackable()
{
this.addEventListener(Event.ADDED_TO_STAGE,addToStage);
return;
}
private function addToStage(e:Event)
{
this.player = new Player(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.money = new Money(int(Math.random() * 300) + 50,int(Math.random() * 200) + 50);
this.score = new ScoreKeeper();
addChild(this.score);
addChild(this.money);
addChild(this.player);
stage.addEventListener(Event.ENTER_FRAME, this.gameLoop);
}
And now we add some type casting to fix the last 3 errors.
replace:
addChild(this.score);
addChild(this.money);
addChild(this.player);
with:
addChild(this.score as DisplayObject);
addChild(this.money as DisplayObject);
addChild(this.player as DisplayObject);
and compile. with any luck, you have no errors, it compiles, loads the SWF and runs perfectly!
If not, try download the source of the finished code and try and figure out what went wrong.
Congratulations! you've successfully overrided your first class!
Now, onto doing something useful.
We'll double player speed and make it so that each "money" pickup gives us 1,000 points.
First, we'll start with the money hack, because the player speed hack is a little more complicated (If you're feeling confident/bored, you can skip to the player speed hack, as it teaches more important stuff).
This one is simple and straightforward.
you'll need a new package (class locations need to be mirrored) called UnhackableEngine, and in there a new class called ScoreKeeper.
Copy and paste the ScoreKeeper code from the decompiler, add this line of code to your document classes variable definitions to make sure it gets compiled in:
private var scoreKeeper:ScoreKeeper;
and compile.
You'll get an error.
Don't worry, it's easy to fix.
Our problem is that variables are not being casted from int/whatever to string, so the compiler is getting shitty with us.
replace the two occurrences of:
score.text = gameScore;
with:
score.text = String(gameScore);
and compile.
It should compile and work without errors.
Now, let's take a look at the addMoney function:
static function addMoney()
{
var _loc_2:* = gameScore + 1;
gameScore = _loc_2;
score.text = String(gameScore);
return;
}
seems easy enough to modify. Let's chuck some 0s in there
static function addMoney()
{
var _loc_2:* = gameScore + 1000;
gameScore = _loc_2;
score.text = String(gameScore);
return;
}
and boom, money pickups now give us 1000 score.
Onto player movement, and advanced class overriding!
I'm sure you know the drill by now.
Create a new class in the UnhackableEngine package named Player.
C+P the code from the decompiler, add a reference to the class in your document class, try to compile and see what errors you get.
Ooh, we get a new, nasty one.
The definition of base class Thing was not found.
We have two options here, overriding the Thing class will solve this problem, but imagine if Thing extended another custom class, which extended another custom class, which ended up being a class chain 20 classes long? it would be impractical to override them all.
But how can you possibly get around it? you can't just dynamically extend classes. That goes directly against AS3s standards. Luckily, in AS3 there's this nasty little thing called the Proxy class that goes against all of AS3s conventions, and makes this possible.
Although we cannot actually dynamically extend classes, we can pretend we do using the Proxy class to dynamically pretend we have properties of classes which we actually don't.
I'm going to warn you now, everything's about to get messy. Which is why I'm stalling.
I guess I'll explain the Proxy class a little, seems like it's the best way to teach this.
The Proxy class allows you to dynamically change the behavior of an object. When set up, you can make it so that if a property is accessed and doesn't exist in an object, a proxy function is called that can deal with it. we use this functionality to make an object act as if it has the properties of another object by making any attempt to access a property that doesn't exist on the object go to the object it is pretending to extend.
Hopefully, the code will help explain what I mean for those who are still confused...
First thing we need to do is make the Player class extend the Proxy class.
replace:
public class Player extends Thing
with:
public class Player extends Proxy
now, add these variables to the Player classes variable definitions:
public var extendedClass:Class = getDefinitionByName("UnhackableEngine.Thing") as Class;
public var extended:Object
add these functions to the class:
override flash_proxy function getProperty(name:*):*
{
return extended[name];
}
override flash_proxy function setProperty(name:*,value:*):void
{
extended[name] = value;
}
override flash_proxy function callProperty(name:*, ...rest):*
{
extended[name].apply(rest);
}
these functions are the backbone of our Proxy hack. We don't actually need most (or any) of them. in most situations, you'll need them, though. There are more Proxy functions you may need in other circumstances, but these are the main ones.
We're gonna have to do quite a bit of modifying to make this class work with us.
Any internal references in the player class to the class it extends need to be changed.
replace:
public function Player(param1, param2)
{
fillColour = 11141120;
this.playerX = param1;
this.playerY = param2;
this.addEventListener(Event.ADDED_TO_STAGE, this.addListeners);
super(param1, param2);
return;
}
with:
public function Player(param1, param2)
{
extended = new extendedClass(param1, param2);
extended.fillColour = 11141120;
extended.drawStuff();
this.playerX = param1;
this.playerY = param2;
extended.addEventListener(Event.ADDED_TO_STAGE, this.addListeners);
return;
}
and
public function doMove()
{
this.playerX = this.playerX + this.xVel * 5;
this.playerY = this.playerY + this.yVel * 5;
drawX = this.playerX;
drawY = this.playerY;
drawStuff();
return;
}
with:
public function doMove()
{
this.playerX = this.playerX + this.xVel * 5;
this.playerY = this.playerY + this.yVel * 5;
extended.drawX = this.playerX;
extended.drawY = this.playerY;
extended.drawStuff();
return;
}
and
private function addListeners(event:Event) : void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, this.keyDownListener);
stage.addEventListener(KeyboardEvent.KEY_UP, this.keyUpListener);
return;
}
with:
private function addListeners(event:Event):void
{
extended.stage.addEventListener(KeyboardEvent.KEY_DOWN, this.keyDownListener);
extended.stage.addEventListener(KeyboardEvent.KEY_UP, this.keyUpListener);
return;
}
As you can tell, the Proxy hack can be a bit messy. sometimes, it's better to just override the class it extends as well. cause now where up to the next problem: type casting.
A Proxy object can't be casted to anything the object it's pretending to extend can. And the addChild function which the player object is given as a parameter to expects a DisplayObject. luckily, we're already overriding the class that calls the function, so go back to the Unhackable class and
replace:
addChild(this.player as DisplayObject);
with:
addChild(this.player.extended as DisplayObject);
compile that and it should work error-free.
The Player class is FINALLY set up for modification (again, the proxy hack isn't really made for this situation, but it's useful to know how to do it).
One quick modification and we'll have double player speed.
change
this.playerX = this.playerX + this.xVel * 5;
this.playerY = this.playerY + this.yVel * 5;
to
this.playerX = this.playerX + this.xVel * 10;
this.playerY = this.playerY + this.yVel * 10;
And we're done!
Download the source for this tutorial here.
Thursday, November 1, 2012
A momentary lapse of progress
So, what's that running through your head right now? something on the lines of "Hey, Bmanatee, you haven't updated this blog in a while... are you dead? What's happening with BPE?" I bet. No? well, why the hell isn't it?
Anyway, BPE has been put on hold while I study for exams (I'll continue working on it near the end of November).
With any luck, strait IP hooks will be added next release (in the form of my pre-hook system). And hopefully I'll do some more work on PEW files, too.
When that's all done and dusted, and I feel the plugin system has been developed enough, I'll move from Pre-Apha phase to Alpha phase and start working on the analyzer part of BPE.
I'm also going to try and write some more complicated plugins for games when I get the time, maybe even a packet-based aimbot. Maybe I'll write a plugin for a game with some basic connection security (eg. data + hash, which would conventionally be nigh impossible to edit using a packet editor without completely replacing the packet).
Anyway, BPE has been put on hold while I study for exams (I'll continue working on it near the end of November).
With any luck, strait IP hooks will be added next release (in the form of my pre-hook system). And hopefully I'll do some more work on PEW files, too.
When that's all done and dusted, and I feel the plugin system has been developed enough, I'll move from Pre-Apha phase to Alpha phase and start working on the analyzer part of BPE.
I'm also going to try and write some more complicated plugins for games when I get the time, maybe even a packet-based aimbot. Maybe I'll write a plugin for a game with some basic connection security (eg. data + hash, which would conventionally be nigh impossible to edit using a packet editor without completely replacing the packet).
Monday, October 8, 2012
BPE Plugin Writing Tutorial #1 (Writing your first plugin)
So, I thought it was about damn time I wrote a tutorial on writing plugins for BPE (Mostly because currently I'm the only person who knows how).
Firstly, I've been updating the Wiki, so hopefully between this tutorial and the Wiki, there should be enough information for people to start writing plugins.
and now the tutorial:
Writing your first plugin.
So, we're gonna make a nice, simple plugin that simply outputs everything happening on the servers/ports being listened to.
It'll do the following:
Properly set up it's window
Output all sent/recieved packets
Output when connections are opened/closed
Now, let me explain a little about the hook system BPE uses. there are two kinds of hooks:
Hooks called by BPE, and
Hooks called by the plugin.
Hooks called by BPE are utilized by creating a public function in the document class of the plugin.
eg:
That above code would be called every time a packet is sent by the client. the variable "packet" contains the payload (data) from the packet in the form of a ByteArray. socketID is an integer containing the ID of the socket. The function returns the unmodified packet, so no modification is made.
Hooks called by the plugin are utilized by creating a public Function variable in the document class of the plugin, and then calling that variable/Function when you need to.
eg:
That above code (when someFunction is called) will scale the size of the window so that the stage is 550 pixels wide and 400 pixels high, then set the plugins window title to say "Debug".
Also note that all used hooks must be specified in the .pep file that goes with the plugin (more on that later, though).
Anyways, I hope that's enough explanation for understanding the hooking system for now. let's get on to making the actual plugin!
I'm going to assume you know your way around Flash and know a little AS3 at this point.
So, create a new AS3 project and a document class called "BPEDebugPlugin".
now, we're gonna be using ByteArray's (for the sent and received data) and TextFields (for the output), so go ahead and add these lines to the includes:
Now, we're gonna need to declare a couple variables in the class.
Firstly, since we want to set the window size and title, we want to use the updateWindow hook, so we need to add a Function variable with the name updateWindow.
Secondly, we want a TextField that we can write our outputted data to.
so, add these lines to your class variable declarations
we're gonna make use of the finishPluginSetup hook. this simple hook function is called after your plugins hooks have been set up and your plugin has been added to the stage. it basically tells you it is now safe to use hooks and access the stage.
Chuck this code right after the end of your constructor function:
As stated before, this function will be called once, when BPE has added it to the stage and set up all it's hooks. it calls the updateWindow hook and changes the window size and label. it will then set up the output TextField for use.
Now, let's get to the actually useful hooks. We'll start with the send and receive hooks, since they're super-similar, and quite simple.
These functions will be called by BPE every time a packet is sent by the client or received by the client. packet is the ByteArray containing the data payload of the packet, and socketID is the ID number for the socket. We'll output the data being sent in the packet.
This is probably a good time to introduce you to BPE's socket ID system. each socket that connects to BPE is given an ID to make them easy to keep track of.
The first socket to connect is given the ID 0
the second 1
the third 2
ect.
The functions then output the sent/recieved data along with the socket ID.
The ByteArray returned by these functions is then run through any remaining plugins and either sent to the client or server depending on whether the packet is being received or sent.
Since we're returning the same, unmodified ByteArray that was the input of the function, the packet is left untouched. if you return an empty ByteArray, the packet is dropped.
Onto the socketOpen and socketClose hooks.
The socketOpenHook is run every time a socket connects to BPE. it gives you the new socket's ID, the address it's attempting to connect to and the port on which it's attempting to connect to. We'll output the address and port on the server it's attempting to connect to.
Next is the socketCloseHook.
The socketCloseHook is called when the server disconnects the client. The Boolean closeSocket tells you whether BPE plans on disconnecting the client. if true, the socket is to be disconnected, if false, the socket connected to the client will stay connected. We'll return the closeSocket value given to us to let the other plugins or BPE decide what to do with the socket connected to the client.
Now, compile that sucker and we're up to creating the .pep file to load our plugin.
PEP files are like an external header for the plugin. it tells BPE everything it needs to know to run your plugin.
I created a simple little tool making it easy to generate the .pep file for your plugin. you can get it here or on the downloads page.
Open the PEP Builder up (do it in your browser if you have to).
For plugin name, type "BPEDebug".
For SWF Filename, write the name of your SWF (mine is "BPEDebug.swf")
and we need to tick the box next to each hook we used
tick the box next to hookUpdateWindow, hookFinishPluginSetup, hookRecievePacket, hookSendPacket, hookSocketOpen and hookSocketClose.
Once you've done that, click the "Save PEP File" button, and save it to the same location as your plugin SWF.
You're done!
Load your plugin with BPE, hook a server and port (web servers are the easiest for testing), and if it works, give yourself a pat on the back.
If it doesn't work, try again or leave a comment.
Here's a link to my finished source.
Firstly, I've been updating the Wiki, so hopefully between this tutorial and the Wiki, there should be enough information for people to start writing plugins.
and now the tutorial:
Writing your first plugin.
So, we're gonna make a nice, simple plugin that simply outputs everything happening on the servers/ports being listened to.
It'll do the following:
Properly set up it's window
Output all sent/recieved packets
Output when connections are opened/closed
Now, let me explain a little about the hook system BPE uses. there are two kinds of hooks:
Hooks called by BPE, and
Hooks called by the plugin.
Hooks called by BPE are utilized by creating a public function in the document class of the plugin.
eg:
public function sendPacketHook(packet:ByteArray,socketID:int):ByteArray
{
output.appendText("["+socketID+"] Sent:"+packet+"\n")
return packet;
}
That above code would be called every time a packet is sent by the client. the variable "packet" contains the payload (data) from the packet in the form of a ByteArray. socketID is an integer containing the ID of the socket. The function returns the unmodified packet, so no modification is made.
Hooks called by the plugin are utilized by creating a public Function variable in the document class of the plugin, and then calling that variable/Function when you need to.
eg:
public var updateWindow:Function;
public function someFunction():void
{
updateWindow(550,400,"Debug"); as
return;
}
That above code (when someFunction is called) will scale the size of the window so that the stage is 550 pixels wide and 400 pixels high, then set the plugins window title to say "Debug".
Also note that all used hooks must be specified in the .pep file that goes with the plugin (more on that later, though).
Anyways, I hope that's enough explanation for understanding the hooking system for now. let's get on to making the actual plugin!
I'm going to assume you know your way around Flash and know a little AS3 at this point.
So, create a new AS3 project and a document class called "BPEDebugPlugin".
now, we're gonna be using ByteArray's (for the sent and received data) and TextFields (for the output), so go ahead and add these lines to the includes:
import flash.text.TextField;
import flash.utils.ByteArray;
Now, we're gonna need to declare a couple variables in the class.
Firstly, since we want to set the window size and title, we want to use the updateWindow hook, so we need to add a Function variable with the name updateWindow.
Secondly, we want a TextField that we can write our outputted data to.
so, add these lines to your class variable declarations
public var updateWindow:Function;
private var output:TextField = new TextField();
we're gonna make use of the finishPluginSetup hook. this simple hook function is called after your plugins hooks have been set up and your plugin has been added to the stage. it basically tells you it is now safe to use hooks and access the stage.
Chuck this code right after the end of your constructor function:
public function finishPluginSetup()
{
updateWindow(550,400,"Debug");
output.x = 20;
output.y = 20;
output.width = 510;
output.height = 360;
output.background = true;
output.backgroundColor = 0xAAAAAA;
output.text = "Output\n";
this.addChild(output);
}
As stated before, this function will be called once, when BPE has added it to the stage and set up all it's hooks. it calls the updateWindow hook and changes the window size and label. it will then set up the output TextField for use.
Now, let's get to the actually useful hooks. We'll start with the send and receive hooks, since they're super-similar, and quite simple.
public function recievePacketHook(packet:ByteArray,socketID:int):ByteArray
{
output.appendText("["+socketID+"] Recieved:"+packet+"\n")
return packet;
}
public function sendPacketHook(packet:ByteArray,socketID:int):ByteArray
{
output.appendText("["+socketID+"] Sent:"+packet+"\n")
return packet;
}
These functions will be called by BPE every time a packet is sent by the client or received by the client. packet is the ByteArray containing the data payload of the packet, and socketID is the ID number for the socket. We'll output the data being sent in the packet.
This is probably a good time to introduce you to BPE's socket ID system. each socket that connects to BPE is given an ID to make them easy to keep track of.
The first socket to connect is given the ID 0
the second 1
the third 2
ect.
The functions then output the sent/recieved data along with the socket ID.
The ByteArray returned by these functions is then run through any remaining plugins and either sent to the client or server depending on whether the packet is being received or sent.
Since we're returning the same, unmodified ByteArray that was the input of the function, the packet is left untouched. if you return an empty ByteArray, the packet is dropped.
Onto the socketOpen and socketClose hooks.
public function socketOpenHook(socketID:int,address:String,port:int):void
{
output.appendText("["+socketID+"] Connected to:"+address+":"+port+"\n")
return;
}
The socketOpenHook is run every time a socket connects to BPE. it gives you the new socket's ID, the address it's attempting to connect to and the port on which it's attempting to connect to. We'll output the address and port on the server it's attempting to connect to.
Next is the socketCloseHook.
public function socketCloseHook(socketID:int,closeSocket:Boolean):Boolean
{
output.appendText("["+socketID+"] Disconnected, "+closeSocket+"\n")
return closeSocket;
}
The socketCloseHook is called when the server disconnects the client. The Boolean closeSocket tells you whether BPE plans on disconnecting the client. if true, the socket is to be disconnected, if false, the socket connected to the client will stay connected. We'll return the closeSocket value given to us to let the other plugins or BPE decide what to do with the socket connected to the client.
Now, compile that sucker and we're up to creating the .pep file to load our plugin.
PEP files are like an external header for the plugin. it tells BPE everything it needs to know to run your plugin.
I created a simple little tool making it easy to generate the .pep file for your plugin. you can get it here or on the downloads page.
Open the PEP Builder up (do it in your browser if you have to).
For plugin name, type "BPEDebug".
For SWF Filename, write the name of your SWF (mine is "BPEDebug.swf")
and we need to tick the box next to each hook we used
tick the box next to hookUpdateWindow, hookFinishPluginSetup, hookRecievePacket, hookSendPacket, hookSocketOpen and hookSocketClose.
Once you've done that, click the "Save PEP File" button, and save it to the same location as your plugin SWF.
You're done!
Load your plugin with BPE, hook a server and port (web servers are the easiest for testing), and if it works, give yourself a pat on the back.
If it doesn't work, try again or leave a comment.
Here's a link to my finished source.
Subscribe to:
Posts (Atom)