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 


Making a trainer using LUA

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine
View previous topic :: View next topic  
Author Message
T4g1
How do I cheat?
Reputation: 0

Joined: 18 Jan 2018
Posts: 1

PostPosted: Thu Jan 18, 2018 3:05 pm    Post subject: Making a trainer using LUA Reply with quote

Hi ! I'm having a lot of somewhat related questions regarding the toolchain to work on trainers:

I'm trying to get my hands on how to make a trainer efficiently and I really feel like using Cheat Engine Lua form is the worst to write LUA code.

Is there a way to use a proper editor (Sublime Text, Notepad++ or anything else ?). I already tried a LUA plugin that added a "external editor" feature but it was not working (lot of errors) and was only aimed at script in the CE table.

Also, is it possible to compile the trainer outside CE ? Using libraries and more traditional stuff ? Like a library that I just need to setup in a C or C++ project or even Python maybe ? I feel like CE tends to silently fails a lot of things which make it hard to debug some basic behaviors :/

Is there a complete documentation out here except the wiki ? (wiki cheatengine org (I can't post URL for wathever reason)) The only function I looked up there where missing informations like return value and/or error codes and examples.

Also, I'm trying to setup a basic AOBScan, apparently there is two ways of doing this, using AOBScan in Lua or aobscan into autoAssemble. In the various use case i've tried, I didn't manage to get anything else than nil return value out of AOBScan without having used it in the CE table first. Is there some requierements to met before using this function ?

This is how i'm doing it right now:
Code:

function onClose(sender)
    updateTimer.destroy()
    return caFree -- Gives access violation on re-start but caHide does not close the trainer for real. What is wrong ? This is undocumented
end

function toggleMemoryRecord(record, checkbox, maxValue)
    record.value = maxValue
    if (checkbox_getState(checkbox) == 1) then
        memoryrecord_freeze(record)
    else
        memoryrecord_unfreeze(record)
    end
end

function toggleMoney(sender)
    local record = getAddressList().getMemoryRecordByDescription("Money") -- Is it possible to get rid of this using [_ressources+offset] directly in LUA ?
    toggleMemoryRecord(record, sender, 2000)
end

function toggleWood(sender)
    local record = getAddressList().getMemoryRecordByDescription("Wood")
    toggleMemoryRecord(record, sender, 50)
end

function toggleStone(sender)
    local record = getAddressList().getMemoryRecordByDescription("Stone")
    toggleMemoryRecord(record, sender, 50)
end

function toggleIron(sender)
    local record = getAddressList().getMemoryRecordByDescription("Iron")
    toggleMemoryRecord(record, sender, 50)
end

function toggleOil(sender)
    local record = getAddressList().getMemoryRecordByDescription("Oil")
    toggleMemoryRecord(record, sender, 50)
end

function onGameLoaded()
    local results = AOBScan("29 83") -- Dummy value used for testing purpose
    if results ~= nil then
        count = stringlist_getCount(results)
        print(count)
    end
    object_destroy(results)
    results = nil
end
--[[ Here is the code that works in CE table:
[ENABLE]

aobscan(get_ressources,8B B8 E8 00 00 00 E8 ?? ?? ?? ?? 8B 80 F0 00 00 00 8D 04 80 8B D8 C1 E3 03 E8 ?? ?? ?? ??)
alloc(newmem,$1000,7FE894E5A7F) -- How not to hardcode this value ? Why $1000 and not 1000 ?

label(code)
label(return)

globalalloc(_ressources, 4)

newmem: -- Useless ? or code useless ?

code:
  mov [_ressources],rax
  mov edi,[rax+000000E8]
  jmp return

get_ressources:
  jmp newmem
  nop
return:
registersymbol(get_ressources)

[DISABLE]

get_ressources:
  db 8B B8 E8 00 00 00

unregistersymbol(get_ressources)
dealloc(newmem)
]]

function update()
    if getOpenedProcessID() == 0 then -- BUG: This always returns a process ID even after the game has been closed
        trainer.executable_status.state = 0
    else
        trainer.executable_status.state = 1
    end
end

form_show(trainer)
getAutoAttachList().add("TheyAreBillions.exe")

updateTimer = createTimer(getMainForm())
updateTimer.Interval = 1000
updateTimer.OnTimer = update

createHotkey(onGameLoaded, VK_F2) -- VK_F1 popup an annoying help window, how to deactivate ?


Let me know if this is not the right place or way of asking all those questions so I can rectify that.
Thanks in advance and happy hacking ![/code]
Back to top
View user's profile Send private message
ParkourPenguin
I post too much
Reputation: 138

Joined: 06 Jul 2014
Posts: 4275

PostPosted: Thu Jan 18, 2018 3:59 pm    Post subject: Reply with quote

For documentation, look at celua.txt (main.lua prior to 6.7) in the main CE directory.

Feel free to write code in other text editors, but everything has to go into the main Lua script in the 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
TheyCallMeTim13
Wiki Contributor
Reputation: 50

Joined: 24 Feb 2017
Posts: 976
Location: Pluto

PostPosted: Thu Jan 18, 2018 4:36 pm    Post subject: Reply with quote

If you want to write the Lua in external files, add them as table files, then import/require. Then this is a function I use for that.

Note that it allows to have files in a "luaFiles" folder in the same folder as the table to override table files for working on debugging or new versions. And that when dealing with table files it always loads the file, so any variables get reinitialized, unlike Lua's require, but if you just load the files only when the table loads it works out fine.

Code:

--------
-------- CE Table Require
--------
local TableLuaFilesDirectory = 'luaFiles'
function CETrequire(moduleStr)
   if moduleStr ~= nil then
      local localTableLuaFilePath = moduleStr
      if TableLuaFilesDirectory ~= nil or TableLuaFilesDirectory ~= '' then
         local sep = package.config:sub(1,1)
         localTableLuaFilePath = TableLuaFilesDirectory .. sep .. moduleStr
      end
      local f, err = io.open(localTableLuaFilePath .. '.lua')
      if f and not err then
         f:close()
         return require(localTableLuaFilePath)
      else
         local tableFile = findTableFile(moduleStr .. '.lua')
         if tableFile == nil then
            return nil
         end
         local stream = tableFile.getData()
         local fileStr = nil
         local bytes = stream.read(stream.Size)
         for i = 1, #bytes do
            if fileStr == nil then
               fileStr = ''
            end
            fileStr = fileStr .. string.char(bytes[i])
         end
         if fileStr then
            return assert(loadstring(fileStr))()
         end
      end
   end
   return nil
end
-- CETrequire('SomeLuaModuleStoredAsTableFile')
-- SomeLuaModuleStoredAsTableFile.printTest() -- Just an example.
---- "SomeLuaModuleStoredAsTableFile.lua" needs to be a table file or in "{Cheat table Folder or Working folder}/luaFiles".

_________________
Back to top
View user's profile Send private message Visit poster's website
FreeER
Grandmaster Cheater Supreme
Reputation: 53

Joined: 09 Aug 2013
Posts: 1091

PostPosted: Thu Jan 18, 2018 7:03 pm    Post subject: Reply with quote

To be as complete as I can

editing: Lua code is just text so you can use any editor you like and copy paste back and forth, but in the end it needs to be loaded through the main table's lua script (because that's what CE runs when it launches a trainer) and there's nothing I know of with any knowledge of the functions CE provides etc. to provide extra info when editing (like VS's intellisense).

Multiple files: While I haven't tried out Tim's method I'm sure they've tested it and it'll work great, I personally just don't tend to make trainers let alone ones large enough to make the extra effort of multiple files worth it Smile

Outside CE: you can certainly pick any language you like and learn how to do GUIs in them, then use ReadProcessMemory and WriteProcessMemory or create a dll that you inject into the target process, etc. There may even be some libraries available to help you, I know I've seen C# code use a BlackMagic library that someone coded and I'm sure there are others. You will not have access to anything Cheat Engine provides if you do this, CE is not a library (someone did start one but it has since been abandoned). You won't be able to use auto assemble scripts etc. unless you can implement it yourself (potentially using libraries like keystone/capstone).

Outside CE cont: Since CE is built using Lazarus 1.6.4 (DB said he has some custom patches as well but not sure what they are for and I've built it without any)- I suppose it may be possible to create the form itself in Lazarus and export it to some format CE can open but I've never looked into anything like that. Most likely you'd still have to deal with everything via lua saved in CE however so...probably not a huge help even if you could. If you happen to know Pascal then you could fork the CE source code on github and work on improving trainer creation, even if it's never merged into CE proper you'd still have your own version that suits your needs and desires.

Documentation: just the source https://www.github.com/cheat-engine/cheat-engine
while celua.txt / main.lua (pre CE6.7) exist in the install directories but they aren't entirely complete (mostly but not entirely).

AOBScan: it should work without needing it to be run in an AA script first, as far as I know they use the same logic by default as far as where they search etc. (though lua does have a way to specify to search only executable memory etc.)

Script:

AA:
"How not to hardcode this value ? Why $1000 and not 1000 ? " $1000 is hex rather like 0x1000 (pascal syntax). As for hardcoding it, you can pass get_resources instead, I honestly have no idea why it doesn't do that by default...

"newmem: -- Useless ? or code useless ? " - refers to the address of the newly allocated memory, "code" is technically useless in that you can remove it and the label but it's often nice to have at least one label to jump to after a compare.

---
Lua:
"Is it possible to get rid of this {getting memory record} using [_ressources+offset] directly in LUA ?" - lua has functions to read and write memory so as long as you have a way to get the address (static/pointer/symbol) sure, you could do it purely in lua.

Code:
    if (checkbox_getState(checkbox) == 1) then
        memoryrecord_freeze(record)
    else
        memoryrecord_unfreeze(record)
    end

can be simplified to record.Active = checkbox.Checked in CE 6.7, at least CE 6.7, I'm not actually sure when userdata objects got the properties and methods added to them.

depending on how the checkboxes are named in CE you can also do something like this

Code:
local getmr = getAddressList().getMemoryByDescription
local info = {}
info.add = function(name, amount)
  info[name] = {}
  info[name].mr = getmr(name)
  info[name].amount = amount
end
info.add('Money', 2000)
info.add('Wood')
info.add('Stone')
info.add('Iron')
info.add('Oil')

-- set every checkbox to use this handler
function checkboxHandler(sender)
  local name = sender.name
  local rec = info[name].mr
  toggleMemoryRecord(rec, sender, info[name].amount or 50)
  -- optionally use metatables to move the default of 50 out of this code
  -- and into the data, ie. the "info" table, or just repeat 50 in each add call
end


it may need to be modified a bit to handle how you have things named, eg local name = sender.name:match('CECheckBox-(%S+)'), but it's possible to have nicer code Smile

I'll have to do a bit of testing with the process and F1...

edit: F1 appears to be hardcoded https://github.com/cheat-engine/cheat-engine/blob/bf6b67a036e7a837f15cb871b0e6473399799e2a/Cheat%20Engine/MainUnit.pas#L4876-L4884 (if it was just the menu shortcut that could have been disabled with lua)

Hm, it's using HtmlHelpA and that's the only place that uses it however so if you could patch that in some manner to return you'd be good to go.... writeBytesLocal('HtmlHelpA', 0xC3) seems to work

edit: of course x86 needs to pop some args so it'd be better to use
Code:
if cheatEngineIs64Bit() then writeBytesLocal('HtmlHelpA', 0xC3) else writeBytesLocal('HtmlHelpA', 0xC2, 0x10, 0x00) end


edit: process issue workaround:
Code:
function processStillAttached()
  return getProcesslist()[getOpenedProcessID()] ~= nil
end
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 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