Since I’m unsure if I’ll ever actually finish my Metro Exodus Enhanced Edition Table I will just post some things I found so far… (It’s not that much, really. But maybe someone else wants to work on it!)
The following scripts were made for v2.0.0.1 - Steam!
- Health Hook
; Game : MetroExodus.exe
; Version: 1.0
; Date : 09-11-2024
; Author : Leunsel
;
; Address of signature = MetroExodus.exe + 0x00A56E79
; "0F 2F ? ? ? ? ? 0F 83 ? ? ? ? 48 8B ? ? ? ? ? 48 85 ? 75"
; ---> MetroExodus.exe+A56E79 - 0F 2F 80 B8 03 00 00 - comiss xmm0,[rax+000003B8]
; ..."0F 2F 80 B8 03 00 00 0F 83 42" <<< Original Pattern
[ENABLE]
aobScanModule(HealthHook,MetroExodus.exe,0F 2F ? ? ? ? ? 0F 83 ? ? ? ? 48 8B ? ? ? ? ? 48 85 ? 75)
alloc(newmem,$1000,HealthHook)
label(return code)
label(HealthPtr)
newmem:
mov [HealthPtr],rax
code:
comiss xmm0,[rax+000003B8]
jmp return
HealthPtr:
dq 0
HealthHook:
jmp newmem
nop 2
return:
registersymbol(HealthHook HealthPtr)
[DISABLE]
HealthHook:
db 0F 2F 80 B8 03 00 00
unregisterSymbol(*)
dealloc(*)
- Mask Health Hook
; Game : MetroExodus.exe
; Version: 1.0
; Date : 09-11-2024
; Author : Leunsel
;
; Address of signature = MetroExodus.exe + 0x0096DA0A
; "F3 0F ? ? ? ? ? ? F3 0F ? ? F3 0F ? ? F3 0F ? ? 0F 28 ? F3 0F ? ? ? ? F3 0F ? ? 48 83 C4"
; ---> MetroExodus.exe+96DA07 - 0F 28 D4 - movaps xmm2,xmm4
; ---> MetroExodus.exe+96DA0A - F3 0F 5C 87 B8 03 00 00 - subss xmm0,[rdi+000003B8]
; ---> MetroExodus.exe+96DA12 - F3 0F 5C E1 - subss xmm4,xmm1
; ..."F3 0F 5C 87 B8 03 00 00" <<< Original Pattern
[ENABLE]
aobScanModule(MaskHealthHook,MetroExodus.exe,F3 0F ? ? ? ? ? ? F3 0F ? ? F3 0F ? ? F3 0F ? ? 0F 28 ? F3 0F ? ? ? ? F3 0F ? ? 48 83 C4)
alloc(newmem_B,$1000,MaskHealthHook)
label(return_B code_B)
label(MaskHealthPtr)
newmem_B:
mov [MaskHealthPtr],rdi
code_B:
subss xmm0,[rdi+000003B8]
jmp return_B
MaskHealthPtr:
dq 0
MaskHealthHook:
jmp newmem_B
nop 3
return_B:
registersymbol(MaskHealthHook MaskHealthPtr)
[DISABLE]
MaskHealthHook:
db F3 0F 5C 87 B8 03 00 00
unregisterSymbol(*)
dealloc(*)
- Transform Hook
; Game : MetroExodus.exe
; Version: 1.0
; Date : 09-11-2024
; Author : Leunsel
;
; Address of signature = PhysX3_x64.dll + 0x0011835A
; "F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? 48 8D ? ? F3 0F"
; ---> PhysX3_x64.dll+11835A - F3 0F 10 50 0C - movss xmm2,[rax+0C]
; ..."F3 0F 10 50 0C" <<< Original Pattern
[ENABLE]
aobScanModule(TransformHook,PhysX3_x64.dll,F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? F3 0F ? ? ? 48 8D ? ? F3 0F)
alloc(newmem,$1000,TransformHook)
label(return code)
label(TransformPtr)
label(TransformOffsets SavedPositionFlt BackupPositionFlt)
newmem:
mov [TransformPtr],rax
code:
movss xmm2,[rax+0C]
jmp return
TransformPtr:
dq 0
TransformOffsets:
dd 0C ; X -> Example: 40
dd 10 ; Y -> Example: 44
dd 14 ; Z -> Example: 48
SavedPositionFlt:
dd (float)0 ; X
dd (float)0 ; Y
dd (float)0 ; Z
BackupPositionFlt:
dd (float)0 ; X
dd (float)0 ; Y
dd (float)0 ; Z
; Those Symbols are only required if you actually
; "plan" on adding a dedicated Teleport.
TransformHook:
jmp newmem
return:
registersymbol(TransformHook TransformPtr)
registersymbol(TransformOffsets SavedPositionFlt BackupPositionFlt)
[DISABLE]
TransformHook:
db F3 0F 10 50 0C
unregisterSymbol(*)
dealloc(*)
- Health Decrease Hook
; Game : MetroExodus.exe
; Version: 1.0
; Date : 09-11-2024
; Author : Leunsel
;
; Address of signature = MetroExodus.exe + 0x00874232
; "F3 0F ? ? ? 48 8B ? F3 41 ? ? ? 8B 41"
; ---> MetroExodus.exe+87422F - 48 8B FA - mov rdi,rdx
; ---> MetroExodus.exe+874232 - F3 0F 5C 52 14 - subss xmm2,[rdx+14]
; ---> MetroExodus.exe+874237 - 48 8B D9 - mov rbx,rcx
; ---> MetroExodus.exe+87423A - F3 41 0F 11 10 - movss [r8],xmm2
; ..."F3 0F 5C 52 14 48" <<< Original Pattern
[ENABLE]
aobScanModule(HealthDecHook,MetroExodus.exe,F3 0F ? ? ? 48 8B ? F3 41 ? ? ? 8B 41)
alloc(newmem,$1000,HealthDecHook)
label(return code exit)
label(HealthDecPtr HealthDecFlag HealthDecMultiplier)
label(Player Mask Entity)
newmem:
push r9
push r10
push r11
push r12
; ...
mov r9,r8 ; To not corrupt the register
sub r9,3B8 ; Base of each Health Hook
; Now we can compare...
; movss [r8],xmm2 -> R8 = HealthPtr + 0x3B8
test r9,r9
jz code
mov r10,HealthPtr
mov r10,[r10]
test r10,r10
jz code
cmp r10,r9
je Player
mov r12,MaskHealthPtr
mov r12,[r12]
test r12,r12
jz code
cmp r12,r9
je Mask
jmp Entity ; This might actually not "work properly" yet.
; I think a dedicated Enemy Compare is necessary.
Player:
mov [HealthDecPtr],r9
cmp byte ptr [HealthDecFlag],0 ; Disabled
je code
cmp byte ptr [HealthDecFlag],1 ; No Damage
jne @f
jmp exit ; We just skip the subtraction!
@@:
cmp byte ptr [HealthDecFlag],2 ; Multiplier (Default)
jne @f
movss xmm15,[rdx+14]
mulss xmm15,[HealthDecMultiplier]
movss [rdx+14],xmm15
jmp code
@@:
mov byte ptr [HealthDecFlag],0
jmp code
Mask:
mov [HealthDecPtr+08],r9
cmp byte ptr [HealthDecFlag+1],0 ; Disabled
je code
cmp byte ptr [HealthDecFlag+1],1 ; No Damage
jne @f
jmp exit ; We just skip the subtraction!
@@:
cmp byte ptr [HealthDecFlag+1],2 ; Multiplier (Default)
jne @f
movss xmm15,[rdx+14]
mulss xmm15,[HealthDecMultiplier+4]
movss [rdx+14],xmm15
jmp code
@@:
mov byte ptr [HealthDecFlag+1],0
jmp code
Entity:
mov [HealthDecPtr+10],r9
cmp byte ptr [HealthDecFlag+2],0 ; Disabled
je code
cmp byte ptr [HealthDecFlag+2],1 ; Feature
jne @f
movss xmm2,[rdx+14] ; We just move the "Damage" into the current health
jmp code
@@:
cmp byte ptr [HealthDecFlag+2],2 ; Multiplier (Default)
jne @f
movss xmm15,[rdx+14]
mulss xmm15,[HealthDecMultiplier+8]
movss [rdx+14],xmm15
jmp code
@@:
mov byte ptr [HealthDecFlag+2],0
jmp code
code:
subss xmm2,[rdx+14]
exit:
pop r12
pop r11
pop r10
pop r9
jmp return
HealthDecPtr:
dq 0 ; Player - 0x00
dq 0 ; Mask - 0x08
dq 0 ; Entity - 0x10
HealthDecFlag:
db 2 ; Player - 0x0
db 2 ; Mask - 0x1
db 2 ; Entity - 0x2
HealthDecMultiplier:
dd (float)0.25 ; Player - 0x0
dd (float)0.25 ; Mask - 0x4
dd (float)3.00 ; Entity - 0x8
HealthDecHook:
jmp newmem
return:
registersymbol(HealthDecHook HealthDecPtr HealthDecFlag HealthDecMultiplier)
[DISABLE]
HealthDecHook:
db F3 0F 5C 52 14
unregisterSymbol(*)
dealloc(*)