From 5e8f4b6d7267b6cc6120ea705bc09d92dd2c3fb7 Mon Sep 17 00:00:00 2001 From: rhueno <150560466+rhueno@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:11:51 +0300 Subject: [PATCH 1/2] feat: detect attach trigger files --- .../java/dev/rhueno/antiagent/AgentCheck.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/rhueno/antiagent/AgentCheck.java b/src/main/java/dev/rhueno/antiagent/AgentCheck.java index 55663f4..4299cea 100644 --- a/src/main/java/dev/rhueno/antiagent/AgentCheck.java +++ b/src/main/java/dev/rhueno/antiagent/AgentCheck.java @@ -60,6 +60,11 @@ static Result inspect() { dynamicAgentDisabled = true; } + boolean attachTriggerObserved = observeAttachTrigger(); + if (attachTriggerObserved) { + findings.add("attach trigger file observed"); + } + return new Result( javaAgent, nativeAgent, @@ -68,6 +73,7 @@ static Result inspect() { attachDisabled, dynamicAgentDisabled, attachListenerRequested, + attachTriggerObserved, observeAttachListener(), Collections.unmodifiableList(new ArrayList(findings)) ); @@ -141,6 +147,28 @@ private static boolean observeAttachListener() { return new File("/tmp", ".java_pid" + pid).exists(); } + private static boolean observeAttachTrigger() { + if (!isUnixLike()) { + return false; + } + + String pid = pid(); + if (pid == null) { + return false; + } + + String name = ".attach_pid" + pid; + if (new File(name).exists()) { + return true; + } + + String temporary = System.getProperty("java.io.tmpdir"); + if (temporary != null && new File(temporary, name).exists()) { + return true; + } + return new File("/tmp", name).exists(); + } + static String pid() { try { Class processHandle = Class.forName("java.lang.ProcessHandle"); @@ -182,10 +210,11 @@ static final class Result { final boolean attachDisabled; final boolean dynamicAgentDisabled; final boolean attachListenerRequested; + final boolean attachTriggerObserved; final boolean attachListenerObserved; final List findings; - Result(boolean javaAgent, boolean nativeAgent, boolean dynamicAgentEnabled, boolean selfAttachEnabled, boolean attachDisabled, boolean dynamicAgentDisabled, boolean attachListenerRequested, boolean attachListenerObserved, List findings) { + Result(boolean javaAgent, boolean nativeAgent, boolean dynamicAgentEnabled, boolean selfAttachEnabled, boolean attachDisabled, boolean dynamicAgentDisabled, boolean attachListenerRequested, boolean attachTriggerObserved, boolean attachListenerObserved, List findings) { this.javaAgent = javaAgent; this.nativeAgent = nativeAgent; this.dynamicAgentEnabled = dynamicAgentEnabled; @@ -193,6 +222,7 @@ static final class Result { this.attachDisabled = attachDisabled; this.dynamicAgentDisabled = dynamicAgentDisabled; this.attachListenerRequested = attachListenerRequested; + this.attachTriggerObserved = attachTriggerObserved; this.attachListenerObserved = attachListenerObserved; this.findings = findings; } From e07f00b75b53db933418fe62b0a9ca839a1d758e Mon Sep 17 00:00:00 2001 From: rhueno <150560466+rhueno@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:12:30 +0300 Subject: [PATCH 2/2] feat: classify attach trigger activity --- src/main/java/dev/rhueno/antiagent/AntiAgent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dev/rhueno/antiagent/AntiAgent.java b/src/main/java/dev/rhueno/antiagent/AntiAgent.java index 40766f6..135c3e9 100644 --- a/src/main/java/dev/rhueno/antiagent/AntiAgent.java +++ b/src/main/java/dev/rhueno/antiagent/AntiAgent.java @@ -169,7 +169,7 @@ private static void refresh() { if (integrity.unsupported) { state = State.UNSUPPORTED; } - if (check.dynamicAgentEnabled || check.selfAttachEnabled || check.attachListenerRequested || attachListenerPresentAtInstall || attachListenerAppeared || runtimeTransformation || monitorFailed) { + if (check.dynamicAgentEnabled || check.selfAttachEnabled || check.attachListenerRequested || check.attachTriggerObserved || attachListenerPresentAtInstall || attachListenerAppeared || runtimeTransformation || monitorFailed) { state = State.SUSPICIOUS; } if (check.javaAgent || check.nativeAgent || agentEvent || coreRuntimeTransformation || (!integrity.intact && !integrity.unsupported)) { @@ -180,6 +180,7 @@ private static void refresh() { environmentToken ^= check.attachDisabled ? 0x243f6a8885a308d3L : 0x13198a2e03707344L; environmentToken ^= check.dynamicAgentDisabled ? 0xa4093822299f31d0L : 0x082efa98ec4e6c89L; environmentToken ^= check.attachListenerRequested ? 0x299f31d0082efa98L : 0xec4e6c89452821e6L; + environmentToken ^= check.attachTriggerObserved ? 0xd4e12c77a96b53f1L : 0x5a1f9c2d8e7034b6L; environmentToken ^= monitorActive ? 0x452821e638d01377L : 0xbe5466cf34e90c6cL; environmentToken ^= monitorFailed ? 0x3f84d5b5b5470917L : 0x9216d5d98979fb1bL; environmentToken ^= agentEvent ? 0xd1310ba698dfb5acL : 0x2ffd72dbd01adfb7L;