Compare commits

...

16 Commits

Author SHA1 Message Date
c4aed126d8
chore: update to 1.21.3
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-10-23 21:37:19 +02:00
fa5aa9edf9
chore: update to 1.21
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-06-14 14:21:37 +02:00
de00f51b06
fix: build in gradle:latest
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-04-25 22:21:50 +02:00
3fa30b834d
chore: update to 1.20.5
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline failed
2024-04-25 21:51:15 +02:00
0e036599cf
fix: don't respond to events for other players if on client
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-03-31 14:13:42 +02:00
3b5e262bea
fix: hook additional methods for a better chance to catch damage
Some checks are pending
ci/woodpecker/tag/woodpecker Pipeline is pending
ci/woodpecker/push/woodpecker Pipeline was successful
2024-03-31 13:58:58 +02:00
26ef532b30
chore: update to 1.20.4
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-12-07 21:16:27 +01:00
70758f3966
fix: switch default crash provider. Someone had reported issues with the previous default, this one might work better.
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-11-02 17:16:12 +01:00
d924c522a7
chore: update to 1.20.2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-09-22 21:16:51 +02:00
d074812af3
feat: Use JNA for WinApiProvider, remove natives
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-07-28 18:54:31 +02:00
49b97ad38d
Bump to 1.20
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-06-09 17:31:37 +02:00
d9bdd56c6b
Bump to 1.19.4 and add "Hang" crash
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-03-14 22:31:09 +01:00
2a20216d32
Additional crash providers: OOM, Segfault and StackOverflow
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2023-03-11 12:13:47 +01:00
21690627d4
Update natives for new paths
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/manual/woodpecker Pipeline failed
ci/woodpecker/tag/woodpecker Pipeline was successful
2023-01-06 11:43:12 +01:00
1cd569d200
Ensure initialized
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-29 15:59:00 +01:00
2289839966
Use new config compiler and experiment with panama (untested and disabled)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-29 15:51:08 +01:00
24 changed files with 420 additions and 191 deletions

View File

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

View File

@ -17,13 +17,17 @@ The values are explained in more detail below
- Method:
- Unsafe_Universal_Forkbomb: Launch a self-multiplying process
- 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.
- 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.
- 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_Segfault: Causes a segmentation fault using lwjgl.
- SemiUnsafe_Universal_StackOverflow: Causes a stack overflow via infinite recursion.
- 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 -->
# Building

View File

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

View File

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

View File

@ -0,0 +1,21 @@
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());
}
}

View File

@ -1,14 +0,0 @@
@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

@ -1,36 +0,0 @@
/*
#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

@ -1,21 +0,0 @@
/* 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,25 +1,47 @@
package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.crash.KnownProviders;
import io.gitlab.jfronny.commons.log.Logger;
import io.gitlab.jfronny.breakme.client.Client;
import io.gitlab.jfronny.breakme.crash.Method;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Language;
public class BreakMe implements ModInitializer {
public static final String MOD_ID = "breakme";
public static final Logger LOGGER = Logger.forName(MOD_ID);
public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID);
@Override
public void onInitialize() {
LOGGER.warn("Prepare for trouble");
}
public static void tryInvokeCrash(PlayerEntity player) throws Exception {
if (BreakMeConfig.event == BreakMeConfig.Cause.All
|| 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 void tryInvokeCrash(BreakMeConfig.Cause cause) throws Exception {
if (BreakMeConfig.event.includes(cause)) {
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,32 +1,43 @@
package io.gitlab.jfronny.breakme;
import io.gitlab.jfronny.breakme.crash.KnownProviders;
import io.gitlab.jfronny.libjf.config.api.v1.JfCustomConfig;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL;
import io.gitlab.jfronny.breakme.crash.Method;
import io.gitlab.jfronny.libjf.config.api.v2.*;
public class BreakMeConfig implements JfCustomConfig {
public static Cause event = Cause.Death;
public static String method = "Exception";
@JfConfig
public class BreakMeConfig {
@Entry public static Cause event = Cause.Death;
@Entry public static Method method = Method.Segfault;
public enum Cause {
Damage,
Death,
All,
None
None;
public boolean includes(Cause cause) {
if (cause == null || cause == None) return false;
return this == All || this == cause;
}
}
@Override
public void register(DSL.Defaulted dsl) {
dsl.register(builder -> builder
.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");
}
})
);
@Verifier
public static void validProvider() {
if (BreakMeConfig.method == null) {
BreakMeConfig.method = Method.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

@ -0,0 +1,12 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,10 @@
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

@ -0,0 +1,15 @@
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,19 +1,128 @@
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.crash.CrashProvider;
import java.io.IOException;
import java.util.function.Supplier;
//import java.lang.foreign.*;
//import java.lang.invoke.MethodHandle;
//
//import static java.lang.foreign.ValueLayout.*;
public class WinApiProvider implements CrashProvider {
private native void CrashWindows_Native();
@Override
public void crash() {
try {
NativeUtils.loadLibraryFromJar("/native/natives.dll");
this.CrashWindows_Native();
} catch (IOException e) {
BreakMe.LOGGER.error("Could not load windows native", e);
// try {
// // Alternate Panama-based implementation
// // To be tested and enabled once panama is out of preview
// System.loadLibrary("ntdll");
//
// // 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

@ -0,0 +1,21 @@
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

@ -1,19 +0,0 @@
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

@ -0,0 +1,29 @@
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,12 +7,16 @@
"breakme.jfconfig.enum.Cause.All": "Damage or Death",
"breakme.jfconfig.enum.Cause.None": "None",
"breakme.jfconfig.method": "Method",
"breakme.jfconfig.method.tooltip": "The method used to perform the crash",
"breakme.jfconfig.method.Exception": "Safe_Universal_Exception",
"breakme.jfconfig.method.ExitCode": "Broken_Universal_ExitCode",
"breakme.jfconfig.method.SecurityException": "SemiUnsafe_Universal_Exception",
"breakme.jfconfig.method.Forkbomb": "Unsafe_Universal_Forkbomb",
"breakme.jfconfig.method.Shutdown": "SemiUnsafe_Universal_Shutdown",
"breakme.jfconfig.method.WinApi": "Unsafe_Windows_WinAPI",
"breakme.jfconfig.method.None": "None"
"breakme.jfconfig.enum.Method.tooltip": "The method used to perform the crash",
"breakme.jfconfig.enum.Method.Exception": "Safe_Universal_Exception",
"breakme.jfconfig.enum.Method.ExitCode": "Broken_Universal_ExitCode",
"breakme.jfconfig.enum.Method.Hang": "Safe_Universal_Hang",
"breakme.jfconfig.enum.Method.SecurityException": "SemiUnsafe_Universal_Exception",
"breakme.jfconfig.enum.Method.Segfault": "SemiUnsafe_Universal_Segfault",
"breakme.jfconfig.enum.Method.StackOverflow": "SemiUnsafe_Universal_StackOverflow",
"breakme.jfconfig.enum.Method.Forkbomb": "Unsafe_Universal_Forkbomb",
"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,9 +4,10 @@
"package": "io.gitlab.jfronny.breakme.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinPlayerEntity"
"PlayerEntityMixin"
],
"client": [
"LivingEntityMixin"
],
"injectors": {
"defaultRequire": 1

View File

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