refactor agent

This commit is contained in:
novice.li 2024-01-20 21:05:18 +08:00
parent 82dfca233c
commit e0a4daa14e
19 changed files with 101 additions and 65 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
*.iml *.iml
.idea/ .idea/
target/ target/
.fastRequest

2
block_url_keywords Normal file
View file

@ -0,0 +1,2 @@
https://account.jetbrains.com/lservice/rpc/validateKey.action
116.62.33.138

View file

@ -13,8 +13,8 @@
<artifactId>jetbra-agent</artifactId> <artifactId>jetbra-agent</artifactId>
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<dependencies> <dependencies>
@ -29,6 +29,13 @@
<artifactId>byte-buddy-agent</artifactId> <artifactId>byte-buddy-agent</artifactId>
<version>1.14.8</version> <version>1.14.8</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -11,15 +11,18 @@ public class AgentMain {
public static void premain(String agentArgs, Instrumentation inst) throws Exception { public static void premain(String agentArgs, Instrumentation inst) throws Exception {
printLogo(); printLogo();
AgentBuilder agentBuilder = newAgentBuilder(); AgentBuilder agentBuilder = newAgentBuilder();
agentBuilder.type(ElementMatchers.named("java.security.cert.PKIXBuilderParameters")) agentBuilder
.type(ElementMatchers.named("java.security.cert.PKIXBuilderParameters"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(PKIXBuilderParametersAdvice.class) .visit(Advice.to(PKIXBuilderParametersAdvice.class)
.on(ElementMatchers.isConstructor().and(ElementMatchers.takesArgument(0, Set.class))))) .on(ElementMatchers.isConstructor().and(ElementMatchers.takesArgument(0, Set.class)))))
.asTerminalTransformation() .asTerminalTransformation()
.type(ElementMatchers.named("sun.net.www.http.HttpClient")) .type(ElementMatchers.named("sun.net.www.http.HttpClient"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(HttpClientAdvice.class) .visit(Advice.to(HttpClientAdvice.class)
.on(ElementMatchers.named("openServer")))) .on(ElementMatchers.named("openServer").and(ElementMatchers.takesArgument(0, String.class)))))
.asTerminalTransformation() .asTerminalTransformation()
.type(ElementMatchers.named("java.lang.System")) .type(ElementMatchers.named("java.lang.System"))
@ -28,12 +31,6 @@ public class AgentMain {
.on(ElementMatchers.named("getProperty")))) .on(ElementMatchers.named("getProperty"))))
.asTerminalTransformation() .asTerminalTransformation()
.type(ElementMatchers.named("java.net.Socket"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
.visit(Advice.to(SocketAdvice.class)
.on(ElementMatchers.named("connect"))))
.asTerminalTransformation()
.installOn(inst); .installOn(inst);
agentBuilder.installOn(inst); agentBuilder.installOn(inst);

View file

@ -1,9 +1,9 @@
package win.novice.li; package win.novice.li;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.TrustAnchor; import java.security.cert.TrustAnchor;
@ -11,9 +11,9 @@ import java.security.cert.X509Certificate;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class TrustAnchorHolder { public class ConfigHelper {
public static Set<TrustAnchor> TRUST_ANCHORS; public static Set<TrustAnchor> TRUST_ANCHORS;
public static Set<String> BLOCK_URL_KEYWORDS;
public static Set<TrustAnchor> loadTrustAnchors() throws Exception { public static Set<TrustAnchor> loadTrustAnchors() throws Exception {
if (TRUST_ANCHORS != null) { if (TRUST_ANCHORS != null) {
@ -22,8 +22,8 @@ public class TrustAnchorHolder {
TRUST_ANCHORS = new HashSet<>(); TRUST_ANCHORS = new HashSet<>();
String certDir; String certDir;
if (System.getenv("JB_HOME") != null) { if (System.getenv("TRUST_CRT_DIR") != null) {
certDir = System.getenv("JB_HOME"); certDir = System.getenv("TRUST_CRT_DIR");
} else { } else {
URI jarURI = getJarURI(); URI jarURI = getJarURI();
if (jarURI == null) { if (jarURI == null) {
@ -39,7 +39,7 @@ public class TrustAnchorHolder {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
for (File item : files) { for (File item : files) {
if (item.getName().endsWith(".crt")) { if (item.getName().endsWith(".crt")) {
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(item)); X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(Files.newInputStream(item.toPath()));
TRUST_ANCHORS.add(new TrustAnchor(cert, null)); TRUST_ANCHORS.add(new TrustAnchor(cert, null));
} }
} }
@ -49,13 +49,42 @@ public class TrustAnchorHolder {
return TRUST_ANCHORS; return TRUST_ANCHORS;
} }
public static Set<String> loadBlockUrlKeywords() throws Exception {
if (BLOCK_URL_KEYWORDS != null) {
return BLOCK_URL_KEYWORDS;
}
BLOCK_URL_KEYWORDS = new HashSet<>();
String blockUrlKeywordFilePath;
if (System.getenv("BLOCK_URL_KEYWORD_FILE_PATH") != null) {
blockUrlKeywordFilePath = System.getenv("BLOCK_URL_KEYWORD_FILE_PATH");
} else {
URI jarURI = getJarURI();
if (jarURI == null) {
return BLOCK_URL_KEYWORDS;
}
blockUrlKeywordFilePath = Paths.get(jarURI).getParent().resolve("block_url_keywords").toString();
}
System.out.println("load block url keywords from " + blockUrlKeywordFilePath);
File file = new File(blockUrlKeywordFilePath);
if (file.exists()) {
for (String line : Files.readAllLines(file.toPath())) {
if (!line.trim().isEmpty()) {
BLOCK_URL_KEYWORDS.add(line);
}
}
}
System.out.println("loaded " + BLOCK_URL_KEYWORDS.size() + " keywords");
return BLOCK_URL_KEYWORDS;
}
public static URI getJarURI() throws Exception { public static URI getJarURI() throws Exception {
URL url = TrustAnchorHolder.class.getProtectionDomain().getCodeSource().getLocation(); URL url = ConfigHelper.class.getProtectionDomain().getCodeSource().getLocation();
if (null != url) { if (null != url) {
return url.toURI(); return url.toURI();
} }
String resourcePath = "/jarLocation.txt"; String resourcePath = "/jarLocation.txt";
url = TrustAnchorHolder.class.getResource(resourcePath); url = ConfigHelper.class.getResource(resourcePath);
if (null == url) { if (null == url) {
return null; return null;
} }

View file

@ -1,14 +1,26 @@
package win.novice.li; package win.novice.li;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import sun.net.www.http.HttpClient;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.util.Set;
public class HttpClientAdvice { public class HttpClientAdvice {
@Advice.OnMethodExit @Advice.OnMethodExit
public static void intercept(@Advice.This Object x) throws Exception { @SuppressWarnings("unchecked")
if (x.toString().contains("validateKey.action")){ public static void intercept(@Advice.This Object httpClient) throws Exception {
Class<?> clazz = Class.forName("win.novice.li.ConfigHelper", true, ClassLoader.getSystemClassLoader());
Method method = clazz.getDeclaredMethod("loadBlockUrlKeywords");
Set<String> BLOCK_URL_KEYWORDS = (Set<String>) method.invoke(null);
String clientString = httpClient.toString();
for (String keyword : BLOCK_URL_KEYWORDS) {
if (clientString.contains(keyword)) {
throw new SocketTimeoutException(); throw new SocketTimeoutException();
} }
} }
} }
}

View file

@ -13,7 +13,7 @@ public class PKIXBuilderParametersAdvice {
@Advice.OnMethodEnter @Advice.OnMethodEnter
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static void intercept(@Advice.Argument(value = 0, readOnly = false) Set<TrustAnchor> trustAnchors) throws Exception { public static void intercept(@Advice.Argument(value = 0, readOnly = false) Set<TrustAnchor> trustAnchors) throws Exception {
Class<?> clazz = Class.forName("win.novice.li.TrustAnchorHolder", true, ClassLoader.getSystemClassLoader()); Class<?> clazz = Class.forName("win.novice.li.ConfigHelper", true, ClassLoader.getSystemClassLoader());
Method method = clazz.getDeclaredMethod("loadTrustAnchors"); Method method = clazz.getDeclaredMethod("loadTrustAnchors");
Set<TrustAnchor> loadedTrustAnchors = (Set<TrustAnchor>)method.invoke(null); Set<TrustAnchor> loadedTrustAnchors = (Set<TrustAnchor>)method.invoke(null);
HashSet<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors); HashSet<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors);

View file

@ -1,20 +0,0 @@
package win.novice.li;
import net.bytebuddy.asm.Advice;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class SocketAdvice {
@Advice.OnMethodExit
public static void intercept(@Advice.Argument(value = 0,readOnly = false) SocketAddress socketAddress) throws Exception {
if (socketAddress instanceof InetSocketAddress){
InetAddress address = ((InetSocketAddress) socketAddress).getAddress();
if (address.getHostAddress().equals("116.62.33.138")){
throw new ConnectException("拒绝连接");
}
}
}
}

View file

@ -2,13 +2,15 @@ package win.novice.li;
import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.Advice;
import java.util.Objects;
public class SystemAdvice { public class SystemAdvice {
// System.getProperty // System.getProperty
@Advice.OnMethodExit @Advice.OnMethodExit
public static void intercept(@Advice.Argument(0) Object x, @Advice.Return(readOnly = false) String r) throws Exception { public static void intercept(@Advice.Argument(0) Object x, @Advice.Return(readOnly = false) String r) throws Exception {
if (x.toString().equals("jb.vmOptionsFile")) { if (Objects.equals(x, "jb.vmOptionsFile")) {
RuntimeException exception = new RuntimeException(); RuntimeException exception = new RuntimeException();
int nullCnt = 0; int nullCnt = 0;
boolean hasReflect = false; boolean hasReflect = false;

View file

@ -41,5 +41,9 @@
<source>${project.parent.basedir}/jetbra-agent/target/jetbra-agent.jar</source> <source>${project.parent.basedir}/jetbra-agent/target/jetbra-agent.jar</source>
<destName>jetbra-agent.jar</destName> <destName>jetbra-agent.jar</destName>
</file> </file>
<file>
<source>${project.parent.basedir}/block_url_keywords</source>
<destName>block_url_keywords</destName>
</file>
</files> </files>
</assembly> </assembly>

View file

@ -13,8 +13,8 @@
<artifactId>jetbra-dist</artifactId> <artifactId>jetbra-dist</artifactId>
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<build> <build>

View file

@ -13,8 +13,8 @@
<artifactId>jetbra-server</artifactId> <artifactId>jetbra-server</artifactId>
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
@ -40,12 +40,12 @@
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId> <artifactId>bcpkix-jdk18on</artifactId>
<version>1.72</version> <version>1.77</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> <artifactId>bcprov-jdk18on</artifactId>
<version>1.72</version> <version>1.77</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>

View file

@ -19,6 +19,7 @@ import java.security.*;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Base64; import java.util.Base64;
import java.util.Collections;
import java.util.Map; import java.util.Map;
@RestController @RestController
@ -45,8 +46,7 @@ public class LicenseController {
String sigResultsBase64 = Base64.getEncoder().encodeToString(signatureBytes); String sigResultsBase64 = Base64.getEncoder().encodeToString(signatureBytes);
String result = licenseId + "-" + licensePartBase64 + "-" + sigResultsBase64 + "-" + Base64.getEncoder().encodeToString(CRT.getEncoded()); String result = licenseId + "-" + licensePartBase64 + "-" + sigResultsBase64 + "-" + Base64.getEncoder().encodeToString(CRT.getEncoded());
return Collections.singletonMap("license", result);
return Map.of("license", result);
} }

View file

@ -1,12 +1,13 @@
package win.novice.li.model; package win.novice.li.model;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@Data @Data

View file

@ -2,10 +2,11 @@
package win.novice.li.model; package win.novice.li.model;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data @Data
public class Product { public class Product {
@NotBlank @NotBlank

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version> <version>2.7.14</version>
<relativePath/> <relativePath/>
</parent> </parent>
<groupId>win.novice</groupId> <groupId>win.novice</groupId>
@ -20,7 +20,7 @@
<module>jetbra-dist</module> <module>jetbra-dist</module>
</modules> </modules>
<properties> <properties>
<java.version>17</java.version> <java.version>1.8</java.version>
</properties> </properties>
</project> </project>

View file

@ -64,7 +64,7 @@ Sub ProcessVmOptions(ByVal file)
Loop Loop
oFile.Close oFile.Close
sNewContent = sNewContent & "-javaagent:" & sJarFile & "=jetbrains" sNewContent = sNewContent & "-javaagent:" & sJarFile
Set oFile = oFS.OpenTextFile(file, 2, 0) Set oFile = oFS.OpenTextFile(file, 2, 0)
oFile.Write sNewContent oFile.Write sNewContent
oFile.Close oFile.Close

View file

@ -45,7 +45,7 @@ Sub ProcessVmOptions(ByVal file)
Loop Loop
oFile.Close oFile.Close
sNewContent = sNewContent & "-javaagent:" & sJarFile & "=jetbrains" sNewContent = sNewContent & "-javaagent:" & sJarFile
Set oFile = oFS.OpenTextFile(file, 2, 0) Set oFile = oFS.OpenTextFile(file, 2, 0)
oFile.Write sNewContent oFile.Write sNewContent
oFile.Close oFile.Close

View file

@ -56,7 +56,7 @@ for PRD in $JB_PRODUCTS; do
sed -i '/^\-javaagent:.*[\/\\]jetbra\-agent\.jar.*/d' "${VM_FILE_PATH}" sed -i '/^\-javaagent:.*[\/\\]jetbra\-agent\.jar.*/d' "${VM_FILE_PATH}"
fi fi
echo "-javaagent:${JAR_FILE_PATH}=jetbrains" >>"${VM_FILE_PATH}" echo "-javaagent:${JAR_FILE_PATH}" >>"${VM_FILE_PATH}"
ENV_NAME=$(echo $PRD | tr '[a-z]' '[A-Z]')"_VM_OPTIONS" ENV_NAME=$(echo $PRD | tr '[a-z]' '[A-Z]')"_VM_OPTIONS"
echo "export ${ENV_NAME}=\"${VM_FILE_PATH}\"" >>"${MY_VMOPTIONS_SHELL_FILE}" echo "export ${ENV_NAME}=\"${VM_FILE_PATH}\"" >>"${MY_VMOPTIONS_SHELL_FILE}"