Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ on:

jobs:
build:

runs-on: ubuntu-latest
name: Build on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}

permissions:
contents: write
Expand All @@ -33,6 +37,8 @@ jobs:
- name: Build with Maven
run: mvn -B package --file pom.xml

# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
# Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive.
# Runs only on Linux to avoid duplicate submissions across matrix legs.
- name: Update dependency graph
if: matrix.os == 'ubuntu-latest' && github.event_name == 'push'
uses: advanced-security/maven-dependency-submission-action@v4
117 changes: 117 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Changelog

All notable changes to this project are documented in this file.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed
- `ProcessSession` is now reference-counted. `Pointer.copy()` retains a new
reference, `Pointer.close()` releases one. The underlying OS handle is only
torn down when the **last** live `Pointer` is closed, removing the
previous footgun where closing a copy made every sibling pointer
unusable. A `java.lang.ref.Cleaner` registered on each `Pointer`
releases the same reference on GC, so forgetting `close()` no longer
leaks the handle.
- AOB scanning (`SignatureUtil.findSignature`) now consults
`NativeAccess.queryProtection` before each 64 KiB read. Unreadable
regions (`MemoryProtection.NONE`) are skipped *explicitly* instead of
surfacing as silent `readMemory` failures, which makes the scan path
honest about what it skipped.

### Added
- `it.adrian.code.platform.NativeAccess` cross-platform layer that selects
the right backend (`WindowsAccess` or `LinuxAccess`) at runtime via
reflective class loading, so the unused backend's native libraries are
never initialised.
- Linux backend that talks to `/proc/<pid>/{maps,mem,comm,exe}` and uses
`libc geteuid()` for the privilege check.
- `Pointer` is now `AutoCloseable`; the underlying handle / file descriptor
is released on `close()` (use it in a try-with-resources block).
- Bulk I/O on `Pointer`: `readBytes(int)`, `writeBytes(byte[])`,
`readString(int [, Charset])`, `writeString(String [, Charset])`,
`readShort` / `writeShort`, `readByte` / `writeByte`.
- Configurable endianness via `Pointer.withByteOrder(ByteOrder)`.
- `Pointer.indirect32()` for chasing 32-bit pointers (32-bit targets).
- `ProcessUtil.listModules(int pid)` returns a cross-platform
`List<ModuleInfo>` (name, full path, base address, size).
- Cross-platform AOB scanning via
`SignatureUtil.findSignature(ProcessSession, …)` and
`new SignatureManager(Pointer)` / `new SignatureManager(ProcessSession, String)`.
- Cross-platform memory protection / allocation primitives:
`NativeAccess.protect`, `allocate`, `free`, `queryProtection`.
Windows wraps `VirtualProtectEx` / `VirtualAllocEx` / `VirtualFreeEx` /
`VirtualQueryEx` (production-ready). **Linux x86_64** ships an
*experimental* ptrace syscall-injection helper for
`protect`/`allocate`/`free` (PTRACE_ATTACH → save regs → patch in
`syscall; int3` at the current RIP → run → restore everything →
PTRACE_DETACH). The end-to-end integration test is marked
`@Disabled` for now — the helper deadlocks when the target is
attached mid-`nanosleep` and the `int3` trap never fires. The
implementation compiles and links on every Linux JVM but should be
treated as experimental until that edge case is fixed.
`queryProtection` does not need injection on either platform and is
fully covered.
- `Pointer.getBaseAddress(String name, int pid)` overload that skips the
PID lookup, useful when several processes share the same executable
name. The single-argument overload is preserved for the common case.
- JUnit 5 integration test suite (`src/test/java/it/adrian/code/Mem4JTests.java`)
with privilege- and OS-aware assumptions: tests skip cleanly when the
JVM is not privileged or runs on the wrong OS / arch instead of
failing. CI runs `mvn -B test` on both `ubuntu-latest` and
`windows-latest` legs.
- `Pointer.force()` returns a sibling pointer whose writes bypass page
protection: on Windows it flips the affected pages to
`PAGE_EXECUTE_READWRITE`, performs the write, then restores the original
protection — so patches into a read-only `.text` section work. On Linux
it is a no-op because `/proc/<pid>/mem` already ignores page protection
for callers with `CAP_SYS_PTRACE`.
- Dedicated exception hierarchy under `it.adrian.code.exceptions`:
`Mem4JException`, `PrivilegeException`, `ProcessNotFoundException`,
`ModuleNotFoundException`, `MemoryAccessException`.
- `LICENSE` (MIT).
- CI matrix (`ubuntu-latest` + `windows-latest`).
- Sources jar and Javadoc jar are now produced as build artefacts so
consumers see docs in their IDE.

### Changed
- **Breaking:** `Memory.readMemory` / `writeMemory` no longer truncate the
offset to 32 bits — the full `long` range is used.
- **Breaking:** missing privileges and missing process now raise
`PrivilegeException` / `ProcessNotFoundException` instead of showing a
`MessageBox` and calling `System.exit(-1)`. The library is now safe to
embed inside larger applications.
- **Breaking:** failed memory reads now throw `MemoryAccessException`
instead of returning zero / garbage bytes silently.
- `SignatureManager` no longer closes its own handle in `finally` — the
caller owns the lifecycle of the underlying `Pointer` / `ProcessSession`.

### Deprecated
- `Pointer(WinNT.HANDLE, com.sun.jna.Pointer)` constructor — use
`Pointer.getBaseAddress(String)` or `new Pointer(ProcessSession, long)`.
- `Pointer.getModuleBaseAddress(int, String)` (returning a JNA pointer) —
use `NativeAccess.get().getModuleBaseAddress(int, String)`.
- `ProcessUtil.getModule(int, String)` — use `ProcessUtil.listModules(int)`.
- `SignatureUtil.findSignature(WinNT.HANDLE, …)` and
`SignatureUtil.readInt(WinNT.HANDLE, …)` — use the
`ProcessSession`-based overloads.
- `new SignatureManager(WinNT.HANDLE, String, int)` — use
`new SignatureManager(Pointer)` or
`new SignatureManager(ProcessSession, String)`.

### Fixed
- `writeFloat` previously allocated and zero-initialised an 8-byte JNA
`Memory` buffer but only wrote 4 bytes, then asked the kernel to write 4
bytes from a buffer it had partially filled (a behaviour bug introduced
in an earlier refactor). Bulk write now goes through a single
`byte[]` that is always the exact size of the value.
- `jitpack.yml` pins the JitPack build to OpenJDK 11; previously it
defaulted to JDK 8 and failed `--release 11`, breaking JitPack consumers.
- GitHub Actions workflow upgraded to `setup-java@v4` (removes the
deprecated `set-output` warning) and granted `contents: write` so the
Dependency Submission API no longer 403s.

## [1.0.0] - 2026-05-16

Initial published release. Windows-only memory manipulation via JNA.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023-2026 ChristopherProject

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading