https://github.com/handy-sun/rcheat
Get/modify variable's value in another Linux running process
https://github.com/handy-sun/rcheat
cli elf gdb process ptrace
Last synced: 2 months ago
JSON representation
Get/modify variable's value in another Linux running process
- Host: GitHub
- URL: https://github.com/handy-sun/rcheat
- Owner: handy-sun
- License: mit
- Created: 2024-08-01T07:08:25.000Z (almost 2 years ago)
- Default Branch: dev0
- Last Pushed: 2025-03-11T13:53:47.000Z (over 1 year ago)
- Last Synced: 2025-03-24T08:42:01.497Z (over 1 year ago)
- Topics: cli, elf, gdb, process, ptrace
- Language: Rust
- Homepage:
- Size: 272 KB
- Stars: 11
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# **rcheat**
**English | [简体中文](./README.zh-CN.md)**
[](https://github.com/handy-sun/rcheat/actions/workflows/build-test.yml)

[](https://crates.io/crates/rcheat)

> *Get/modify simple variable's value in another Linux running process*
**Please note that this project is only for learning and research purposes, and the author is not responsible for any legal consequences caused by the use of this project.**
------
## Table of Contents
* 1. [Installation](#Installation)
* 1.1. [Via cargo](#Viacargo)
* 1.2. [Build src](#Buildsrc)
* 1.2.1. [Dependencies](#Dependencies)
* 1.2.2. [Building](#Building)
* 2. [Simple Example](#SimpleExample)
* 3. [Lua Scripting](#lua-scripting)
* 4. [Todo](#Todo)
Some ways to install cargo
- can be obtained using [rustup](https://rust-lang.github.io/rustup/)(Recommond)
- use Linux package management(e.g. apt, yum, dnf, pacman)
- download a offline tarball from [forge.rust-lang.org](https://forge.rust-lang.org/infra/archive-stable-version-installers.html)
In order to install, just run the following command
```sh
cargo install --force rcheat
```
This will install cargo-make in your `~/.cargo/bin`.
Make sure to add `~/.cargo/bin` directory to your `PATH` variable.
You will have a executable available: *`rcheat`*
- [cargo](https://github.com/rust-lang/cargo/) >= 1.74
- [rustc](https://www.rust-lang.org/) >= 1.74
Suggest using the latest version
```shell
git clone https://github.com/handy-sun/rcheat.git
cd rcheat
cargo build
```
You will have a executable available: *`./target/debug/rcheat`*
**Tips:**
If download speed from `crates.io` is too slow. use a mirror to speed up(e.g. use [rsproxy](https://rsproxy.cn)).
for example, a `C` source file `onlyc.c` with some global variables:
```c
#include
const char sc_sig_arr[][6] = { " ", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "BUS", "FPE", "KILL" };
const char techs[] = "\x02str.wa : ? !\ndaw\r21";
struct DemoStru {
int int32;
short uint16;
};
struct DemoStru structure;
int main() {
structure.int32 = 0x7ffe8092;
structure.uint16 = 0x321b;
while (1) {
sleep(30);
}
return 0;
}
```
Then compile and run it:
```sh
gcc onlyc.c -o onlyc && ./onlyc
```
Get pid of `onlyc`(e.g. use command: `pidof`) and use `rcheat` with `-p` option:
**NOTE: This program must be run with root privileges!**
```sh
pidof onlyc
# output: 13725
sudo rcheat -p 13725
```
Then will get the output about all global variables about this program
```
...
Matched count: 3
Index: var_name | var_size(B)
0: sc_sig_arr | 60
1: structure | 8
2: techs | 21
Please input index to choose the var(default is 0):
```
Input `2` and `Enter`, you will see the byte value and ascii content of this variable (control char that unvisible show as `.`)
```
0x0000: 0273 7472 2e77 6120 3a20 3f20 210a 6461 ┃ .str.wa : ? !.da
0x0010: 770d 3231 00 ┃ w.21.
```
You also can specify the total name or partly keyword of the variable with option `-k`
```sh
sudo rcheat -p 13725 -k sig_arr
```
```
...
0x0000: 2000 0000 0000 4855 5000 0000 494e 5400 ┃ .....HUP...INT.
0x0010: 0000 5155 4954 0000 494c 4c00 0000 5452 ┃ ..QUIT..ILL...TR
0x0020: 4150 0000 494f 5400 0000 4255 5300 0000 ┃ AP..IOT...BUS...
0x0030: 4650 4500 0000 4b49 4c4c 0000 ┃ FPE...KILL..
```
After version `0.1.3`, option `-n/--name` can query pid by process name
```
sudo rcheat -n onlyc -k sig_arr
```
## 3. Lua Scripting
Since version `0.2.0`, rcheat supports using Lua scripts to define custom binary struct parsing and formatted table output. Use the `-f lua` option to enable it.
### How It Works
1. Place Lua script files in `/etc/rcheat/lua/`
2. Run `rcheat` with `-f lua`:
```sh
sudo rcheat -n onlyc -k structure -f lua
```
3. rcheat loads `core.lua` (built-in), then loads all `.lua` files from the script directory
4. Matches the variable name against `Structure.match_table` to find the alias
5. Calls `Structure:new_(bytes)` to parse the raw bytes into a table
6. Outputs a formatted table
### Writing a Lua Script
Every script must define a global `Structure` table with:
- `match_table` — maps variable name patterns (Lua string.find) to aliases
- `new_(bytes)` — constructor that parses raw bytes and returns an instance
Column definition format:
| Field | Description | Examples |
|-------|-------------|----------|
| `name` | Column header name | `'id'`, `'health'` |
| `size` | Number of bytes | `1`, `2`, `4`, `8` |
| `fmt` | [string.unpack](https://www.lua.org/manual/5.4/manual.html#6.4.2) format | `'i'` signed, `'I'` unsigned, `'f'` float, `'s'` string, `'c'` char, `nil` auto signed int |
When `fmt` is `'i'`, `'I'`, `'s'`, or `'c'`, the size is appended automatically (e.g. `i4`, `I1`). When `fmt` is `nil`, it defaults to `i` (signed integer). For `'f'`, the size is determined by the format itself (4 bytes for `f`, 8 for `d`).
### Example
`/etc/rcheat/lua/example.lua`:
```lua
Structure = {}
Structure.__index = Structure
-- Match variable names containing 'pcmStateList' to alias 'psl'
Structure.match_table = {
['pcmStateList'] = 'psl',
}
-- Constructor: parse bytes into a table with columns {id, stared, act}
function Structure:new_psl(bytes)
self.psl_col = {
{ name = 'id', size = 4, fmt = 'i' }, -- signed 32-bit int
{ name = 'stared', size = 1, fmt = 'I' }, -- unsigned 8-bit int
{ name = 'act', size = 4, fmt = 'f' }, -- 32-bit float
}
return setmetatable({ psl = SetupTableData(bytes, self.psl_col) }, Structure)
end
```
Output (rcheat will format it as an aligned table):
```
╭─────┬────┬────────╮
│ (i) │ id │ stared │ act │
├─────┼────┼────────┤───────┤
│ 0 │ 1 │ 0 │ 3.50 │
│ 1 │ 2 │ 1 │ 7.25 │
╰─────┴────┴────────┴───────╯
```
### Built-in Functions (core.lua)
`SetupTableData(bytes, tab_list)` — Iterates over raw bytes according to the column definitions and returns a two-dimensional table. Each row is an array of `{ name, size, data }` entries. The function loops over the byte array, slicing it by each column's `size` and unpacking with `string.unpack` using the specified `fmt`.
*The development plan of the project and the functions to be implemented*
- [ ] parse `.debug*` section
- [ ] use log crate such as `log/env_logger` etc.
- [ ] write data to tracee process' memory
- [ ] use config.toml to reduce some inputs
- [x] use lib like `table` to format matrix table data
- [x] use `lua` to customized output
- [x] search pid by process name (like linux command: `pidof/pgrep`)
- [x] regex replace String.contain
- [x] if match more than 1 entry name, ask for which one to select
- [x] demangle symbols