Open-source project
JLospinoso/gargoyle avatar
JLospinoso/gargoyle

gargoyle: a Windows temporal memory-state research artifact, refreshed

Historical Windows temporal memory-state research artifact for studying time-bound memory observations, validation limits, and defensive visibility.

917 stars113 forksPythonAGPL-3.0

At a glance

What is it?
Gargoyle is Josh Lospinoso's 2017 proof of concept for temporal memory state, where code is observable only during a short work window and dormant in between, now rebuilt with x64, ARM64 and ARM64EC siblings and a Python acceptance harness. It is aimed at memory forensics researchers studying why a scanner sees what it sees.
Who is it for?
Adopt gargoyle as a research artifact if you study memory forensics or build memory scanners, since it gives you a reproducible way to see time-bound memory observations behave differently and a harness that states exactly what the evidence does and does not prove.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 177 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • JLospinoso/gargoyle917 ★ · +1
Star history
Repository2026-10-222026-11-07
JLospinoso/gargoyle916917

1 Stars in the last 16 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

A 2017 proof of concept, rebuilt after a decade

Gargoyle is described in the README as a historical Windows research proof of concept for temporal memory state. It originated as a Win32/x86 research artifact, published in an article in 2017, and the README keeps that history central rather than presenting the project as new work.

The mechanism it demonstrates is about time, not about hiding code in general. A benign action is observable during a small work window, while the relevant code region spends its dormant interval non-executable before timer or APC re-entry.

Read that carefully, because the ordering is the whole point. The scanner that walks process memory sees the region when it is executable and when something is happening in it. Between those moments, the same bytes are not executable. A scanner that samples memory at the wrong time sees nothing meaningful, and a scanner that dumps the region sees code that cannot be running because it is not mapped as executable.

The refreshed repository keeps the original design canonical and adds sibling x64, ARM64 and ARM64EC demonstrations, a reproducible validation harness and clearer evidence language. It also documents the corrected timer and APC path around `SleepEx(INFINITE, TRUE)`, which the README describes as the corrected alertable-wait evidence path in the docs.

The original article and the author's later retrospective, Gargoyle, a decade later, are both linked from the README, and the homepage of the project is that retrospective.

The project states what it is not

The README has a paragraph that is unusual in a security repository and worth quoting in substance. Gargoyle does not claim invisibility or product bypass. It is not a loader, operator workflow, or deployment guide, and it does not provide persistence, injection, credential access, networking, or C2 guidance.

That is a deliberate framing and it changes what the repository is for. There is no armory package here, no operator steps, and no way to take the demonstration and turn it into a deployed capability without writing all of that yourself. What there is, is a working demonstration of a timing behaviour and a set of claims about what has been shown.

The topics list gives the same picture from the other side: dfir, memory-analysis, memory-forensics, reverse-engineering, windows-internals, native-code, assembly, code-injection, pic, x86, x64 and arm64ec. This is the vocabulary of someone working on the boundary between offensive tooling and defensive analysis, and the repository is published on the research side of that line.

The docs structure reinforces it. There is a Responsible use page for scope boundaries and non-goals, a Research references page and a lineage page for source mapping and relationship boundaries, and an Architecture comparison page for what each sibling demonstration validates and does not prove.

The licence is AGPL-3.0, with the pyproject metadata recording `AGPL-3.0-only`. For research code you intend to read, modify and publish, that is the strict end of the spectrum, and it is a deliberate choice for a tool whose whole point is that its evidence can be audited.

What each architecture validates, and what it does not

The Architecture And Evidence Boundaries section is the most valuable part of the README for anyone evaluating the work, because it is written as a list of things the project does not prove.

Win32/x86 is the canonical historical implementation. The x64 sibling is not a direct port of the original x86 `mshtml.dll` gadget and trampoline path. That is stated plainly, and it is the kind of statement most projects avoid, because it means the x64 build demonstrates a related idea through different means rather than the same technique on a different architecture.

The validation limits are equally specific. The x86 and x64 live validation uses two benign MessageBoxes, which validates initial execution and later controlled re-entry, but not callback identity or every memory-protection transition. So the demonstration shows that a benign action happens and that re-entry works, and it does not show that a specific callback is the one that runs, or that the memory protection transitions are the complete set.

The ARM64 and ARM64EC headless validation goes further, checking completed-round and callback-round counters, which gives stronger callback-delivery evidence. The README is careful about what ARM64EC does and does not show as well: it exercises the EC-code allocation behavior used by the demo, and it does not demonstrate mixed x64 DLL interop or prove every ARM64EC dynamic-code pattern.

For a reader, this is the difference between a demonstration and a claim. The project tells you the boundary of each experiment, which means you can build on the parts that hold.

The Python acceptance harness and the local gate

The refreshed repository adds a Python side, and the repository layout shows it as a separate package from the native code. The pyproject declares the project as `gargoyle-acceptance`, version 0.1.0, described as an acceptance harness for the Gargoyle memory-scanner evasion proof of concept. It requires Python 3.13 or newer, depends on `rich` and `typer`, and exposes a console script `gargoyle-acceptance` bound to `gargoyle_acceptance.cli:main`. The build backend is hatchling, and the wheel packages `src/gargoyle_acceptance`.

The local gate is two commands:

powershell
uv sync --all-groups
just ci

The `justfile` shows what is behind them. The tool runs under PowerShell with a no profile and a bypass execution policy, and the tasks are `sync` with `uv sync --all-groups --frozen`, `lock` and `lock-check` with `uv lock`, `lint` and `lint-fix` with ruff, `format-check` and `format` with ruff format, `pydoclint`, `typecheck` with mypy, `test` with pytest, and `docs` and `docs-serve` with mkdocs.

The strictness is notable for a research repository. Ruff is configured with a line length of 100, target py313, and a wide rule selection including `B`, `C4`, `E`, `F`, `I`, `N`, `PL`, `PTH`, `RET`, `RUF`, `S`, `SIM`, `UP` and `W`. Mypy runs in strict mode over `src/gargoyle_acceptance` with `warn_unreachable` enabled. Pytest runs with `--strict-markers` and coverage flags, and coverage fails under 88.

That combination is what makes the artifact reproducible rather than anecdotal. The native demonstration is a research claim, and the harness is the part that can be run by someone else and checked.

Building the native side with NASM and MSBuild

The native code is Windows only, and the build scripts make that concrete.

The justfile's build configuration locates NASM under `LOCALAPPDATA\bin\NASM` and prepends it to the path when `nasm.exe` is present, then resolves MSBuild from the `MSBUILD` environment variable, or from a Visual Studio 18 Community path, or falls back to `MSBuild.exe` on the path. It invokes `& $msbuild Gargoyle.sln /p:Configuration={{configuration}} /p:Platform=x86 $extra /m`, with an optional `GARGOYLE_PLATFORM_TOOLSET` environment variable adding `/p:PlatformToolset=` to the command line. There are `build-debug` and `build-release` tasks that pass the configuration through.

The `{{configuration}}` placeholder and the `/m` flag are worth pausing on. The configuration is passed as a recipe argument rather than hardcoded, which is what lets one task serve both Debug and Release, and `/m` builds the solution in parallel. The `extra` array is the extension point for a non-default platform toolset, which matters on a machine with a different Visual Studio install.

At the top level of the repository you can see the sources these scripts consume: `Gargoyle.sln` and `Gargoyle.vcxproj` for the x86 project, `GargoyleX64/`, `GargoyleArm64/` and `GargoyleArm64EC/` for the siblings, `src/`, `main.cpp`, `gadget.nasm` and `setup.nasm` for the assembly side, a `build/` directory, `tests/` and `docs/` with an `mkdocs.yml`.

The assembly files are the heart of the original demonstration. `gadget.nasm` is the gadget, and `setup.nasm` the setup, and both are assembled by NASM before the C++ project is compiled.

Reading paths, docs and a single refresh release

The README offers a reading path rather than a tutorial, and the links are organised by what a reader needs.

The documentation home at `docs/index.md` holds reader paths and project orientation. The Quickstart gives the shortest safe build and validation path. `docs/concepts/timer-apc-sleepex.md` covers the corrected timer and APC path around `SleepEx(INFINITE, TRUE)`, which is the alertable-wait evidence path. `docs/architectures/comparison.md` sets out what each sibling validates and does not prove. `docs/validation/overview.md` explains the evidence language used across the repository, and `docs/research/references.md` and `docs/research/lineage.md` handle source mapping and the boundaries of the project's relationships to other work.

Two things about that structure are worth noting. The separation of a validation overview from the concept documents suggests the evidence vocabulary is treated as a first class artefact rather than a description in prose, which is what you would want from something whose claims are about what can and cannot be observed. And the lineage page exists to state relationship boundaries, which is how a research project avoids its readers over-reading the relationship between the artifact and other published techniques.

On releases, there is exactly one, tagged `2026-refresh` and described as a 2026 refresh for temporal memory-state validation, published on 2026-05-15. The last push was on the same date. That is a project that refreshes periodically rather than continuously, and it means there is no long tag history to read: the README, the docs and the single release are the material.

The repository is also published under AGPL-3.0 in the metadata, and the docs are built with mkdocs and the material theme, listed in the dependency groups along with mkdocstrings for API documentation.

Editorial conclusion

Adopt gargoyle as a research artifact if you study memory forensics or build memory scanners, since it gives you a reproducible way to see time-bound memory observations behave differently and a harness that states exactly what the evidence does and does not prove. Skip it if you are looking for a working offensive tool, because the repository states plainly that it is not a loader, operator workflow or deployment guide and provides no persistence, injection, credential access, networking or C2 guidance. Verify first which sibling architecture matches your target, since the x64 build is explicitly not a direct port of the original x86 path, and read the validation overview before drawing conclusions from any single run. The licence field on the repository says AGPL-3.0, and the only tagged release is 2026-refresh from 2026-05-15.

Frequently asked questions

What is the gargoyle research project?

Gargoyle is a historical Windows research proof of concept for temporal memory state. A benign action is observable during a small work window, while the relevant code region spends its dormant interval non-executable before timer or APC re-entry. The README states that it does not claim invisibility or product bypass.

What does gargoyle explicitly not provide?

The README says Gargoyle is not a loader, operator workflow or deployment guide, and that it does not provide persistence, injection, credential access, networking or C2 guidance. The repository publishes a responsible use page describing scope boundaries and non-goals.

Which architectures does gargoyle cover and what are the limits?

Win32/x86 is the canonical historical implementation, with x64, ARM64 and ARM64EC as sibling demonstrations rather than replacements. The README notes the x64 sibling is not a direct port of the original x86 path, that x86 and x64 live validation uses two benign MessageBoxes and does not validate callback identity or every memory-protection transition, and that ARM64EC does not demonstrate mixed x64 DLL interop.

How do I build and validate gargoyle locally?

The local gate is `uv sync --all-groups` followed by `just ci`. The justfile provides tasks for linting with ruff, type checking with mypy, testing with pytest, and building the docs with mkdocs, and the native side is built with MSBuild and NASM through the build tasks.

What is the gargoyle-acceptance Python package?

It is the acceptance harness for the Gargoyle proof of concept, declared in pyproject.toml with the name `gargoyle-acceptance`, version 0.1.0, requiring Python 3.13 or newer and exposing a `gargoyle-acceptance` console script. It depends on rich and typer, and the coverage configuration fails under 88.

What licence is gargoyle released under?

The licence field on the repository says AGPL-3.0, and the pyproject metadata records `AGPL-3.0-only` with a LICENSE file at the top level. The only tagged release is 2026-refresh from 2026-05-15, and the last push was on the same date.

Official sources

  1. JLospinoso/gargoyle on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jlospinoso-gargoyle.svg)](https://hysenlabs.com/projects/jlospinoso-gargoyle)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/jlospinoso-gargoyle.svg)](https://hysenlabs.com/projects/jlospinoso-gargoyle)

Was this useful?