PDA

نسخه کامل مشاهده نسخه کامل : ساخت Trainer در C



ALt3rnA
14-06-2006, 15:45
منبع یکی از دوستانم







Simple In-game Trainer Menus

----------------------------
Author: Orr


NOTE!
This tutorial is _Definetly_ NOT for newbies. Best read with NOTEPAD.

Introduction
------------
Say you made a trainer with 10 or more options. The game you trained uses routines to
protect against Alt+Tabbing outside the game. Say that the gamer using your trainer
forgot what are the trainers options, or he forgot what keys to use. He can do two
things now. Quit the game, or try to press all the keys and see how it affects him.
Is there a solution for this kind of situation? Well, There is!

The method I will suggest in this tutorial was not invented by me. As far as I know,
it was already done in the old DOS days. That method is called Ingame Trainer Menus.
The purpose, is to show the trainer option menu, inside the game, when the user hits
a hotkey.

What I will show in the tutorial, is how to make a trainer with one hotkey, that when
pressed, will pop up a Message Box from inside my favorite target game: (pam pam pam!!)
"The House of the Dead 2".

The tools I will be using are SoftICE, IDA, HIEW, and Visual C++ (not a must).


Theory
------
Basically the idea I will suggest works like that:

1. The user presses the menu hotkey.
2. The Trainer injects some code to a free space in the game's memory.
3. The Trainer overwrites a place in the gameloop.
4. The code injected will be run (the code is a messagebox) by the game.
5. The Trainer fixes the place it overwritten in the gameloop.

In case you don't know how to perform in-mem code injections, I suggest you go read
alittle about it in [SHEEP]'s tutorial, or keep reading on, as I will explain some
fundumentals of injections.


Finding a Game Loop
-------------------
A Problem arises with what we want to do. We want to inject code to the game, and have
the game run it by itself. Injecting the code isn't much of a problem, it is actually
quite easy. But how do we make the GAME run OUR code?

The solution is quite simple.

If we find a place that is getting executed ALL the time (like, in a huge loop :), we
could locate a good place to patch there, and inject our code to am empty space. The
question is, how do we find a place, a loop that runs all the time?

Basically, what I did was, whiile playing that game alittle, I poped SoftICE for several
times, until I saw I am in the correct process (look in the bottom-right corner of SoftICE
for the CLSID), in my case it is HOD2. I poped SoftICE in times that I wasn't doing much,
so I would see what code is executed even when I am IDLE.

After poping up in a place that looked OK, I began tracing alot. Some cases I did it
manually, and some cases I did it using the T command (T 100 will trace 100 instructions).
After a while, I saw that some loop is being executed alot of times, so I wanted to check
it out. I disassembled the file with IDA, and got to that location. I am terribly sorry
to tell you I really forgot what location it was... What I did though, was seeing what
function that location was, and then seeing who calls it... for example:


.text:004A4EA0 sub_4A4EA0 proc near ; CODE XREF: sub_4A41C0+142p
.text:004A4EA0 push ebx
.text:004A4EA1 push ebp
:
:
:
.text:004A4F47 test ah, 41h ; Say, this location :)
:
:
:
.text:004A4FDA pop ebp
.text:004A4FDB pop ebx
.text:004A4FDC retn
.text:004A4FDC sub_4A4EA0 endp


This function is called from the location sub_4A41C0. So I went there. and there
I found a cool place that executed many API's. Anyway, I chose this location:

.text:004A5967 push ecx ; lpMsg
.text:004A5968 call ds:GetMessageA
.text:004A596E test eax, eax

Why? Because GetMessage is a Windows API that gets executed all the time. I checked
for my suspicion by simply setting a breakpoint at that location, and I saw that
I couldn't even play for one sec, because SoftICE kept popping after I pressed F11.

Also, I am a fan of overwriting API calls. Why?
a) They have a sufficient amount of OPCodes (6, in many cases).
b) They can be executed later on from anywhere in the program, with the same opcodes.
c) Because Micro$oft coders did them (and because I couldn't find another reason :)

OK, So we found a place to overwrite with our jump... now we actually need a place
to jump to!

To summarize:
You can do 2 things in order to find a place that is getting executed all the time:

- Find a place that loops alot manually, by simply stopping the game in an IDLE
point, and trace from there. Tracing can be done manually, or it can be done
using the T command in SoftICE.

- Breakpoint on known API's that are likely to get executed all the time:
GetMessage, GetTickCount.


Finding a Place to Inject
-------------------------
OK, This is my favorite part.

Windows EXE's are based on the PE (Portable Executable) file format. The PE format
supports sectioning of the file. Every section of the file has a different job.
There are Code/Data/Resource/Import/Export/etc sections. Most sections are different
in size, so they all must be aligned. Because of that nice feature compilers leave
us, there are often alot of 'dead' NULL bytes, that are simply wasted just to align
the section size. There is a difference between those code caves, because these are
mapped to memory, while there may be cases you will see empty places, but they won't
be mapped into memory, thus you cannot jump to them.

There are few ways to find the alignments in the exe:

1. You simply scroll through the entire EXE looking for those alignments. Once you
see empty spaces, you check if they are indeed code caves (later on how to check).

2. In a hex editor, look for a binary string that contains nothing but 00's. It will bring
you to many odd places, but eventually to a cave.

3. You do the "proffesional" way. In IDA (or any other PE editor), we get some information
about the sections. We go to the beginning of the code (generally on top), and we see this:

.text:00401000 ; File Name : D:\Games\THoTD2\Hod2.exe
.text:00401000 ; Format : Portable executable for IBM PC (PE)
.text:00401000 ! ; Section 1. (virtual address 00001000)
.text:00401000 ! ; Virtual size : 000C1940 ( 792896.)
.text:00401000 ; Section size in file : 000C2000 ( 794624.)
.text:00401000 ; Offset to raw data for section: 00001000
.text:00401000 ; Flags 60000020: Text Executable Readable
.text:00401000 ; Alignment : 16 bytes ?
.text:00401000 ; OS type : MS Windows
.text:00401000 ; Application type: Executable 32bit


You see that the Virtual Address is 1000, and that the Virtual Size is C1940?
You add those up together, and you get C2940. You go to that OFFSET in the file, and you
will see a nice and clean code cave. :)

In order to check if this is indeed a CODE cave, and not just a dead cave, in HIEW, you
notice if there is a dot (.) before the address of not. The address will be 4C2940, if you
see this: .004C2940, then this is code... if you see just 004C2940 then it won't work.
Trust me on this one, I spent a lot of hours figuring why it didn't work on some injection
I was working on a while ago.


What to Inject?
---------------
OK, So we know where to jump from, and where to jump to. But all of this is useles unless
we inject something! In this tutorial, I will show how to inject a simple MessageBox.

A standard MessageBoxA call looks like that:

push Style
push Caption
push Text
push WindowHandle
call MessageBoxA

But remember, that we have overwritten an API... so we need to execute it again, and jump
to the location we came from (actually we jump to the instruction after the API call):

call GetMessage
jmp 4A596E

After that, we need to actually inject the text for MessageBox caption and text. So I chose
location 4C2970 for the caption, and 4C2980 for the actual text. The style will be left 0.
So we have this code now:

push 0
push 4C2970
push 4C2980
push 0
call MessageBoxA
call GetMessage
jmp 4A596E

But this code won't work... because we push 0 as the window handle. If we use 0 as window
handle, then the MessageBox will be shown OUTSIDE the game, and sometimes cause it to
crash. So how do we solve this? We need to find the window handle, and push it. Basically
the Window Handle is saved in a variable after the window was created. So we go back to
IDA, and we track down the CreateWindowExA function. We see where it is referenced from,
and we find this location:

.text:004A5885 call ds:CreateWindowExA
.text:004A588B test eax, eax
.text:004A588D mov dword_7DC8AC, eax

So we see that the hWnd is saved in a global variable which is located inside the
memory address 7DC8AC. So now, we have to get that value, and push it, instead of push 0:

push 0
push 4C2970
push 4C2980
mov eax, [7DC8AC]
push eax
call MessageBoxA
call GetMessage
jmp 4A596E


OK, now we get a little practical and summarize what we have:

1. A place to jump from : 4A5968
2. A place to jump to : 4C2949 (not 4C2940, because I want to leave some space)
3. A place to put strings: 4C2970
4. A place to return to : 4A596E

Make a copy of hod2.exe, and name if hod2_.exe or whatever. We will be doing all the
changes to this one. Open up HIEW, select HOD2_.exe, and then press F4 and go to DECODE
mode. Press F5, and type ".4A5968" (Without quotes ofcourse). Now you are in this loc:

.text:004A5968 call ds:GetMessageA

Press F3 (to be in EDIT mode), and then press F2 (to be in ASSEMBLE mode), and type this:
jmp 4C2949 [Enter]
nop [Enter]
[Escape]

Press F9 to update.

now go to the cave (.4C2949), and assemble the code block we wanted to add (see above).
For API's you cannot assemble, so you will have to leave 6 nop's for each API. how to
add an API? Simply. Do you remember that I told you that it can be executed from anywhere
in the program, and also with the same opcodes all the time? Simply go to a location
that calls GetMessage (4A5968), and a location that calls MessageBoxA (49E148), and copy
the opcodes (FF 15 xx xx xx xx).

After that go to add the strings (F3 and then TAB), and simply write them. Remember!
In order to separate strings there has to be a 00 between them:

.004C2970: 54 72 61 69-6E 65 72 20-4F 70 74 69-6F 6E 73 00 Trainer Options
.004C2980: 48 69 21 Hi!


OK, I believe we are all set.


The Trainer
-----------

This is how the source of the trainer looks like:

#include <windows.h>
#include "resource.h"

// Define sizes for writing into memory.
#define OPT1 6
#define OPT2 58


char wname[]="The House of the Dead 2"; // Window Name
BYTE opt1[OPT1]={0x90,0xE9,0xDC,0xCF,0x01,0x00}; // Jump my_injection
BYTE opt1_off[OPT1]={0xFF,0x15,0x34,0x32,0x4C,0x00}; // Call GetMessage();

// The rest of the injection
BYTE opt2[OPT2]={0x90,0x6A,0x00,0x68,0x70,0x29,0x4C,0x00,0x68,0x8 0,0x29,0x4C,0x00,\
0xA1,0xAC,0xC8,0x7D,0x00,0x50,0xFF,0x15,0xFC,0x31, 0x4C,0x00,0xFF,\
0x15,0x34,0x32,0x4C,0x00,0xE9,0x01,0x30,0xFE,0xFF, 0x00,0x00,0x00,\
0x54,0x72,0x61,0x69,0x6E,0x65,0x72,0x20,0x4F,0x70, 0x74,0x69,0x6F,\
0x6E,0x73,0x00,0x48,0x69,0x21};


LRESULT CALLBACK main (HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
HWND g;


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// Basic Windows API main entry

hInst = hInstance;
DialogBox(hInst, MAKEINTRESOURCE( IDD_DIALOG1 ), 0, (DLGPROC)main);
return(0);
}


int Write(char windowname[], long address, BYTE *writearr, long sizeofarr)
{

// My WRITE engine

HWND hwnd;
HANDLE phandle;
DWORD pid,bytesw;

hwnd = FindWindow(0, windowname);
if (hwnd == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Find Game Window!");
goto quit;
}

GetWindowThreadProcessId(hwnd, (unsigned long *)&pid);

phandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (phandle == 0) {
SetDlgItemText(g, ID_EDIT1, "Error: Cannot Open Game Process!");
goto quit;
}

WriteProcessMemory(phandle, (void *)(address), &writearr[0],sizeofarr, &bytesw);
return(1);

quit:
return(0);
}


BOOL GetKeyPress(int key)
{
// HotKey handling routine
return ((GetAsyncKeyState(key) & 1)==1);
}


VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
// This is the actual thing!
{
if (GetKeyPress(VK_F4)) { // If F4 was pressed
Write(wname, 0x4C2949, opt2, OPT2); // Write The injection
Write(wname, 0x4A5968, opt1, OPT1); // Patch the call
Sleep(2000); // Wait a little (2 seconds)
Write(wname, 0x4A5968, opt1_off, OPT1); // Change back the call
}
}


LRESULT CALLBACK main(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

// Main Message function

g = hDlg;
switch (uMsg)
{
case WM_INITDIALOG:
SetTimer(hDlg,0, 100, TimerProc);
break;

case WM_COMMAND:
if (wParam == ID_QUIT) ExitProcess(0x31337);
break;

default : return(FALSE);
}

return(TRUE);
}




Explanation:
What I did, was writing all the injected bytes into memory. First I wrote the injection,
then I Patched the place to jump from, then waited for 2 seconds, and then patched it
back again. I didn't bother to Zero out all the injection, because it won't get executed
anyway.


Ending
------
Phew! That was a lot to write! I have been working 2 days on this menu + another day
actually WRITING this. Looking back, it wasn't very tough, I just had to reboot alot
due to blue screens and other sorts of page faults and weird exceptions.

What you have to keep in mind while doing an ingame menu, is:

1. Finding a place that runs all the time.
2. Finding a code cave.
3. Adding your code, followed by doing the instructions you overwritten.
4. Finally jumping back to the place.

There can be many problems and diffuculties that can occur. For example, what happens
if you don't find a global variable that contains the Window Handle? For that case you
can simply use FindWindow(0,"Window Name"). But what happens if you don't have FindWindow
imported in the EXE? You can import it like this:

push offset "User32.dll" ; Find the address of User32.DLL in memory
call GetModuleHandle ; eax contains the address

push offset "FindWindowA" ; Function to find
push eax ; what DLL? (the one we found eariler)
call GetProcAddress ; eax contains the address of the function

push offset "Window Name" ; What window name?
push 0 ; What CLSID?
call eax ; call FindWindowA

Finally, my little advice, BE CREATIVE. Think of more ideas, like adding DIALOG BOXES, with
many more options, or perhaps even injecting the ENTIRE trainer to the game, so you wouldn't
even have to use an external program besides a memory patcher.

Attached to this package is the trainer source, and a nice pic hehe :)

BioHazard
14-06-2006, 17:44
سلام
مرسی گیم هکر جان
عالی بود

ALt3rnA
15-06-2006, 17:06
خواهش میکنم قابل نداشت

Dash Ashki
15-06-2006, 18:14
سلام
gamehackir جان میتونی بگی ترینر اصلا چیه و کجا ازش استفاده میکنند

ALt3rnA
19-06-2006, 14:49
[ برای مشاهده لینک ، لطفا با نام کاربری خود وارد شوید یا ثبت نام کنید ]

لبته کامل نیست