Hi! Thank you for following my blog! I just wanted to notify you that my blog is actually now over at https://grahambest.xyz for the time being, however I _may_ comeback and use this one.
Reversing a Crackme Writeup 12/31/2019
Got a hold of this reverse me from the new crackme site that was released. It’s called “xordemo”, it was an interesting little crackme I reversed up and wanted to give a write up on.
Upon opening up xordemo inside of IDA you’ll noticed its an executable using the ELF64 format (AKA it runs on UNIX). I personally do not use Linux, and I didn’t want to go through the hassle of installing Linux, as I mostly just reverse to learn and toy around, so I just reversed it, documenting how it worked, and also writing my own program that handles decrypting.
Anyways, you’ll notice the main function is accessing program launch flags
.text:0000000000000825 push rbp .text:0000000000000826 mov rbp, rsp .text:0000000000000829 sub rsp, 20h .text:000000000000082D mov [rbp+var_14], edi .text:0000000000000830 mov [rbp+var_20], rsi .text:0000000000000834 cmp [rbp+var_14], 2 ; launch flags get accessed here and are compared to 2 .text:0000000000000838 jz short loc_84D .text:000000000000083A lea rdi, s ; "Need exactly one argument." .text:0000000000000841 call _puts .text:0000000000000846 mov eax, 0FFFFFFFFh .text:000000000000084B jmp short locret_88D
Program flags get stored in var_14 which is accessed using the frame pointer, not surprising as the frame pointer has access to local variables and function parameters (in this main function).
Further down the start function you’ll see references to a subroutine
.text:000000000000084D loc_84D: ; CODE XREF: main+13j .text:000000000000084D mov rax, [rbp+var_20] .text:0000000000000851 add rax, 8 .text:0000000000000855 mov rax, [rax] .text:0000000000000858 mov rdi, rax .text:000000000000085B call key_encryptor .text:0000000000000860 mov [rbp+var_1], al .text:0000000000000863 cmp [rbp+var_1], 0 .text:0000000000000867 jz short loc_87C .text:0000000000000869 lea rdi, aJackpot ; "Jackpot"
I renamed the subroutine to key_encryptor, but you notice the string "jackpot" is referenced right after the call to this certain subroutine. Using basic logic and the process of elimination, its obvious that that this function has some sort of play with the key itself. Going further down into it key_encryptor, you’ll notice there is a string, "1feebdab", and an array of byte code is being stored in the rax register:
.text:0000000000000756 mov rax, '1feebdab' ; the string that gets encrypted .text:0000000000000760 mov qword ptr [rbp+s], rax .text:0000000000000764 mov [rbp+var_2E], 32h .text:000000000000076A mov rax, 10 14 0A 05 0C 17 0A 02 ; byte code that is store
"1feebdab" gets reversed later on due to endianness on x86, the littlest endian gets put up front, while the most significant gets put in the back, so I’ll just refer to it as "badbeef1", which is what it truly is, anyways.
Later on in the program there is this big chunk of disassembly:
.text:0000000000000787 loc_787: ; CODE XREF: key_encryptor+8Dj .text:0000000000000787 mov eax, [rbp+var_3C] .text:000000000000078A cdqe .text:000000000000078C movzx ecx, [rbp+rax+s] .text:0000000000000791 mov eax, [rbp+var_3C] .text:0000000000000794 movsxd rdx, eax .text:0000000000000797 mov rax, [rbp+var_48] .text:000000000000079B add rax, rdx .text:000000000000079E movzx eax, byte ptr [rax] .text:00000000000007A1 xor ecx, eax .text:00000000000007A3 mov edx, ecx .text:00000000000007A5 mov eax, [rbp+var_3C] .text:00000000000007A8 cdqe .text:00000000000007AA mov [rbp+rax+s1], dl .text:00000000000007AE add [rbp+var_3C], 1 .text:00000000000007B2 .text:00000000000007B2 loc_7B2: ; CODE XREF: key_encryptor+4Bj .text:00000000000007B2 mov eax, [rbp+var_3C] .text:00000000000007B5 movsxd rbx, eax .text:00000000000007B8 lea rax, [rbp+s] .text:00000000000007BC mov rdi, rax ; s .text:00000000000007BF call _strlen .text:00000000000007C4 cmp rbx, rax .text:00000000000007C7 jbe short loc_787
This whole chunk loops over string, and xor’s each character at X by bytecode at X which is iterated over. For better understanding:
b gets XOR’d by 0x10 a XOR 0x14 d XOR 0x0A b XOR 0x05 e XOR 0x0C e XOR 0x17 f XOR 0x0A 1 XOR 0x02You’ll notice on this line
movzx eax, byte ptr [rax]
the current indexed byte code gets stored in eax, which then gets XOR’d by ecx, which is the current character in the string,
movzx ecx, [rbp+rax+s] ; brackets signify a dereference
Where the XOR’ing is happening:
.text:000000000000079E movzx eax, byte ptr [rax] .text:00000000000007A1 xor ecx, eax .text:00000000000007A3 mov edx, ecx
Anyways, despite me not being able to run the program on Windows, I decided to write my own little program which does all the work for you:
std::vector do_xor()
{
// const char* base_key = "1feebdab";
// the string gets reversed based on the assembly shown,
// so it actually is:
const char* base_key = "badbeef1";
std::uint8_t byte_code[] =
{ 0x10, 0x14, 0x0A, 0x05, 0x0C, 0x17, 0x0A, 0x02 };
const std::int32_t size = std::strlen(base_key);
std::vector data;
for (std::int32_t i = 0; i < size; i++)
{
std::uint8_t xor_value = base_key[i] ^ byte_code[i];
data.push_back(xor_value);
}
return data;
}
This (very bad) code will return the data back into an std::vector, which you can use to then print the key
Reversing a simple CTF, tips through conquering CTFs
Hello people, I decided to get back in to CTF competitions, and the one I’m currently competing in has a great reverse me thats perfect for anyone who wants to learn how to reverse.
First off, the program is ELF, which means it’s most likely compiled on Linux, this isn’t always true however. as ELF is on ALL Unix OS’s. If you’d like to learn more about ELF, there is a great article on Wikipedia (https://en.wikipedia.org/wiki/Executable_and_Linkable_Format).
So first off, I don’t know the rules against supplying the file, so I’m going to leave it to me, if you’d like it. Please, PM me, or comment. However, the file is called “Time”, the whole point is to capture a flag, normally looking like something similar to this flag{SOME_stup1d_L33T_c0d3}, some flags are easy as pie to get, others can be extremely difficult. The one I did was relatively easy, taking me about 5 – 10 minutes to solve, which is extremely short compared to most flags you find.
Before we begin though, if you plan on doing CTFs I’d like to supply a few tips you can keep with you, stuff I realized has helped me.
Tip 1: When in doubt, GOOGLE, this applies to weird memory addresses, encryption method, bitwise operations, and much more.
Tip 2: Don’t be scared to mess around, whether you’re going to patch the file, mess with the encryption, or just straight bruteforce it. Remember, the people who created the CTF can make mistakes to!
Tip 3 (last one): CTFs are no easy task, but they are extremely fun and you’ll get the best feeling once you solve one. Its like a puzzle, with many many pieces, and some pieces you can just 100% leave out. 😉
Alright, finally, we can now begin. Once I opened up the file in IDA, I immediately went into strings, and searched "flag", this is a common string in most CTF reverse mes. I found multiple. The most interesting being "Flag is". If reversed correctly, we can get the flag. So I xref’ed that string, and found 1 occurrence inside a function. I went to the function, and saw where it was at.
void __noreturn sub_8514()
{
int v0; // [sp+0h] [bp-Ch]@1
int i; // [sp+4h] [bp-8h]@2
puts("Enter your Key");
_isoc99_scanf("%ld", &v0);
if ( dword_108D0 - dword_108DC == v0 )
{
puts("Seems you guessed it.");
printf("Flag is ");
for ( i = 0; i <= 33; ++i )
putchar(dword_1084C[i] ^ 7);
exit(0);
}
puts("Flag check failed");
exit(-1);
}
You can clearly see stuff, that looks very odd. I’ll try to explain this as thoroughly as possible, from top, to bottom. First off, puts is a C/C++ function that prints to the console, sounds easy. _isoc99_scanf, is a C99 function, its equivalent to C99, and you might be wondering why scanf wasn’t used. I’m pretty sure its because %ld isn’t available in C standards. So _isoc99_scanf was used. Correct me if I’m wrong. That comparison is comparing if the key is correct, how do I know this? Because inside of the if statement, you see it printing out the flag, which is dword_1084C[i]. The rest is pretty self explanatory. So whats a summary of the flow? A short and sweet one is that this function checks your input, if wrong it prints Flag check failed and if right it loops over 33 chars (the chars of the string), then it sets the key to equal to each xor’d iteration by 7
(https://www.cprogramming.com/tutorial/xor.html).
This is pretty easy, now you have to rebuild the function. To speed things up, its pretty straightforward, make a function that does the same exact thing, then prints out the buffer (dword_104C). Here is my implementation (C++):
#include <iostream>
#include <cstdint>
#define MAX_KEY_LENGTH 33
void key(int32_t xor_base)
{
char buf[MAX_KEY_LENGTH] =
{
'n', 'i', 'd', 's', 'a', '|', 'S', 'o', '6', 't', 'X',
'&', 't', 'X', 'm', 'R', 't', 's', 'X', 's', 'o', '4',
'X', 'E', '4', '`', 'n', 'i', 'I', 'n', 'i', '`', 'z'
};
for (int32_t i = 0; i <= MAX_KEY_LENGTH; i++)
{
buf[i] = buf[i] ^ xor_base;
std::printf("%i", buf[i]);
}
std::printf("\nFlag is: ");
std::printf("\n");
std::printf("%s", buf);
}
int32_t main(int32_t argc, char* argv[])
{
key(7);
system("pause");
}
Where buf was the array of chars IDA recognized.
When compiled you’ll see that this prints out
10511099116102123841044911595331159510685115116951161045195665110310511078105110103125-53
Flag is:
inctf{Th1s_!s_jUst_th3_B3ginNing}╦╠╠╠╠╠╠Xrm╪·»
Thank you, I hope you learnt something. Please, comment what you thought of this blog post!
ZDoom Reversing Part 1
Hello everyone!
Thanks for coming back to my blog, I’ve been struggling with a bit of family issues, so I couldn’t post anything.
However, I’ve been reverse engineering ZDoom. ZDoom is a source port of DOOM, it mostly adds support for other games build by iD Software.
Alright, let’s start.
First off, we must know ZDoom is an x86 exe file. As I said before in my previous blog posts, I prefer to reverse x86 executables due to there being MS Detours support, and reversing x86 executables just tends to be easier, and more coder friendly. Also, before we continue. I would like to say that I reversed this game without looking at the source code whatsoever, and I really encourage you guys to do the same.
Anyways, I started off with trying to find the vtable ptr for player_t in ZDoom.
This was a relatively easy task, and I’ll explain how I managed to complete this task.
First off, open up the executable inside IDA, and let it disassemble. We’re going to use some logic here, whats a good string idea we could search up to find the vtable ptr to player_t?
Well, we could search up health…
Once you do that, after some playing around and xrefing the string “Health” (there is multiple), then you’ll find a function called
unsigned int __userpurge sub_4B2010
If you go through it and find the place where the string was referenced, you’ll see this
if ( (unsigned __int8)sub_49C090("Health") )
{
sub_4A1070(v11);
*(_DWORD *)(a2 + 188) = *(_DWORD *)&dword_64F2BC;
goto LABEL_120;
}
You’ll notice something…
a2 + 188
This right here means that a2 is definitely a struct, you can see the addition sign, which means its that far of an offset off a2. Please, name the struct something like APlayer, where 188 is the players health. Thats what I’m going to assume. For those who do not know how to create a struct in IDA, right click on the var / arg, and click on “Create new struct type”, and rename the struct to APlayer. If you do not see “Create new struct type” then go get this IDA plugin https://github.com/REhints/HexRaysCodeXplorer
Anyways, the code becomes much easier to read. We can now see that there is a struct and fields for the struct!
Lets go ahead and rename that field that was equal to
*(_DWORD *)&dword_64F2BC
to player. I can only assume this. I do not know if that truly is player, but for anyone reading this, how about you try to find out yourself as a little fun task? Reverse engineering is all about trial and error.
Anyways, go to the IDA Disassembly view, and look at the address
.text:004B23D7 mov [edi+0BCh], edx
I’d like to pause here, and let you think of what we should do next. If you do not know, don’t worry 🙂
Ready? Good, so what we’re going to do is find out what edi is, and to do that, we’re going to breakpoint on address 004B23D7 in x32dbg,/ OllyDbg / whatever, and see what happens. We can then find out what edi is by looking in the registers box. Lets give it a shot eh?
Go into x32dbg and set a breakpoint at that address with F2.
Play around in the game until it gets hit, and bam, go into the registers box and take edi. There is the address, then after that, you can go into Reclass, and reverse the player struct! Thanks! 🙂
Well… I kinda broke Quake 3: Arena
Hello guys, and girls! Welcome back
I did actually end up achieving what I wanted to, and that was to break Quake 3. I did this by overwriting convars in the game. And actually reversed an entire set of convars + a class that can contain these convars!
So lets get to what I did, and how it works, shall we? First off, go open up Quake 3 Arena in IDA and go ahead and generate the list of strings. Done? Good, now we’re going to be a little newbie here, and search up on google, list of convars in quake, but hey, who said using resources is newbie?
Once you’ve done that, find a convar, some of them were not implemented into quake 3, but do not worry. For me, I searched up cl_showSend, xref that string. And you should get a couple, to one result (hopefully one).

You’ll notice this is a push. That means its getting pushed onto the stack. Probably meaning its getting pushed into a functions arguments. Thats how I remember it.
Now, we’re going to use common sense here, only 1 result for a string thats a convar? And its taken as arguments for a function? Whats this mean? Well, this means that function is probably a RegisterCVar function. I named mine CV_RegisterCVar. But you can name it what you’d like
Okay, so, lets get back to it.
Now, theres something VERY special about this function. It moves the eax register into B3A42C
This is great! IDA literally just gave us the address.
Throw that into reclass, and make a pointer @ B3A42C, then in that pointer, add about 2048 bytes, until you see a string called “r_showNormals”
This is actually a great way to make a simple wallhack! We’re going to show normals in the game, then be able to see enemies, and objects alike, through walls! 😀
Alright, we ran into a problem though. We don’t know what value to set. We’ve kinda messed up. What value do we set to change the value of that convar?
Okay, so if you go back into IDA. Compare that
.text:0040F020 push offset a0 ; "0"
with whats in reclass. See a zero? Good, you can compare other convars to. You’ll probably see lots of zeroes but don’t worry. We got this. Okay, so the one right before the next pointer is the convar. Value, I’ll show you what I mean.

Alright, sweet, we found the value. How did I know this? Well because I compared multiple values in IDA versus the value in reclass. Sometimes you have to reload your map for convars to actually change, so if it doesn’t change automatically, try that. Also, float values are the second one before the next pointer.
Thanks guys!! 🙂
Quake 3: Arena Reversing
Hey guys, I’m back again with another blog post. This time, on Quake 3 Arena. I recently got back into reverse engineering. And decided to start off with a fun classic video game, known as Quake 3: Arena. Quake 3: Arena is a multiplayer online shooter. Created by id Games, it still is a popular game. It really stands the test of time!
Anyways, lets get to reversing. When I reverse. I like to pop the program open and just get straight to hacking away. I went into my quake console, and looked for an interesting string. Ahaha, found one! It says: WARNING: could not find %s - using default, where %s is actually a string for the sound it couldn’t find. Anyways, this is probably apart of some register sound function, quite obvious (and it is). I like to reverse without reading any bit of source. So, lets get straight to it! X-Ref that string, and you should come across three results. After close inspection of all three, you’ll notice the second one has something, odd. It looks like its being pushed into a printf function! Yes! Quake 3, has their own printf function for the console
LABEL_33: Con_PrintF(a3warningCouldN, (_BYTE)v8 + 0x18); return 0;
Here is how its being called. I have good knowledge of quake, so I know this is called Con_PrintF. Lets go ahead and name it that. You’ll also notice something very strange and odd in this call. Theres something called (_BYTE)v8 + 0x18), what is this?!?! Its actually, an offset of a value. So that gives us an exact idea as to what v8 is. Its a variable of type struct!! 🙂
The reason I say struct, is because there are classes in C++. And we know that. There are indeed, classes in C++, but not C.
Lets get back to coding. We can rename v8 to something like, sound_ptr because we know that prints out WARNING: could not find 'something.wav' - using default, and this is a sound. So, if you right click on that variable you’ll see something called reconstruct type (don’t panic if you don’t). If you do not see reconstruct type, you’re missing the plugin. You can find it over at: https://github.com/REhints/HexRaysCodeXplorer
Okay, once you have dl’ed that, you can now reconstruct the type. We can reconstruct the type of that variable, to some struct. In my case, I called the struct sound_t.
Lets call the function register sound. So your IDA pseudo code should look like:
int __cdecl S_RegisterSound(const char *a1)
Okay, so, now we can get to reversing and the juicy part!!
Once you reconstructed the type, you should get a new type called sound_t. IDA auto-detects the size of it. Goto the structures tab, and we should see the struct there.
00000000 sound_t struc ; (sizeof=0x60, mappedto_68) 00000000 field_0 dd ? 00000004 bool_use dd ? 00000008 field_8 dd ? 0000000C field_12 dd ? 00000010 db ? ; undefined 00000011 db ? ; undefined 00000012 db ? ; undefined 00000013 db ? ; undefined 00000014 db ? ; undefined 00000015 db ? ; undefined 00000016 db ? ; undefined 00000017 db ? ; undefined 00000018 sound_name dd ? ; offset 0000001C db ? ; undefined 0000001D db ? ; undefined 0000001E db ? ; undefined 0000001F db ? ; undefined 00000020 db ? ; undefined 00000021 db ? ; undefined 00000022 db ? ; undefined 00000023 db ? ; undefined 00000024 db ? ; undefined 00000025 db ? ; undefined 00000026 db ? ; undefined 00000027 db ? ; undefined 00000028 db ? ; undefined 00000029 db ? ; undefined 0000002A db ? ; undefined 0000002B db ? ; undefined 0000002C db ? ; undefined 0000002D db ? ; undefined 0000002E db ? ; undefined 0000002F db ? ; undefined 00000030 db ? ; undefined 00000031 db ? ; undefined 00000032 db ? ; undefined 00000033 db ? ; undefined 00000034 db ? ; undefined 00000035 db ? ; undefined 00000036 db ? ; undefined 00000037 db ? ; undefined 00000038 db ? ; undefined 00000039 db ? ; undefined 0000003A db ? ; undefined 0000003B db ? ; undefined 0000003C db ? ; undefined 0000003D db ? ; undefined 0000003E db ? ; undefined 0000003F db ? ; undefined 00000040 db ? ; undefined 00000041 db ? ; undefined 00000042 db ? ; undefined 00000043 db ? ; undefined 00000044 db ? ; undefined 00000045 db ? ; undefined 00000046 db ? ; undefined 00000047 db ? ; undefined 00000048 db ? ; undefined 00000049 db ? ; undefined 0000004A db ? ; undefined 0000004B db ? ; undefined 0000004C db ? ; undefined 0000004D db ? ; undefined 0000004E db ? ; undefined 0000004F db ? ; undefined 00000050 db ? ; undefined 00000051 db ? ; undefined 00000052 db ? ; undefined 00000053 db ? ; undefined 00000054 db ? ; undefined 00000055 db ? ; undefined 00000056 db ? ; undefined 00000057 db ? ; undefined 00000058 db ? ; undefined 00000059 db ? ; undefined 0000005A db ? ; undefined 0000005B db ? ; undefined 0000005C field_92 dd ? 00000060 sound_t ends
Heres what mine looks like. WOW a big struct for only 5 members. I already reversed sound_name, and we’ll get to that later. Now you might be asking, why is it 0x60 bytes long? Well, its 0x60 bytes long because field_92 is actually a type of another struct! I haven’t reversed this yet. But that is indeed why.
So, we can get back into IDA pseudo code view and rename this part of that function
strcpy((char *)&sound_to_play->sound_name, a1);
And set the name to sound_t name. And make sure to set that type to char* aswell
You can now hook this function using detours. And then call sounds via it! Great! You have now seen what IDA can do in this blog post. Now, go do something 🙂
Thanks! 🙂
Cube 2: Sauerbraten Reverse Engineering
Hello guys, welcome to my blog post about Cube 2: Sauerbraten reversing. I’ve recently been hacking this game, and would like to post the process of what I did. Lets get to it shall we?
First off, I fixed the game to run in x86 instead of x64. Which is a lot easier to reverse engineer, at least in my opinion due to the lesser hexadecimals and less instructions. To do this, we go into the .bat file, edit it, and paste the following code in:
@ECHO OFF
set SAUER_BIN=bin
IF /I "%PROCESSOR_ARCHITECTURE%" == "amd64" (
set SAUER_BIN=bin
)
IF /I "%PROCESSOR_ARCHITEW6432%" == "amd64" (
set SAUER_BIN=bin
)
start %SAUER_BIN%\sauerbraten.exe "-q$HOME\My Games\Sauerbraten" -glog.txt %*
So, when you open it up in IDA, go into the imports tab and we’re going to reverse a simple render loop. So, you should see it uses OpenGL and SDL, this is great! IDA’s already recognized that it uses these 2 libraries, now, a basic render loop in a video game normally has SDL_GL_SwapBuffers, which swaps the OpenGL framebuffers. So, lets quit out what we have open inside of IDA, and now we’ll open up bin/SDL.dll, go into the functions window and search up in the functions window, SDL_GL_SwapBuffers. Once you have found it, we can now make a simple render loop. Make a function pointer, here is mine:
typedef void(__cdecl* tSDL_SwapBuffers)(); tSDL_SwapBuffers oSDL_SwapBuffers;
Now, make a function called hkSDL_SwapBuffers, or whatever you’d like, and just have it CALL the function pointer, which is oSDL_SwapBuffers. Here is an example
void hkSDL_SwapBuffers()
{
std::cout << "Hello" << std::endl;
oSDL_SwapBuffers();
}
The reason for the std::cout << "Hello" << std::endl; is because it should spam this in console if we've successfully hooked the function. Now, call hkSDL_SwapBuffers in your DllMain and when you inject the x86 DLL you should see it spam "Hello" in console. This is a good thing! It means we've successfully hooked the function, now, lets get to calling a function like DrawString. Which will draw a string to the screen, which can be useful. So, go back into sauerbraten.exe in IDA and go into strings. Search up something that is being drawn to the screen. In my case, I searched up "SPECTATOR" and xrefed it to this function, sub_B2970. Also, if you haven't rebased your program, please do so, rebase it to 0x0, this will make it so we don't have RVA's (relative virtual addresses). Now, after that, we can see how sub_B2970 is calling DrawString. You can also make a function pointer for this, but I did it the "bad" way to learn x86 assembly more. Of course, you could just make a function pointer, but the whole process of programming is to try new things and learn, right? Here is what I did, compare it to the way its being called in disassembly mode inside of IDA:
drawStringAddy = (uintptr_t)(GetModuleHandleW(0)) + 0x00107750;
void DrawString(char* msg, int x, int y, int red, int green, int blue, int alpha, int format, int format2)
{
__asm
{
push format2;
push format;
push alpha;
push blue;
push green;
push red;
push y;
mov ecx, msg;
push x;
push ecx;
call drawStringAddy; // call the function
add esp, 0x24; // clean up stack
}
}
Now, you can call that inside of you render loop, before you call the original function, and you should have something draw to the screen :D.
Okay, now that concludes my blog post for today, I’ll be posting quite a bit more later. Thanks for reading!! 😀
PS: Heres a nice player class I reversed in ReClass 😉
// Generated using ReClass 2016
#include "Vector.h" // you should already have a vector class, if you do not, go get one off the valves source sdk or smthing lol
class BasePlayer;
class Player;
class BasePlayer
{
public:
Player* ply; //0x0000
char pad_0x0004[0x8A4]; //0x0004
}; //Size=0x08A8
class Player
{
public:
Vector3 plyPos; //0x0000
char pad_0x000C[0x8]; //0x000C
__int32 plyMode; //0x0014 not sure about this
char pad_0x0018[0x8]; //0x0018
float plyJumpPow; //0x0020
char pad_0x0024[0xC]; //0x0024
Vector3 plyPos_2; //0x0030
Vector2 plyViewAngles; //0x003C
char pad_0x0044[0x4]; //0x0044
float plySpeed; //0x0048
__int32 plyJumpHeight; //0x004C
char pad_0x0050[0x28]; //0x0050
__int32 UNK15; //0x0078
char pad_0x007C[0x2C]; //0x007C
__int32 UNK14; //0x00A8
char pad_0x00AC[0x8]; //0x00AC
float plyWalkMode; //0x00B4
char pad_0x00B8[0x8]; //0x00B8
__int32 UNK13; //0x00C0
char pad_0x00C4[0x1C]; //0x00C4
__int32 UNK18; //0x00E0
__int32 UNK11; //0x00E4
char pad_0x00E8[0x4]; //0x00E8
float UNK12; //0x00EC
char pad_0x00F0[0x4]; //0x00F0
__int32 UNK10; //0x00F4
__int32 UNK9; //0x00F8
__int32 UNK8; //0x00FC
char pad_0x0100[0x4]; //0x0100
float UNK7; //0x0104
char pad_0x0108[0x28]; //0x0108
__int32 UNK4; //0x0130
__int32 UNK5; //0x0134
char pad_0x0138[0x20]; //0x0138
__int32 plyTicksPassed; //0x0158 possibly ticks?
__int32 plyHealth; //0x015C
__int32 plyMaxHealth; //0x0160
__int32 plyArmor; //0x0164
char pad_0x0168[0x8]; //0x0168
__int32 plyWeaponSlot; //0x0170
char pad_0x0174[0x4]; //0x0174
__int32 UNK1; //0x0178
__int32 plyGrenades; //0x017C
char pad_0x0180[0x10]; //0x0180
__int32 plyPistolRounds; //0x0190
char pad_0x0194[0x1C]; //0x0194
__int32 UNK6; //0x01B0
char pad_0x01B4[0x38]; //0x01B4
__int32 UNK2; //0x01EC
__int32 UNK3; //0x01F0
char pad_0x01F4[0x3C4]; //0x01F4
__int32 UNK16; //0x05B8
char pad_0x05BC[0x1390]; //0x05BC
__int32 UNK17; //0x194C
char pad_0x1950[0x8B4]; //0x1950
__int32 inkyMaskCol; //0x2204
char pad_0x2208[0x98]; //0x2208
__int32 inkyWingsMaskCol; //0x22A0
char pad_0x22A4[0x570]; //0x22A4
}; //Size=0x2814
PLAYING WITH QUAKE, A JOURNEY THROUGH REVERSING (PART TWO)
Hello! Welcome back to this series. Haven’t done much, however I managed to do some teleportation in Quake. So, plyPos (player position) is at the 0AD4 offset of the player pointer. Its a Vector3 type. So go there. Good, now in Visual Studio, make a DLL project, or whatever IDE you use. And copy the following code in.
#include <iostream>
#include <Windows.h>
#include "SDK.h"
#include "Vector.h"
void Init()
{
AllocConsole(); // allocate a console
freopen("CONIN$", "r", stdin); // open the stdin pipe (input)
freopen("CONOUT$", "w", stdout); // open the stdout pipe (output)
SetConsoleTitle("Quake"); // set the console window name, in our case its Quake
base = reinterpret_cast<Quake::Base*>(0x00428C24); // set base = 0x00428C24 (base player pointer)
std::cout << base << std::endl; // cout base, only did this to see if its right
while (true)
{
std::cout << base->ply->plyPos.y << std::endl;
base->ply->plyPos.y = FLT_MAX; // set plyPos.y to maximum float.
}
}
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpVoid)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Init, 0, 0, 0);
break;
}
return TRUE;
}
Vector3 class is something you gotta make yourself, you can just use the source-sdk-2013 one which is public (what Valve uses). As for the classes for the game, here is something you can use.
#include "Vector.h"
class Player;
class Model;
class Base;
class Map;
class TextBase;
class ConCommand;
class Console;
class ConsoleManipulation;
namespace Quake
{
class Player
{
public:
__int32 plyHealth; //0x0000
char pad_0x0004[0x8]; //0x0004
__int32 plyCurAmmo; //0x000C
char pad_0x0010[0x8]; //0x0010
__int32 plyShotgunShells; //0x0018
__int32 plyNumNails; //0x001C
char pad_0x0020[0x8]; //0x0020
__int32 plyWeaponSlot; //0x0028 probably weapon slot, no idea
char pad_0x002C[0x340]; //0x002C
Model* plyPlayerMdl; //0x036C
Model* plyEyeMdl; //0x0370
Model* plyHPlayerMdl; //0x0374
Model* plyGib1Mdl; //0x0378
Model* plyGib2Mdl; //0x037C
Model* plyGib3Mdl; //0x0380
Model* plyBubbleMdl; //0x0384
Model* plyExplodMdl; //0x0388
Model* plyAxeMdl; //0x038C
Model* plyShotMdl; //0x0390
Model* plyNailMdl; //0x0394
Model* plyRockMdl; //0x0398
Model* plyShot2Mdl; //0x039C
Model* plyNail2Mdl; //0x03A0
Model* plyRock2Mdl; //0x03A4
Model* plyBoltMdl; //0x03A8
Model* plyBolt2Mdl; //0x03AC
Model* plyBolt3Mdl; //0x03B0
Model* plyLavaballMdl; //0x03B4
Model* plyMissleMdl; //0x03B8
Model* plyGrenadeMdl; //0x03BC
Model* plySpikeMdl; //0x03C0
Model* plySSpikeMdl; //0x03C4
Model* plyBackPackMdl; //0x03C8
Model* plyZombieGibMdl; //0x03CC
Model* plyLightMdl; //0x03D0
Map* plyBH25Bsp; //0x03D4
Model* plyArmorMdl; //0x03D8
Map* plyEXBOX2Bsp; //0x03DC
Map* plyBSHellBsp; //0x03E0
Map* plyNail1Bsp; //0x03E4
Map* plyNail0Bsp; //0x03E8
Map* plyRock1Bsp; //0x03EC
Map* plyBSHell1Bsp; //0x03F0
Map* plyBBH10Bsp; //0x03F4
Map* plyBBH100Bsp; //0x03F8
Model* plyGShotMdl; //0x03FC
Model* plyGRockMdl; //0x0400
Model* plYBGKeyMdl; //0x0404
Model* plyEnforcerMdl; //0x0408
Model* plyHMegaMdl; //0x040C
Model* plyLaserMdl; //0x0410
Model* plySoldierMdl; //0x0414
Model* plyHGuardMdl; //0x0418
Model* plyHDogMdl; //0x041C
Model* plyDogMdl; //0x0420
Model* plyGNailMdl; //0x0424
Model* plySuitMdl; //0x0428
Model* plyInvulnerableMdl; //0x042C
Model* plyQuadDamageMdl; //0x0430
Model* plyBSKeyMdl; //0x0434
Model* plyInvisibleMdl; //0x0438
Map* plyBHB10Bsp; //0x043C
Map* plyBNail1Bsp; //0x0440
char pad_0x0444[0x628]; //0x0444
char* plyCurMap; //0x0A6C
char pad_0x0A70[0x64]; //0x0A70
Vector3 plyPos; //0x0AD4 players pos.
char pad_0x0AE0[0x18]; //0x0AE0
Vector2 plyAngle; //0x0AF8 players view angles. only in 2d.
char pad_0x0B00[0x474]; //0x0B00
Model* plyFlameMdl; //0x0F74
char pad_0x0F78[0x800]; //0x0F78
}; //Size=0x1778
class Model
{
public:
char pad_0x0000[0x440]; //0x0000
}; //Size=0x0440
class Base
{
public:
Player* ply; //0x0000
char pad_0x0004[0x3C]; //0x0004
}; //Size=0x0040
class Map
{
public:
char pad_0x0000[0x40]; //0x0000
}; //Size=0x0040
class TextBase
{
public:
char pad_0x0000[0x10C]; //0x0000
Console* console; //0x010C
char pad_0x0110[0x7A0]; //0x0110
}; //Size=0x08B0
class ConCommand
{
public:
char pad_0x0000[0x1810]; //0x0000
}; //Size=0x1810
class Console
{
public:
char pad_0x0000[0x10]; //0x0000
ConsoleManipulation* consoleManipulation; //0x0010
char pad_0x0014[0x20]; //0x0014
}; //Size=0x0034
class ConsoleManipulation
{
public:
ConCommand* conCmd; //0x0000
char pad_0x0004[0x3C]; //0x0004
}; //Size=0x004
}
Quake::Base* base;
If you don’t have Vector3 or Vector3. Just go ahead and print health ;).
If you don’t know how to print health. Change these lines
while (true)
{
std::cout << base->ply->plyPos.y << std::endl;
base->ply->plyPos.y = FLT_MAX; // set plyPos.y to maximum float.
}
to
while (true)
{
std::cout << base->ply->plyHealth << std::endl;
}
Thanks for reading! Happy hacking. More blogs to come later 🙂
