What Is ModTools.h? This is the main point of this article, modtools.h is a class that i made to facilitate codecaving and hijacking other programs. It should be known that this example is for starcraft but modtools could work with any program (mostly) as long as you can inject the .dll it should work.
Intended audience: People who know how to program using c++ and classes but may not know the in-out of codecaves and such. Or, just people who want a quick easy way to make codecaves and mods. You should be well versed with c++ and know at least how to mov and pushad/popad in asm.
Purpose: To show people how to use the ModTools class to quickly make mods. This tutorial is not a in depth "how to make a unit alert" if you want that look at yonders tutorial. This tutorial will just get you started making a unit alert. Also I dont show how I got the offsets we use until the end (Appendix).
Software Used:
Visual Studio 2008
Windows XP (this tut might not work in vista)
Cheat engine - not needed
Olly debug - not needed
Windows Calculator - great tool
Date: 11/18/08
Author: zonemikel
SCVer: 1.15.3
TIME: it took me about 2 hours to do this while writing the tutorial alongside, and then i came back and revised it later took me like 30 minutes to revise. It should take you about 30 minutes to do everything.
Revised: 11/19/08, it actually prints out all units and the player that made them now. See screen shot.
Steps
- Create a new VS project
- Set up the ModTools class and includes
- Call the constructor with the right variables
- Create a function for our code cave
- Setup our code cave using the class and nop out the garbage
- use printf statments to print the unit type to our debug console
Note: This class is a work in progress, if you find anything wrong with it or think of better ways to do stuff let me know.
Thanks: Yonder, Jakor and others (like hellinsect)
Create a new VS project
Setup a VS 2008 project to work as a .dll
- Start visual studio and create a new project of type "win32 project"
- Name it UnitAlert click OK
- (IMPORTANT) click next, not finish
- Under application type click DLL
- Now click finish
Set up the ModTools class and includes
Insert the ModTools.h class into your header files
- Download ModTools.h
- Right click on header files
- Add -> Existing Item
- Navagate to where you put Modtools.h, select it
- Click add
- (IMPORTANT) also copy the file ModTools.h to your UnitAlert\UnitAlert directory
You must now add all the includes that I used
- Double click stdafx.h to open it
- type these lines in at the bottom
PHP Code:
#include <stdio.h>
#include <iostream>
#include <io.h>
#include <stdio.h>
#include <fstream>
using namespace std;
Now we include ModTools.h in your UnitAlert.cpp
- Double click UnitAlert.cpp
- Type in this line just below #include stdafx.h
PHP Code:
#include "ModTools.h"
Now is a great time to try and compile to make sure everything works !
Call the constructor with the right variables
There are three constructors, we will use the third
Before we can call the constructor we need to create what i call a "engine" , this will be the heart of your program. It will be run every 10milliseconds in the thread that will be created. So type this in your program
PHP Code:
long WINAPI myEngine(long lparam)
{
mt.Console(); // start a console for debugging output
// ------- stuff that runs once here !!
while(1){ // this goes forever
Sleep(10); // ~10 millisecond delay so it dont lag
if(GetAsyncKeyState(VK_F12) == -32767) // if they hit F12
{
mt.Console(); // toggle console on/off
}
}
return 0;
}
From there we can call the constructor. From there you can add a declaration or put this below the "engine", you should know what i mean. Anyway add this code.
PHP Code:
ModTools mt("brood war", &myEngine);
Now is a good time to compile to make sure it all works
Create a function for our code cave
We now create the function for our jmp patch
One of the neat things about my class is that you can use normal functions as code caves. The function stripJmpPatch() will search through the jmps and find your function. It will also strip off the first part of your function so it does not have the c++ code, just your asm.
The drawback of this are thus:
The first line of your code cave function must be __asm{
The asm must return
Of course you can still do it the way most people do, but for this tutorial ill show how to use stripJmpPatch.
Before we can patch to our codecave function we need to create it so type this in at the bottom somewhere then declare it at the top.
PHP Code:
void myCodeCave1()
{
__asm{
PUSHAD
MOV newUnitPtr, ESI // save location of new unit
POPAD
// replace the line of code we nop'd
MOV DWORD PTR DS:[ECX*0x04+0x6283E0],ESI
JMP returnPt // return to after our jmppatch
}
}
this code gets pointers to all newly created units and stores it in the variable newUnitPtr, so create that var in a global scope;
PHP Code:
DWORD newUnitPtr = 0; // pointer to new units
we also jmp retrunPt as the last line in our codecave function, that returns us to just after the place where we patched. So be sure to make that var in a global scope like so
PHP Code:
DWORD returnPt = 0x004A02BB; // return from our code cave
Now compile again make sure it works.
Setup our code cave using the class and nop out the garbage
now we actually patch to our code cave function
- go to the point in the engine where the comment "// ------- stuff that runs once here !! " and just below that line type
PHP Code:
mt.stripJmpPatch(&myCodeCave1, (PBYTE)0x004A02B6);
mt.nopIt((PBYTE)0x004A02BB, 2); // nop out the code we messed up
This will strip our function mycodecave1 and make it look like a naked function, then it will find the new location of our function through the jmps and then it will setup the jmp patch.
After that the "nopIt" nops out 2 bytes after the place where we put the patch, we replace this code in our code cave (you can look).
use printf statments to print the unit type to our debug console
We now use all the stuff we have just set up to actually do something
What we want to do is print out the unit type every time a unit is created. We know that from the unit pointer the offset to the unit type is 0x64 and the offset to the unit owner is 0x4C. There are tons of offsets if you look at my other posts.
So basically our algorithm is
if newUnitPtr != 0
print unit info and unit owner info
set newUnitPtr to 0
Pretty simple, so lets put this code in our engine just below Sleep(10), or wherever you want.
PHP Code:
if(newUnitPtr != 0)
{
printf("\n New Unit Player: 0x%X Type 0x%X",
*(BYTE*)(newUnitPtr+0x4C), // dereference player number from unitptr
*(BYTE*)(newUnitPtr+0x64) // dereference unit type from unit ptr
);
newUnitPtr = 0; // reset unit pointer to 0
}
The end
Thats it, compile it and then inject it into starcraft using a dll injector or a free program like RemoteDLL.
FINAL NOTE: I fixed this up so it now shows the player and the unit type. Its your job now to make units that you want to be alerted of like lurkers and dt's and record their type. Then change your if statment to only print out if its a unit you care about, which should be pretty easy, good luck!
Also i tried to add the whole UnitAlert project but bwhacks like wont let me upload it , it times out you can dl it
here its 6meg.
And of course you dont want it to print out stuff in the debug console you want it to print out in starcraft. Im not including anything like "bwpubprint" in modtools.h because printing to starcrafts screen is unique to starcraft. I want modtools.h to be modular and work with any application, i have functions like bwpubprint and such in another header called scfxn.h, i might write a tutorial about that later but im not finished with it yet.
Download the entire ProjectAfter deleting some stuff from the project i got it small enough to upload to bwhacks. You can download the entire
working project (1.5.3) from here.
This is what your unitalert.cpp should look like
PHP Code:
// UnitAlert.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "ModTools.h"
long WINAPI myEngine(long lparam);
void myCodeCave1();
DWORD newUnitPtr = 0; // unit type
DWORD returnPt = 0x004A02BB; // return from our code cave
ModTools mt("brood war", &myEngine);
long WINAPI myEngine(long lparam)
{
mt.Console(); // start a console for debugging output
// ------- stuff that runs once here !!
mt.stripJmpPatch(&myCodeCave1, (PBYTE)0x004A02B6);
mt.nopIt((PBYTE)0x004A02BB, 2); // nop out the code we messed up
while(1){ // this goes forever
Sleep(10); // ~10 millisecond delay so it dont lag
if(newUnitPtr != 0)
{
printf("\n New Unit Player: 0x%X Type 0x%X",
*(BYTE*)(newUnitPtr+0x4C), // dereference player number from unitptr
*(BYTE*)(newUnitPtr+0x64) // dereference unit type from unit ptr
);
newUnitPtr = 0; // reset unit pointer to 0
}
if(GetAsyncKeyState(VK_F12) == -32767) // if they hit F12
{
mt.Console(); // toggle console on/off
}
}
return 0;
}
void myCodeCave1()
{
__asm{
PUSHAD
MOV newUnitPtr, ESI // save location of new unit
POPAD
// replace the line of code we nop'd
MOV DWORD PTR DS:[ECX*0x04+0x6283E0],ESI
JMP returnPt // return to after our jmppatch
}
}