Crash when asm meet with the bad value at mov?

pigeon

Expert Cheater
Mar 4, 2017
51
2
8
#1
Hi!
At current moment i faced with the problem when script with compares and mov multilevel pointers very unstable: it can be activated on "press any key" screen of the AC:Origins game, but not when map already loaded even with fullaccess and even while AOB is correct or it just crash when it can be activated anytime.
I'm already give up to deal with this multipointer and found another one-level compare that looks stable, but for learning purposes and if i made here some mistake, i want to understand what's the problem here. Or maybe this can be because of the game? Here is post of SunBeam that can help to understand some aspects of this game and why here is fullaccess on the top of the script:http://fearlessrevolution.com/viewtopic.php?p=31616#p31616
but if short, it is CPY version of the game, game have denovu and vmprotect.

And "clear" script,without of any null checks:
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( newmem, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
alloc(newmem,0x1000,ACOrigins.exe)
alloc(store_pointer,8)
alloc(myExposure,8) // use external "myExposure" address for control Exposure

label(code)
label(return)
registersymbol(store_pointer)

store_pointer:
dd 00

newmem:
  push rax
  push rcx
  mov rax,[rbx+348] // first level pointer
  mov rcx,[rax+34]  // second level, crash here if script can be enabled
  mov [store_pointer],rcx // this and next two lines should be commented if script can not to run
  cmp [store_pointer],00CB0002 // if rbx+348+34 equal 00CB0002, than this should be Exposure value
  jne code
  pop rcx
  pop rax
  mov eax,[myExposure] // Send decided Exposure value
  mov [rbx],eax // original code
  add rsp,00000090
  jmp return

code:
  pop rcx
  pop rax
  mov [rbx],eax
  add rsp,00000090
  jmp return

Enviro1:
  jmp newmem
  nop
  nop
  nop
  nop
return:
registersymbol(Enviro1)
registersymbol(myExposure)

[DISABLE]

Enviro1:
  db 89 03 48 81 C4 90 00 00 00
unregistersymbol(Enviro1)
unregistersymbol(myExposure)
unregistersymbol(store_pointer)
dealloc(myExposure)
dealloc(store_pointer)
dealloc(newmem)



{
// ORIGINAL CODE - INJECTION POINT: "ACOrigins.exe"+84DF92

"ACOrigins.exe"+84DF78: 0F B7 06                    -  movzx eax,word ptr [rsi]
"ACOrigins.exe"+84DF7B: 66 89 03                    -  mov [rbx],ax
"ACOrigins.exe"+84DF7E: 0F B6 46 02                 -  movzx eax,byte ptr [rsi+02]
"ACOrigins.exe"+84DF82: 88 43 02                    -  mov [rbx+02],al
"ACOrigins.exe"+84DF85: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DF8C: 5F                          -  pop rdi
"ACOrigins.exe"+84DF8D: 5E                          -  pop rsi
"ACOrigins.exe"+84DF8E: 5B                          -  pop rbx
"ACOrigins.exe"+84DF8F: C3                          -  ret 
"ACOrigins.exe"+84DF90: 8B 06                       -  mov eax,[rsi]
// ---------- INJECTING HERE ----------
"ACOrigins.exe"+84DF92: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DF94: 48 81 C4 90 00 00 00        -  add rsp,00000090
// ---------- DONE INJECTING  ----------
"ACOrigins.exe"+84DF9B: 5F                          -  pop rdi
"ACOrigins.exe"+84DF9C: 5E                          -  pop rsi
"ACOrigins.exe"+84DF9D: 5B                          -  pop rbx
"ACOrigins.exe"+84DF9E: C3                          -  ret 
"ACOrigins.exe"+84DF9F: 8B 06                       -  mov eax,[rsi]
"ACOrigins.exe"+84DFA1: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DFA3: 0F B7 46 04                 -  movzx eax,word ptr [rsi+04]
"ACOrigins.exe"+84DFA7: 66 89 43 04                 -  mov [rbx+04],ax
"ACOrigins.exe"+84DFAB: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DFB2: 5F                          -  pop rdi
}
So what happened here is when i found address for Exposure (it's more like multiplier for original exposure), because this instruction access for a tons of addresses, i check dissect data and at first i found stable value at rbx+348+34 offset (in pointer) and looks like anything else here have it's own unique and stable value. But because of something, anything i try to make script works cause crash or script just can't be enabled. I mean i try to past compare for rax and rcx before and after of some strings:
Code:
cmp rax,0
je code
Using TEST, only rax:
Code:
mov rax,[rbx+348]
mov rax,[rax+34]
does not make difference too and if script run, it anyway crash at rax,[rax+34]. Interesting here, that if i Toggle Breakpoint at "push rax" (here why i'm sure which string cause crash) and check how it's going - i can see that sometimes it passes through the whole script normally, but than it cause crash and i'm not have enough of skill to read information around it. Here is example if i try use script with compares for "0" and right after game crash when something wrong happen at mov rcx,[rax+34]


Just in case the whole script which was using for taking screenshot above:
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( newmem, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
alloc(newmem,0x1000,ACOrigins.exe)
alloc(store_pointer,8)
alloc(myExposure,8)

label(code)
label(return)
registersymbol(store_pointer)

store_pointer:
dd 00

newmem:
  push rax
  push rcx
  mov rax,[rbx+348]
  cmp rax,0 // difference
  je code // difference
  mov rcx,[rax+34]
  cmp rcx,0 // difference
  je code // difference
  mov [store_pointer],rcx
  cmp [store_pointer],00CB0002
  jne code
  pop rcx
  pop rax
  mov eax,[myExposure]
  mov [rbx],eax
  add rsp,00000090
  jmp return

code:
  pop rcx
  pop rax
  mov [rbx],eax
  add rsp,00000090
  jmp return

Enviro1:
  jmp newmem
  nop
  nop
  nop
  nop
return:
registersymbol(Enviro1)
registersymbol(myExposure)

[DISABLE]

Enviro1:
  db 89 03 48 81 C4 90 00 00 00
unregistersymbol(Enviro1)
unregistersymbol(myExposure)
unregistersymbol(store_pointer)
dealloc(myExposure)
dealloc(store_pointer)
dealloc(newmem)
In the very end, very two simple versions of the script that just disable instruction and works great:
Code:
[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
Enviro1:
  db 90 90
registersymbol(Enviro1)

[DISABLE]

Enviro1:
  db 89 03
unregistersymbol(Enviro1)
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( newmem, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
alloc(newmem,0x1000,ACOrigins.exe)

label(code)
label(return)

newmem:

code:
  //mov [rbx],eax
  add rsp,00000090
  jmp return

Enviro1:
  jmp newmem
  nop
  nop
  nop
  nop
return:
registersymbol(Enviro1)

[DISABLE]

Enviro1:
  db 89 03 48 81 C4 90 00 00 00

unregistersymbol(Enviro1)
dealloc(newmem)
 

sbryzl

Expert Cheater
Mar 4, 2017
97
6
8
#2
It's likely a null pointer problem. You can try this.

cmp [rbx+348],100000
jb code

which will clear out a lot of lower values which are not pointers. Other than that you can call isbadreadptr which can be resource heavy if you throw a lot at it.
 

SunBeam

RCE Fanatics
Talents
Fearless Donors
Feb 4, 2018
687
357
63
#3
..or hook below an engine check that already verifies for you if the pointer is valid :) Ever thought of that? I had the same problem recently with a script in my table (Stop Movement). See this:
Code:
ACOrigins.exe+EDDD30 - 48 8B C4              - mov rax,rsp
ACOrigins.exe+EDDD33 - 57                    - push rdi
ACOrigins.exe+EDDD34 - 48 81 EC 90000000     - sub rsp,00000090
ACOrigins.exe+EDDD3B - 48 8B F9              - mov rdi,rcx
ACOrigins.exe+EDDD3E - C6 81 000A0000 00     - mov byte ptr [rcx+00000A00],00
// ---------- INJECTING HERE ----------
ACOrigins.exe+EDDD45 - 48 8B 89 C0090000     - mov rcx,[rcx+000009C0]
// ---------- DONE INJECTING  ----------
ACOrigins.exe+EDDD4C - 48 85 C9              - test rcx,rcx
ACOrigins.exe+EDDD4F - 0F84 82030000         - je ACOrigins.exe+EDE0D7
ACOrigins.exe+EDDD55 - 80 7F 4A 00           - cmp byte ptr [rdi+4A],00
ACOrigins.exe+EDDD59 - 0F85 78030000         - jne ACOrigins.exe+EDE0D7
ACOrigins.exe+EDDD5F - 80 BF 040A0000 00     - cmp byte ptr [rdi+00000A04],00
ACOrigins.exe+EDDD66 - 48 89 58 08           - mov [rax+08],rbx
ACOrigins.exe+EDDD6A - 0F29 70 E8            - movaps [rax-18],xmm6
ACOrigins.exe+EDDD6E - 74 0C                 - je ACOrigins.exe+EDDD7C
ACOrigins.exe+EDDD70 - E8 0BB20000           - call ACOrigins.exe+EE8F80
ACOrigins.exe+EDDD75 - C6 87 040A0000 00     - mov byte ptr [rdi+00000A04],00
My aim in the above code is to set rdi+4A to 1 for all entities but Bayek (I later on thought of adding Senu and allies to it as well, but couldn't find a discriminator; all other entities but Bayek have the calculated id = 2). Now, back to the code: I didn't want to place the hook at ACOrigins.exe+EDDD55 because I need 5 bytes for a JMP; that location offers only 4. Furthermore, the CMP is between two jumps (a JE and a JNE) which would require me to also port the JNE to my cave. Plus am not fully sure (I could check) if the CMP is perhaps used by some code higher in the chain that would get engine to crash. So.. I placed the hook at ACOrigins.exe+EDDD45. But, as you can see, what follows that is a "test rcx,rcx". Initially, I didn't use this in my code so I just did the Entity check and moved 1 to any Entity+4A. But.. if RCX is 0, then you're fucked :) The test's role there is to filter out any NULLs. So in the end my hook became:
Code:
MoveHook:
mov rcx,[rcx+9C0] <-- original
test rcx,rcx <-- had to put this in for the NULLs
je short @f
  push rax
  mov rax,[pEntity] <-- pEntity is Bayek's entity pointer
  cmp [rdi+10],rax
  pop rax
  je short @f
    mov byte ptr [rdi+4A],1 <-- now I can write 1 to any Entity model, but Bayek's
    jmp StopMovement+7
@@:
jmp StopMovement+7
What the code above does is to stop movement of all entities, but Bayek, in a radius of 100-200m from Bayek. You'll see that if you disable the script, then get far away from those who were already not moving, once you get past the 100-200m threshold, they start moving again :)

BR,
Sun

P.S.#1: I'll read further in your code in a bit. Just got to work :p

P.S.#2: Above code works with any BipedComponent. That being said, if you enable this script in a chariot race, you'll see the driver stuck, but his chariot will still move. That's because there are 2 more components to the whole group: QuadrupedComponent for each of the 2 horses and WheeledActorComponent for the chariot. And those would need freezing as well, if you wanna cheat by not allowing your opponent (driver, horses and chariot) to move :D

P.S.#3: Can you tell me what your script actually does? What's this 'exposure'? Screenshots would also help. Cheers!
 

SunBeam

RCE Fanatics
Talents
Fearless Donors
Feb 4, 2018
687
357
63
#4
First glance at your script: can you tell me, if you define 'newmem' to be a static location, why you reallocate it? o_O
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( newmem, ACOrigins.exe+500 ) <-- if this was defined...

[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
alloc(newmem,0x1000,ACOrigins.exe) <-- ...don't reallocate/redefine here
The point of the define is to tell the script that your "cave" is ACOrigins.exe+500. If you then do alloc(newmem,..), you're telling script newmem is the newly allocated memory.

Secondly, if you store an 8-byte pointer, why do you use a DWORD (4-bytes)?
Code:
mov [store_pointer],rcx <-- this is an 8-byte address
..
store_pointer:
dd 00 <-- this tells me it's 4-bytes
Third, you can do the POPs before the JNE ;) This saves having to write the pops two times per CMP branch.

Here's the fixed script:
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( Hook, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule( Enviro_AOB, ACOrigins.exe, 89034881C4900000005F5E5BC38B )
label( Enviro1 )
registersymbol( Enviro1 ) // SB: we need it like this for the restore to work in [DISABLE] section
label( store_pointer ) // SB: no need to allocate random memory for these when you already use a static cave; just label them out :P
registersymbol( store_pointer )
label( myExposure ) // use external "myExposure" address for control Exposure; SB: same here, label, not alloc -- remember allocs fail when in-game cuz of the memory usage
registersymbol( myExposure )

Hook:
push rax
push rcx
mov rax,[rbx+348] // first level pointer
mov rcx,[rax+34]  // second level, crash here if script can be enabled
mov [store_pointer],rcx // this and next two lines should be commented if script can not to run
cmp [store_pointer],00CB0002 // if rbx+348+34 equal 00CB0002, than this should be Exposure value
pop rcx // SB: you can restore these prior to the JNE
pop rax // SB: you can restore these prior to the JNE
jne short @f
  mov eax,[myExposure] // Send decided Exposure value
@@:
mov [rbx],eax // original code
add rsp,00000090
jmp Enviro_AOB+9 // SB: replaced the return/back label with this one.. [1]

store_pointer:
dq 0 // this has to be a quad (QWORD), not DWORD
myExposure:
dq 0 // this has to be a quad (QWORD), not DWORD
  
Enviro_AOB:
Enviro1:
jmp Hook
db 90 90 90 90
// SB: ..so you wouldn't have the need for a return/back label here [1]

[DISABLE]

Enviro1:
db 89 03 48 81 C4 90 00 00 00
  
unregistersymbol( myExposure )
unregistersymbol( store_pointer )
unregistersymbol( Enviro1 )

{
// ORIGINAL CODE - INJECTION POINT: "ACOrigins.exe"+84DF92

"ACOrigins.exe"+84DF78: 0F B7 06                    -  movzx eax,word ptr [rsi]
"ACOrigins.exe"+84DF7B: 66 89 03                    -  mov [rbx],ax
"ACOrigins.exe"+84DF7E: 0F B6 46 02                 -  movzx eax,byte ptr [rsi+02]
"ACOrigins.exe"+84DF82: 88 43 02                    -  mov [rbx+02],al
"ACOrigins.exe"+84DF85: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DF8C: 5F                          -  pop rdi
"ACOrigins.exe"+84DF8D: 5E                          -  pop rsi
"ACOrigins.exe"+84DF8E: 5B                          -  pop rbx
"ACOrigins.exe"+84DF8F: C3                          -  ret 
"ACOrigins.exe"+84DF90: 8B 06                       -  mov eax,[rsi]
// ---------- INJECTING HERE ----------
"ACOrigins.exe"+84DF92: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DF94: 48 81 C4 90 00 00 00        -  add rsp,00000090
// ---------- DONE INJECTING  ----------
"ACOrigins.exe"+84DF9B: 5F                          -  pop rdi
"ACOrigins.exe"+84DF9C: 5E                          -  pop rsi
"ACOrigins.exe"+84DF9D: 5B                          -  pop rbx
"ACOrigins.exe"+84DF9E: C3                          -  ret 
"ACOrigins.exe"+84DF9F: 8B 06                       -  mov eax,[rsi]
"ACOrigins.exe"+84DFA1: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DFA3: 0F B7 46 04                 -  movzx eax,word ptr [rsi+04]
"ACOrigins.exe"+84DFA7: 66 89 43 04                 -  mov [rbx+04],ax
"ACOrigins.exe"+84DFAB: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DFB2: 5F                          -  pop rdi
}
Keep in mind I've not added-in any NULL checks yet. Test it as is and provide feedback (if it still crashes); I don't think your problem are the NULLs :)
 

pigeon

Expert Cheater
Mar 4, 2017
51
2
8
#5
@sbryzl
Still crash. In my guess, it's looks like at [rax+34] (second level) happens something very bad, that crash the game when it try to access for it. But i'm not sure about it :)

@SunBeam
Plus am not fully sure (I could check) if the CMP is perhaps used by some code higher in the chain that would get engine to crash.
Maybe this is the case? Will check it.
Tried your solution, but still crash even at "press any key" screen (and if enable it after map is load) at the same "rcx,[rax+34]" step, but i think i can mess up with such jumps as "jne short @f" because i never use it before and if it something different than "je code".
For now i'm not sure about anything in this script, but i maded attempt to check for NULLs by using test, and after it crash i also try to paste checks advised from @sbryzl, so the code (that still cause crash) become looks this:
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( Hook, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule( Enviro_AOB, ACOrigins.exe, 89034881C4900000005F5E5BC38B )
label( Enviro1 )
registersymbol( Enviro1 ) // SB: we need it like this for the restore to work in [DISABLE] section
label( store_pointer ) // SB: no need to allocate random memory for these when you already use a static cave; just label them out :P
registersymbol( store_pointer )
label( myExposure ) // use external "myExposure" address for control Exposure; SB: same here, label, not alloc -- remember allocs fail when in-game cuz of the memory usage
registersymbol( myExposure )

Hook:
push rax
push rcx
cmp [rbx+348],100000 // compare if it not live pointer
jb short @f
mov rax,[rbx+348] // first level pointer
test rax,rax // test for null, i guess :)
je short @f
cmp [rax+34],100000 // compare if it not live pointer
jb short @f
mov rcx,[rax+34]  // second level, crash here if script can be enabled
test rcx,rcx // test for null, i guess :)
je short @f
mov [store_pointer],rcx // this and next two lines should be commented if script can not to run
cmp [store_pointer],00CB0002 // if rbx+348+34 equal 00CB0002, than this should be Exposure value
pop rcx // SB: you can restore these prior to the JNE
pop rax // SB: you can restore these prior to the JNE
jne short @f
  mov eax,[myExposure] // Send decided Exposure value
@@:
mov [rbx],eax // original code
add rsp,00000090
jmp Enviro_AOB+9 // SB: replaced the return/back label with this one.. [1]


store_pointer:
dq 0 // this has to be a quad (QWORD), not DWORD
myExposure:
dq 0 // this has to be a quad (QWORD), not DWORD

Enviro_AOB:
Enviro1:
jmp Hook
db 90 90 90 90
// SB: ..so you wouldn't have the need for a return/back label here [1]

[DISABLE]

Enviro1:
db 89 03 48 81 C4 90 00 00 00

unregistersymbol( myExposure )
unregistersymbol( store_pointer )
unregistersymbol( Enviro1 )

{
// ORIGINAL CODE - INJECTION POINT: "ACOrigins.exe"+84DF92

"ACOrigins.exe"+84DF78: 0F B7 06                    -  movzx eax,word ptr [rsi]
"ACOrigins.exe"+84DF7B: 66 89 03                    -  mov [rbx],ax
"ACOrigins.exe"+84DF7E: 0F B6 46 02                 -  movzx eax,byte ptr [rsi+02]
"ACOrigins.exe"+84DF82: 88 43 02                    -  mov [rbx+02],al
"ACOrigins.exe"+84DF85: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DF8C: 5F                          -  pop rdi
"ACOrigins.exe"+84DF8D: 5E                          -  pop rsi
"ACOrigins.exe"+84DF8E: 5B                          -  pop rbx
"ACOrigins.exe"+84DF8F: C3                          -  ret
"ACOrigins.exe"+84DF90: 8B 06                       -  mov eax,[rsi]
// ---------- INJECTING HERE ----------
"ACOrigins.exe"+84DF92: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DF94: 48 81 C4 90 00 00 00        -  add rsp,00000090
// ---------- DONE INJECTING  ----------
"ACOrigins.exe"+84DF9B: 5F                          -  pop rdi
"ACOrigins.exe"+84DF9C: 5E                          -  pop rsi
"ACOrigins.exe"+84DF9D: 5B                          -  pop rbx
"ACOrigins.exe"+84DF9E: C3                          -  ret
"ACOrigins.exe"+84DF9F: 8B 06                       -  mov eax,[rsi]
"ACOrigins.exe"+84DFA1: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DFA3: 0F B7 46 04                 -  movzx eax,word ptr [rsi+04]
"ACOrigins.exe"+84DFA7: 66 89 43 04                 -  mov [rbx+04],ax
"ACOrigins.exe"+84DFAB: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DFB2: 5F                          -  pop rdi
}
can you tell me, if you define 'newmem' to be a static location, why you reallocate it? o_O
This is how i learn this things :D I mean, when i google something that seems to be what i was looking for - i try to implement it and if it crash i go to search for another working solution, compare difference and google why this difference matter. Here i do not noticed that in your script you comment "alloc(newmem,0x1000,ACOrigins.exe)", but it works with the other scripts, so i was focused on another strings :rolleyes: Same thing with "dd 00". I just remember how i play with it when i making cheats for theHunter:COTW and that it works whatever i use: "db 0", "dd 0", "dq 0". But if you told that this is matter - i trust you and will pay attention for it :oops:
P.S.#3: Can you tell me what your script actually does? What's this 'exposure'? Screenshots would also help. Cheers!
This instruction control a lot of specific graphic settings, such as fog, sun/moon power, sandstorm amount, exposure multiplier and so on and also a lot of things that i do not understand what actually does, so i need to divide what i interesting in from another addresses.
I'm not sure that i will use variables like "myExposure" for them since i found stable pointer and that's will be better to use because some of this values are not equal to zero, but for the same learning purposes i leave it until i found more useful values. I don't know if this pointers will work in legacy version, but you can try to check if you are interesting in it:
Fog: "ACOrigins.exe"+03BA0D98+248+30+0
Exposure: "ACOrigins.exe"+03BA0D98+248+30+1c8
B/W with higher contrast: "ACOrigins.exe"+03BA0D98+248+30+1bc

What exposure does is... Some kind of brightness but with high dynamic range (sorry anybody if i explain it wrong actually). Here is screenshot that show it better. Here i'm increase exposure value and night become very bright, but not just like if increasing brightness:

open image in new tab for see it in full size
and here is another example, but with few values changed. First image with default values, second with just increased exposure and third image with cnaging another values:

You also can notice how exposure work when in game at sunny day you enter in dark house area - in few seconds image become brighter, and if at night you enter in bright area - image become darker. But this one, dynamic in-game exposure value, is somehow tricky, because i can't catch it with searching for inc/dec dec/inc float/4bytes/2bytes/double ... The same issue was in Ghost Recon Wildlands, so i think that this in-game dynamic exposure is, probably, encrypted.

For better understanding, if you just nop this instruction - than almost all weather and environment effects will freeze and there is will be not much difference between day and night and walking around can produce some graphical bugs :)
And with compares like this there is will be possible to take control under values that matter while all another will work as they should. BTW, here is working current version of script (i almost do not touch it after reading your post and it contain some experiments, so do not blame me a lot :D )
Code:
fullaccess( ACOrigins.exe, 0x1000 )
define( newmem, ACOrigins.exe+500 )

[ENABLE]

aobscanmodule(Enviro1,ACOrigins.exe,89 03 48 81 C4 90 00 00 00 5F 5E 5B C3 8B) // should be unique
//alloc(newmem,0x1000,ACOrigins.exe)
globalalloc(myExposure,8)
myExposure:
dq 0

globalalloc(mySaturation,8)
mySaturation:
dq 0

globalalloc(myBW,8)
myBW:
dq 0

globalalloc(mySmog,8)
mySmog:
dq 0

globalalloc(mySun,8)
mySun:
dq 0

label(code)
label(return)

newmem:

Exposure:
  mov eax,[myExposure]
  mov [rbx],eax
  add rsp,00000090
  jmp return

Saturation:
  mov eax,[mySaturation]
  mov [rbx],eax
  add rsp,00000090
  jmp return

BW:
  mov eax,[myBW]
  mov [rbx],eax
  add rsp,00000090
  jmp return

Smog:
  mov eax,[mySmog]
  mov [rbx],eax
  add rsp,00000090
  jmp return

Sun:
  mov eax,[mySun]
  mov [rbx],eax
  add rsp,00000090
  jmp return

code:
  cmp [rbx+2d0],000C0010
  je Exposure
  cmp [rbx+2d0],000C0000
  je Saturation
  cmp [rbx+2d0],0000FFFF
  je BW
  cmp [rbx+2d0],40A00000
  je Smog
  cmp [rbx+2d0],050D95C0
  je Sun
  mov [rbx],eax
  add rsp,00000090
  jmp return

Enviro1:
  jmp code
  nop
  nop
  nop
  nop
return:
registersymbol(Enviro1)

[DISABLE]

Enviro1:
  db 89 03 48 81 C4 90 00 00 00

unregistersymbol(Enviro1)
dealloc(newmem)

{
// ORIGINAL CODE - INJECTION POINT: "ACOrigins.exe"+84DF92

"ACOrigins.exe"+84DF78: 0F B7 06                    -  movzx eax,word ptr [rsi]
"ACOrigins.exe"+84DF7B: 66 89 03                    -  mov [rbx],ax
"ACOrigins.exe"+84DF7E: 0F B6 46 02                 -  movzx eax,byte ptr [rsi+02]
"ACOrigins.exe"+84DF82: 88 43 02                    -  mov [rbx+02],al
"ACOrigins.exe"+84DF85: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DF8C: 5F                          -  pop rdi
"ACOrigins.exe"+84DF8D: 5E                          -  pop rsi
"ACOrigins.exe"+84DF8E: 5B                          -  pop rbx
"ACOrigins.exe"+84DF8F: C3                          -  ret 
"ACOrigins.exe"+84DF90: 8B 06                       -  mov eax,[rsi]
// ---------- INJECTING HERE ----------
"ACOrigins.exe"+84DF92: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DF94: 48 81 C4 90 00 00 00        -  add rsp,00000090
// ---------- DONE INJECTING  ----------
"ACOrigins.exe"+84DF9B: 5F                          -  pop rdi
"ACOrigins.exe"+84DF9C: 5E                          -  pop rsi
"ACOrigins.exe"+84DF9D: 5B                          -  pop rbx
"ACOrigins.exe"+84DF9E: C3                          -  ret 
"ACOrigins.exe"+84DF9F: 8B 06                       -  mov eax,[rsi]
"ACOrigins.exe"+84DFA1: 89 03                       -  mov [rbx],eax
"ACOrigins.exe"+84DFA3: 0F B7 46 04                 -  movzx eax,word ptr [rsi+04]
"ACOrigins.exe"+84DFA7: 66 89 43 04                 -  mov [rbx+04],ax
"ACOrigins.exe"+84DFAB: 48 81 C4 90 00 00 00        -  add rsp,00000090
"ACOrigins.exe"+84DFB2: 5F                          -  pop rdi
}
 

SunBeam

RCE Fanatics
Talents
Fearless Donors
Feb 4, 2018
687
357
63
#6
So.. let me get this straight.. you're comparing at that location if set values are.. 0x000C0010, 0x000C0000, 0x0000FFFF, 0x40A00000, 0x050D95C0?.. Cuz to me, your script doesn't make any sense.

First up, you compare for those values, which, for the record, can be set to anything; you just found a logic of your own whereas those values match your exposure etc. But from my perspective, I wouldn't use that, especially when that location is used by a ton shit of addresses:



Secondly, dq is used when you want to store the value of a qword pointer. In your case, you would use dd, because what you actually fiddle with are floats (also seen as DWORDs, 4-bytes values).

Script doesn't work properly for me, those 4-5 conditions don't break as supposed to because the values you compare against don't really exist on my end. I'm on the official game version, but it shouldn't matter, as the aob leads to same location you appointed. So.. any other tutorial to get to those addresses without the hook? What kind of value scans should be applied?..
 

pigeon

Expert Cheater
Mar 4, 2017
51
2
8
#7
Same thing was with another game theHunter:COTW, with a small difference. In COTW, for example, for fog Red color there was 2 values. One goes from instruction that control only fog RGB and another instruction as well control fog RBG and almost all graphic settings like SSAO settings, water settings and so on. Changing both addresses have the same result on actual fog color.
I do not know why is this work like that. My own speculation based on what i hear from devs. They told in one of their dev stream that their QA team test game builds, before they go public, by using some kind of in-game cheats, like they can place specific animal right before the camera and test how shooting works. So my speculation is that, probably, release version of the game have the same possibility, because in such case they will be sure that nothing and nowhere in code was changed after QA approve current build. Maybe it's some kind of debug dev console, like it was with Forza Horizon, and maybe this console work with this instruction, that control a lot of settings. Maybe i'm wrong, but, in my opinion, that makes sense. So i think that maybe in AC:Origins the same instruction control a lot of settings. Only seems not only graphic, but some others. And if so, why not taking control under this particular instruction, since it looks much better than disabled ~100 instructions? Maybe in this particular case it can affect performance or cause crashes or doesn't work in different versions... Like right now, seems legacy and CPY version used different values to compare and i even no have idea why this compare can't work on your side. I still keeps think about how it can be done better.
Another idea, that i do not test yet, is that probably somewhere in memory all specific graphic settings should be stored. I mean, it probably should looks like "if there 12am, than sun RGB have this values, when 6pm, another...". And my guess is that these values should be recorded once on starting the game, so it might be possible later to find them not from instruction, but with searching for specific AOB and changing them without of nop any instruction. But i can't confirm it at current moment.
At current moment, i no have another ideas. If addresses with offsets that i provide early doesn't work for you too, than i can suggest you only to find value by your own and test how it works. At least i can tell how it changing! So go here, because values can be different in different "biomes":

While scan, do not exit to menu, because sometimes it can cause zeroing values. Much easier will be to search for "fog with clouds". So start from searching Float "Rounded (default)" and time should be 23 o'clock (if my time cheat doesn't work, than time here is in 24h format, float, so value of 23 o'clock in-game will be 23.0). The value of fog at this time is: 0.0007999999798
Then, it stable and do not changing until almost 5 o'clock.
At 5 o'clock this value is 0.0007337662391 (i check it 3 times with traveling between different locations, should be just like that). Testing it by myself, here you should get only two values, both go from two instructions with the same "spam" behavior and both affect fog.
But if you still have a lot of addresses, than this value keeps increasing until 7 o'clock, when it equal 0.001300000353 .
Then, it starts to decrease until 9 o'clock, when its equal 0.000505633885
12 o'clock its 0.001000000164
15 o'clock 0.0004999997909
21 o'clock 0.001500001294

Than, with offset -C you should get bit another fog; +1B0 should get you some kind of contrast; +1A4 saturation and +1BC exposure.

Actually, by testing this by myself i was found that after first scan and few "Unchanged", there was two more values that actually works as i predict, they does not changing but affect fog too! :) But they works only for that particular time and be careful with changing nearest values - some of them may cause crash, but seems like here is 1 value that actually does something and 3 that can cause crash, then 1 more that affect graphic and 3 about to crash, and so on :D
Try to search this two AOBs and that should lead you right to the fog value, that should affect fog amount at 23 o'clock:
17 B7 51 3A 17 B7 51 3A 00 00 00 00 63 00 00 00 00 00 00 00 E0 AB 1C 2C 0E 00 00 00 C8 7A FC 16 0E 00 00 00 C8 7A FC 16
17 B7 51 3A 00 00 00 00 63 00 00 00 00 00 00 00 E0 AB 1C 2C 0E 00 00 00 C8 7A FC 16 0E 00 00 00 C8 7A FC 16 0E 00 00 00
 

SunBeam

RCE Fanatics
Talents
Fearless Donors
Feb 4, 2018
687
357
63
#8
Yeaps, found it. Directions did help and so did the Time of Day freezer (well, NOPer).

Try this out:
Code:
fullaccess( ACOrigins.exe+342D4E0, 0x1000 )
define( Hook, ACOrigins.exe+342D4E0 )

[ENABLE]

aobscanmodule( PropertyController_AOB, ACOrigins.exe, F30F100C10410FB7C3660F6EC04A8D0491 )
label( PropertyController )
registersymbol( PropertyController )
label( bIncMe )
label( Hook_exit )
label( pBaseFog )
registersymbol( pBaseFog )

Hook:
cmp r11,2D0
jne short Hook_exit
  cmp [bIncMe],2
  je short @f
    cmp [bIncMe],3
    je short Hook_exit
      inc [bIncMe]
      jmp short Hook_exit
  @@:
    push rcx
    lea rcx,[rax+rdx]
    mov [pBaseFog],rcx
    pop rcx
    inc [bIncMe]
Hook_exit:
movss xmm1,[rax+rdx]
jmp PropertyController_AOB+5

bIncMe:
dd 0
pBaseFog:
dq 0

PropertyController_AOB:
PropertyController:
jmp Hook

[DISABLE]

PropertyController:
db F3 0F 10 0C 10 41

unregistersymbol( pBaseFog )
unregistersymbol( PropertyController )

{
ACOrigins.exe+74B54F0 - F3 0F10 0C 10         - movss xmm1,[rax+rdx]
ACOrigins.exe+74B54F5 - 41 0FB7 C3            - movzx eax,r11w
ACOrigins.exe+74B54F9 - 66 0F6E C0            - movd xmm0,eax
ACOrigins.exe+74B54FD - 4A 8D 04 91           - lea rax,[rcx+r10*4]
ACOrigins.exe+74B5501 - 0F5B C0               - cvtdq2ps xmm0,xmm0
ACOrigins.exe+74B5504 - F3 0F59 C3            - mulss xmm0,xmm3
ACOrigins.exe+74B5508 - F3 0F5C C2            - subss xmm0,xmm2
ACOrigins.exe+74B550C - F3 0F5E F0            - divss xmm6,xmm0
ACOrigins.exe+74B5510 - F3 0F10 04 10         - movss xmm0,[rax+rdx]
ACOrigins.exe+74B5515 - F3 0F5C C1            - subss xmm0,xmm1
ACOrigins.exe+74B5519 - F3 0F59 F0            - mulss xmm6,xmm0
ACOrigins.exe+74B551D - F3 0F58 F1            - addss xmm6,xmm1
ACOrigins.exe+74B5521 - F3 0F11 37            - movss [rdi],xmm6
ACOrigins.exe+74B5525 - 48 8B 5C 24 68        - mov rbx,[rsp+68]
ACOrigins.exe+74B552A - 0F28 74 24 40         - movaps xmm6,[rsp+40]
ACOrigins.exe+74B552F - 48 83 C4 50           - add rsp,50
ACOrigins.exe+74B5533 - 5F                    - pop rdi
ACOrigins.exe+74B5534 - C3                    - ret
}
Tweak it if you want it to work on anytime you go to main menu, then back in-game. Else, just disable/re-enable script so it picks-up the pointer :p Note this is the base value, not the calculated one you've found at your hook; I backtraced to find where the actual value was acquired from.

default: 0.0007999999798



modded: 0.05



modded: 0.1



BR,
Sun
 

pigeon

Expert Cheater
Mar 4, 2017
51
2
8
#10
Yes! Works just great! And this proves that there is can be done proper compares that work with both versions... So i did something wrong in previous my attempts.
And i'm especially like this one from you:
Code:
  push rcx
  lea rcx,[rax+rdx]
  mov [pBaseContrast],rcx
  pop rcx
  //movss xmm1,[rax+rdx]
After i saw that there is few addresses in beginning that "write" for one address, i start to think about how it can be done... It looks so obvious, but before i saw it, i no have idea!
By testing final instruction, looks like there is not so much values that we really need. Like, i will add later compares for chromatic aberrations, heat haze, rain (did you ever see wet desert, btw? In this game this is possible xD ) and probably something else that i forget... But i'm quite not sure, for example, that Sun size are really important and deserve to be compared, right? :D Because if we go to add everything possible - than this script is not our method, but usual NOPing with pointers (otherwise, we will drown in compares) :/

And thank you a lot for your help! I learn with you a lot of interesting things.
 
Top Bottom