Sample of Cheat Engine Lua Script for Shared Memory Handling

A forum dedicated to use and support LUA for Cheat Engine.


Post Reply
User avatar
bbfox
Table Master
Table Master
Journeyman Hacker
Journeyman Hacker
Posts: 229
Joined: Sat Jul 23, 2022 8:59 am
Answers: 0
x 519

Sample of Cheat Engine Lua Script for Shared Memory Handling

Post by bbfox »

Sample of Cheat Engine Lua Script for Shared Memory Handling

Please Note: I just share my test case, it works but may not 100% correct...

The provided Lua script for Cheat Engine focuses on managing shared memory with specific data types and synchronization between processes by using CE's built-in lua functions. Here's a detailed breakdown of its purpose and functionality:


1. Initialization and Memory Management

The script begins with the [ENABLE] section, executed upon enabling the script in Cheat Engine. You do not need to attach any process because share memory will be created by CE itself.

  • Memory Clearing: It ensures that any existing shared memory is deallocated to prevent conflicts and memory leaks.

    Code: Select all

    if _G.sharedMemory.mem ~= nil then
        deallocateSharedMemoryLocal(_G.sharedMemory.mem)
        _G.sharedMemory.mem = nil
    end
    
  • Memory Allocation: New memory blocks are allocated for data (64KB) and state management (8 bytes).

    Code: Select all

    local memSize = 65536
    local memStatSize = 8
    _G.sharedMemory.mem = allocateSharedMemoryLocal('MySharedMemory', memSize)
    _G.sharedMemoryState.mem = allocateSharedMemoryLocal('MySharedMemoryState', memStatSize)
    

In my test case, share memory is always there unless you close CE.


2. Shared Memory Operations

Functions for Memory Handling

  • readSignedInteger(address): Converts a memory-read integer into a signed 32-bit value.

    Code: Select all

    function readSignedInteger(address)
        local value = readIntegerLocal(address)
        if value >= 0x80000000 then
            return value - 0x100000000
        else
            return value
        end
    end
    
  • slowClearSharedMemory(): Resets all shared memory locations to zero using 32-bit integer writes.

    Code: Select all

    function slowClearSharedMemory()
      local intZero = 0
      for offset = 0, memSize - 4, 4 do
          writeIntegerLocal(_G.sharedMemory.mem + offset, intZero)
      end
    end
    
  • waitForIdleState(timeout_ms): Waits until the shared memory is idle (state 0) or until a timeout occurs.

  • State Functions: setOperationState(state) and setDataType(dataType) set operation state and data type for the shared memory block.


3. Writing Data to Shared Memory

Function: writeSharedMemory(data, dataType)
This function writes various data types into shared memory. Supported data types include:

  • 32-bit int (dd)

  • 64-bit int (dq)

  • 32-bit Single (float)

  • 64-bit double (double)

  • String (string)

  • 64-bit address + 32-bit integer (12 bytes per entry)

  • 64-bit address + 32-bit float (12 bytes per entry)

  • 64-bit address + 64-bit integer (16 bytes per entry)

The script uses conditionals to set the data type, clear memory if needed, and write data accordingly.

Code: Select all

function writeSharedMemory(data, dataType)
    if _G.sharedMemory.mem ~= nil then
        waitForIdleState()
        setOperationState(-1)
        local offset = 0
        if dataType == "dd" then
            setDataType(1)
            writeIntegerLocal(_G.sharedMemory.mem, data)
        -- Additional data type conditions...
        end
        setOperationState(-3)
        print("Data written to shared memory as type", dataType)
    else
        print("Shared memory is not created yet!")
    end
end

4. Reading Data from Shared Memory

Function: readSharedMemory()
This function reads data from shared memory if it is in the -3 state, retrieving data based on its type.

Code: Select all

function readSharedMemory()
    if _G.sharedMemory.mem ~= nil then
        if readSignedInteger(_G.sharedMemoryState.mem) ~= -3 then
            print("No new data to read.")
            return nil
        end
        setOperationState(-2)
        local dataType = readIntegerLocal(_G.sharedMemoryState.mem + 4)
        local result = {dataType = dataType, dataValue = nil}
        -- Data reading logic based on type...
        setOperationState(0)
        return result
    else
        print("Shared memory is not created yet!")
    end
end

5. State Management and Cleanup

The script handles shared memory states carefully:

  • State Management: Sets states like -1 (write), -2 (read), and 0 (idle).

  • Cleanup: The [DISABLE] section deallocates shared memory to free up resources.

    Code: Select all

    [DISABLE]
    if syntaxcheck then return end
    if memrec then print(memrec.Description) end
    deallocateSharedMemoryLocal(_G.sharedMemory.mem)
    _G.sharedMemory.mem = nil
    deallocateSharedMemoryLocal(_G.sharedMemoryState.mem)
    _G.sharedMemoryState.mem = nil
    getLuaEngine().Close()
    

6. CE Lua example
I executed two CE instances & share data between them:
Left side: rendom write address:float numbers into memory
Right side: read data from share memory

Image



7. CE <=> .EXE communication example
Executed one CE and one Windows executable. Share memory is created by CE. Need to enable CE script "Enable share memory block & do a read test" first. It's not allowed to attach zip or exe file here, so i just provide some code pieces & screenshot here.

We need to write some functions/procedures to access share memory:
Example:

Code: Select all

  private
    SharedMemoryHandle: THandle;
    SharedMemoryStateHandle: THandle;
    procedure OpenSharedMemory;
    procedure CloseSharedMemory;
    function IsMemoryIdle: Boolean;
    procedure WaitForIdleState;
    procedure SetMemoryState(State: Integer);
    procedure AppendOutputWithTimestamp(const Msg: string);
    procedure AppendSysOutputWithTimestamp(const Msg: string);
    procedure ClearSharedMemory;
    function GetOperationState: Integer;
    procedure SetOperationState(State: Integer);
    procedure SetDataType(DataType: Integer);
    procedure StartWriteIntBlock;
    procedure AppendIntBlockData(Address: Int64; Value: Integer);
    procedure EndWriteIntBlock;
    procedure StartWriteFloatBlock;
    procedure AppendFloatBlockData(Address: Int64; Value: Single);
    procedure EndWriteFloatBlock;
    procedure StartWriteQWordBlock;
    procedure AppendQWordBlockData(Address: Int64; Value: Int64);
    procedure EndWriteQWordBlock;
  public

Open share memory:

Code: Select all

procedure TMainForm.OpenSharedMemory;
begin
  SharedMemorySize := 65536;
  SharedMemoryName := 'MySharedMemory';
  SharedMemoryStateName := 'MySharedMemoryState';

  SharedMemoryHandle := OpenFileMapping(FILE_MAP_READ or FILE_MAP_WRITE, False, PChar(SharedMemoryName));
  SharedMemoryStateHandle := OpenFileMapping(FILE_MAP_READ or FILE_MAP_WRITE, False, PChar(SharedMemoryStateName));

  if SharedMemoryHandle = 0 then
  begin
    AppendSysOutputWithTimestamp('***Failed to open shared memory!');
  end
  else
    AppendSysOutputWithTimestamp('Open shared memory successfully.');

  if SharedMemoryStateHandle = 0 then
  begin
    AppendSysOutputWithTimestamp('***Failed to open shared memory state!');
  end
  else
    AppendSysOutputWithTimestamp('Open shared memory state successfully.');
end;

Close Share memory:

Code: Select all

procedure TMainForm.CloseSharedMemory;
begin
  if SharedMemoryHandle <> 0 then
    CloseHandle(SharedMemoryHandle);
  if SharedMemoryStateHandle <> 0 then
    CloseHandle(SharedMemoryStateHandle);
end;

Read share memory:

Code: Select all

  Ptr := MapViewOfFile(SharedMemoryHandle, FILE_MAP_READ, 0, 0, SharedMemorySize);
  if Ptr = nil then
  begin
    AppendSysOutputWithTimestamp('***Unable to map shared memory for reading.');
    SetOperationState(0);
    Exit;
  end;
  .
  .
  .
  try
    Offset := 0;
    OutputText := '';
    case DataType of
      1: begin  
Move(Ptr^, IntData, SizeOf(IntData)); OutputText := 'dd: ' + IntToStr(IntData); end; 2: begin
Move(Ptr^, QwordData, SizeOf(QwordData)); OutputText := 'dq: ' + IntToStr(QwordData); end; 3: begin
Move(Ptr^, FloatData, SizeOf(FloatData)); OutputText := 'fp: ' + FloatToStr(FloatData); end;
. . .

Image

Lazarus source: ...

Attachments
ShareMem.CT
Share memory table scripts
(37.21 KiB) Downloaded 31 times

I create tables to suit my preferences. Table is free to use, but need to leave the author's name and source URL: https://opencheattables.com.
Table will not be up-to-date. Feel free to modify it, but kindly provide credit to the source.


Post Reply