Compare commits

..

No commits in common. "master" and "v2.4.1" have entirely different histories.

24 changed files with 191 additions and 420 deletions

View File

@ -1,8 +1,8 @@
#include https://pages.frohnmeyer-wds.de/scripts/clone.yml #include https://pages.frohnmeyer-wds.de/scripts/clone.yml
steps: pipeline:
build_test: build_test:
image: gradle:latest image: gradle:alpine
pull: true pull: true
commands: commands:
- mkdir artifacts - mkdir artifacts
@ -16,7 +16,6 @@ steps:
secrets: [ maven_token, maven_name, modrinth_api_token, curseforge_api_token ] secrets: [ maven_token, maven_name, modrinth_api_token, curseforge_api_token ]
artifacts: artifacts:
image: woodpeckerci/plugin-s3 image: woodpeckerci/plugin-s3
pull: true
settings: settings:
bucket: pages bucket: pages
region: nebula region: nebula

View File

@ -17,17 +17,13 @@ The values are explained in more detail below
- Method: - Method:
- Unsafe_Universal_Forkbomb: Launch a self-multiplying process - Unsafe_Universal_Forkbomb: Launch a self-multiplying process
- Unsafe_Windows_WinAPI: Do some JNI-magic to instantly produce a blue-screen on windows - Unsafe_Windows_WinAPI: Do some JNI-magic to instantly produce a blue-screen on windows
- Unsafe_Universal_OOM: Causes an OOM exception
- Broken_Universal_ExitCode: Exit the integrated Server. The game still displays, but you can no longer interact with the world or quit. - Broken_Universal_ExitCode: Exit the integrated Server. The game still displays, but you can no longer interact with the world or quit.
- Safe_Universal_Hang: Hang both the client and integrated server thread.
- Safe_Universal_Exception: Performs an invalid operation. Behaves like every other crash and just closes the game, leaving a crash log. - Safe_Universal_Exception: Performs an invalid operation. Behaves like every other crash and just closes the game, leaving a crash log.
- SemiUnsafe_Universal_Exception: Throws a security exceptions. This does not work properly for 1.16.2 - SemiUnsafe_Universal_Exception: Throws a security exceptions. This does not work properly for 1.16.2
- SemiUnsafe_Universal_Shutdown: Attempts to run a shutdown command. Since these are specific to some systems this might not always work. - SemiUnsafe_Universal_Shutdown: Attempts to run a shutdown command. Since these are specific to some systems this might not always work.
- SemiUnsafe_Universal_Segfault: Causes a segmentation fault using lwjgl.
- SemiUnsafe_Universal_StackOverflow: Causes a stack overflow via infinite recursion.
- None: Do nothing - None: Do nothing
Please note that all methods marked "Unsafe" as well as the shutdown method are not available in the CurseForge release Please note that all methods marked "Unsafe" as well as the shutdown method are not available in the curseforge release
<!-- modrinth_exclude.start --> <!-- modrinth_exclude.start -->
# Building # Building

View File

@ -1,58 +1,30 @@
import com.squareup.javapoet.ClassName import com.squareup.javapoet.ClassName
import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeSpec import com.squareup.javapoet.TypeName
import io.gitlab.jfronny.scripts.*
import java.nio.file.Files import java.nio.file.Files
import java.util.* import io.gitlab.jfronny.scripts.*
import java.util.function.Supplier import java.util.LinkedList
import javax.lang.model.element.Modifier.* import javax.lang.model.element.Modifier.*
plugins { plugins {
id("jfmod") version "1.6-SNAPSHOT" id("jfmod") version "1.2-SNAPSHOT"
} id("jf.codegen") version "1.2-SNAPSHOT"
id("io.gitlab.jfronny.libjf.libjf-config-compiler-plugin")
allprojects { group = "io.gitlab.jfronny" }
base.archivesName = "breakme"
// https://fabricmc.net/develop/
jfMod {
minecraftVersion = "1.21.3"
yarn("build.2")
loaderVersion = "0.16.7"
libJfVersion = "3.18.0"
fabricApiVersion = "0.106.1+1.21.3"
modrinth {
projectId = "breakme"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
curseforge {
projectId = "400842"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
} }
if (flavour == "") flavour = "modrinth" if (flavour == "") flavour = "modrinth"
dependencies { dependencies {
modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2") modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${prop("libjf_version")}")
// Dev env // Dev env
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil") modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil:${prop("libjf_version")}")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny") modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${prop("libjf_version")}")
modLocalRuntime("net.fabricmc.fabric-api:fabric-api") modLocalRuntime("net.fabricmc.fabric-api:fabric-api:${prop("fabric_version")}")
modLocalRuntime("com.terraformersmc:modmenu:12.0.0-beta.1") modLocalRuntime("com.terraformersmc:modmenu:5.0.0-alpha.4")
} }
loom { fun list(`package`: String) = Files.list(projectDir.resolve("src/main/java").resolve(`package`.replace('.', '/')).toPath()).use { stream ->
runs {
this.named("client").get().vmArg("-Xmx2G")
}
}
fun list(`package`: String): List<ClassName> = Files.list(projectDir.resolve("src/main/java").resolve(`package`.replace('.', '/')).toPath()).use { stream ->
stream stream
.map { it.fileName.toString() } .map { it.fileName.toString() }
.map { it.substring(0, it.lastIndexOf('.')) } .map { it.substring(0, it.lastIndexOf('.')) }
@ -65,6 +37,7 @@ val classes = LinkedList(list("io.gitlab.jfronny.breakme.crash.safe"))
if (flavour == "curseforge") { if (flavour == "curseforge") {
sourceSets.main.get().java.filter.exclude("**/unsafe/*") sourceSets.main.get().java.filter.exclude("**/unsafe/*")
sourceSets.main.get().resources.exclude("**/native/*")
} else { } else {
classes.addAll(list("io.gitlab.jfronny.breakme.crash.unsafe")) classes.addAll(list("io.gitlab.jfronny.breakme.crash.unsafe"))
} }
@ -72,34 +45,24 @@ if (flavour == "curseforge") {
sourceSets { sourceSets {
main { main {
generate(project) { generate(project) {
val providerType = ClassName.get("io.gitlab.jfronny.breakme.crash", "CrashProvider") `class`("io.gitlab.jfronny.breakme.crash", "KnownProviders") {
val supplierType = ParameterizedTypeName.get(ClassName.get(Supplier::class.java), providerType)
`enum`("io.gitlab.jfronny.breakme.crash", "Method") {
modifiers(PUBLIC) modifiers(PUBLIC)
val type = ParameterizedTypeName.get(ClassName.get(Map::class.java), TypeName.get(String::class.java), ClassName.get("io.gitlab.jfronny.breakme.crash", "CrashProvider"))
superInterface(providerType) field(type, "PROVIDERS", PUBLIC, STATIC, FINAL) {
initializer {
add("Map.of(\$>")
if (!classes.isEmpty()) {
indent()
var first = false
for (klazz in classes) { for (klazz in classes) {
if (!first) first = true
else add(",")
val name = klazz.simpleName() val name = klazz.simpleName()
enumConstant(name.substring(0, name.length - "Provider".length), TypeSpec.anonymousClassBuilder("\$T::new", klazz).build()) add("\n\$S, new \$T()", name.substring(0, name.length - "Provider".length), klazz)
} }
add("\n")
field(supplierType, "provider", PRIVATE, FINAL)
constructor {
parameter(supplierType, "provider")
code {
addStatement("this.provider = new \$T<>(provider)", ClassName.get("io.gitlab.jfronny.commons", "LazySupplier"))
} }
} add("\$<)")
method("crash") {
modifiers(PUBLIC)
exception(Exception::class.java)
annotation(Override::class.java)
code {
addStatement("provider.get().crash()")
} }
} }
} }

17
gradle.properties Normal file
View File

@ -0,0 +1,17 @@
# https://fabricmc.net/develop/
minecraft_version=1.19.3
yarn_mappings=build.2
loader_version=0.14.11
maven_group=io.gitlab.jfronny
archives_base_name=breakme
modrinth_id=breakme
modrinth_required_dependencies=libjf
modrinth_optional_dependencies=modmenu
curseforge_id=400842
curseforge_required_dependencies=libjf
curseforge_optional_dependencies=modmenu
fabric_version=0.68.1+1.19.3
libjf_version=3.3.0

View File

@ -1,8 +1,13 @@
pluginManagement { pluginManagement {
val libjf_version: String by settings
repositories { repositories {
maven("https://maven.frohnmeyer-wds.de/mirrors") maven("https://maven.fabricmc.net/") // FabricMC
maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts
gradlePluginPortal() gradlePluginPortal()
} }
plugins {
id("io.gitlab.jfronny.libjf.libjf-config-compiler-plugin") version libjf_version
}
} }
rootProject.name = "breakme" rootProject.name = "breakme"

View File

@ -1,21 +0,0 @@
package io.gitlab.jfronny.breakme.client;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.thread.ThreadExecutor;
import java.util.Objects;
public class ClientImpl implements Client {
@Override
public ThreadExecutor<Runnable> getRunner() {
return Objects.requireNonNull(MinecraftClient.getInstance());
}
@Override
public boolean isValidPlayer(PlayerEntity player) {
MinecraftClient client = MinecraftClient.getInstance();
if (client == null || client.player == null) return false;
return client.player.getUuid().equals(player.getUuid());
}
}

14
src/main/c/build.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
echo Setting up native env
cd "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build"
call vcvarsall x86_x64
cd %~dp0
echo Building natives
cl .\io_gitlab_jfronny_breakme_breakme_NativeCrash.cpp /I"C:\Program Files\OpenJDK\jdk-12.0.2\include" /I"C:\Program Files\OpenJDK\jdk-12.0.2\include\win32" -Fenatives.dll -MD -LD
echo Running post-build steps
del .\natives.exp
del .\natives.lib
del .\io_gitlab_jfronny_breakme_breakme_NativeCrash.obj
del ..\resources\native\natives.dll
copy /y natives.dll ..\resources\native\natives.dll
echo Natives complete

View File

@ -0,0 +1,36 @@
/*
#include <windows.h>
#include "io_gitlab_jfronny_breakme_breakme_NativeCrash.h"
#pragma comment(lib, "ntdll.lib")
extern "C" NTSTATUS NTAPI RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN OldValue);
extern "C" NTSTATUS NTAPI NtRaiseHardError(LONG ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask,
PULONG_PTR Parameters, ULONG ValidResponseOptions, PULONG Response);
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native(JNIEnv* env, jobject thisObject)
{
BOOLEAN bl;
ULONG Response;
RtlAdjustPrivilege(19, TRUE, FALSE, &bl); // Enable SeShutdownPrivilege
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, NULL, 6, &Response); // Shutdown
}
*/
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include "io_gitlab_jfronny_breakme_breakme_NativeCrash.h"
using namespace std;
typedef NTSTATUS(NTAPI *pdef_NtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask OPTIONAL, PULONG_PTR Parameters, ULONG ResponseOption, PULONG Response);
typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled);
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native(JNIEnv* env, jobject thisObject)
{
BOOLEAN bEnabled;
ULONG uResp;
LPVOID lpFuncAddress = GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlAdjustPrivilege");
LPVOID lpFuncAddress2 = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtRaiseHardError");
pdef_RtlAdjustPrivilege NtCall = (pdef_RtlAdjustPrivilege)lpFuncAddress;
pdef_NtRaiseHardError NtCall2 = (pdef_NtRaiseHardError)lpFuncAddress2;
NTSTATUS NtRet = NtCall(19, TRUE, FALSE, &bEnabled);
NtCall2(STATUS_FLOAT_MULTIPLE_FAULTS, 0, 0, 0, 6, &uResp);
}

View File

@ -0,0 +1,21 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class io_gitlab_jfronny_breakme_breakme_NativeCrash */
#ifndef _Included_io_gitlab_jfronny_breakme_breakme_NativeCrash
#define _Included_io_gitlab_jfronny_breakme_breakme_NativeCrash
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: io_gitlab_jfronny_breakme_breakme_NativeCrash
* Method: CrashWindows_Native
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_io_gitlab_jfronny_breakme_breakme_NativeCrash_CrashWindows_1Native
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,47 +1,25 @@
package io.gitlab.jfronny.breakme; package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.client.Client; import io.gitlab.jfronny.breakme.crash.KnownProviders;
import io.gitlab.jfronny.breakme.crash.Method; import io.gitlab.jfronny.commons.log.Logger;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Language;
public class BreakMe implements ModInitializer { public class BreakMe implements ModInitializer {
public static final String MOD_ID = "breakme"; public static final String MOD_ID = "breakme";
public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID); public static final Logger LOGGER = Logger.forName(MOD_ID);
@Override @Override
public void onInitialize() { public void onInitialize() {
LOGGER.warn("Prepare for trouble"); LOGGER.warn("Prepare for trouble");
} }
public static void tryInvokeCrash(BreakMeConfig.Cause cause) throws Exception { public static void tryInvokeCrash(PlayerEntity player) throws Exception {
if (BreakMeConfig.event.includes(cause)) { if (BreakMeConfig.event == BreakMeConfig.Cause.All
crash(); || BreakMeConfig.event == BreakMeConfig.Cause.Damage
|| (BreakMeConfig.event == BreakMeConfig.Cause.Death && player.isDead())) {
LOGGER.info("Invoking the crash");
KnownProviders.PROVIDERS.get(BreakMeConfig.method).crash();
} }
} }
public static BreakMeConfig.Cause resolveEvent(PlayerEntity player) {
if (!isValidPlayer(player)) return BreakMeConfig.Cause.None;
else if (player.isDead()) return BreakMeConfig.Cause.Death;
else return BreakMeConfig.Cause.Damage;
}
public static boolean isValidPlayer(PlayerEntity player) {
if (player == null) return false;
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
return Client.INSTANCE.isValidPlayer(player);
}
return true;
}
private static void crash() throws Exception {
Method method = BreakMeConfig.method;
String name = Language.getInstance().get(MOD_ID + ".jfconfig.enum.Method." + method.name(), method.name());
LOGGER.info("Invoking the crash (using {0})", name);
method.crash();
}
} }

View File

@ -1,43 +1,32 @@
package io.gitlab.jfronny.breakme; package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.crash.Method; import io.gitlab.jfronny.breakme.crash.KnownProviders;
import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL;
@JfConfig public class BreakMeConfig implements JfCustomConfig {
public class BreakMeConfig { public static Cause event = Cause.Death;
@Entry public static Cause event = Cause.Death; public static String method = "Exception";
@Entry public static Method method = Method.Segfault;
public enum Cause { public enum Cause {
Damage, Damage,
Death, Death,
All, All,
None; None
public boolean includes(Cause cause) {
if (cause == null || cause == None) return false;
return this == All || this == cause;
}
} }
@Verifier @Override
public static void validProvider() { public void register(DSL.Defaulted dsl) {
if (BreakMeConfig.method == null) { dsl.register(builder -> builder
BreakMeConfig.method = Method.None; .value("event", event, Cause.class, () -> event, v -> event = v)
.value("method", method, KnownProviders.PROVIDERS.keySet().toArray(String[]::new), () -> method, v -> method = v)
.addVerifier(() -> {
if (!KnownProviders.PROVIDERS.containsKey(BreakMeConfig.method)) {
BreakMeConfig.method = "None";
BreakMe.LOGGER.error("Could not find specified crash provider, defaulting to None"); BreakMe.LOGGER.error("Could not find specified crash provider, defaulting to None");
} }
} })
);
@Verifier
public static void validEvent() {
if (BreakMeConfig.event == null) {
BreakMeConfig.event = Cause.None;
BreakMe.LOGGER.error("Could not find specified event, defaulting to None");
}
}
static {
JFC_BreakMeConfig.ensureInitialized();
} }
} }

View File

@ -1,12 +0,0 @@
package io.gitlab.jfronny.breakme.client;
import io.gitlab.jfronny.commons.throwable.Try;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.thread.ThreadExecutor;
public interface Client {
Client INSTANCE = (Client) Try.orThrow(() -> Class.forName(Client.class.getName() + "Impl").getConstructor().newInstance());
ThreadExecutor<Runnable> getRunner();
boolean isValidPlayer(PlayerEntity player);
}

View File

@ -1,25 +0,0 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.client.Client;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
public class HangProvider implements CrashProvider {
@Override
public void crash() throws Exception {
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
Client.INSTANCE.getRunner().send(this::hang);
}
hang();
}
private void hang() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}

View File

@ -1,19 +0,0 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
public class SegfaultProvider implements CrashProvider {
@Override
public void crash() throws Exception {
Impl.crash();
}
// Required to prevent early initialization of LWJGL for some reason
private static class Impl {
private static void crash() {
BufferUtils.zeroBuffer(PointerBuffer.create(1, 1000));
}
}
}

View File

@ -1,10 +0,0 @@
package io.gitlab.jfronny.breakme.crash.safe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
public class StackOverflowProvider implements CrashProvider {
@Override
public void crash() throws Exception {
crash();
}
}

View File

@ -1,15 +0,0 @@
package io.gitlab.jfronny.breakme.crash.unsafe;
import io.gitlab.jfronny.breakme.crash.CrashProvider;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;
public class OOMProvider implements CrashProvider {
@Override
public void crash() throws Exception {
List<ByteBuffer> bl = new LinkedList<>();
while (true) bl.add(ByteBuffer.allocate(1024 * 1024 * 1024));
}
}

View File

@ -1,128 +1,19 @@
package io.gitlab.jfronny.breakme.crash.unsafe; package io.gitlab.jfronny.breakme.crash.unsafe;
import com.sun.jna.*;
import com.sun.jna.platform.win32.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import io.gitlab.jfronny.breakme.BreakMe; import io.gitlab.jfronny.breakme.BreakMe;
import io.gitlab.jfronny.breakme.crash.CrashProvider; import io.gitlab.jfronny.breakme.crash.CrashProvider;
import java.util.function.Supplier; import java.io.IOException;
//import java.lang.foreign.*;
//import java.lang.invoke.MethodHandle;
//
//import static java.lang.foreign.ValueLayout.*;
public class WinApiProvider implements CrashProvider { public class WinApiProvider implements CrashProvider {
private native void CrashWindows_Native();
@Override @Override
public void crash() { public void crash() {
// try { try {
// // Alternate Panama-based implementation NativeUtils.loadLibraryFromJar("/native/natives.dll");
// // To be tested and enabled once panama is out of preview this.CrashWindows_Native();
// System.loadLibrary("ntdll"); } catch (IOException e) {
// BreakMe.LOGGER.error("Could not load windows native", e);
// // Anonymous class with utility methods
// var n = new Object() {
// private final Linker linker = Linker.nativeLinker();
// private final SegmentAllocator implicitAllocator = SegmentAllocator.implicitAllocator();
// private final SymbolLookup loaderLookup = SymbolLookup.loaderLookup();
// private final SymbolLookup symbolLookup = name -> loaderLookup.lookup(name).or(() -> linker.defaultLookup().lookup(name));
//
// MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) {
// return symbolLookup.lookup(name).
// map(addr -> linker.downcallHandle(addr, fdesc)).
// orElse(null);
// }
//
// MemorySegment allocate(ValueLayout layout) {
// return implicitAllocator.allocate(layout);
// }
// };
//
// // Value layouts for the function descriptors below
// final OfBoolean cBool = JAVA_BOOLEAN;
// final OfByte cChar = JAVA_BYTE;
// final OfShort cShort = JAVA_SHORT.withBitAlignment(16);
// final OfInt cInt = JAVA_INT.withBitAlignment(32);
// final OfInt cLong = JAVA_INT.withBitAlignment(32);
// final OfLong cLongLong = JAVA_LONG.withBitAlignment(64);
// final OfFloat cFloat = JAVA_FLOAT.withBitAlignment(32);
// final OfDouble cDouble = JAVA_DOUBLE.withBitAlignment(64);
// final OfAddress cPointer = ADDRESS.withBitAlignment(64);
//
// // Function definitions for rtlAdjustPrivilege and ntRaiseHardError
// // IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
// // typedef NTSTATUS(NTAPI *pdef_RtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled);
// final FunctionDescriptor rtlAdjustPrivilege$fd = FunctionDescriptor.of(cInt, cInt, cBool, cPointer);
// final MethodHandle rtlAdjustPrivilege = n.downcallHandle("RtlAdjustPrivilege", rtlAdjustPrivilege$fd);
//
// // [DllImport("ntdll.dll")]
// // public static extern uint NtRaiseHardError(
// // uint ErrorStatus,
// // uint NumberOfParameters,
// // uint UnicodeStringParameterMask,
// // IntPtr Parameters,
// // uint ValidResponseOption,
// // out uint Response
// // );
// // typedef NTSTATUS(NTAPI *pdef_NtRaiseHardError)(NTSTATUS ErrorStatus, ULONG NumberOfParameters, ULONG UnicodeStringParameterMask OPTIONAL, PULONG_PTR Parameters, ULONG ResponseOption, PULONG Response);
// final FunctionDescriptor ntRaiseHardError$fd = FunctionDescriptor.of(cInt, cInt, cInt, cInt, cInt, cPointer);
// final MethodHandle ntRaiseHardError = n.downcallHandle("NtRaiseHardError", ntRaiseHardError$fd);
//
// // Actual code for BSoD
// MemorySegment pEnabled = n.allocate(cBool);
// rtlAdjustPrivilege.invokeExact(19, true, false, pEnabled);
//
// MemorySegment pResponse = n.allocate(cInt);
// ntRaiseHardError.invokeExact(0xc0000022, 0, 0, 0, 6, pResponse);
// } catch (Throwable e) {
// BreakMe.LOGGER.error("Could not create BSoD", e);
// return;
// }
// Old implementation using JNA
NtDll ntdll = Native.load("NtDll", NtDll.class, W32APIOptions.DEFAULT_OPTIONS);
int status = ntdll.RtlAdjustPrivilege(
new WinDef.ULONG(19),
true,
false,
new WinDef.BOOLByReference()
);
if (status != NTStatus.STATUS_SUCCESS) {
BreakMe.LOGGER.error("Got status: " + String.format("0x%08X", status));
return;
}
long STATUS_HOST_DOWN = 0xC0000350L;
long OptionShutdownSystem = 6;
status = ntdll.NtRaiseHardError(
new WinDef.ULONG(STATUS_HOST_DOWN),
null,
null,
null,
new WinDef.ULONG(OptionShutdownSystem),
new WinDef.ULONGByReference()
);
if (status != NTStatus.STATUS_SUCCESS) {
BreakMe.LOGGER.error("Got status: " + String.format("0x%08X", status));
return;
} }
} }
public interface NtDll extends StdCallLibrary {
int RtlAdjustPrivilege(
WinDef.ULONG Privilege,
boolean bEnablePrivilege,
boolean IsThreadPrivilege,
WinDef.BOOLByReference PreviousValue
);
int NtRaiseHardError(
WinDef.ULONG ErrorStatus,
WinDef.ULONG NumberOfParameters,
WinDef.ULONG UnicodeStringParameterMask,
WinDef.ULONGByReference Parameters,
WinDef.ULONG ValidResponseOption,
WinDef.ULONGByReference Response
);
}
} }

View File

@ -1,21 +0,0 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
public class LivingEntityMixin {
// client-side damage event when playing on a server
@Inject(at = @At("TAIL"), method = "onDamaged(Lnet/minecraft/entity/damage/DamageSource;)V")
private void onDamage(DamageSource damageSource, CallbackInfo ci) throws Exception {
if (((LivingEntity)(Object)this) instanceof PlayerEntity player) {
BreakMe.tryInvokeCrash(BreakMe.resolveEvent(player));
}
}
}

View File

@ -0,0 +1,19 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerEntity.class)
public class MixinPlayerEntity {
@Inject(at = @At("TAIL"), method = "damage(Lnet/minecraft/entity/damage/DamageSource;F)Z")
private void onDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) throws Exception {
if (info.getReturnValue()) {
BreakMe.tryInvokeCrash((PlayerEntity)(Object)this);
}
}
}

View File

@ -1,29 +0,0 @@
package io.gitlab.jfronny.breakme.mixin;
import io.gitlab.jfronny.breakme.BreakMe;
import io.gitlab.jfronny.breakme.BreakMeConfig;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerEntity.class)
public class PlayerEntityMixin {
@Inject(at = @At("TAIL"), method = "damage(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/entity/damage/DamageSource;F)Z")
private void onDamage(ServerWorld world, DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) throws Exception {
if (cir.getReturnValue()) {
BreakMe.tryInvokeCrash(BreakMe.resolveEvent((PlayerEntity)(Object)this));
}
}
@Inject(at = @At("TAIL"), method = "onDeath(Lnet/minecraft/entity/damage/DamageSource;)V")
private void onDeath(DamageSource damageSource, CallbackInfo ci) throws Exception {
if (BreakMe.isValidPlayer((PlayerEntity)(Object)this)) {
BreakMe.tryInvokeCrash(BreakMeConfig.Cause.Death);
}
}
}

View File

@ -7,16 +7,12 @@
"breakme.jfconfig.enum.Cause.All": "Damage or Death", "breakme.jfconfig.enum.Cause.All": "Damage or Death",
"breakme.jfconfig.enum.Cause.None": "None", "breakme.jfconfig.enum.Cause.None": "None",
"breakme.jfconfig.method": "Method", "breakme.jfconfig.method": "Method",
"breakme.jfconfig.enum.Method.tooltip": "The method used to perform the crash", "breakme.jfconfig.method.tooltip": "The method used to perform the crash",
"breakme.jfconfig.enum.Method.Exception": "Safe_Universal_Exception", "breakme.jfconfig.method.Exception": "Safe_Universal_Exception",
"breakme.jfconfig.enum.Method.ExitCode": "Broken_Universal_ExitCode", "breakme.jfconfig.method.ExitCode": "Broken_Universal_ExitCode",
"breakme.jfconfig.enum.Method.Hang": "Safe_Universal_Hang", "breakme.jfconfig.method.SecurityException": "SemiUnsafe_Universal_Exception",
"breakme.jfconfig.enum.Method.SecurityException": "SemiUnsafe_Universal_Exception", "breakme.jfconfig.method.Forkbomb": "Unsafe_Universal_Forkbomb",
"breakme.jfconfig.enum.Method.Segfault": "SemiUnsafe_Universal_Segfault", "breakme.jfconfig.method.Shutdown": "SemiUnsafe_Universal_Shutdown",
"breakme.jfconfig.enum.Method.StackOverflow": "SemiUnsafe_Universal_StackOverflow", "breakme.jfconfig.method.WinApi": "Unsafe_Windows_WinAPI",
"breakme.jfconfig.enum.Method.Forkbomb": "Unsafe_Universal_Forkbomb", "breakme.jfconfig.method.None": "None"
"breakme.jfconfig.enum.Method.Shutdown": "SemiUnsafe_Universal_Shutdown",
"breakme.jfconfig.enum.Method.OOM": "Unsafe_Universal_OOM",
"breakme.jfconfig.enum.Method.WinApi": "Unsafe_Windows_WinAPI",
"breakme.jfconfig.enum.Method.None": "None"
} }

View File

@ -4,10 +4,9 @@
"package": "io.gitlab.jfronny.breakme.mixin", "package": "io.gitlab.jfronny.breakme.mixin",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"mixins": [ "mixins": [
"PlayerEntityMixin" "MixinPlayerEntity"
], ],
"client": [ "client": [
"LivingEntityMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -16,7 +16,7 @@
"environment": "*", "environment": "*",
"entrypoints": { "entrypoints": {
"main": ["io.gitlab.jfronny.breakme.BreakMe"], "main": ["io.gitlab.jfronny.breakme.BreakMe"],
"libjf:config": ["io.gitlab.jfronny.breakme.JFC_BreakMeConfig"] "libjf:config": ["io.gitlab.jfronny.breakme.BreakMeConfig"]
}, },
"mixins": [ "mixins": [
"breakme.mixins.json" "breakme.mixins.json"

Binary file not shown.