Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Ergebnis 1 bis 9 von 9
  1. Beiträge anzeigen #1 Zitieren
    Veteran
    Registriert seit
    Jan 2012
    Beiträge
    681
     
    Frank-95 ist offline

    Knowing hook length

    Hi all.

    This is more an asm general question but it applies to gothic too.

    How can I know the hook length I should pass to HookFunction? I know there is a file with the length for every function, but I would need to hook part of code inside some function but I don't know how "long" they are.

    Thank you

  2. Beiträge anzeigen #2 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    If you don't mind using Google translate, I'll just reference a post from Lehona. It basically comes down to counting the bytes of the instruction at that address in IDA and making sure it is at least 5 bytes long and does not contain relative addresses (any kind of jump instruction). If an instruction is shorter then 5 bytes you may include the next instruction so long you always take the full length of the instructions and never "cut" them off.

  3. Beiträge anzeigen #3 Zitieren
    Veteran
    Registriert seit
    Jan 2012
    Beiträge
    681
     
    Frank-95 ist offline
    Ok thank you. One question if you don't mind.

    Code:
      7629a8:    8b 0d d4 27 ab 00        mov    ecx,DWORD PTR ds:0xab27d4
      7629ae:    8b f0                    mov    esi,eax
      7629b0:    e8 9b 3d fd ff           call   0x736750
      7629b5:    3b f3                    cmp    esi,ebx
      7629b7:    75 08                    jne    0x7629c1
    If I wanted to hook 7629b5 I should include the successive lines which includes a jump and it's not ok, as far as you said. So is it fine to start hooking from the previous line with length 7? If ebx was set by the call, but I wanted to know its value, hooking from the previous line would store ebx in the daedalus variable BEFORE the call, though, right?

  4. Beiträge anzeigen #4 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.447
     
    Lehona ist offline
    You can't hook call or jmp instructions (it would mess up the relative addresses). So you'd have to hook 7629a8h unless you need the result of that call...

    Edit: Yes, if you could hook there, EBX would contain the value before the function call.

  5. Beiträge anzeigen #5 Zitieren
    Veteran
    Registriert seit
    Jan 2012
    Beiträge
    681
     
    Frank-95 ist offline
    unless you need the result of that call
    And how would you do that if you did need it?
    Geändert von Frank-95 (18.12.2017 um 15:02 Uhr)

  6. Beiträge anzeigen #6 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Frank-95 Beitrag anzeigen
    And how would you do that you did need it?
    If you absolutely cannot hook at a later point, what you could do is overwrite the call with nop, hook at that address and manually call the overwritten function at the beginning of your hooking function (including pushing the arguments properly and updating the registers afterwards). This is prone to errors and it's very easy to mess up.
    Some problems that come to mind: using a recyclable call would require you to read and and re-push all arguments as well as overwriting any prior push instructions with nop (otherwise the addresses of the arguments will become invalid in game saves); you'll need a safeguard that prevents the hook from being overwritten at initialization of loading or at new game.

    I wouldn't recommend it and you should avoid doing that at all costs. Usually there is a way around it. If you share what you want to do with/around the call, there might be an alternative.

  7. Beiträge anzeigen #7 Zitieren
    Veteran
    Registriert seit
    Jan 2012
    Beiträge
    681
     
    Frank-95 ist offline
    Okay, so...

    My aim would be to implement a steal system like G3 (or similar at least). I actually don't want to draw a custom inventory with LeGo function, so I tried to look for some built-in functions that might be used for it.

    The most similar I've found is oCNpc:OpenDeadInventory, which obviously checks whether the focused npc is dead or unconscious.

    Code:
      762970:    64 a1 00 00 00 00        mov    eax,fs:0x0
      762976:    6a ff                    push   0xffffffff
      762978:    68 4e 6f 82 00           push   0x826f4e
      76297d:    50                       push   eax
      76297e:    64 89 25 00 00 00 00     mov    DWORD PTR fs:0x0,esp
      762985:    83 ec 18                 sub    esp,0x18
      762988:    53                       push   ebx
      762989:    56                       push   esi
      76298a:    57                       push   edi
      76298b:    8b f9                    mov    edi,ecx
      76298d:    e8 5e 02 fd ff           call   0x732bf0
      762992:    33 db                    xor    ebx,ebx
      762994:    3b c3                    cmp    eax,ebx
      762996:    a3 d4 27 ab 00           mov    ds:0xab27d4,eax
      76299b:    0f 84 2b 01 00 00        je     0x762acc
      7629a1:    8b c8                    mov    ecx,eax
      7629a3:    e8 98 3d fd ff           call   0x736740
      7629a8:    8b 0d d4 27 ab 00        mov    ecx,DWORD PTR ds:0xab27d4
      7629ae:    8b f0                    mov    esi,eax
      7629b0:    e8 9b 3d fd ff           call   0x736750
      7629b5:    3b f3                    cmp    esi,ebx
      7629b7:    75 08                    jne    0x7629c1
      7629b9:    3b c3                    cmp    eax,ebx
      7629bb:    0f 84 0b 01 00 00        je     0x762acc
    (if you're wondering why I don't have an IDA interface is because I decompiled gothic.exe under linux with objdump)

    Red functions are oCNpc::IsDead and oCNpc::IsUnconscious. At first I thought about inverting the result of one of those to "simulate" a dead npc. IsUnconscious was difficult, IsDead was easy but as soon as I wrote the bytes (that would have been restored to original after few milliseconds) every npc died because IsDead returned True for everyone; I acqually never dreamt that that function was continuously called.

    Green addresses are adresses which I think make the function returns (but I may be wrong). My second idea would be to hook blue istructions to read what there is in those registers, because I suppose there might be return values of oCNpc::IsDead and oCNpc::IsUnconscious. Hence if I'm right I could change those instead of the functions above.


    The problem is that they are between call and jump istruction and they cannot be hooked as far as you told me.
    What do you think about it?

    Thanks

  8. Beiträge anzeigen #8 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.447
     
    Lehona ist offline
    How are you calling it? Let's assume your Daedalus-Code looks like this:

    Code:
    func void openStealInventory(var c_npc slf) { 
    
    /* Complex Call stuff */
    
    };
    You can probably do it like this:

    Code:
    func void openStealInventory(var c_npc slf) { 
    
    DisableOpenDeadInventoryChecks();
    /* Complex Call stuff */
    EnableOpenDeadInventoryChecks();
    };


    In the Disable-Function you simply override the relevant jumps with a nop-instruction (decimal value is 144, i.e. a single byte, but there's a constant for that somewhere in LeGo...). In the Enable-Function you just restore the original bytes.


    I might be able to say more when I get home (couple o' days), because I don't have access to a windows machine, either

  9. Beiträge anzeigen #9 Zitieren
    Veteran
    Registriert seit
    Jan 2012
    Beiträge
    681
     
    Frank-95 ist offline
    Code:
      76299b:    0f 84 2b 01 00 00        je     0x762acc
      7629a1:    8b c8                    mov    ecx,eax
      7629a3:    e8 98 3d fd ff           call   0x736740
      7629a8:    8b 0d d4 27 ab 00        mov    ecx,DWORD PTR ds:0xab27d4
      7629ae:    8b f0                    mov    esi,eax
      7629b0:    e8 9b 3d fd ff           call   0x736750
      7629b5:    3b f3                    cmp    esi,ebx
      7629b7:    75 08                    jne    0x7629c1
      7629b9:    3b c3                    cmp    eax,ebx
      7629bb:    0f 84 0b 01 00 00        je     0x762acc
    I "noped" the last jump istruction but the hero says "nothing to plunder, even though I'm sure there is.

    Nervetheless I'm sure that is the return address because I "decompiled" the code by clicking F5 in IDA, and there is a goto LABEL twice in the first part of the code: after oCNpc:etFocusVob, that jumps if it is not valid, and after oCNpc:IsDead and oCNpc:IsUnconscious, inside an if statement that jumps if both function return FALSE, so when the inventory cannot be opened.
    So it's pretty annoying.

    How are you calling it?
    I have an item in the inventory which a click, and via FF calls another function after few second, so that player inventory is closed at that moment. The last called function is made like you said:

    Code:
    NopJumps;
    CALL__thiscall(heroaddress, 0x762970 /*oCNpc:OpenDeadInventory*/);
    RestoreJumps;

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide