GTA Modification Forums
[C++|ASM] Alter damage received
 |
|
 |
| |
Fantaseb  |
|
One Nation, One Love, But Who? ;)

Group: BUSTED!
Joined: Oct 17, 2011


|
| 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 This post has been edited by Fantaseb on Friday, Mar 30 2012, 22:05
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
FaTony  |
Posted: Saturday, Mar 31 2012, 00:30
|
C++ guy

Group: Members
Joined: Aug 12, 2011

|
| 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
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
LMS  |
Posted: Saturday, Mar 31 2012, 00:47
|
Punk-ass Bitch

Group: Members
Joined: Jun 30, 2005


|
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
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
LMS  |
Posted: Saturday, Mar 31 2012, 10:55
|
Punk-ass Bitch

Group: Members
Joined: Jun 30, 2005


|
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.
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
FaTony  |
Posted: Saturday, Mar 31 2012, 15:11
|
C++ guy

Group: Members
Joined: Aug 12, 2011

|
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
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
FaTony  |
Posted: Saturday, Mar 31 2012, 15:59
|
C++ guy

Group: Members
Joined: Aug 12, 2011

|
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 |
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
LMS  |
Posted: Saturday, Mar 31 2012, 18:27
|
Punk-ass Bitch

Group: Members
Joined: Jun 30, 2005


|
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
|
|
|
|
|
 |
|
 |
 |
|
 |
| |
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:
Pages:
(2) [1] 2
Track this topic
Receive email notification when a reply has been made to this topic and you are not active on the board.
Subscribe to this forum
Receive email notification when a new topic is posted in this forum and you are not active on the board.
Download / Print this Topic
Download this topic in different formats or view a printer friendly version.
| |
 |
|
 |
|