[WEEKLY SHOWCASE] More [ASSAULTCUBE] Hack Tutorials

Posts 17 of 7 · Page 1 of 1
[WEEKLY SHOWCASE] More [ASSAULTCUBE] Hack Tutorials
AC Sourcecode tells us:
Code:
playerent *ge***ient(int cn)   // ensure valid entity
{
    return players.inrange(cn) ? players[cn] : NULL;
}

void ini***ient()
{
    clientmap[0] = 0;
    newname("unarmed");
    changeteam(rnd(2), false);
}
We wan't ge***ient, but that has nothing easy to search for...
Lets take ini***ient, which has "unarmed"!

Rough estimation of what we will encounter:
1. the string "unarmed" will be somewhere near the top of the function
2. near the bottom we should find something to do with teams.

RVSF and CLA are the team names in AC, so we'll encounter one of those probably.

First unarmed I encountered with olly contined stuff with 'your current name is', so, its not the one we want.
But the second unarmed I find is a whole lot more interesting!
It contains both unarmed and team related stuff

Now if you scroll up a bit from there, you'll see this function:
Code:
004205C0  /$ 85C0           TEST EAX,EAX
004205C2  |. 7C 12          JL SHORT ac_clien.004205D6
004205C4  |. 3B05 983C4D00  CMP EAX,DWORD PTR DS:[4D3C98]
004205CA  |. 7D 0A          JGE SHORT ac_clien.004205D6
004205CC  |. 8B0D 903C4D00  MOV ECX,DWORD PTR DS:[4D3C90]
004205D2  |. 8B0481         MOV EAX,DWORD PTR DS:[ECX+EAX*4]
004205D5  |. C3             RETN
004205D6  |> 33C0           XOR EAX,EAX
004205D8  \. C3             RETN
now compare that to this:
Code:
playerent *ge***ient(int cn)   // ensure valid entity
{
    return players.inrange(cn) ? players[cn] : NULL;
}
Did we just find ourselves the function???
YES!

First off eax is tested against itself, and its followed JL(jump if lower), thts probably because there are no players for negative indexes.

next off its compared to the value at DWORD pointer 0x4D3C98, and then tested with JGE(jump if greater/equal)
Which is because there are no players after playercount-1, so if the index specified is equal to the playercount or bigger, we return 0.

Now
0x4D3C90 is moved into ECX, thats the base address for the player list.
Now take a look at this:
Code:
MOV EAX,DWORD PTR DS:[ECX+EAX*4]
What do you think that does?
if you didnt think 'oh, they add the index we specified * 4 because a pointer is 4 bytes on my 32 bit OS to the base address we just saw', then you're either a retard or you suck at assembly.

Anyway, its exactly what I just written above. They take the base pointer 0x4D3C90, add 4*index to it to get the pointer of the player we want.

Now finally some C++ code:

Code:
int playercount = *(DWORD*)0x004D3C98;
for(int i = 0; i < playercount-1; i++)
{
    DWORD pTable = *(DWORD*)0x004D3C90;
    playerent *pPlayer = (playerent*)(pTable+(0x4*playercount));
    pPlayer->health = 0;
}
Feel free to add this to the AssaultCube tutorials posted by Hell_Demon(kinda weird to talk about yourself in third person o__O)

edit: the *** is t-c-l, no idea why they block it...
More [ASSAULTCUBE] Hack Tutorials
renderhud.cpp
Code:
void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater)
{
    playerent *p = camera1->type<ENT_CAMERA ? (playerent *)camera1 : player1;
    
    ...more code here...

    if(lastmillis < damageblendmillis)
    {
        static Texture *damagetex = NULL;
        if(!damagetex) damagetex = textureload("packages/misc/damage.png", 3);
The very first line is interesting.
Code:
playerent *p = camera1->type<ENT_CAMERA ? (playerent *)camera1 : player1;
bool spectating = player1->isspectating();
ENT_CAMERA is defined as 2

Now the last line I pasted above:
Code:
if(!damagetex) damagetex = textureload("packages/misc/damage.png", 3);
We have ourselves a string

Well what do you know, its the first result you find with olly
Code:
00408F70  /$ 55             PUSH EBP
00408F71  |. 8BEC           MOV EBP,ESP
00408F73  |. 83E4 C0        AND ESP,FFFFFFC0
00408F76  |. 81EC 34010000  SUB ESP,134
00408F7C  |. A1 50E84C00    MOV EAX,DWORD PTR DS:[4CE850]
00408F81  |. 8078 6B 02     CMP BYTE PTR DS:[EAX+6B],2
00408F85  |. 8B0D 203C4D00  MOV ECX,DWORD PTR DS:[4D3C20]
00408F8B  |. 53             PUSH EBX
00408F8C  |. 56             PUSH ESI
00408F8D  |. 57             PUSH EDI
00408F8E  |. 894424 34      MOV DWORD PTR SS:[ESP+34],EAX
00408F92  |. 72 04          JB SHORT ac_clien.00408F98
00408F94  |. 894C24 34      MOV DWORD PTR SS:[ESP+34],ECX
00408F98  |> 8A41 6A        MOV AL,BYTE PTR DS:[ECX+6A]
00408F9B  |. 3C 05          CMP AL,5
So, which of these is the camera1, and which is player1(which we are interested in?)
There's multiple ways to find out
First method:
Code:
00408F7C  |. A1 50E84C00    MOV EAX,DWORD PTR DS:[4CE850]
00408F81  |. 8078 6B 02     CMP BYTE PTR DS:[EAX+6B],2 ; <- compare to 2
00408F85  |. 8B0D 203C4D00  MOV ECX,DWORD PTR DS:[4D3C20]
..more..
00408F8E  |. 894424 34      MOV DWORD PTR SS:[ESP+34],EAX
00408F92  |. 72 04          JB SHORT ac_clien.00408F98; <- below 2? jump
00408F94  |. 894C24 34      MOV DWORD PTR SS:[ESP+34],ECX
Looking at the C++ code, if it was checked to be below ENT_CAMERA, it would become camera1.
So, in assembly, if JB is taken, it was the camera, thus EAX is camera, ECX is player1

So our C++ code to get player1 is:
Code:
playerent *pPlayer1 = (playerent*)0x004D3C20;
The other way to see which is the camera1 and which is player1 is the following:
Code:
00408F98  |> 8A41 6A        MOV AL,BYTE PTR DS:[ECX+6A]
00408F9B  |. 3C 05          CMP AL,5
equiv C++ code:
Code:
player1->isspectating();
isspectating checks if the player's state is equal to CS_SPECTATE, which is 5.

So now we have our player1 pointer.
All that is left is get ourselves the function that checks if there is a wall between position 1 and 2, and we can make ourselves a fully functionl aimbot.

I'll post up the visibilty check function when I find it.
More [ASSAULTCUBE] Hack Tutorials
This one was slightly harder to find.
I know bots made use of CBot::IsVisible, but none of those contained strings.
So I wen't to look for TraceLine itself, after finding it, I chose to do Find all references

One of the references was
Code:
TraceLine(player1->o, dest, player1, true, &tr);
in BotManager, it uses player1, so it would give us a way to confirm we have the right function once we find it in olly.

So I double clicked it, and WHT THE FUCK!! YAY! ITS A COMMAND! =D
telebot!
Knowing from past usage of COMMAND, its a define takes two arguments, the first one is the name of the command and at the same time the name of the function it's calling, the second argument is what amount of arguments it has.
the define calls a function with 3 arguments, the first one being the text string, 2nd being the pointer to the function, and the third being the paramcount.

COMMAND(telebot, ARG_NONE);

"telebot" is what we will search for with olly!
it was quite easy to find, since its the only telebot command

Code:
00491BE0   . 6A 04          PUSH 4
00491BE2   . 68 90524700    PUSH ac_clien.00475290
00491BE7   . 68 0CDF4900    PUSH ac_clien.0049DF0C                   ;  ASCII "telebot"
00491BEC   . E8 8FDEFBFF    CALL ac_clien.0044FA80
00491BF1   . 83C4 0C        ADD ESP,0C
00491BF4   . A2 A0084E00    MOV BYTE PTR DS:[4E08A0],AL
00491BF9   . C3             RETN
ARG_NONE is 4(push 4, last param).
PUSH ac_clien.00475290 is the pointer to the telebot function.

Control+G in olly and go to 00475290

Code:
TraceLine(player1->o, dest, player1, true, &tr);
     if (!tr.collided)
!tr.collided = !true = false = 0

Code:
...lots of arguments...
00475368  |. E8 A365FFFF    CALL ac_clien.0046B910                   ; \ac_clien.0046B910
0047536D  |. 83C4 24        ADD ESP,24
00475370  |. 807C24 3C 00   CMP BYTE PTR SS:[ESP+3C],0 ;<-- compared to 0 ;)
00475375  |. 0F85 96000000  JNZ ac_clien.00475411
So 0x0046B910 is traceline!
Code:
void (*TraceLine)(vec from, vec to, dynent *pTracer, bool CheckPlayers, traceresult_s *tr, bool SkipTags) = (void (__cdecl *)(vec,vec,dynent *,bool,traceresult_s *,bool))0x0046B910;

bool IsVisible(vec v1, vec v2, dynent *tracer, bool SkipTags)
{
     traceresult_s tr;
     TraceLine(v1, v2, tracer, (tracer!=NULL), &tr, SkipTags);
     return !tr.collided;
}
usage:
Code:
bool bEnemyVisible = IsVisible(player1->o, players[i]->o, NULL, false);
Now you have everyting to make a fully functional aimbot
More [ASSAULTCUBE] Hack Tutorials
Had some problems with TraceLine(for some reason it teleports enemies to me)

So here's the aimbot release, currently checks if enemy and yourself are alive and on different teams if its a team game.

Aims for the closest enemy(through walls) and is bound to right mouse button.
CubeHack.rarattachment deleted · 66 downloads before removal
A new set of tutorials by HD. I will be showcasing them in this sticky for about the next week or so. After which they will be archived here: http://www.mpgh.net/forum/31-c-c/866...tutorials.html

I think I'll continue to do a weekly showcase like this, if it seems like a good idea.
Quote Originally Posted by why06 View Post
A new set of tutorials by HD. I will be showcasing them in this sticky for about the next week or so. After which they will be archived here: http://www.mpgh.net/forum/31-c-c/866...tutorials.html

I think I'll continue to do a weekly showcase like this, if it seems like a good idea.
Great idea, I'll release code weekly to keep you fools amused
Why don't you just add your code to the SourceCode and recompile it? Using OllyDbg with this game really is a waste of time.
Posts 17 of 7 · Page 1 of 1
This thread is closed for replies.

Similar Threads

Tags for this Thread

None

Need help?