Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Inserting ASM at specific location using Lau

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Discussions
View previous topic :: View next topic  
Author Message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Fri Jan 26, 2018 9:35 am    Post subject: Inserting ASM at specific location using Lau Reply with quote

Goal: detect which game vs is loaded (Dx9 ~ Dx10), and change asm code accordingly.
(see image here: [imgur_com/a/SbUR2]


Action: upon enabling 'Health' script, insert proper ASM using Lua:

1. GetMD5 function:
Does not seem to write the integer to memory? The value (= 1) is correct though...
(1st print in Lua info box)
Plus: the AddrID value is also correct !

2. GetHealthASM function:
Reads the 'IntVal' but always returns 0 (because of pt 1. I suppose)
Plus: the AddrID value is also correct !

3. I want to "insert" asm code based on 'IntVal' at specific location (at label LuaCode)
With/out test, asm code is not added/inserted...
(last jump = 'jmp return')
My assumption is still: CE preprocesses any lua code and "dumps" the outcome into script at location where 'lua is called'...?! (btw: also tried with {$lua})

ps1: I did search around first to see if somebody came up with a similar solution?! If you can refer me to such an article, please do... (I could not find anything myself sofar)
ps2: I also tried with the 'return [[..]]', but nogo.
ps3: ignore the fact that 'pop ebx' is not present; it is in my original DX10 vs.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Fri Jan 26, 2018 11:10 am    Post subject: Reply with quote

You probably shouldn't be injecting at a jcc instruction.

"local" is a keyword you should be using in your Lua code.

"luacall" calls Lua code when the script is assembled and doesn't insert any return values. Use a {$lua} block for that. If you tried, you didn't do it correctly.

Expressions in AA scripts aren't entirely evaluated in the same order as they are written in the script. For example, this will fail:
Code:
globalalloc(foo,2048)

{$lua}
getAddress('foo')
{$asm}


If you're familiar with preprocessor macros, do something like this:
Code:
{$lua}
local t
if process == 'AssassinsCreed_Dx10.exe' then
  t = {'define(AOB_SIG,89 46 14 7D 33)',
       'define(ADDRESS1,AssassinsCreed_Dx10.exe+92560F)',
       --...
       }
elseif process == 'AssassinsCreed_Dx9.exe' then
  t = {'define(AOB_SIG,89 46 14 7D 34)',
       'define(ADDRESS1,AssassinsCreed_Dx9.exe+75161F)',
       --...
       }
else
  error('Invalid process name')
end
return table.concat(t,'\r\n')
{$asm}

[ENABLE]
aobscanmodule(Health,$process,AOB_SIG)
//...

someCode:
  jmp ADDRESS1

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Sat Jan 27, 2018 8:04 am    Post subject: Got some progress... Reply with quote

@ParkourPenguin:
Just an update: I spent some more time this morning, and got now this far: see [imgur_com/a/99QaL]. Iow it does insert the code at the proper location, as long - as you stated - one uses the {$lua} tag!

BUT: as you also can see, I'm now trying to pass on the ASM code via a string variable. Because: if I just complete the IF-construction with the DX10 "counterpart", CE returns an error about the 'DX10.exe' and won't run/enable the script thereafter.
Unfortunately: tried already some combos on string variants, without any success. (see error: caused by replacing current return instruction with 'return asmCodeDX9')

That said: I've looked at your suggestion, which - basically - does exactly what I think it does: return a string based on that IF-construction. So I'll be trying this out, and report back...

Q: 'local' is the keyword: I thought that any variable declared "inside" a function is considered 'local'. Would you mind explaining (or referring to another article) the pros (and/or cons) for not using that?

And finally: yes, I'm "aware" about preprocessor macros (that's it basically Cool ). In fact, I'm currently reading 'The Art of Assembly Language 2nd Ed', in which the author of HLA (Randall Hyde) claims to have 'one of the most powerful macro processing facilities' among computer languages...
(I also skipped that section btw...)

PS1:
I solved the 'Intval' problem by return-ing it via the function.

PS2:
in the mean time, I also found out about my "continous" errors related to the function(s) I was using. Apparently CE loads the 'Cheat Table Lua Script' only once (when starting CE). Since I do an autoattach for the DX10 exe, ignoring that exe and then attaching DX9 exe causes this...
(btw: opening the lua script table and press [Execute] does the trick as well, but obviously I can not expect gamers to do/know this)

Q: is there a CE/Lua function that allows us to "force" executing that lua script table again... at will? Already checked the Wiki pages: maybe 'loadTable' (although that seems overkill?)...
(btw: got this info from one of your replies to another article. Forgot to save the link though)

PS3: I'm glad you mentioned 'not to use jcc instructions' there. Something I've been trying to avoid in the past as well. In that respect: one of the nice features I like about [x64dbg] is its 'jump reference' feature beyond the screen boundaries (see [imgur_com/a/HUhg3]). The "problem" is: when it comes to debugging games, CE is simply superior (at least for a beginner like myself). Not to memtion the fact that the CE debugger is 'non-intrusive' (compared to other debuggers such as x64dbg)!
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Sat Jan 27, 2018 8:27 am    Post subject: Reply with quote

In Lua all variables (strings, numbers, functions, etc) are declared as global by default, unless the local keyword is used, this just helps with memory lookup and clean up. So if I have 2 values in the Lua global table then they get looked up fairly quickly, but if the global table holds 10 million it will take a bit longer to find the one I want. Plus locals use integers for keys and globals use a string under the hood (or so I have been told, never looked into how that works).
Locals Vs Globals

The table Lua code only gets executed when loading, if you need continues execution then you will need to use a timer or put the code in a function to call when needed.

_________________
Back to top
View user's profile Send private message Visit poster's website
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Sat Jan 27, 2018 10:29 am    Post subject: UPDATE: confirm working... Reply with quote

@ParkourPenguin:
I misread your snippet at first: you are actually defining constants here (like with #define in C++; and probably other HLLs). And dump that stuff in a table... And apparently these constants can be used in the {$asm} section. Big thx for that.
(basically, no asm code is returned/inserted; just a "bunch" of memory constants)
That said: it is possible - using {$lua} section - to insert asm code where appropriate, as initially shown in my example. I'm not sure if this works with multiple lua sections; will probably try that out... (although one does not have the same flexibilty ofc)
-UPDATE-: tested and working; see [imgur_com/a/dIDir]

sidenote: "constant" is probably not the correct word here; but rather "macro". In C++, I only used them as constants, hence...

@TheyCallMeTim13:
thx for giving me that reference link... and for giving me another headache Wink (I'm sure one day I'll get stuff like that).

As for loading the CE lua table: when the user decides NOT to load/execute the script at startup, none of the functions will be recognized. Iow even if you attach the correct exe thereafter, those functions will simply not be known: {attempt to call a nil value (global 'GetMD5')}.
The only way to solve this - based on my current experience - is a) reload the table (and obviously accept execution) or b) open the CE lua table and press the [Execute] button...
(btw: I assume a timer will not help me out either if "execution" is not accepted ~ did not try/test this though)
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Sat Jan 27, 2018 10:50 am    Post subject: Reply with quote

paul44 wrote:
I spent some more time this morning, and got now this far: see [imgur_com/a/99QaL].

That picture doesn't show the line that caused the error.
paul44 wrote:
Q: 'local' is the keyword: I thought that any variable declared "inside" a function is considered 'local'. Would you mind explaining (or referring to another article) the pros (and/or cons) for not using that?

In Lua, any variable name not explicitly declared as local is assumed to be global. It's generally good programming style to use local variables unless you have a specific reason to make something global. The improvement in performance of local variables over global variables is negligible unless it's done in a critical loop (not relevant in this case), but using local variables avoids cluttering the global environment, helps with debugging (e.g. variables that should've been initialized), and lets Lua automatically collect the garbage when they go out of scope.
paul44 wrote:
Q: is there a CE/Lua function that allows us to "force" executing that lua script table again... at will?

I guess you could by wrapping everything in a function and calling the function, but you'd be better off using a timer to check if the process still exists.
paul44 wrote:
And finally: yes, I'm "aware" about preprocessor macros (that's it basically Cool ).

My point in providing that example code was to show you that you're making this more complicated than it needs to be. You don't need to MD5 anything, and instead of inserting an instruction via an ugly {$lua} block in the middle of your code, just define the address at the beginning.

Of course, you could avoid many of these problems if you didn't inject at the jcc instruction (i.e. select 1 or 2 instructions before "mov [esi+14],eax").

paul44 wrote:
when the user decides NOT to load/execute the script at startup, none of the functions will be recognized.

That's their problem. If you want to try to keep users from being stupid, you could lazily initialize every Lua object in every script where they're used.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Sat Jan 27, 2018 12:30 pm    Post subject: Reply with quote

The only thing I can add is may be put the Lua table script in a AA script, nest the rest under it so it has to be enabled to even show the rest, but you will get some one the tries it in the wrong order.
_________________
Back to top
View user's profile Send private message Visit poster's website
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Sun Jan 28, 2018 4:38 am    Post subject: Rounding up and closing the topic... Reply with quote

@ParkourPenguin:
I might not have emphasized this, but the whole point of my exercise here was to come up with some routine that would take versioning into account. I've tried this already before last year, without luck. But I do think I got something here now.
I agree: for this particular script/table, it is over the top (and ugly). But to give you an idea where I come from: I've been reading some more on lua string concatenation, and found out... that those '[[..]]' brackets are actually lua syntax for a string literal; and not some CE specific feature... (yep, beginner and all that). Which made me realize why I got that error on the 'asmCode' variable. So this works just as well:

(just a fyi for anyone interested):
[code]
{$lua}
-- insert proper asm instruction based on game vs...
local intVal = GetMD5(0)
local asmCode
if intVal == 1 then
-- ussing a "simple" string
asmCode = "jnl AssassinsCreed_Dx9.exe+751657"
elseif intVal == 2 then
-- using a literal string
asmCode = [[jnl AssassinsCreed_Dx10.exe+925647]]
else
error('Incorrect process name')
end
return asmCode
[/code]
(as you correctly stated: it is much cleaner to use a function at the start of the script, and define/use them macros instead)

That said: I AM interesting to find out how you would handle versioning (if not using something like an MD5 check ~ a suggestion offered in another topic on the subject). Situation being f.e.: x64_exe (so $process remains the same) which gets updated regularly, and aob_string changes according to particular game vs updates.

Btw: in that respect, I've been looking at some tables lately for games such as Shadow of War (impressive work from #SeiKur0 & #Kalas there) and Ghost Recon Wildlands (where i uploaded a script that no longer worked by the time I posted it...).
Btw2: hereafter the topic which helped me to pinpoint my 'nil value' error: [../forum/viewtopic.php?t=592822&sid=e10816a34361e5e6a7980265afffa72c]

@TheyCallMeTim13:
I thought about that as well (it definitely circumvents the popup message), but I personally do not like that since you start with an "empty" table (sort of speak). Iow if something fails in your 'main' script, you never get to see what is offered (unless you tick off the 'Hide children...').

PS: I came up with a "gracefull" solution on the 'accept execution' message box: see [imgur_com/a/XRKjW]. I get the security idea behind it, but the major issue with public/private key architecture (if that is what sits behind the idea) is... trust. And from a tactical point of view, its infrastructure. Iow who - that we can trust - will take the honor to sign all those tables...
(not my cup of tea though, on any level on the subject ~ let's say: less then beginner)

sidenotes:
a) I'm getting this "security check" prompt again?!
b) I have no idea why the 'code' tags do not work for me?!
Back to top
View user's profile Send private message
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Sun Jan 28, 2018 5:05 am    Post subject: Reply with quote

At this point I want to ask what do your AOBs look like.

Here's an AOB that works for CE tutorial 3.3 and 3.4 step 2:
Code:
8Dxxxx8Bxxxxxxxxxx29xx89xxxxxxxxxx8DxxxxE8xxxxxxxx8Bxxxx8BxxxxxxxxxxE8xxxxxxxx83


EDIT:
So with this AOB I don't care what registries or offsets are used, just the main instructions to find the code. Because if it always has to do some operations around what I want to hook, then the main instructions should stay the same
ENDEDIT:

Then I just use "readMem" and/or "reassemble" as needed to deal with registry and offset changes. I also like to use "assert" to make sure the script will fail but still have working AOBs, allowing for updates without debugging crashes.

Code:
{
   Process         : Tutorial-i386.exe  -  (x32)
   Module         : Tutorial-i386.exe
   Game Title      : Tutorial-i386
   Game Version   : 3.3
   CE Version      : 6.7
   Script Version   : 0.0.1
   Date         : 01/28/18
   Author         : TheyCallMeTim13
   Name         : Step2Hook

   Step 2 Hook
}

{$STRICT}

define(address, Tutorial-i386.exe+23B00)
define(bytes, 89 83 80 04 00 00)

////
//// ------------------------------ ENABLE ------------------------------
[ENABLE]
aobScanModule(aobStep2Hook, Tutorial-i386.exe, 8Dxxxx8Bxxxxxxxxxx29xx89xxxxxxxxxx8DxxxxE8xxxxxxxx8Bxxxx8BxxxxxxxxxxE8xxxxxxxx83xxxxxxxxxxxx)
define(injStep2Hook, aobStep2Hook+B)
assert(injStep2Hook, bytes)
registerSymbol(injStep2Hook)

alloc(memStep2Hook, 0x400, injStep2Hook)

label(ptrStep2Hook)
registerSymbol(ptrStep2Hook)

label(n_code)
label(o_code)
label(exit)
label(return)

memStep2Hook:
   ptrStep2Hook:
      dd 0
   align 10 CC
   n_code:
      mov [ptrStep2Hook],ebx
      mov eax,(int)1000
   o_code:
      mov [ebx+00000480],eax
   exit:
      jmp return


////
//// ---------- Injection Point ----------
injStep2Hook:
   jmp n_code
   nop
   return:


////
//// ------------------------------ DISABLE ------------------------------
[DISABLE]
////
//// ---------- Injection Point ----------
injStep2Hook:
   db bytes

unregisterSymbol(injStep2Hook)

unregisterSymbol(ptrStep2Hook)

dealloc(memStep2Hook)

{
//// Injection Point: Tutorial-i386.exe+23B00  -  00423B00
//// AOB address: 00423AF5  -  Tutorial-i386.exe+23AF5
//// Process: Tutorial-i386.exe  -  00400000
//// Module: Tutorial-i386.exe  -  00400000
//// Module Size: 0020B000
Tutorial-i386.exe+23ABD:  00 00                       -  add [eax],al                       
Tutorial-i386.exe+23ABF:  00 55 89                    -  add [ebp-77],dl                   
Tutorial-i386.exe+23AC2:  E5 8D                       -  in eax,-73                         
Tutorial-i386.exe+23AC4:  64 24 D4                    -  and al,-2C                         
Tutorial-i386.exe+23AC7:  53                          -  push ebx                           
Tutorial-i386.exe+23AC8:  89 C3                       -  mov ebx,eax                       
Tutorial-i386.exe+23ACA:  C7 45 D4 00000000           -  mov [ebp-2C],00000000             
Tutorial-i386.exe+23AD1:  B8 01000000                 -  mov eax,00000001                   
Tutorial-i386.exe+23AD6:  8D 55 DC                    -  lea edx,[ebp-24]                   
Tutorial-i386.exe+23AD9:  8D 4D F4                    -  lea ecx,[ebp-0C]                   
Tutorial-i386.exe+23ADC:  E8 CF99FEFF                 -  call 0040D4B0                     
Tutorial-i386.exe+23AE1:  E8 DAB4FEFF                 -  call 0040EFC0                     
Tutorial-i386.exe+23AE6:  50                          -  push eax                           
Tutorial-i386.exe+23AE7:  85 C0                       -  test eax,eax                       
Tutorial-i386.exe+23AE9:  75 65                       -  jne 00423B50                       
Tutorial-i386.exe+23AEB:  B8 05000000                 -  mov eax,00000005                   
Tutorial-i386.exe+23AF0:  E8 FBABFEFF                 -  call 0040E6F0                     
Tutorial-i386.exe+23AF5:  8D 50 01                    -  lea edx,[eax+01]                   <<<--- AOB Starts Here
Tutorial-i386.exe+23AF8:  8B 83 80040000              -  mov eax,[ebx+00000480]             
Tutorial-i386.exe+23AFE:  29 D0                       -  sub eax,edx                       
////  INJECTING START  ----------------------------------------------------------
Tutorial-i386.exe+23B00:  89 83 80040000              -  mov [ebx+00000480],eax             
////  INJECTING END  ----------------------------------------------------------
Tutorial-i386.exe+23B06:  8D 55 D4                    -  lea edx,[ebp-2C]                   
Tutorial-i386.exe+23B09:  E8 02620100                 -  call 00439D10                     
Tutorial-i386.exe+23B0E:  8B 55 D4                    -  mov edx,[ebp-2C]                   
Tutorial-i386.exe+23B11:  8B 83 6C040000              -  mov eax,[ebx+0000046C]             
Tutorial-i386.exe+23B17:  E8 24FB0600                 -  call 00493640                     
Tutorial-i386.exe+23B1C:  83 BB 80040000 00           -  cmp dword ptr [ebx+00000480],00   
Tutorial-i386.exe+23B23:  7D 2B                       -  jnl 00423B50                       
Tutorial-i386.exe+23B25:  A1 24F25400                 -  mov eax,[0054F224]                 [Tutorial-i386.exe+19E744]
Tutorial-i386.exe+23B2A:  E8 E14A0F00                 -  call 00518610                     
Tutorial-i386.exe+23B2F:  B8 64000000                 -  mov eax,00000064                   
Tutorial-i386.exe+23B34:  89 83 80040000              -  mov [ebx+00000480],eax             
Tutorial-i386.exe+23B3A:  8D 55 D4                    -  lea edx,[ebp-2C]                   
Tutorial-i386.exe+23B3D:  E8 CE610100                 -  call 00439D10                     
Tutorial-i386.exe+23B42:  8B 55 D4                    -  mov edx,[ebp-2C]                   
Tutorial-i386.exe+23B45:  8B 83 6C040000              -  mov eax,[ebx+0000046C]             
Tutorial-i386.exe+23B4B:  E8 F0FA0600                 -  call 00493640                     
Tutorial-i386.exe+23B50:  E8 DB9BFEFF                 -  call 0040D730                     
Tutorial-i386.exe+23B55:  8D 45 D4                    -  lea eax,[ebp-2C]                   
Tutorial-i386.exe+23B58:  E8 5300FEFF                 -  call 00403BB0                     
Tutorial-i386.exe+23B5D:  58                          -  pop eax                           
//// Template: I2CEA_AOBFullInjection
//// Generated with: I2 Cheat Engine Auto Assembler Script Template Generator
//// Code Happy, Code Freely, Be Awesome.
}



And above the "o_code" could be more robust:
Code:

   o_code:
      reassemble(injStep2Hook)


EDIT:
But I tend to just let it fail first.

- If it ain't broke, don't fix it.

_________________
Back to top
View user's profile Send private message Visit poster's website
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Sun Jan 28, 2018 10:29 am    Post subject: Reply with quote

paul44 wrote:
I might not have emphasized this, but the whole point of my exercise here was to come up with some routine that would take versioning into account.

Then MD5 is fine. Based on your previous posts, it looked like you were only trying to differentiate between dx9 and dx10.

paul44 wrote:
I've been reading some more on lua string concatenation, and found out... that those '[[..]]' brackets are actually lua syntax for a string literal; and not some CE specific feature... (yep, beginner and all that).

Single quotes and double quotes are as well. Square brackets are weird in that they can run for several lines, don't evaluate escape sequences, and replace CR/LF characters with a single LF character (the Lua console won't display it correctly). String literals denoted by single quotes or double quotes work like most other languages.

_________________
I don't know where I'm going, but I'll figure it out when I get there.
Back to top
View user's profile Send private message
paul44
Expert Cheater
Reputation: 2

Joined: 20 Jul 2017
Posts: 152

PostPosted: Tue Jan 30, 2018 3:32 am    Post subject: AOB signature Reply with quote

@TheyCallMeTim13:
Yep, this seems to be the approach that pretty much everyone else is following. In fact, during my research on versioning earlier this month, one of the tables I looked at, referred to this article: [../viewtopic.php?t=584799]. Another interesting table to look at in that respect is the one from #SeiKur0 ~ Shadow of War!
I'm pretty sure I'll wind up taking the same approach... eventually Wink

btw: thx for the code.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Discussions All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites