feat: add tooltip for switch

This commit is contained in:
ReaJason
2025-12-16 21:55:21 +08:00
parent db85ec4bee
commit d51f7c1283
7 changed files with 158 additions and 27 deletions
@@ -2,6 +2,7 @@ import {
ArrowUpRightIcon, ArrowUpRightIcon,
AxeIcon, AxeIcon,
CommandIcon, CommandIcon,
InfoIcon,
NetworkIcon, NetworkIcon,
ServerIcon, ServerIcon,
ShieldOffIcon, ShieldOffIcon,
@@ -40,6 +41,11 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { Tabs } from "@/components/ui/tabs"; import { Tabs } from "@/components/ui/tabs";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { import {
type MainConfig, type MainConfig,
type ServerConfig, type ServerConfig,
@@ -359,7 +365,7 @@ export default function MainConfigCard({
)} )}
/> />
</div> </div>
<div className="flex gap-4 mt-4 flex-col sm:flex-row xl:grid xl:grid-cols-2 2xl:grid 2xl:grid-cols-3"> <div className="flex gap-4 mt-4 flex-col lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3">
<FormField <FormField
control={form.control} control={form.control}
name="debug" name="debug"
@@ -372,7 +378,17 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<FormLabel htmlFor="debug">{t("common:debug")}</FormLabel> <div className="flex items-center gap-1">
<FormLabel htmlFor="debug">{t("common:debug")}</FormLabel>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:debug.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -388,7 +404,17 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="probe">{t("common:probe")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="probe">{t("common:probe")}</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:probe.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -404,7 +430,19 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="bypass">{t("common:byPassJavaModule")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="bypass">
{t("common:byPassJavaModule")}
</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:byPassJavaModule.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -420,9 +458,19 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="lambdaSuffix"> <div className="flex items-center gap-1">
{t("common:lambdaSuffix")} <Label htmlFor="lambdaSuffix">
</Label> {t("common:lambdaSuffix")}
</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:lambdaSuffix.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -438,7 +486,17 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="shrink">{t("common:shrink")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="shrink">{t("common:shrink")}</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:shrink.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -454,9 +512,19 @@ export default function MainConfigCard({
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="staticInitialize"> <div className="flex items-center gap-1">
{t("common:staticInitialize")} <Label htmlFor="staticInitialize">
</Label> {t("common:staticInitialize")}
</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:staticInitialize.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -1,4 +1,4 @@
import { ServerIcon } from "lucide-react"; import { InfoIcon, ServerIcon } from "lucide-react";
import { useCallback, useEffect, useMemo } from "react"; import { useCallback, useEffect, useMemo } from "react";
import { FormProvider, type UseFormReturn } from "react-hook-form"; import { FormProvider, type UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -22,6 +22,11 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import type { ServerConfig } from "@/types/memshell"; import type { ServerConfig } from "@/types/memshell";
import type { ProbeShellFormSchema } from "@/types/schema"; import type { ProbeShellFormSchema } from "@/types/schema";
import { Separator } from "../ui/separator"; import { Separator } from "../ui/separator";
@@ -288,7 +293,7 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
const SwitchGroup = useMemo( const SwitchGroup = useMemo(
() => ( () => (
<div className="flex gap-4 mt-4 flex-col sm:flex-row xl:grid xl:grid-cols-2 2xl:grid 2xl:grid-cols-3"> <div className="flex gap-4 mt-4 flex-col lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3">
<FormField <FormField
control={form.control} control={form.control}
name="debug" name="debug"
@@ -301,7 +306,17 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<FormLabel htmlFor="debug">{t("debug")}</FormLabel> <div className="flex items-center gap-1">
<FormLabel htmlFor="debug">{t("debug")}</FormLabel>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:debug.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -317,7 +332,17 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="bypass">{t("byPassJavaModule")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="bypass">{t("byPassJavaModule")}</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:byPassJavaModule.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -333,7 +358,17 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="lambdaSuffix">{t("common:lambdaSuffix")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="lambdaSuffix">{t("common:lambdaSuffix")}</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:lambdaSuffix.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -349,7 +384,17 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="shrink">{t("shrink")}</Label> <div className="flex items-center gap-1">
<Label htmlFor="shrink">{t("shrink")}</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:shrink.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
@@ -365,9 +410,19 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
</FormControl> </FormControl>
<Label htmlFor="staticInitialize"> <div className="flex items-center gap-1">
{t("common:staticInitialize")} <Label htmlFor="staticInitialize">
</Label> {t("common:staticInitialize")}
</Label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger>
<TooltipContent>
<p>{t("common:staticInitialize.description")}</p>
</TooltipContent>
</Tooltip>
</div>
</FormItem> </FormItem>
)} )}
/> />
+6
View File
@@ -2,10 +2,12 @@
"about": "About", "about": "About",
"basicInfo": "BasicInfo", "basicInfo": "BasicInfo",
"byPassJavaModule": "BypassModule", "byPassJavaModule": "BypassModule",
"byPassJavaModule.description": "JDK 9+ module system strictly restricts reflective defineClass calls. When enabled, automatically inserts Unsafe-based module bypass code into injector",
"cancel": "Cancel", "cancel": "Cancel",
"copyLabelSuccess": "Copy {{label}} successfully", "copyLabelSuccess": "Copy {{label}} successfully",
"copySuccess": "Copy successfully", "copySuccess": "Copy successfully",
"debug": "Debug Mode", "debug": "Debug Mode",
"debug.description": "When enabled, injector prints injection info to logs and memshell prints exception stack traces for troubleshooting. Recommended for local testing environments",
"download": "Downlaod", "download": "Downlaod",
"encryptor": "Encryptor", "encryptor": "Encryptor",
"feedback": "Feedback", "feedback": "Feedback",
@@ -28,7 +30,9 @@
"server": "Server", "server": "Server",
"serverVersion": "Server Version", "serverVersion": "Server Version",
"shrink": "Shrink", "shrink": "Shrink",
"shrink.description": "Uses ASM SKIP_DEBUG to remove debug info. Recommended to enable",
"staticInitialize": "StaticInitialize", "staticInitialize": "StaticInitialize",
"staticInitialize.description": "Adds static code block to invoke constructor. Suitable for scenarios where vulnerability sink is Class.forName(name, true, classLoader) but cannot trigger newInstance",
"toast.generateError": "Generation failed, {{error}}", "toast.generateError": "Generation failed, {{error}}",
"toast.generateSuccess": "Generation successful", "toast.generateSuccess": "Generation successful",
"urlPattern": "URL Pattern", "urlPattern": "URL Pattern",
@@ -37,7 +41,9 @@
"version.updateAvailableTooltip": "Click to Open Github Release Page ( v{{currentVersion}} -> v{{latestVersion}})", "version.updateAvailableTooltip": "Click to Open Github Release Page ( v{{currentVersion}} -> v{{latestVersion}})",
"shellTool": "Shell Tool", "shellTool": "Shell Tool",
"lambdaSuffix": "LambdaSuffix", "lambdaSuffix": "LambdaSuffix",
"lambdaSuffix.description": "Bypass active scanning device detection. When enabled, adds $Proxy0$$Lambda$1 suffix to injector and memshell class names to evade detection via whitelist mechanism",
"probe": "Probe Mode", "probe": "Probe Mode",
"probe.description": "Used to verify memshell injection success in non-local environments. Embeds injector bytecode into probe shell. Note: Do not enable if echo is unsupported or fails",
"advancedConfig": "Advanced Config", "advancedConfig": "Advanced Config",
"commandTemplate": "Command Template", "commandTemplate": "Command Template",
"commandTemplate.placeholder": "e.g., sh -c \"{command}\" 2>&1", "commandTemplate.placeholder": "e.g., sh -c \"{command}\" 2>&1",
+6
View File
@@ -2,10 +2,12 @@
"about": "关于", "about": "关于",
"basicInfo": "基本信息", "basicInfo": "基本信息",
"byPassJavaModule": "绕过模块限制", "byPassJavaModule": "绕过模块限制",
"byPassJavaModule.description": "JDK 9+ 模块化系统严格限制反射调用 defineClass。开启后会在注入器中自动插入使用 Unsafe 绕过模块限制的代码",
"cancel": "取消", "cancel": "取消",
"copyLabelSuccess": "复制 {{label}} 成功", "copyLabelSuccess": "复制 {{label}} 成功",
"copySuccess": "复制成功", "copySuccess": "复制成功",
"debug": "调试模式", "debug": "调试模式",
"debug.description": "开启后注入器会打印注入信息到业务日志,内存马会打印异常堆栈信息,便于排查问题。本地测试环境推荐开启",
"download": "下载", "download": "下载",
"encryptor": "加密器", "encryptor": "加密器",
"feedback": "反馈", "feedback": "反馈",
@@ -28,7 +30,9 @@
"server": "服务类型", "server": "服务类型",
"serverVersion": "服务版本", "serverVersion": "服务版本",
"shrink": "缩小字节码", "shrink": "缩小字节码",
"shrink.description": "使用 ASM SKIP_DEBUG 去除调试信息,建议开启",
"staticInitialize": "静态初始化", "staticInitialize": "静态初始化",
"staticInitialize.description": "在类中添加静态代码块调用构造方法。适用于无法触发 newInstance 漏洞 sink 点为 Class.forName(name, true, classLoader) 的场景",
"toast.generateError": "生成失败,{{error}}", "toast.generateError": "生成失败,{{error}}",
"toast.generateSuccess": "生成成功", "toast.generateSuccess": "生成成功",
"urlPattern": "请求路径", "urlPattern": "请求路径",
@@ -37,7 +41,9 @@
"version.updateAvailableTooltip": "点击前往 GitHub Release ( v{{currentVersion}} -> v{{latestVersion}})", "version.updateAvailableTooltip": "点击前往 GitHub Release ( v{{currentVersion}} -> v{{latestVersion}})",
"shellTool": "内存马工具", "shellTool": "内存马工具",
"lambdaSuffix": "Lambda 类名后缀", "lambdaSuffix": "Lambda 类名后缀",
"lambdaSuffix.description": "绕过主动扫描设备检测。开启后会在注入器和内存马类名后添加 $Proxy0$$Lambda$1 后缀,利用白名单机制躲避检测",
"probe": "回显模式", "probe": "回显模式",
"probe.description": "用于非本地环境下判断内存马注入是否成功。开启后会将注入器字节码放入回显马。注意:不支持回显或回显失败的场景请勿开启",
"advancedConfig": "高级配置", "advancedConfig": "高级配置",
"commandTemplate": "命令模板", "commandTemplate": "命令模板",
"commandTemplate.placeholder": "例如:sh -c \"{command}\" 2>&1", "commandTemplate.placeholder": "例如:sh -c \"{command}\" 2>&1",
+1 -1
View File
@@ -124,7 +124,7 @@ export default function MemShellPage() {
return ( return (
<HomeLayout {...baseOptions()} links={siteConfig.navLinks}> <HomeLayout {...baseOptions()} links={siteConfig.navLinks}>
<div className="container mx-auto max-w-7xl p-4"> <div className="container mx-auto max-w-8xl p-6">
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(onSubmit)}
+1 -1
View File
@@ -104,7 +104,7 @@ export default function ProbeShellGenerator() {
}; };
return ( return (
<HomeLayout {...baseOptions()} links={siteConfig.navLinks}> <HomeLayout {...baseOptions()} links={siteConfig.navLinks}>
<div className="container mx-auto max-w-7xl p-4"> <div className="container mx-auto max-w-8xl p-6">
<Form {...form}> <Form {...form}>
<form <form
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(onSubmit)}
+1 -5
View File
@@ -1,8 +1,4 @@
{ {
"title": "Java Servlet 规范内存马", "title": "Java Servlet 规范内存马",
"pages": [ "pages": ["servlet", "filter", "listener"]
"servlet",
"filter",
"listener"
]
} }