Skip to content
Back to skills

Monoscript

ASecurity

Cheat Engine Mono and Unity IL2CPP runtime scripting, reverse engineering, and Auto Assembler integration. Use this skill when inspecting, hooking, scanning, or calling Mono/.NET/IL2CPP code, classes, methods, fields, and objects in target processes via monoscript.lua and MonoDataCollector.

  • 42 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 5, 2026
toolsapi

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add cheat-engine/AITools --skill monoscript --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Monoscript?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Monoscript
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/cheat-engine-monoscript/badge)](https://www.skillsdirectory.com/skills/cheat-engine-monoscript)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: monoscript
description: Cheat Engine Mono and Unity IL2CPP runtime scripting, reverse engineering, and Auto Assembler integration. Use this skill when inspecting, hooking, scanning, or calling Mono/.NET/IL2CPP code, classes, methods, fields, and objects in target processes via monoscript.lua and MonoDataCollector.
---

# Cheat Engine MonoScript Skill (`monoscript.lua`)

The `monoscript` skill enables AI agents to reverse engineer, inspect, hook, and manipulate applications and games built with the **Mono runtime** (e.g., Unity Mono, standalone .NET Mono) or **Unity IL2CPP** via Cheat Engine's `autorun/monoscript.lua` and injected **MonoDataCollector**.

---

## When to Use This Skill

Activate this skill when:
- Investigating, reverse engineering, or writing cheats for Unity or Mono-based games.
- Resolving managed classes, methods, and field offsets at runtime without hardcoding static offsets.
- JIT-compiling methods to obtain native execution entry points for mid-function or detour hooking.
- Finding all active instances of a class in the managed heap.
- Reading or writing static variables and instance fields across game updates.
- Dynamically invoking managed methods (e.g., calling game methods, spawning items, unlocking achievements).
- Writing Cheat Engine Auto Assembler (AA) scripts using `USEMONO`, `FINDMONOMETHOD`, or `GETMONOSTRUCT`.

For the exhaustive catalog of all 180+ functions and constants, see [`references/api_reference.md`](./Extensions/AITools/skills/monoscript/references/api_reference.md).

---

## Core Architecture & Connection

Cheat Engine interacts with target runtimes through a dual-process architecture:
1. **Host (Cheat Engine)**: [`monoscript.lua`](./autorun/monoscript.lua) runs in CE's Lua engine, providing high-level APIs, symbol lookups, and AA directives.
2. **Target (Game Process)**: Injected `MonoDataCollector` library (`MonoDataCollector64.dll`, `libMonoDataCollector-linux-x86_64.so`, etc.) attaches to the runtime (`mono_thread_attach` / `il2cpp_thread_attach`) and executes `MONOCMD_*` commands.
3. **IPC Transport**: Named pipe `cemonodc_pid<PID>` (or local TCP socket `127.0.0.1:52737` under Wine).

```
Cheat Engine (monoscript.lua)  <--- Named Pipe / TCP --->  MonoDataCollector DLL in Target
```

---

## Workflows & Practical Examples

### 1. Attaching to the Mono / IL2CPP Runtime

Always ensure the data collector is initialized before invoking Mono functions:

```lua
-- Attach data collector if not already active
if not mono_isValid() then
  LaunchMonoDataCollector()
end

if mono_isil2cpp() then
  print("Target is Unity IL2CPP")
else
  print("Target is standard Mono")
end
```

> [!TIP]
> If a Cheat Engine table has `UsesMono` enabled, Cheat Engine will auto-launch the collector on process attach.

---

### 2. Finding Classes, Methods & Compiling Native Addresses

To hook or disassemble a method, first locate its class and compile it:

```lua
-- Find class across all loaded assemblies
local klass = mono_findClass("PlayerController")
-- Or with namespace:
-- local klass = mono_findClass("Assembly-CSharp", "Game.PlayerController")

if klass and klass ~= 0 then
  -- Find method by name
  local method = mono_class_findMethod(klass, "TakeDamage")
  
  if method and method ~= 0 then
    -- JIT compile the method into native machine code
    local entryPoint = mono_compile_method(method)
    printf("TakeDamage native address: 0x%X", entryPoint)
    
    -- In standard Mono, you can also inspect CIL bytecode:
    if not mono_isil2cpp() then
      local ilText = mono_method_disassemble(method)
      print(ilText)
    end
  end
end
```

---

### 3. Enumerating Fields & Reading/Writing Values

Inspect field layouts and offsets dynamically without guessing struct padding:

```lua
local klass = mono_findClass("PlayerController")
local fields = mono_class_enumFields(klass, true, true)

for i, f in ipairs(fields) do
  printf("Field: %s | Offset: 0x%X | Type: %s | Static: %s", 
    f.name, f.offset, f.typename, tostring(f.isStatic))
  
  -- If field is static, read its value directly
  if f.isStatic and not f.isConst then
    local val = mono_class_getStaticFieldValue(klass, f.field)
    printf("  Static value: %s", tostring(val))
  end
end
```

To modify a static field:
```lua
mono_class_setStaticFieldValue(klass, fieldHandle, 9999)
```

---

### 4. Finding Live Object Instances in Memory

Locate active instances of a class on the heap:

```lua
local klass = mono_findClass("Player")

-- Synchronous lookup (in Unity, leverages Resources.FindObjectsOfTypeAll)
local instances = mono_class_findInstancesOfClassListOnly(klass)

if instances then
  for i, addr in ipairs(instances) do
    printf("Instance %d at 0x%X", i, addr)
    
    -- Read all instance fields into a Lua table
    local values = mono_object_enumValues(addr)
    for fieldName, val in pairs(values) do
      printf("  %s = %s", fieldName, tostring(val))
    end
  end
end
```

---

### 5. Invoking Managed Methods Dynamically

Call arbitrary managed methods inside the target process with marshalled arguments:

```lua
local klass = mono_findClass("InventoryManager")
local method = mono_class_findMethod(klass, "AddItem")

-- Find instance of InventoryManager
local instances = mono_class_findInstancesOfClassListOnly(klass)
if instances and #instances > 0 then
  local instance = instances[1]
  
  -- Method signature: AddItem(int itemId, int quantity)
  local args = {
    { type = vtDword, value = 401 }, -- Item ID
    { type = vtDword, value = 10 }   -- Quantity
  }
  
  local result, exception = mono_invoke_method(nil, method, instance, args)
  if exception then
    print("Invocation error: " .. exception)
  else
    print("Method invoked successfully. Result: " .. tostring(result))
  end
end
```

---

### 6. Auto Assembler Commands

`monoscript.lua` introduces 3 commands directly into Cheat Engine's Auto Assembler:

#### `USEMONO`
Initializes MonoDataCollector before executing the script. Always include this at the top of the `[ENABLE]` section:
```asm
[ENABLE]
USEMONO
```

#### `FINDMONOMETHOD(DefineName, Namespace:ClassName:MethodName)`
Compiles the target method and assigns its native address to `DefineName`:
```asm
[ENABLE]
USEMONO
FINDMONOMETHOD(TakeDamageEntry, Assembly-CSharp:Player:TakeDamage)

TakeDamageEntry:
  jmp newmem
  nop
```

Note though that FINDMONOMETHOD is obsolete and just referencing a symbol with the same name will cause cheat engine to compile it for you as well

#### `GETMONOSTRUCT(StructName, Namespace:ClassName)`
Generates an Auto Assembler structure representing the class layout:
```asm
[ENABLE]
USEMONO
GETMONOSTRUCT(PlayerStruct, Assembly-CSharp:Player)

// Fields can now be referenced symbolically:
mov [rax+PlayerStruct.currentHealth], #9999
```

---

### 7. Symbol Resolution in Disassembler & Hex View

Once `LaunchMonoDataCollector()` is active, Cheat Engine registers:
1. **Symbol Lookups**: Address fields and scripts accept:
   - `Assembly-CSharp:Player:Update` -> Resolves to JIT address.
   - `Player:health` -> Resolves to field offset or static memory address.
2. **Address Lookups**: Disassembly displays names automatically:
   - `Assembly-CSharp:Player:TakeDamage+14` appears in memory view instead of bare addresses.

---

## Mono vs Unity IL2CPP: Key Nuances

| Feature | Standard Mono | Unity IL2CPP |
| :--- | :--- | :--- |
| **Method Compilation** | JIT compiles on-demand via `mono_compile_method()`. | Pre-compiled AOT native code. `mono_compile_method()` returns existing address. |
| **CIL Bytecode** | `mono_getILCodeFromMethod()` & `mono_method_disassemble()` return IL bytecode. | IL bytecode is not in memory; returns `nil` / empty. Inspect native disassembly instead. |
| **VTable Resolution** | Full dynamic vtables (`mono_class_getVTable()`). | Static class pointers; `mono_class_getVTable()` returns class pointer itself. |
| **Class Fallbacks** | Fast metadata table inspection. | May fall back to pattern scanning (`mono_image_enumClasses_il2cppfallback`). |
| **Symbol Enum** | Loaded per assembly on demand. | Emits background symbol list (`monoIL2CPPSymbolEnum`). |

---

## Concurrency & Thread-Safety Rules

> [!WARNING]
> Do not create pipes yourself. Just use the API provided by Cheat Engine's monoscript.lua

1. **Worker Threads**:
   If executing Mono calls inside a Lua worker thread (`createThread`), accessing lua functions will autocreate pipe connections for you which will be destroyed upon thread termination   

2. **Main Thread GUI Operations**:
   `LaunchMonoDataCollector()` and `libmono.terminate()` must be executed on the main UI thread. If calling from an external thread, wrap in `synchronize()`:
   ```lua
   synchronize(function()
     LaunchMonoDataCollector()
   end)
   ```

---

## Essential Function Quick Reference

| Task | Primary Function | Secondary / Alternative |
| :--- | :--- | :--- |
| **Connect** | `LaunchMonoDataCollector()` | `getMonoPipe()`, `mono_isValid()` |
| **Class Query** | `mono_findClass("Namespace.Class")` | `mono_findClass2(fullName, assembly)` |
| **Method Query** | `mono_class_findMethod(class, name)` | `mono_findMethod(namespace, class, method, params)` |
| **JIT Compile** | `mono_compile_method(method)` | Native entry point address returned |
| **Field Info** | `mono_class_enumFields(class, true)` | Returns table of `{name, offset, isStatic, ...}` |
| **Static Value**| `mono_class_getStaticFieldValue(class, field)` | `mono_class_setStaticFieldValue(class, field, val)` |
| **Find Objects**| `mono_class_findInstancesOfClassListOnly(class)` | `mono_class_findInstancesOfClass(domain, class, cb)` |
| **Invoke Code** | `mono_invoke_method(nil, method, obj, args)` | `mono_invoke(name, obj, args)` |
| **Read String** | `mono_string_readString(address)` | `mono_new_string(domain, "text")` |
| **Dissect GUI** | `mono_dissect()` | Opens interactive Mono Dissector window |

See [references/api_reference.md](references/api_reference.md) for full parameter and return schemas (loadable on demand via `getSkill(skillName='monoscript', reference='references/api_reference.md')`).

Files in this skill

  • SKILL.md9.9 KB
  • references/api_reference.md20.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…