MinoMino / minqlx

Extends Quake Live's dedicated server with extra functionality and scripting.
GNU General Public License v3.0
110 stars 42 forks source link

How to find function signatures? #94

Open agkr234 opened 4 years ago

agkr234 commented 4 years ago

Hello, I have been making some sort of mods on Quake Live using minqlx. I recently came up with a new idea, but I need to find function signatures that are not listed in "patterns.h" to realize the idea. I searched for the methods, and I ran into this page: https://wiki.alliedmods.net/Signature_Scanning#Finding_the_Signature_of_a_Function

As a practice, I compared G_FreeEntity's function signatures on qlds's qagamex64.so and ioquake3's qagamex86_64.so. However, both instructions are, If anything, not similar and I found that this method wouldn't work for me.

I wonder how the developers of minqlx found out the function patterns on qlds. If someone could teach me how to do it, I would really appreciate it.

em92 commented 4 years ago

I have been making some sort of mods on Quake Live using minqlx.

harosh!

I wonder how the developers of minqlx found out the function patterns on qlds

Use this, examples available: https://github.com/MinoMino/minfuncfind To generate pattern from qagamex64.so you don't need last "0x400000" param.

Also check this for function addresses which I used once, maybe you will have function you need https://gist.github.com/em92/c6a6cd66aa354311265d10c19515dd06

agkr234 commented 4 years ago

Wow! You are such a great man! I wanted to modify pmove things, so PMOVE's address will be very useful. thanks!

And I'm sorry but maybe I should have written function "addresses" instead of function signatures. If possible, could you also teach me how to find function addresses?

em92 commented 4 years ago

could you also teach me how to find function addresses?

There is no universal method for that. I will write some of them (when I have time).

  1. Detecting function address by referenced string (using IDA Pro).

Disclaimer: I am writing from my memory.

Function can use constant strings. Find it using "Text Search" in IDA. After finding, scroll up until you see that IDA defines this as separate function.

As example you can try to find G_FreeEntity by searching string "freed" (https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/game/g_utils.c#L472) and G_TempEntity by searching string "tempEntity" (https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/game/g_utils.c#L493)

May not work, if method that we are try to search is called or used anywhere once in code. As for example: Pickup_PersistantPowerup. Compiler, that Id Software used to compile qagame library, merged or inlined body of Pickup_PersistantPowerup inside Touch_Item. So when you scroll up, you probably will find address of Touch_Item, not Pickup_PersistantPowerup.

The other method is running qlds + minqlx using GDB. Will write it somewhen later

notallmighty commented 4 years ago

I would be thankfull, too. If you are anyhow eager to drop some light on those functions somewhen.

agkr234 commented 4 years ago

Thank you for taking the time to write the detailed explanation! Actually, I have the free version of IDA on Linux and haven't used it recently since I didn't know how to use it. But now I have tried out your method and it seems to work for certain functions.

If you have some time, I would like to know how to know what arguments a function needs. One day, I tried hooking G_AddEvent, but it keeps causing segmentation fault when G_AddEvent is called. Below are the codes I added to minqlx's source code.

In "hook.c":

void __cdecl My_G_AddEvent(gentity_t* ent, int event, int eventParm) {
    G_AddEvent(ent, event, eventParm);
}
res = Hook((void*)G_AddEvent, My_G_AddEvent, (void*)&G_AddEvent);
if (res) {
    DebugPrint("ERROR: Failed to hook G_AddEvent: %d\n", res);
    failed = 1;
}
count++;

In "quake_common.h": void __cdecl My_G_AddEvent(gentity_t* ent, int event, int eventParm);

I just copied a code that is related to hooking and changed its name and arguments as necessary.

I'm just wondering why the hooking done by this way can't work, so you don't need to bother about it if you don't have time.

em92 commented 4 years ago

why the hooking done by this way can't work

It is a bug in minqlx, it may not correctly hook сertain functions.

The problem is when function starts like this:

.text:00000000000982F0                 test    esi, esi
.text:00000000000982F2                 jz      short loc_98340

To hook a function while leaving original function's behavior minqlx creates trampolines. You can read "Constructing Trampolines" section from http://jbremer.org/x86-api-hooking-demystified/#ah-trampoline2

It seems to me, than minqlx does not correctly handle "jz" instruction when creating trampoline, so it leads to segfault when running hooked G_AddEvent. It needs some debugging using gdb or something to find out more.

em92 commented 4 years ago

It seems to me, than minqlx does not correctly handle "jz" instruction

Ignore this. I was wrong.

You can try to make following changes:

diff --git a/simple_hook.c b/simple_hook.c
index 9ba8879..c6c52fa 100644
--- a/simple_hook.c
+++ b/simple_hook.c
@@ -8,7 +8,7 @@
 #if defined(__x86_64__) || defined(_M_X64)
 typedef uint64_t pint;
 typedef int64_t sint;
-#define WORST_CASE                     40
+#define WORST_CASE                     42
 #define JUMP_SIZE                      sizeof(JMP_ABS)
 #elif defined(__i386) || defined(_M_IX86)
 typedef uint32_t pint;
@@ -69,7 +69,7 @@ int Hook(void* target, void* replacement, void** func_ptr) {

     int difference = ct.newIPs[ ct.nIP - 1 ];
     for (int i=JUMP_SIZE; i<difference; i++) {
-        *((uint8_t*)target + i) = NOP;
+//        *((uint8_t*)target + i) = NOP;
     }

     *func_ptr = trmp;

Hook on G_AddEvent will work after this (tested with making rocketjumps's). But I am not sure if other hooks work fine.

agkr234 commented 4 years ago

Oh, thanks for fixing the code. Actually, I'm not sure what caused a segfault. Was it replacing instructions which shouldn't be overwrited with NOP instructions?

And I'm sorry but I have found that TeleportPlayer hooking also doesn't work. I added the following lines.

in "hook.c"

void __cdecl My_TeleportPlayer(gentity_t* player, vec3_t origin, vec3_t angles) {
    Com_Printf("TeleportPlayer");
    TeleportPlayer(player, origin, angles);
}
res = Hook((void*)TeleportPlayer, My_TeleportPlayer, (void*)&TeleportPlayer);
if (res) {
    DebugPrint("ERROR: Failed to hook TeleportPlayer: %d\n", res);
    failed = 1;
}
count++;

in "quake_common.h" void __cdecl My_TeleportPlayer(gentity_t* player, vec3_t origin, vec3_t angles);

After a player entity went through a teleporter, the console didn't say "TeleportPlayer" and not even cause any segfault, as if I didn't implement any hooking on TeleportPlayer. The address of "TeleportPlayer" must be right since I succeeded teleporting a player entity by calling TeleportPlayer function, so the problem may be the trampoline or hooking things.

P.S. the hooking didn't work after I fixed the "simple_hook.c"

agkr234 commented 4 years ago

never mind.

The server console actually said "TeleportPlayer", but it took a while for console to show it since I forgot to add "\n" after "TeleportPlayer" in Com_Printf. And your changes on "simple_hooks.c" made my day. I really appreciate it.

Maybe it will be the last question. I want to understand trampoline and hooking implemented on minqlx, but is there any sites or videos worth reading?

em92 commented 4 years ago

I want to understand trampoline and hooking implemented on minqlx, but is there any sites or videos worth reading?

You can read article given above: http://jbremer.org/x86-api-hooking-demystified/

But it is assumed, that you have some experience in reverse engineering. I have some experience with it in 2008-2009 when I was dealing with crackmes. Lena's tutorials were popular that time or later, but I didn't watch them.

agkr234 commented 4 years ago

Thanks! I'm starting to get what an assembly does by comparing instructions in an assembly with codes of quake3, but I still haven't fully understand trampoline or hooking things.

Anyway, I'm deeply grateful for your kindness and thank you for everything!