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 


LUA logfile script HELP! [1st time on LUA]

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Sun Jun 26, 2016 2:43 pm    Post subject: LUA logfile script HELP! [1st time on LUA] Reply with quote

I'm trying to write down a logfile script for debugging purposes.

I need it because I'm dealing with an event base managed game (one function for reading almost everything).
So, not only I have to identify the memory by its relative label/event but also by the sequence of chained events leading to it.

I have two problems (after hours kicking my head to the wall - smashing my PC wasn't a wise move):

1) in the logfile I managed to obtain all numbers are decimal and I wasn't able to store them in hex;
2) I need that after filling 10000 records in logfile, the script pause the process and end itself for an eventual restart.

Like stating in the subject, it's my first time on LUA


Code:
ck_addr = getAddress("exec.exe+[offset]")   -- like "Tutorial-x86_64.exe+12F8"
logfile = [[D:\tmplog.txt]]

function debugger_onBreakpoint()
   if (EIP==ck_addr) then
      tmp_EAX = EAX
      addr_EAX = tmp_EAX + 0x1C    -- I don't understand why EAX + 0x1C returns a wrong value,
                                      and the same goes for EAX + 28

      if (readString(addr_EAX)~=nil) then     -- I don't understand why (readString(EAX)~=nil)
                                                 doesn't work

         str_EAX = readString(addr_EAX)
         addr_ECX = ECX + 0x04
         val_ECX = readInteger(addr_ECX)
         f = io.open(logfile,"a+")
         f:write(addr_ECX .. ", " .. val_ECX .. ", " .. EAX .. ", " .. str_EAX .. "\n")
         f:close()
      else
         debug_continueFromBreakpoint(co_run)
      end
      debug_continueFromBreakpoint(co_run)
      return 1
   else
      return 0
   end
end

debug_setBreakpoint(ck_addr)



What do I have to add/change to solve my problems?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Sun Jun 26, 2016 4:03 pm    Post subject: Reply with quote

Use string.format("%X",number) to get the string representation of a number in hex.
I'm not sure what you mean by "end itself for an eventual restart."
For all relevant intents and purposes, addr_EAX is the exact same as EAX+0x1C when you call readString. It was something else in your code that was wrong.
I don't know what you're trying to do with "readString(EAX)~=nil" if it doesn't work for you. Pretty much all you're doing is checking if EAX points to a valid memory location.
Code:
logFileCount = 0;
debug_setBreakpoint("exec.exe+[offset]", 1, bptExecute, function()
    local eaxStr = readString(EAX+0x1C,1000)
    if eaxStr then
      f = io.open("D:\\tmplog.txt","a+")
      f:write(string.format("%X, %d, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, eaxStr))
      f:close()
      logFileCount = logFileCount + 1
    end
    debug_continueFromBreakpoint(co_run)
    if logFileCount > 10000 then pause() end
    return 1
  end)

_________________
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
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Sun Jun 26, 2016 8:20 pm    Post subject: Reply with quote

Thanks for your answer.

Quote:
I don't know what you're trying to do with "readString(EAX)~=nil" [...]Pretty much all you're doing is checking if EAX points to a valid memory location.

Yes, in a few cases EAX is not an address, but just a value.

Quote:
I'm not sure what you mean by "end itself for an eventual restart."

Like I wrote, the process is an event base managed game, and I'm trying to logging into a function reading almost everything. That's means it's prone to crash - I already tested someone else table, that worked flawlessly for a few hours and suddenly the game crashed.
Trying to use "Break and trace instructions" is no use, because VEH debugger crashes and the same goes using for a handful of seconds (less then 30) "Find out what addresses this code accesses".

So I need to remove the bp, but I think it's enough to insert debug_removeBreakpoint(address) in your script.
Code:
[ ... ]
    if logFileCount > 10000 then
       pause()
       debug_removeBreakpoint("exec.exe+[offset]")    <---  here, I think
    end
    return 1
end


Please, tell me if I'm wrong.


One last question:
Where can I use the code you posted? In a LUA engine window only? Or inside a AA script too?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Sun Jun 26, 2016 8:46 pm    Post subject: Reply with quote

That would be correct. If the process still crashes, you may want to remove pause().

You can enter it in the Lua script window, the Lua engine window, or an AA script. You can directly copy and paste it into the Lua script or Lua engine windows, but you have to format an AA script with the {$lua} tag:

Code:
{$lua}
if syntaxcheck then return end
[ENABLE]
-- Lua code to run when script is enabled
[DISABLE]
-- Lua code to run when script is disabled

CE's auto assembler will execute the code when you change it or assign it to the cheat table in order to do a syntax check of it. If you're certain the script is correct, you can avoid this by checking the variable syntaxcheck (CE sets this to true if it's doing a syntaxcheck).

When inside a {$lua} block, the [ENABLE] and [DISABLE] tags will still be recognized by CE's parser even though the syntax highlighter doesn't do anything to them.

You can use {$asm} to switch back to assembly if you want.

The [ENABLE] and [DISABLE] sections do not share a common scope; however, anything before the [ENABLE] tag will be executed both when the script is enabled and disabled:
Code:
{$lua}
print("script toggled") -- prints on both enable and disable
[ENABLE]
local a = 5
print(tostring(a))      -- prints 5
[DISABLE]
print(tostring(a))      -- prints nil

_________________
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
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Mon Jun 27, 2016 6:24 am    Post subject: Reply with quote

In order to recap.

Inside Lua script window, or Lua engine window:

Code:
logFileCount = 0;
debug_setBreakpoint("exec.exe+[offset]", 1, bptExecute, function()
    if (readString(EAX+0x1C,1000)) then
      f = io.open("D:\\tmplog.txt","a+")
      f:write(string.format("%X, %X, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, readString(EAX+0x1C,1000))
      f:close()
      logFileCount = logFileCount + 1
    end
    debug_continueFromBreakpoint(co_run)
    if logFileCount > 10000 then
       pause()
       debug_removeBreakpoint("exec.exe+[offset]")
    end
    return 1
end


Inside an AA script

Code:
{$lua}
if syntaxcheck then return end
{$asm}
[ENABLE]
AOBScanModule(aobname,exec.exe,[array pattern])
alloc(newmem,$1000)
label1
[...]
labeln
registersymbol(aobname)

newmem:
[originalcode]

label1:        \
[asm code]     |
[...]           >  placement irrelevant
labeln:        |
[asm code]     /

{$lua}
logFileCount = 0;
    if (readString(EAX+0x1C,1000)) then
      f = io.open("D:\\tmplog.txt","a+")
      f:write(string.format("%X, %X, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, readString(EAX+0x1C,1000))
      f:close()
      logFileCount = logFileCount + 1
    end
    if logFileCount > 10000 then
       pause()
    end
    return 1
end
{$asm}

aobname:
jmp newmem
(nops)
return:

[DISABLE]
aobname:
[originalcode]

dealloc(newmem)
unregistersymbol(aobname)


Are they both correct?
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Mon Jun 27, 2016 9:01 am    Post subject: Reply with quote

Why do you have that random Lua block inside the AA script? That's only going to get executed once when the script is first enabled. If you're going to execute the Lua code inside the Lua script/engine window, then you don't need any of this Lua code inside your AA script.
_________________
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
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Mon Jun 27, 2016 12:36 pm    Post subject: Reply with quote

I wasn't saying I wanted to use both at the same time.
I was just trying to put down two different alternatives.

The solution using a Lua script inside an AA script could be useful in order to avoid involving the debugger and bps (fps drop down hardly, and crashes happen easily).

But I understand that it can require a pretty much different approach.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Mon Jun 27, 2016 12:47 pm    Post subject: This post has 1 review(s) Reply with quote

Ah, my apologies.

Regardless, you'll still need to use the debugger inside the AA script. It's not like the game is running that section of Lua; it's CE that's running it once when the script first activates.
Code:
{$lua}
if syntaxcheck then return end
[ENABLE]
logFileCount = 0
debug_setBreakpoint("exec.exe+[offset]", 1, bptExecute, function()
    local eaxStr = readString(EAX+0x1C,1000)
    if eaxStr then
      f = io.open("D:\\tmplog.txt","a+")
      f:write(string.format("%X, %d, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, eaxStr))
      f:close()
      logFileCount = logFileCount + 1
    end
    debug_continueFromBreakpoint(co_run)
    if logFileCount > 10000 then
       pause()
       debug_removeBreakpoint("exec.exe+[offset]")
    end
    return 1
  end)
[DISABLE]
debug_removeBreakpoint("exec.exe+[offset]")
logFileCount = nil


You can call CE to run a Lua function from the game by using "Template -> Call CE Lua function" from an AA script. Note that anything you can do in Lua you can also do in asm. It may take longer to write it, but it's possible to do.

_________________
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
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Mon Jun 27, 2016 2:07 pm    Post subject: Reply with quote

When I said it requires a different approach, I mean:

- making an AA script hooking and injecting on the address where otherwise I have to put a bp
- retrieve the registers and checking if they contain addresses in the AA script then
a) retrieve data needed and put them into global allocated memory (AA)
- pass memory to Lua in order to open and write the logfile

OR
b) pass just the registers to Lua
- retrieve data and open and write the logfile

- in both cases, after reaching a manageable number of lines, put on pause the process to review and clear the logfile.


P.S.: Testing right now the script again and it's very hard to understand whats going on, because game runs so dramatically slow.
I assume that's due to the debugger full time job
Back to top
View user's profile Send private message
Zanzer
I post too much
Reputation: 126

Joined: 09 Jun 2013
Posts: 3278

PostPosted: Mon Jun 27, 2016 8:05 pm    Post subject: Reply with quote

Just open the file once when you enable the script. Close after your counter or the disable.
Code:
{$lua}
if syntaxcheck then return end
[ENABLE]
f = io.open("D:\\tmplog.txt","a+")
logFileCount = 0
debug_setBreakpoint("exec.exe+[offset]", 1, bptExecute, function()
    local eaxStr = readString(EAX+0x1C,1000)
    if eaxStr then
      f:write(string.format("%X, %d, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, eaxStr))
      logFileCount = logFileCount + 1
    end
    debug_continueFromBreakpoint(co_run)
    if logFileCount > 10000 then
      pause()
      debug_removeBreakpoint("exec.exe+[offset]")
      f:close()
      f = nil
    end
    return 1
  end)
[DISABLE]
debug_removeBreakpoint("exec.exe+[offset]")
logFileCount = nil
if f then
  f:close()
  f = nil
end
Back to top
View user's profile Send private message
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Tue Jun 28, 2016 4:35 am    Post subject: Reply with quote

Like I said, testing the script made this way it's very hard to understand whats going on, because the game nearly freezes.
One of the reason is that leaving opened the memory view you can see registers and stacktrace constantly changing.

So, I had to change the script this way:

Code:

ck_addr = getAddress("exec.exe+[offset]")
logFileCount = 0;

function debugger_onBreakpoint()
   if (EIP==ck_addr) then
      local eaxStr = readString(EAX+0x1C,1000)
      if eaxStr then
         f:write(string.format("%X, %X, %X, %s\n", ECX+4, readInteger(ECX+4), EAX, eaxStr)))
         f:close()
         logFileCount = logFileCount + 1
      end
      debug_continueFromBreakpoint(co_run)
      if logFileCount > 10000 then
         pause()
         debug_removeBreakpoint("exec.exe+[offset]")
         f = nil
      end
      debug_continueFromBreakpoint(co_run)
      return 1
   end
end

debug_setBreakpoint(ck_addr, 1, bptExecute)

At least this way I can see what the game is doing, even if really slowly.

I think that a better way should be keeping a Lua script that takes care of populating, managing and save the logfile, while in an AA script hooking the target code and retrieving needed data.
What I don't know is how passing register values to Lua, without using the debugger.

Another note: as soon as I unpause it, or I have to run the Lua script again or the game crashes.
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 140

Joined: 06 Jul 2014
Posts: 4289

PostPosted: Tue Jun 28, 2016 10:32 am    Post subject: Reply with quote

GrandPa wrote:
What I don't know is how passing register values to Lua, without using the debugger.
As I said before:
ParkourPenguin wrote:
You can call CE to run a Lua function from the game by using "Template -> Call CE Lua function" from an AA script.

Alternatively, you can put it inside some memory location used as a buffer and have Lua flush that buffer every once in a while.
Code:
[ENABLE]
AOBScanModule(aobname,exec.exe,[array pattern])
alloc(newmem,$1000)
alloc(results,$14000)  // allocate more memory if needed
label(exit)
registersymbol(aobname)
registersymbol(results)

newmem:
  push edx
  mov edx,[results]
  cmp edx,#10000
  jae short @f
    lea edx,[edx*8+results+4]
    mov [edx],eax
    mov [edx+4],ecx
    inc [results]
    jmp short exit
  @@:
    mov [results],FFFFFFFF //signal to Lua for max reached
exit:
  pop edx
  //[originalcode]
  jmp return

aobname:
  jmp newmem
  //(nops)
return:

[DISABLE]
aobname:
  //[originalcode]

dealloc(newmem)
dealloc(results)
unregistersymbol(aobname)
unregistersymbol(results)

In Lua, make a timer that checks if the max has been reached (i.e. readInteger("results") == 0xFFFFFFFF). If it has, go through that memory region, check which addresses are still valid, and record those you want. When finished, move 0 back into "results" to signal the code injection to overwrite everything it has written with new results.

Note that if memory is moved around, it could miss a valid pointer to a string in the time it takes for the buffer to fill up.


PS: I don't see f = io.open(...) anywhere in that last script you posted. Also the optimization Zanzer suggested is a good idea and I would strongly suggest you take it.

_________________
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
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Tue Jun 28, 2016 1:43 pm    Post subject: Reply with quote

My apologies. I missed the part:
<< using "Template -> Call CE Lua function" from an AA script >>

For the part: f = io.open(...), I probably lost it inside the clipboard.


Thanks. I'll try to adapt the Lua script to meet the conditions you explained.

I'll let you know as soon as done.
Back to top
View user's profile Send private message
Gottwald
Newbie cheater
Reputation: 0

Joined: 16 Dec 2012
Posts: 12

PostPosted: Tue Jul 05, 2016 8:09 pm    Post subject: Reply with quote

Smile Little off-topic post if I may:
@GrandPa

Could you maybe take a look and make an update in your spare time?
forum.cheatengine.org/viewtopic.php?t=580977

Thanks!
Back to top
View user's profile Send private message
GrandPa
Advanced Cheater
Reputation: 3

Joined: 09 Jul 2010
Posts: 87
Location: Italy

PostPosted: Wed Jul 06, 2016 7:34 pm    Post subject: Reply with quote

@ParkourPenguin:
I changed a bit your AA script in order to avoid those changes in memory over time that could give wrong results.
After checking other posts on Lua matter, I also changed the Lua script a bit in order to insert a timer for checking if the "results" area was filled.
All of the scripts worked.

I would have made some other tests and something more permanent, but, really, that game made me disgusted (strange behaviors like not triggering a level end, then crashing, or cheats always working that throw errors for a while and after a couple of restarts working again) so I quit for now, waiting for some game worth the efforts (or programs, why not).


@Gottwald:
Please, read my post dated Aug 30, 2015. I can work out nothing without feeling personal involvements. Sorry.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting 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