{"id":17137186,"url":"https://github.com/squeek502/memreader","last_synced_at":"2025-03-24T07:15:14.851Z","repository":{"id":77411228,"uuid":"113759076","full_name":"squeek502/memreader","owner":"squeek502","description":"Lua module for reading the memory of Windows processes","archived":false,"fork":false,"pushed_at":"2017-12-12T11:41:50.000Z","size":54,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-29T12:32:41.713Z","etag":null,"topics":["lua","memory"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/squeek502.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-10T15:02:02.000Z","updated_at":"2022-05-10T18:09:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"34daa065-19f9-44d3-80ce-0ff0b273d1f5","html_url":"https://github.com/squeek502/memreader","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squeek502%2Fmemreader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squeek502%2Fmemreader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squeek502%2Fmemreader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/squeek502%2Fmemreader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/squeek502","download_url":"https://codeload.github.com/squeek502/memreader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245224581,"owners_count":20580367,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","memory"],"created_at":"2024-10-14T20:06:26.472Z","updated_at":"2025-03-24T07:15:14.815Z","avatar_url":"https://github.com/squeek502.png","language":"C","readme":"# memreader\n\n[![Build status](https://ci.appveyor.com/api/projects/status/2wvir44l54xuuoau?svg=true)](https://ci.appveyor.com/project/squeek502/memreader)\n\n`memreader` is a [Lua](https://www.lua.org/) module for reading the memory of Windows processes.\n\n```lua\nlocal memreader = require('memreader')\n\n-- Find a window by title and open a handle to its process\nlocal window = memreader.findwindow(\"Your Window Title\")\nlocal process = memreader.openprocess(window.pid)\n\n-- Read the first 8 bytes from the start of the main module's memory\nlocal data_rel = process:readrelative(0, 8)\n\n-- Do the same thing, but using the absolute address this time\nlocal address = process.base\nlocal data_abs = process:read(address, 8)\n\n-- Data is returned as a string of the specified length (not null-terminated)\nassert(#data_rel == 8 and #data_abs == 8)\nassert(data_rel == data_abs)\n```\n\n## Installation\nWith [Luarocks](https://luarocks.org):\n```\nluarocks install memreader\n```\n\n## Building\nTo build memreader, you'll need to install [`cmake`](https://cmake.org), some version of [Visual Studio](https://www.visualstudio.com/), and have a Lua `.lib` file that [can be found by `cmake`](https://cmake.org/cmake/help/v3.0/module/FindLua.html) (preferably built with the same compiler you're using to build memreader).\n\n### Using `cmake-gui`\n- Run `cmake-gui`\n- Browse to memreader directory and set the build directory (typically just add `/build` to the memreader directory path)\n- Click Configure\n- Select the Generator and hit *Finish*\n- Hit Generate and then Open Project to open the project in Visual Studio\n- Build the project in Visual Studio as normal\n\n### Using `cmake`\nOpen a command line in the `memreader` directory and do the following:\n```sh\nmkdir build\ncd build\ncmake ..\ncmake --build . --config Release\n```\nIf needed, you can specify a [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) by doing `cmake -G \"Visual Studio 14 2015 Win64\" ..` instead of `cmake ..`\n\n## API Reference\n\n### `memreader.debugprivilege([state = true])`\nAttempts to adjust the access token of the Lua process to set the [`SeDebugPrivilege`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx) privilege (needed to access the memory of processes owned by other accounts). Calling this may or may not be necessary depending on how Lua is spawned, your use case, etc. \n\nOn success, returns `true`; otherwise, returns `nil, errmsg`.\n\n### `memreader.processes()`\nReturns an iterator for all the processes in the system, in `pid, name` pairs. \n\nExample:\n```lua\nlocal process\nfor pid, name in memreader.processes() do\n  if name == \"target.exe\" then\n    process = memreader.openprocess(pid)\n    break\n  end\nend\n```\n\n\u003e Relevant WinAPI docs: [`CreateToolhelp32Snapshot`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682489(v=vs.85).aspx), [`Process32Next`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684836(v=vs.85).aspx)\n\n### `memreader.findwindow(title)`\nFinds a window by title. If found, returns a [`memreader.window`](#memreaderwindow) usertype; otherwise, returns `nil, errmsg`.\n\n*Note: If there are multiple windows with the same title, this will only return the first (in arbitrary order). `findwindow` is faster than iterating with `processes`, but is not as precise or thorough.*\n\n\u003e Relevant WinAPI docs: [`FindWindow`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx)\n\n### `memreader.openprocess(pid)`\nAttempts to open a handle to the process with the given process ID using the flags [`PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx). On success, returns a [`memreader.process`](#memreaderprocess) usertype; otherwise, returns `nil, errmsg`.\n\n\u003e Relevant WinAPI docs: [`OpenProcess`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx)\n\n### `memreader.process`\n\nA usertype for process handles.\n\n**Fields (read-only):**\n\n- `process.pid`: The process ID (e.g. `280`)\n- `process.name`: The name of the process' main module (e.g. `lua.exe`)\n- `process.path`: The full path to the process' main module (e.g. `C:\\lua.exe`)\n- `process.base`: The base address of the process' main module, as a [`memreader.address`](#memreaderaddress) usertype (e.g. `0000000076EA0000`)\n\n#### `process:read(address, nbytes)`\nReads the specified number of bytes starting at the given address (can be either a number or a [`memreader.address`](#memreaderaddress)) and returns that memory as a string (not null-terminated). On failure, returns `nil, errmsg`.\n\n#### `process:readrelative(offset, nbytes)`\nLike `process:read()`, except that `offset` is added to the process' main module's base address to determine the address to start from.\n\n```lua\n-- The following are exactly equivalent\nprocess:read(process.base + 0x40, 4)\nprocess:readrelative(0x40, 4)\n```\n\n#### `process:modules()`\nReturns an iterator for all the modules of the process, as [`memreader.module`](#memreadermodule) usertypes.\n\nExample:\n```lua\nfor module in process:modules() do\n  print(module.name, module.base)\nend\n```\n\n#### `process:exitcode()`\nReturns the exit code of the process (if it has exited). If the process is still running, then it will instead return `nil`. On failure, returns `nil, errmsg`.\n\n#### `process:version()`\nRetrieves the file and product version info embedded in the process' main module and returns it as a table. On failure, returns `nil, errmsg`.\n\nStructure of the returned table:\n```lua\n{ \n  file = { major=1, minor=0, build=3, revision=105 },\n  product = { major=3, minor=0, build=0, revision=0 }\n}\n```\n\n### `memreader.module`\n\nA usertype for process modules.\n\n**Fields (read-only):**\n\n- `module.name`: The name of the module (e.g. `lua51.dll`)\n- `module.path`: The full path to the module (e.g. `C:\\lua51.dll`)\n- `module.base`: The base address of the module, as a [`memreader.address`](#memreaderaddress) usertype (e.g. `0000000076EA0000`)\n- `module.size`: The size (in bytes) of the module (e.g. `32768`)\n\n### `memreader.address`\n\nA usertype for an address in memory ([`LPVOID`](https://en.wikibooks.org/wiki/Windows_Programming/Handles_and_Data_Types#LPVOID)). Can be manipulated by adding/subtracting it with numbers or other `memreader.address` instances.\n\nExample:\n```lua\nlocal a = process.base\nlocal b = a + 0x40\nlocal c = b - a\n```\n\n### `memreader.window`\n\nA usertype for window handles.\n\n**Fields (read-only):**\n\n- `window.pid`: The process ID of the window's main thread (e.g. `280`)\n- `window.title`: The title of the window (e.g. `Your Window Title`)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsqueek502%2Fmemreader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsqueek502%2Fmemreader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsqueek502%2Fmemreader/lists"}