IMG

 
IMG
IMG   IMG
  Welcome to GTAForums! Be sure to check out the Grand Theft Auto V Forum.

You are not registered! (If you are, click here to login) Registering is fast, free and easy and allows you to instantly reply to any topic on GTAForums.
Why wait? Click here to register your own unique username and become part of the ever-growing community!


( Log In | Register | Revalidate Validation E-mail )
Quick Log-In:
  IMG
       
>
Forum Rules GTA Modification Forums

Post mod/code requests in the Mod Requests topic

Post mod releases in the Mod Showroom

Read the Modding Rules BEFORE posting!

GTAGarage.com
free mod hosting from GTANet, simply login with your GTAForums account details

GTAModding.com
GTANet's modding wiki

GTA Modding Chatroom
provided by irc.gtanet.com (Don't have an IRC client? Click here)


Pages: (2) [1] 2   ( Go to first unread post ) Reply to this topicStart new topicStart Poll

 [C++|ASM] Alter damage received

 
FaTony  
Posted: Thursday, Mar 29 2012, 22:40
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Hello there.

I would like to be able to alter damage received by Niko. For example, to be able to survive explosion or high fall but still take some damage.

Obviously, I can monitor player health very frequently, but this won't block 1-hit kills as player will already be dead when I would check him.

I'm good at C++ but bad at reverse engineering, so if anyone would kindly provide C prototype and address to patch or at least some clues of where to look, it would be greatly appreciated.
PM
  Top
 

 
LMS  
Posted: Friday, Mar 30 2012, 14:46
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



Since you are talking about Niko, I assume you are using GTA IV and Patch #7.

Have a look at sub_0ABB170, it handles damaging peds. When immediately returning all peds are invincible. The first param is the ped, so you could check if ped is player and then alter the damage value.
PM
  Top
 

 
FaTony  
Posted: Friday, Mar 30 2012, 21:07
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Ok, how exactly do I do this? I'm familiar with jump hooking but that completely overrides function, but I only need to change the value of argument. It looks like there are 23 calls to that function, should I patch those to use the address of my function and then call original function in the body of mine?

Some code would be appreciated.

And just to be sure that I've found the correct function, here's the prototype IDA gives me:
CODE
int __stdcall sub_ABB170(int, float);
PM
  Top
 

 
Fantaseb  
Posted: Friday, Mar 30 2012, 22:00
Quote Post


One Nation, One Love, But Who? ;)
Group Icon
Group: BUSTED!
Joined: Oct 17, 2011

uk.gif

XXXXX



QUOTE (FaTony @ Friday, Mar 30 2012, 21:07)
Ok, how exactly do I do this? I'm familiar with jump hooking but that completely overrides function, but I only need to change the value of argument. It looks like there are 23 calls to that function, should I patch those to use the address of my function and then call original function in the body of mine?

Some code would be appreciated.

And just to be sure that I've found the correct function, here's the prototype IDA gives me:
CODE
int __stdcall sub_ABB170(int, float);

ASM is ScoToolBox right? Why not just a a key board button, which would be like
CODE

:Label6791
PushD 41 //Look whatever key you want
Call Native SET_PLAYER_INIVINCIBLE 2 0
Var3
PushD 41


Something like that cant remember that much or just in c++ the same native but it would be like this if using scocl:

CODE
SET_PLAYER_INIVINCIBLE (pid, TRUE);


Is this what you mean, that would make the player not take any damage, or just go into the Weaponfile.xml and change the pedplayer (Or whatever it is called) to 0 and same for networkpedplayer, and add in fall etc and just everything from UZI_DRIVEBY etc. I dont know much about the c++ aru thing, i only know about Scocl (high level compiler) or the scotoolbox, hope this helped smile.gif

This post has been edited by Fantaseb on Friday, Mar 30 2012, 22:05
PM
  Top
 

 
FaTony  
Posted: Saturday, Mar 31 2012, 00:30
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



QUOTE (Fantaseb @ Friday, Mar 30 2012, 22:00)
ASM is ScoToolBox right?


No, I mean x86 assembly language.

Anyway, I was googling on hooking and made up some code:
CODE
DWORD dwLoadOffset = ((DWORD)GetModuleHandle(NULL) - 0x400000);
DWORD address = 0;
BYTE originalcode[6];
BYTE patchedcode[6] = { 0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3 };

typedef int (__stdcall *ABB170)(int, float);

ABB170 func;

void InstallHooks(void)
{
address = 0xABB170 + dwLoadOffset;
func = (ABB170)address;
DWORD addressdiff = ((DWORD)&my_ABB170 - (address + 5));
memcpy(patchedcode + 1, &addressdiff, sizeof(DWORD));
DWORD oldp;
   VirtualProtect((LPVOID)address, 6, PAGE_EXECUTE_READWRITE, &oldp);
memcpy(originalcode, (void *)address, 6);
memcpy((void *)address, patchedcode, 6);
}

int __stdcall my_ABB170(int ped, float damage)
{
memcpy((void *)address, originalcode, 6);
int ret = func(ped, damage);
memcpy((void *)address, patchedcode, 6);
return ret;
}


It crashes at
CODE
int ret = func(ped, damage);


Looking through a debugger, damage has an insane value. Wrong prototype?

Hex-Rays decompiler gives me this:
CODE
void __userpurge sub_ABB170(int a1<ecx>, double a2<st0>, __m128i a3<xmm2>, __m128d a4<xmm3>, __int128 a5<xmm4>, __m128i a6<xmm7>, int a7, int a8);


This post has been edited by FaTony on Saturday, Mar 31 2012, 00:35
PM
  Top
 

 
LMS  
Posted: Saturday, Mar 31 2012, 00:47
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



This should work (untested though):

CODE

#include "PedDamageHook.h"

#include "Helper.h"
#include "Detour.h"

static DWORD dwRealFunction;
// Max damage player can take
static float fMaxValue = 2;

void PedDamageHook::HookPedDamage()
{
// Calculate function address
DWORD dwFunc = Helper::GetGameBase() + 0xABB170;

// Place jmp instruction and overwrite first 8 bytes (so we destroy no opcodes).
// Note: To simplify matters I'll put the first 8 bytes at the end of the codecave, so you can better follow my code
// Note2: This function returns the first parameter (so dwFunc) + the bytes to overwrite (so 8), so we can jump back right after our hook
dwRealFunction = (DWORD)DetourFunction((PBYTE)dwFunc, (PBYTE)PedDamageHook::Hooked_damagePed, 8);
}


// Naked so we have no prolog/epilog code
__declspec( naked ) int __stdcall PedDamageHook::Hooked_damagePed(void* ped, float damage)
{
// Simple asm code, which checks if the ped is the local player ped and if so ensures that damage isn't greater than 2
_asm
{
 push  eax
 push  ecx
 push  esi

 // 08788D0 is the function that returns the ped associated to the player
 call  Helper::GetGameBase
 add   eax, 08788D0h
 push  0 // player index
 call  eax
 add   esp, 04

 mov   esi, ped
 cmp   esi, eax
 jnz   NotLocalPlayer

 // Read and compare damage value
 movss  xmm0, [ecx+4h]
 comiss   xmm0, fMaxValue
 jbe   ValueOk

 // Adjust damage value
 movss  xmm0, fMaxValue
 movss  [ecx+4h], xmm0

ValueOk:
NotLocalPlayer:
 pop   esi
 pop   ecx
 pop   eax

// Code from '0ABB170', 8 ovewritten bytes
 sub  esp, 10h
 push ebp
 mov  ebp, [esp+1Ch]

 jmp   dwRealFunction
}
}


CODE

DWORD Helper::GetGameBase()
{
if(m_dwGameBase == NULL)
{
 m_dwGameBase = ((DWORD)GetModuleHandle(NULL) - 0x400000);
}
return m_dwGameBase;
}


Edit: Works fine on EFLC 1.1.2.0 (changed offsets of course)

This post has been edited by LMS on Saturday, Mar 31 2012, 00:54
PM
  Top
 

 
FaTony  
Posted: Saturday, Mar 31 2012, 01:21
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Nice one! Except I'm really bad at assembly. By writing the whole function in assembly you're able to preserve the stack, which was not in my case.

So, if I'm using C++ ScriptHook, can I compare that void * to Scripting::Ped that ScriptHook returns? What about the stack, can this inline assembly be redone into C++ code? And, of course, what's the offset for EFLC?
PM
  Top
 

 
LMS  
Posted: Saturday, Mar 31 2012, 10:55
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



I prefer assembly for simple functions like this, especially when hooking so I know what's going on there and don't have C++ possibly crash my code because of prolog or epilog code fails.
void* ped is a pointer to the actual ped class iv uses internally while Scripting::Ped is only a wrapper around a handle, so no you can't compare them. But when you look at my asm code I simply called an internal function that returns the player ped associated to the player index to check if it's the local player we are handling. It can be redone in C++ of course, I'd suggest you to use a library like MS Detours then, which also saves the bytes the hook overwrites so you don't have to place them at the end of your function like I did. EFLC offset is: sub_0AE2B30 and sub_0846EA0 to get the local player ped.

BTW: The code was just a quick mockup I wrote and will limit all damage. Since you are looking for falling damage, you should set a bp on the first instruction in the function, fall down somewhere and then trace back the call. You could then do something like, before the fall code calls the damage code, set a static var like "damageType = FallingDamage" and then in your damage code hook you can check for the damage source. Just an idea though.
PM
  Top
 

 
FaTony  
Posted: Saturday, Mar 31 2012, 15:11
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Ok, I'm trying to use MS detours:
CODE
#include <windows.h>
#include <detours.h>

DWORD dwLoadOffset = ((DWORD)GetModuleHandle(NULL) - 0x400000);
DWORD realaddress = 0;

typedef int (__stdcall *ABB170)(void *, float);

ABB170 realfunc;

void InstallHooks(void)
{
realaddress = 0xABB170 + dwLoadOffset;
realfunc = (ABB170)realaddress;
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)realfunc, &my_ABB170);
DetourTransactionCommit();
}

int __stdcall my_ABB170(void *ped, float damage)
{
return realfunc(ped, damage);
}


Damage value is still strange in the debugger. I tried to follow the code into disassembly and it looks like MS detours correctly patch memory so the flow goes just right after the jmp to ABB178, then it jumps into sub_AB94C0 and in it goes to
CODE
00AB94C8  mov         eax,dword ptr [edi+0Ch]

and then crashes with: Unhandled exception at 0x00ab94c8 in GTAIV.exe: 0xC0000005: Access violation reading location 0x0000000c.

I guess I messed up the value of edi. It's 0 in my case but should contain a pointer to some valid memory, right?

Any help?

This post has been edited by FaTony on Saturday, Mar 31 2012, 15:24
PM
  Top
 

 
LMS  
Posted: Saturday, Mar 31 2012, 15:38
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



Please post the assembly code of ABB170 (like the first 20bytes), your detour and where your detour jumps to (where the overwritten bytes are saved).
PM
  Top
 

 
FaTony  
Posted: Saturday, Mar 31 2012, 15:59
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Here's patched code:
CODE
00ABB16C  int         3  
00ABB170  jmp         my_ABB170 (24E1636h)  
00ABB175  int         3  
00ABB176  int         3  
00ABB177  int         3  
00ABB178  mov         al,byte ptr [ebp+4]  
00ABB17B  test        al,1  
00ABB17D  push        edi  
00ABB17E  mov         edi,ecx  
00ABB180  jne         00ABB692  
00ABB186  xorps       xmm0,xmm0  
00ABB189  and         al,0C1h  
00ABB18B  or          al,1  
00ABB18D  push        esi  
00ABB18E  mov         esi,dword ptr [esp+20h]
etc.


Here's my function:
CODE
int __stdcall my_ABB170(void *ped, float damage)
{
024E5900  push        ebp  
024E5901  mov         ebp,esp  
024E5903  sub         esp,0C0h  
024E5909  push        ebx  
024E590A  push        esi  
024E590B  push        edi  
024E590C  lea         edi,[ebp-0C0h]  
024E5912  mov         ecx,30h  
024E5917  mov         eax,0CCCCCCCCh  
024E591C  rep stos    dword ptr es:[edi]  
return realfunc(ped, damage);
024E591E  mov         esi,esp  
024E5920  push        ecx  
024E5921  fld         dword ptr [damage]  
024E5924  fstp        dword ptr [esp]  
024E5927  mov         eax,dword ptr [ped]  
024E592A  push        eax  
024E592B  call        dword ptr [func (24F5290h)]  
024E5931  cmp         esi,esp  
024E5933  call        @ILT+1125(__RTC_CheckEsp) (24E146Ah)  
}
024E5938  pop         edi  
024E5939  pop         esi  
024E593A  pop         ebx  
024E593B  add         esp,0C0h  
024E5941  cmp         ebp,esp  
024E5943  call        @ILT+1125(__RTC_CheckEsp) (24E146Ah)  
024E5948  mov         esp,ebp  
024E594A  pop         ebp  
024E594B  ret         8  


And here's trampoline that patched realfunc points to:

CODE
40AA00D8  sub         esp,10h  
40AA00DB  push        ebp  
40AA00DC  mov         ebp,dword ptr [esp+1Ch]  
40AA00E0  jmp         00ABB178  


PM
  Top
 

 
LMS  
Posted: Saturday, Mar 31 2012, 16:21
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



I suspect the prototype is just wrong/incomplete, but I'm not sure how the real prototype looks like. Any chance you can use a little inline assembler to read/write the value?
CODE

int __stdcall my_ABB170(void *ped, float damage)
{
float dmg;

_asm
{
 // Read value into dmg
 movss xmm0, [ecx+4h]
 movss dmg, xmm0

 // Write changed value back
 movss xmm0, dmg
 movss [ecx+4h], xmm0
}
}
PM
  Top
 

 
FaTony  
Posted: Saturday, Mar 31 2012, 16:33
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Maybe you can just modify the asm code you wrote a few posts back to call my function?

So my_ABB170 will be naked in asm and it will call another function such as void OnDamage(void *ped, float &damage) that will be written in C++.

I don't know how to call C functions from asm (all those calling conventions and stack, ugh), so I'll need your help. Also, what's the prototype of function to get player ped, void *func(void)?

Thanks for your help so far.
PM
  Top
 

 
LMS  
Posted: Saturday, Mar 31 2012, 18:27
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



I did some more work on this and wrapped all asm calls in C++ functions. This should work fine on IV 1.0.7.0. Simply place your C++ code in "OnPedDamage".

CODE

#include "PedDamageHook.h"

#include "Helper.h"
#include "Detour.h"

static DWORD dwRealFunction;
// Max damage player can take
static float fMaxValue = 2;

void PedDamageHook::HookPedDamage()
{
// Calculate function address
DWORD dwFunc = Helper::GetGameBase() + 0xABB170;

// Place jmp instruction and overwrite first 8 bytes (so we destroy no opcodes).
// Note: To simplify matters I'll put the first 8 bytes at the end of the codecave, so you can better follow my code
// Note2: This function returns the first parameter (so dwFunc) + the bytes to overwrite (so 8), so we can jump back right after our hook
dwRealFunction = (DWORD)DetourFunction((PBYTE)dwFunc, (PBYTE)PedDamageHook::Hooked_damagePed, 8);
}

DWORD dwECX;

void* PedDamageHook::GetPlayerPed(int index)
{
void* ped;
_asm
{
 // 08788D0 is the function that returns the ped associated to the player
 call  Helper::GetGameBase
 add   eax, 08788D0h
 push  index // player index
 call  eax
 add   esp, 04
 mov   ped, eax
}
return ped;
}
float PedDamageHook::ReadDamage()
{
float value = 0.0f;
_asm
{
 push  ecx
 mov   ecx, dwECX
 movss  xmm0, [ecx+4h]
 movss  value, xmm0
 pop   ecx
}
return value;
}
void PedDamageHook::SetDamage(float damage)
{
_asm
{
 push ecx
 mov  ecx, dwECX
 movss xmm0, damage
 movss [ecx+4h], xmm0
 pop  ecx
}
}
__declspec( naked ) int __stdcall PedDamageHook::Hooked_damagePed(void* unknown, void* target)
{
_asm
{
 // Save ecx
 mov  dwECX, ecx
 // Call function
 call OnPedDamage
 // Restore ecx
 mov  ecx, dwECX
 jmp  dwRealFunction
}
}

void PedDamageHook::OnPedDamage(void* unknown, void* target)
{
// Read damage value
float damage = PedDamageHook::ReadDamage();

// Modify if needed
if (damage > 10)
{
 void* playerPed = PedDamageHook::GetPlayerPed(0);
 if (playerPed == target)
 {
  PedDamageHook::SetDamage(1.0f);
 }
}
}


I hope this helps you a little.

Edit: Works fine on EFLC.

Edit2: Found a way to get the ped that is dealing the damage, check this out:

CODE

void* source = 0;
_asm
{
 push eax
 mov  eax, [ebp+14h]
 mov  source, eax
 pop  eax
}

// If damage is dealt by player, multiply by 20
if (source == playerPed)
{
 PedDamageHook::SetDamage(damage * 20);
}


This post has been edited by LMS on Saturday, Mar 31 2012, 19:03
PM
  Top
 

 
FaTony  
Posted: Sunday, Apr 1 2012, 13:18
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



I'm currently copying your code, but I wonder where did you put the first 8 bytes of original function?
PM
  Top
 

 
LMS  
Posted: Sunday, Apr 1 2012, 13:44
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



QUOTE (FaTony @ Sunday, Apr 1 2012, 14:18)
I'm currently copying your code, but I wonder where did you put the first 8 bytes of original function?

My own hook functions saves the bytes and will execute them before returning to the real function (just like MS detours does).
PM
  Top
 

 
FaTony  
Posted: Sunday, Apr 1 2012, 14:22
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Do you use Xliveless?

I'm halfway through copying and it doesn't crash when peds get damaged, but it randomly crashes after few minutes in the game.

EDIT: Ok, it looks like I've triggered GFWL protection. It doesn't load now.

This post has been edited by FaTony on Sunday, Apr 1 2012, 14:29
PM
  Top
 

 
LMS  
Posted: Sunday, Apr 1 2012, 14:32
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



Yeah, you should switch to xliveless for memory patching.
PM
  Top
 

 
FaTony  
Posted: Sunday, Apr 1 2012, 15:53
Quote Post


C++ guy
Group Icon
Group: Members
Joined: Aug 12, 2011

XXXXX



Oh well, thanks a lot for your help. I'm not ready to switch to Xliveless yet.

I'm going to stop here now and hope someone will make this thread into nice Xliveless-compatible trainer.

Thanks again.
PM
  Top
 

 
LMS  
Posted: Sunday, Apr 1 2012, 16:49
Quote Post


Punk-ass Bitch
Group Icon
Group: Members
Joined: Jun 30, 2005

gr.gif

XXXXX



Check this out: http://www.gtaforums.com/index.php?showtopic=419908 - This will disable the xlive code that is checking your memory for changes.
No problem, after all these "omg how to use scripthook!!111 help!11" topics here, it was a real pleasure to actually help someone coding something that does not consist of two .NET calls. Good luck with your project and I'd recommend you to give assembly a shot, it's worth it when it comes down to reversing.
PM
  Top
 

 

1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)

0 Members:

Pages: (2) [1] 2 

Topic Options Reply to this topicStart new topicStart Poll
Search topic for posted by (exact match)



 
IMG IMG