├── .gitignore ├── .idea ├── .gitignore ├── discord.xml ├── encodings.xml ├── misc.xml └── uiDesigner.xml ├── README.md ├── cpp src ├── Natives │ ├── DLLInjector.cpp │ └── MemoryEditor.cpp └── Process Injector │ ├── Injector.cpp │ └── Process Injector.cpp ├── pom.xml └── src └── main ├── java └── uk │ └── whitedev │ ├── InjectClassLoader.java │ ├── InjectableMain.java │ ├── JavaSourceFromString.java │ ├── classes │ └── ClassCheckerGui.java │ ├── injector │ ├── DLLInjector.java │ └── InjectorGui.java │ ├── memory │ ├── MemoryEditor.java │ ├── MemoryEditorGUI.java │ ├── MemoryLocation.java │ └── WindowInfo.java │ ├── monitor │ └── ProcessProfilerGui.java │ └── utils │ ├── ClassUtil.java │ ├── ColorUtils.java │ ├── FieldUtil.java │ ├── MonitorUtil.java │ ├── NativeLoader.java │ └── ProcessUtil.java └── resources ├── assets └── cfr-0.152.jar └── natives ├── DLLInjector.dll └── MemoryEditor.dll /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Process Inspector [JPI] 🖥️ 2 | 3 | This is a sophisticated tool designed for dynamically browsing, analyzing, and modifying a running Java process ⚡ 4 | 5 | ## Basic information 6 | 7 | It allows users to interact with the Java application's live state, inspect its code, and make changes in real-time, offering a powerful solution for everyone, who need deep insights and control over Java applications during execution. 8 | 9 | The program has a basic GUI that is easy to use and does not take up much memory. 10 | 11 | ## Functions 12 | 13 | #### 🔧 Dynamic Executor for Java Code: 14 | This feature allows you to force the program, to which JPI is attached, to execute specific lines of code written in the built-in code editor provided with JPI. It offers full access to use any classes and methods, enabling real-time manipulation and testing of the application’s behavior. 15 | 16 | #### ✏️ Memory Editor: 17 | The Memory Editor is a powerful tool that enables you to search for specific values within the process's memory and dynamically modify them while the process is running. This function provides direct access to the internal state of the application, allowing precise and immediate adjustments. 18 | 19 | #### 🔌 DLL Injector: 20 | A straightforward tool designed to inject DLL files into the process. This function simplifies the process of adding external libraries, enabling extended functionality or modifications to the running application. 21 | 22 | #### 🔍 Loaded Class Checker: 23 | This feature allows you to inspect all the classes loaded by the process, decompile them, and view their source code. Additionally, it provides the capability to dump all loaded classes to a specified folder. 24 | 25 | #### 💻 Process Profiler: 26 | Real-time Java process monitoring and profiling solution. Displays performance metrics, resource utilization, process details and enables field inspection, providing a comprehensive overview of the running process. 27 | 28 | ## How to inject JPI 29 | - To attach JPI to a java process, run Process Injector.exe 30 | - Find the pid of the process you are interested in (java/javaw) 31 | - Enter the pid of the process you want to attach JPI to (confirm with enter) 32 | - Enter the full path to the dll file "injector.dll" (confirm with enter) `Example: C:\\Users\\whitedev\\Files\\injector.dll` 33 | 34 | ## Disclaimer 35 | Remember that modifying memory, dynamically injecting new classes and various modifications in the running java process are quite dangerous and can cause various errors with your application, use this with caution. 36 | 37 | ## Project Suppot 38 | If you need help, join to our community: 39 | - Discord Server: https://discord.gg/KhExwvqZb5 40 | - WebSite: https://devsmarket.eu/ 41 | 42 | ## Authors 43 | 44 | - [@0WhiteDev](https://github.com/0WhiteDev) 45 | - [@DevsMarket](https://github.com/DEVS-MARKET) 46 | -------------------------------------------------------------------------------- /cpp src/Natives/DLLInjector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | extern "C" { 10 | JNIEXPORT jboolean JNICALL Java_uk_whitedev_injector_DLLInjector_injectDLL(JNIEnv *env, jclass clazz, jlong pid, jstring dllPath); 11 | } 12 | 13 | bool InjectDLL(DWORD processID, const std::string& dllPath) { 14 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); 15 | if (!hProcess) { 16 | std::cerr << "OpenProcess failed" << std::endl; 17 | return false; 18 | } 19 | 20 | LPVOID pRemoteMemory = VirtualAllocEx(hProcess, NULL, dllPath.size() + 1, MEM_COMMIT, PAGE_READWRITE); 21 | if (!pRemoteMemory) { 22 | std::cerr << "VirtualAllocEx failed" << std::endl; 23 | CloseHandle(hProcess); 24 | return false; 25 | } 26 | 27 | if (!WriteProcessMemory(hProcess, pRemoteMemory, dllPath.c_str(), dllPath.size() + 1, NULL)) { 28 | std::cerr << "WriteProcessMemory failed" << std::endl; 29 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 30 | CloseHandle(hProcess); 31 | return false; 32 | } 33 | 34 | HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); 35 | if (!hKernel32) { 36 | std::cerr << "GetModuleHandleA failed" << std::endl; 37 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 38 | CloseHandle(hProcess); 39 | return false; 40 | } 41 | 42 | LPVOID pLoadLibrary = (LPVOID)GetProcAddress(hKernel32, "LoadLibraryA"); 43 | if (!pLoadLibrary) { 44 | std::cerr << "GetProcAddress failed" << std::endl; 45 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 46 | CloseHandle(hProcess); 47 | return false; 48 | } 49 | 50 | HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pRemoteMemory, 0, NULL); 51 | if (!hThread) { 52 | std::cerr << "CreateRemoteThread failed" << std::endl; 53 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 54 | CloseHandle(hProcess); 55 | return false; 56 | } 57 | 58 | WaitForSingleObject(hThread, INFINITE); 59 | 60 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 61 | CloseHandle(hThread); 62 | CloseHandle(hProcess); 63 | 64 | return true; 65 | } 66 | 67 | JNIEXPORT jboolean JNICALL Java_uk_whitedev_injector_DLLInjector_injectDLL(JNIEnv *env, jclass clazz, jlong pid, jstring dllPath) { 68 | const char *pathChars = env->GetStringUTFChars(dllPath, NULL); 69 | if (!pathChars) { 70 | std::cerr << "Failed to convert jstring to C string" << std::endl; 71 | return JNI_FALSE; 72 | } 73 | 74 | std::string dllPathStr(pathChars); 75 | env->ReleaseStringUTFChars(dllPath, pathChars); 76 | 77 | bool result = InjectDLL(static_cast(pid), dllPathStr); 78 | 79 | return result ? JNI_TRUE : JNI_FALSE; 80 | } 81 | -------------------------------------------------------------------------------- /cpp src/Natives/MemoryEditor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" { 11 | JNIEXPORT jobject JNICALL Java_uk_whitedev_memory_MemoryEditor_listProcesses(JNIEnv* env, jobject obj); 12 | JNIEXPORT jobjectArray JNICALL Java_uk_whitedev_memory_MemoryEditor_getOpenWindows(JNIEnv *env, jclass clazz); 13 | JNIEXPORT jobjectArray JNICALL Java_uk_whitedev_memory_MemoryEditor_scanMemory(JNIEnv *env, jclass clazz, jlong pid, jstring searchStr, jint dataType); 14 | JNIEXPORT void JNICALL Java_uk_whitedev_memory_MemoryEditor_modifyMemory(JNIEnv *env, jclass clazz, jlong pid, jobjectArray locationsArray, jstring newValueStr, jint type); 15 | } 16 | 17 | JNIEXPORT jobject JNICALL Java_uk_whitedev_memory_MemoryEditor_listProcesses(JNIEnv* env, jobject obj) { 18 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 19 | if (snapshot == INVALID_HANDLE_VALUE) { 20 | std::cerr << "Failed to take process snapshot." << std::endl; 21 | return nullptr; 22 | } 23 | 24 | PROCESSENTRY32 processEntry; 25 | processEntry.dwSize = sizeof(PROCESSENTRY32); 26 | 27 | std::map processMap; 28 | 29 | if (Process32First(snapshot, &processEntry)) { 30 | do { 31 | processMap[processEntry.th32ProcessID] = processEntry.szExeFile; 32 | } while (Process32Next(snapshot, &processEntry)); 33 | } else { 34 | std::cerr << "Failed to retrieve first process entry." << std::endl; 35 | } 36 | 37 | CloseHandle(snapshot); 38 | 39 | jclass hashMapClass = env->FindClass("java/util/HashMap"); 40 | jmethodID hashMapInit = env->GetMethodID(hashMapClass, "", "()V"); 41 | jmethodID hashMapPut = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 42 | 43 | jobject hashMapObject = env->NewObject(hashMapClass, hashMapInit); 44 | 45 | jclass integerClass = env->FindClass("java/lang/Integer"); 46 | jmethodID integerInit = env->GetMethodID(integerClass, "", "(I)V"); 47 | 48 | jclass stringClass = env->FindClass("java/lang/String"); 49 | jmethodID stringInit = env->GetMethodID(stringClass, "", "(Ljava/lang/String;)V"); 50 | 51 | for (const auto& entry : processMap) { 52 | jobject pidObject = env->NewObject(integerClass, integerInit, entry.first); 53 | jstring nameString = env->NewStringUTF(entry.second.c_str()); 54 | env->CallObjectMethod(hashMapObject, hashMapPut, pidObject, nameString); 55 | } 56 | 57 | return hashMapObject; 58 | } 59 | 60 | struct WindowInfo { 61 | std::wstring title; 62 | DWORD pid; 63 | }; 64 | 65 | std::vector windowList; 66 | 67 | BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { 68 | if (!IsWindowVisible(hwnd)) { 69 | return TRUE; 70 | } 71 | 72 | DWORD pid; 73 | GetWindowThreadProcessId(hwnd, &pid); 74 | 75 | wchar_t windowTitle[256]; 76 | GetWindowTextW(hwnd, windowTitle, sizeof(windowTitle) / sizeof(wchar_t)); 77 | 78 | if (wcslen(windowTitle) > 0) { 79 | windowList.push_back({windowTitle, pid}); 80 | } 81 | 82 | return TRUE; 83 | } 84 | 85 | JNIEXPORT jobjectArray JNICALL Java_uk_whitedev_memory_MemoryEditor_getOpenWindows(JNIEnv *env, jclass clazz) { 86 | windowList.clear(); 87 | EnumWindows(EnumWindowsProc, 0); 88 | 89 | jclass windowInfoClass = env->FindClass("uk/whitedev/memory/WindowInfo"); 90 | if (windowInfoClass == nullptr) return nullptr; 91 | 92 | jmethodID constructor = env->GetMethodID(windowInfoClass, "", "(Ljava/lang/String;J)V"); 93 | if (constructor == nullptr) return nullptr; 94 | 95 | jobjectArray resultArray = env->NewObjectArray(windowList.size(), windowInfoClass, nullptr); 96 | if (resultArray == nullptr) return nullptr; 97 | 98 | for (size_t i = 0; i < windowList.size(); ++i) { 99 | const WindowInfo &info = windowList[i]; 100 | 101 | jstring titleString = env->NewString(reinterpret_cast(info.title.c_str()), info.title.length()); 102 | jobject windowInfoObj = env->NewObject(windowInfoClass, constructor, titleString, info.pid); 103 | env->SetObjectArrayElement(resultArray, i, windowInfoObj); 104 | env->DeleteLocalRef(windowInfoObj); 105 | env->DeleteLocalRef(titleString); 106 | } 107 | 108 | return resultArray; 109 | } 110 | 111 | struct MemoryLocation { 112 | uintptr_t address; 113 | std::string value; 114 | }; 115 | 116 | std::vector ScanMemory(HANDLE processHandle, const std::string& searchStr, int dataType) { 117 | SYSTEM_INFO sysInfo; 118 | GetSystemInfo(&sysInfo); 119 | 120 | MEMORY_BASIC_INFORMATION mbi; 121 | uintptr_t address = (uintptr_t)sysInfo.lpMinimumApplicationAddress; 122 | 123 | std::vector foundLocations; 124 | 125 | while (address < (uintptr_t)sysInfo.lpMaximumApplicationAddress) { 126 | if (VirtualQueryEx(processHandle, (LPCVOID)address, &mbi, sizeof(mbi)) == sizeof(mbi)) { 127 | if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_READWRITE)) { 128 | std::vector buffer(mbi.RegionSize); 129 | SIZE_T bytesRead; 130 | 131 | if (ReadProcessMemory(processHandle, mbi.BaseAddress, buffer.data(), mbi.RegionSize, &bytesRead)) { 132 | switch (dataType) { 133 | case 0: { 134 | size_t searchLen = searchStr.length(); 135 | for (size_t i = 0; i < bytesRead - searchLen + 1; ++i) { 136 | if (std::memcmp(buffer.data() + i, searchStr.c_str(), searchLen) == 0) { 137 | MemoryLocation loc; 138 | loc.address = (uintptr_t)mbi.BaseAddress + i; 139 | loc.value = searchStr; 140 | foundLocations.push_back(loc); 141 | } 142 | } 143 | break; 144 | } 145 | 146 | case 1: { 147 | int searchValue = std::stoi(searchStr); 148 | for (size_t i = 0; i < bytesRead - sizeof(int) + 1; ++i) { 149 | int valueAtAddr; 150 | std::memcpy(&valueAtAddr, buffer.data() + i, sizeof(int)); 151 | if (valueAtAddr == searchValue) { 152 | MemoryLocation loc; 153 | loc.address = (uintptr_t)mbi.BaseAddress + i; 154 | loc.value = std::to_string(searchValue); 155 | foundLocations.push_back(loc); 156 | } 157 | } 158 | break; 159 | } 160 | 161 | case 2: { 162 | double searchValue = std::stod(searchStr); 163 | for (size_t i = 0; i < bytesRead - sizeof(double) + 1; ++i) { 164 | double valueAtAddr; 165 | std::memcpy(&valueAtAddr, buffer.data() + i, sizeof(double)); 166 | if (valueAtAddr == searchValue) { 167 | MemoryLocation loc; 168 | loc.address = (uintptr_t)mbi.BaseAddress + i; 169 | loc.value = std::to_string(searchValue); 170 | foundLocations.push_back(loc); 171 | } 172 | } 173 | break; 174 | } 175 | 176 | case 3: { 177 | long searchValue = std::stol(searchStr); 178 | for (size_t i = 0; i < bytesRead - sizeof(long) + 1; ++i) { 179 | long valueAtAddr; 180 | std::memcpy(&valueAtAddr, buffer.data() + i, sizeof(long)); 181 | if (valueAtAddr == searchValue) { 182 | MemoryLocation loc; 183 | loc.address = (uintptr_t)mbi.BaseAddress + i; 184 | loc.value = std::to_string(searchValue); 185 | foundLocations.push_back(loc); 186 | } 187 | } 188 | break; 189 | } 190 | 191 | case 4: { 192 | float searchValue = std::stof(searchStr); 193 | for (size_t i = 0; i < bytesRead - sizeof(float) + 1; ++i) { 194 | float valueAtAddr; 195 | std::memcpy(&valueAtAddr, buffer.data() + i, sizeof(float)); 196 | if (valueAtAddr == searchValue) { 197 | MemoryLocation loc; 198 | loc.address = (uintptr_t)mbi.BaseAddress + i; 199 | loc.value = std::to_string(searchValue); 200 | foundLocations.push_back(loc); 201 | } 202 | } 203 | break; 204 | } 205 | 206 | case 5: { 207 | short searchValue = std::stoi(searchStr); 208 | for (size_t i = 0; i < bytesRead - sizeof(short) + 1; ++i) { 209 | short valueAtAddr; 210 | std::memcpy(&valueAtAddr, buffer.data() + i, sizeof(short)); 211 | if (valueAtAddr == searchValue) { 212 | MemoryLocation loc; 213 | loc.address = (uintptr_t)mbi.BaseAddress + i; 214 | loc.value = std::to_string(searchValue); 215 | foundLocations.push_back(loc); 216 | } 217 | } 218 | break; 219 | } 220 | } 221 | } 222 | } 223 | address += mbi.RegionSize; 224 | } else { 225 | break; 226 | } 227 | } 228 | 229 | return foundLocations; 230 | } 231 | 232 | JNIEXPORT jobjectArray JNICALL Java_uk_whitedev_memory_MemoryEditor_scanMemory(JNIEnv *env, jclass clazz, jlong pid, jstring searchStr, jint dataType) { 233 | HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 234 | if (processHandle == nullptr) return nullptr; 235 | const char *nativeSearchStr = env->GetStringUTFChars(searchStr, 0); 236 | std::vector locations = ScanMemory(processHandle, nativeSearchStr, dataType); 237 | env->ReleaseStringUTFChars(searchStr, nativeSearchStr); 238 | 239 | jclass memoryLocationClass = env->FindClass("uk/whitedev/memory/MemoryLocation"); 240 | if (memoryLocationClass == nullptr) return nullptr; 241 | 242 | jobjectArray resultArray = env->NewObjectArray(locations.size(), memoryLocationClass, nullptr); 243 | if (resultArray == nullptr) return nullptr; 244 | 245 | jmethodID constructor = env->GetMethodID(memoryLocationClass, "", "(JLjava/lang/String;)V"); 246 | if (constructor == nullptr) return nullptr; 247 | 248 | for (size_t i = 0; i < locations.size(); ++i) { 249 | const MemoryLocation &loc = locations[i]; 250 | 251 | jstring valueString = env->NewStringUTF(loc.value.c_str()); 252 | jobject memoryLocationObj = env->NewObject(memoryLocationClass, constructor, loc.address, valueString); 253 | env->DeleteLocalRef(valueString); 254 | 255 | env->SetObjectArrayElement(resultArray, i, memoryLocationObj); 256 | env->DeleteLocalRef(memoryLocationObj); 257 | } 258 | 259 | return resultArray; 260 | } 261 | 262 | void ModifyMemory(HANDLE processHandle, const std::vector& locations, const std::string& newValue, int dataType) { 263 | size_t newLen; 264 | std::vector newBuffer; 265 | 266 | for (const auto& loc : locations) { 267 | switch (dataType) { 268 | case 0: 269 | newLen = newValue.length(); 270 | newBuffer.resize(newLen); 271 | std::memcpy(newBuffer.data(), newValue.c_str(), newLen); 272 | break; 273 | 274 | case 1: { 275 | int newIntValue = std::stoi(newValue); 276 | newLen = sizeof(int); 277 | newBuffer.resize(newLen); 278 | std::memcpy(newBuffer.data(), &newIntValue, newLen); 279 | break; 280 | } 281 | 282 | case 2: { 283 | double newDoubleValue = std::stod(newValue); 284 | newLen = sizeof(double); 285 | newBuffer.resize(newLen); 286 | std::memcpy(newBuffer.data(), &newDoubleValue, newLen); 287 | break; 288 | } 289 | 290 | case 3: { 291 | long newLongValue = std::stol(newValue); 292 | newLen = sizeof(long); 293 | newBuffer.resize(newLen); 294 | std::memcpy(newBuffer.data(), &newLongValue, newLen); 295 | break; 296 | } 297 | 298 | case 4: { 299 | float newFloatValue = std::stof(newValue); 300 | newLen = sizeof(float); 301 | newBuffer.resize(newLen); 302 | std::memcpy(newBuffer.data(), &newFloatValue, newLen); 303 | break; 304 | } 305 | 306 | case 5: { 307 | short newShortValue = std::stoi(newValue); 308 | newLen = sizeof(short); 309 | newBuffer.resize(newLen); 310 | std::memcpy(newBuffer.data(), &newShortValue, newLen); 311 | break; 312 | } 313 | } 314 | 315 | SIZE_T bytesWritten; 316 | if (!WriteProcessMemory(processHandle, (LPVOID)loc.address, newBuffer.data(), newLen, &bytesWritten)) { 317 | std::cerr << "Failed to write memory at address: " << std::hex << loc.address << std::endl; 318 | } else { 319 | std::cout << "Modified memory at: " << std::hex << loc.address << " to value: " << newValue << std::endl; 320 | } 321 | 322 | if (newLen < loc.value.length()) { 323 | size_t bytesToClear = loc.value.length() - newLen; 324 | std::vector clearBuffer(bytesToClear, '\0'); 325 | if (!WriteProcessMemory(processHandle, (LPVOID)(loc.address + newLen), clearBuffer.data(), bytesToClear, &bytesWritten)) { 326 | std::cerr << "Failed to clear remaining bytes at address: " << std::hex << (loc.address + newLen) << std::endl; 327 | } 328 | } 329 | } 330 | } 331 | 332 | JNIEXPORT void JNICALL Java_uk_whitedev_memory_MemoryEditor_modifyMemory(JNIEnv *env, jclass clazz, jlong pid, jobjectArray locationsArray, jstring newValueStr, jint type) { 333 | HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 334 | if (processHandle == nullptr) return; 335 | 336 | jclass memoryLocationClass = env->FindClass("uk/whitedev/memory/MemoryLocation"); 337 | if (memoryLocationClass == nullptr) return; 338 | 339 | jmethodID getAddressMethod = env->GetMethodID(memoryLocationClass, "getAddress", "()J"); 340 | jmethodID getValueMethod = env->GetMethodID(memoryLocationClass, "getValue", "()Ljava/lang/String;"); 341 | if (getAddressMethod == nullptr || getValueMethod == nullptr) return; 342 | 343 | jsize length = env->GetArrayLength(locationsArray); 344 | std::vector locations; 345 | for (jsize i = 0; i < length; ++i) { 346 | jobject locationObj = env->GetObjectArrayElement(locationsArray, i); 347 | if (locationObj == nullptr) continue; 348 | 349 | jlong address = env->CallLongMethod(locationObj, getAddressMethod); 350 | jstring valueStr = (jstring)env->CallObjectMethod(locationObj, getValueMethod); 351 | const char *valueChars = env->GetStringUTFChars(valueStr, nullptr); 352 | std::string value(valueChars); 353 | env->ReleaseStringUTFChars(valueStr, valueChars); 354 | 355 | locations.push_back({ static_cast(address), value }); 356 | env->DeleteLocalRef(locationObj); 357 | } 358 | 359 | const char *newValueChars = env->GetStringUTFChars(newValueStr, nullptr); 360 | std::string newValue(newValueChars); 361 | env->ReleaseStringUTFChars(newValueStr, newValueChars); 362 | 363 | ModifyMemory(processHandle, locations, newValue, type); 364 | 365 | CloseHandle(processHandle); 366 | } 367 | -------------------------------------------------------------------------------- /cpp src/Process Injector/Injector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void LoadJarToJVM(JNIEnv* env, const char* jarPath, const char* mainClassName) { 6 | jclass classLoaderClass = env->FindClass("java/net/URLClassLoader"); 7 | jmethodID constructor = env->GetMethodID(classLoaderClass, "", "([Ljava/net/URL;)V"); 8 | 9 | jclass fileClass = env->FindClass("java/io/File"); 10 | jmethodID fileConstructor = env->GetMethodID(fileClass, "", "(Ljava/lang/String;)V"); 11 | 12 | jstring jJarPath = env->NewStringUTF(jarPath); 13 | jobject fileObject = env->NewObject(fileClass, fileConstructor, jJarPath); 14 | 15 | jmethodID toURI = env->GetMethodID(fileClass, "toURI", "()Ljava/net/URI;"); 16 | jobject uriObject = env->CallObjectMethod(fileObject, toURI); 17 | 18 | jclass uriClass = env->FindClass("java/net/URI"); 19 | jmethodID toURL = env->GetMethodID(uriClass, "toURL", "()Ljava/net/URL;"); 20 | jobject urlObject = env->CallObjectMethod(uriObject, toURL); 21 | 22 | jobjectArray urlArray = env->NewObjectArray(1, env->FindClass("java/net/URL"), urlObject); 23 | jobject urlClassLoader = env->NewObject(classLoaderClass, constructor, urlArray); 24 | 25 | jmethodID loadClass = env->GetMethodID(classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); 26 | jstring jMainClassName = env->NewStringUTF(mainClassName); 27 | jclass mainClass = (jclass)env->CallObjectMethod(urlClassLoader, loadClass, jMainClassName); 28 | 29 | if (mainClass == nullptr) { 30 | std::cerr << "Could not find main class: " << mainClassName << std::endl; 31 | return; 32 | } 33 | 34 | jmethodID mainMethod = env->GetStaticMethodID(mainClass, "main", "([Ljava/lang/String;)V"); 35 | if (mainMethod == nullptr) { 36 | std::cerr << "Could not find main method in class: " << mainClassName << std::endl; 37 | return; 38 | } 39 | 40 | jobjectArray mainArgs = env->NewObjectArray(0, env->FindClass("java/lang/String"), nullptr); 41 | env->CallStaticVoidMethod(mainClass, mainMethod, mainArgs); 42 | } 43 | 44 | JNIEnv* GetJNIEnv() { 45 | JavaVM* jvm; 46 | JNIEnv* env; 47 | JavaVMInitArgs vmArgs; 48 | JavaVMOption options[1]; 49 | 50 | vmArgs.version = JNI_VERSION_1_8; 51 | vmArgs.nOptions = 1; 52 | vmArgs.options = options; 53 | vmArgs.ignoreUnrecognized = false; 54 | 55 | jint result = JNI_GetCreatedJavaVMs(&jvm, 1, nullptr); 56 | if (result != JNI_OK || jvm == nullptr) { 57 | std::cerr << "Failed to get created JVMs. Error code: " << result << std::endl; 58 | return nullptr; 59 | } 60 | 61 | result = jvm->AttachCurrentThread((void**)&env, nullptr); 62 | if (result != JNI_OK) { 63 | std::cerr << "Failed to attach to JVM. Error code: " << result << std::endl; 64 | return nullptr; 65 | } 66 | 67 | return env; 68 | } 69 | 70 | extern "C" __declspec(dllexport) void InjectJar(const char* jarPath, const char* mainClassName) { 71 | JNIEnv* env = GetJNIEnv(); 72 | if (env == nullptr) { 73 | std::cerr << "Failed to obtain JNI environment." << std::endl; 74 | return; 75 | } 76 | 77 | LoadJarToJVM(env, jarPath, mainClassName); 78 | } 79 | 80 | 81 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { 82 | switch (ul_reason_for_call) { 83 | case DLL_PROCESS_ATTACH: 84 | LoadJarToJVM(GetJNIEnv(), "JPI.jar", "uk.whitedev.InjectableMain"); 85 | break; 86 | case DLL_THREAD_ATTACH: 87 | case DLL_THREAD_DETACH: 88 | case DLL_PROCESS_DETACH: 89 | break; 90 | } 91 | return TRUE; 92 | } 93 | -------------------------------------------------------------------------------- /cpp src/Process Injector/Process Injector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool InjectDLL(DWORD processID, const std::string& dllPath) { 8 | HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID); 9 | if (!hProcess) { 10 | std::cerr << "OpenProcess failed" << std::endl; 11 | return false; 12 | } 13 | 14 | LPVOID pRemoteMemory = VirtualAllocEx(hProcess, NULL, dllPath.size() + 1, MEM_COMMIT, PAGE_READWRITE); 15 | if (!pRemoteMemory) { 16 | std::cerr << "VirtualAllocEx failed" << std::endl; 17 | CloseHandle(hProcess); 18 | return false; 19 | } 20 | 21 | if (!WriteProcessMemory(hProcess, pRemoteMemory, dllPath.c_str(), dllPath.size() + 1, NULL)) { 22 | std::cerr << "WriteProcessMemory failed" << std::endl; 23 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 24 | CloseHandle(hProcess); 25 | return false; 26 | } 27 | 28 | HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); 29 | LPVOID pLoadLibrary = (LPVOID)GetProcAddress(hKernel32, "LoadLibraryA"); 30 | 31 | if (!pLoadLibrary) { 32 | std::cerr << "GetProcAddress failed" << std::endl; 33 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 34 | CloseHandle(hProcess); 35 | return false; 36 | } 37 | 38 | HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pRemoteMemory, 0, NULL); 39 | if (!hThread) { 40 | std::cerr << "CreateRemoteThread failed" << std::endl; 41 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 42 | CloseHandle(hProcess); 43 | return false; 44 | } 45 | 46 | WaitForSingleObject(hThread, INFINITE); 47 | 48 | VirtualFreeEx(hProcess, pRemoteMemory, 0, MEM_RELEASE); 49 | CloseHandle(hThread); 50 | CloseHandle(hProcess); 51 | 52 | return true; 53 | } 54 | 55 | std::vector ListJavaProcesses() { 56 | std::vector javaProcessIDs; 57 | 58 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 59 | if (snapshot == INVALID_HANDLE_VALUE) { 60 | std::cerr << "Failed to take process snapshot." << std::endl; 61 | return javaProcessIDs; 62 | } 63 | 64 | PROCESSENTRY32W processEntry; 65 | processEntry.dwSize = sizeof(PROCESSENTRY32W); 66 | 67 | if (Process32FirstW(snapshot, &processEntry)) { 68 | do { 69 | if (wcscmp(processEntry.szExeFile, L"java.exe") == 0) { 70 | javaProcessIDs.push_back(processEntry.th32ProcessID); 71 | } 72 | } while (Process32NextW(snapshot, &processEntry)); 73 | } else { 74 | std::cerr << "Failed to retrieve first process entry." << std::endl; 75 | } 76 | 77 | CloseHandle(snapshot); 78 | return javaProcessIDs; 79 | } 80 | 81 | void ListProcesses() { 82 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 83 | if (snapshot == INVALID_HANDLE_VALUE) { 84 | std::cerr << "Failed to take process snapshot." << std::endl; 85 | return; 86 | } 87 | 88 | PROCESSENTRY32 processEntry; 89 | processEntry.dwSize = sizeof(PROCESSENTRY32); 90 | 91 | if (Process32First(snapshot, &processEntry)) { 92 | std::cout << "Process ID\tProcess Name" << std::endl; 93 | do { 94 | std::wcout << processEntry.th32ProcessID << "\t\t" << processEntry.szExeFile << std::endl; 95 | } while (Process32Next(snapshot, &processEntry)); 96 | } else { 97 | std::cerr << "Failed to retrieve first process entry." << std::endl; 98 | } 99 | 100 | CloseHandle(snapshot); 101 | } 102 | 103 | int main() { 104 | ListProcesses(); 105 | 106 | std::cout << "Enter the Process ID to inject the class: "; 107 | DWORD processID; 108 | std::cin >> processID; 109 | 110 | std::cin.ignore(); 111 | 112 | std::cout << "Enter the full path to the DLL containing the class: "; 113 | std::string dllPath; 114 | std::getline(std::cin, dllPath); 115 | 116 | if (InjectDLL(processID, dllPath)) { 117 | std::cout << "DLL injected successfully!" << std::endl; 118 | } else { 119 | std::cerr << "DLL injection failed." << std::endl; 120 | } 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | uk.whitedev 8 | JPI 9 | 1.0.2 10 | 11 | 12 | 8 13 | 8 14 | UTF-8 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/InjectClassLoader.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev; 2 | 3 | import java.net.URL; 4 | import java.net.URLClassLoader; 5 | 6 | public class InjectClassLoader extends URLClassLoader { 7 | public InjectClassLoader(URL url) { 8 | super(new URL[]{url}); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/InjectableMain.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev; 2 | 3 | import uk.whitedev.classes.ClassCheckerGui; 4 | import uk.whitedev.injector.InjectorGui; 5 | import uk.whitedev.memory.MemoryEditorGUI; 6 | import uk.whitedev.monitor.ProcessProfilerGui; 7 | import uk.whitedev.utils.ColorUtils; 8 | import uk.whitedev.utils.ProcessUtil; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | import java.io.*; 13 | import javax.swing.event.DocumentEvent; 14 | import javax.swing.event.DocumentListener; 15 | import javax.swing.text.BadLocationException; 16 | import javax.swing.text.StyledDocument; 17 | import javax.tools.*; 18 | import java.lang.reflect.Field; 19 | import java.nio.file.Files; 20 | import java.util.*; 21 | 22 | public class InjectableMain extends JFrame { 23 | private final JTextPane codeArea; 24 | private final JTextArea outputArea; 25 | private boolean isApplyingHighlighting = false; 26 | 27 | public InjectableMain() { 28 | setTitle("Dynamic Java Code Executor [Java Process Inspector]"); 29 | setSize(850, 400); 30 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 31 | setLayout(new BorderLayout()); 32 | 33 | JPanel centerPanel = new JPanel(); 34 | centerPanel.setLayout(new GridLayout(1, 2)); 35 | centerPanel.setBackground(Color.DARK_GRAY); 36 | 37 | codeArea = new JTextPane(); 38 | StyledDocument doc = codeArea.getStyledDocument(); 39 | ColorUtils.addStylesToDocument(doc); 40 | codeArea.setText( 41 | "import java.io.PrintStream;\n" + 42 | "public class DynamicClass {\n" + 43 | " public static void execute(PrintStream out) {\n" + 44 | " //Your code here (don't change classname and main method (execute))\n" + 45 | " }\n" + 46 | "}"); 47 | ColorUtils.applySyntaxHighlighting(codeArea.getText(), doc); 48 | codeArea.setBackground(new Color(50, 50, 50)); 49 | codeArea.setForeground(Color.WHITE); 50 | codeArea.setCaretColor(Color.WHITE); 51 | centerPanel.add(new JScrollPane(codeArea)); 52 | 53 | outputArea = new JTextArea("####### JAVA CODE OUTPUT #######"); 54 | outputArea.setEditable(false); 55 | outputArea.setBackground(new Color(50, 50, 50)); 56 | outputArea.setForeground(Color.WHITE); 57 | centerPanel.add(new JScrollPane(outputArea)); 58 | 59 | doc.addDocumentListener(new DocumentListener() { 60 | @Override 61 | public void insertUpdate(DocumentEvent e) { 62 | handleTextChanged(e, EditFunc.INSERT); 63 | } 64 | 65 | @Override 66 | public void removeUpdate(DocumentEvent e) { 67 | handleTextChanged(e, EditFunc.REMOVE); 68 | } 69 | 70 | @Override 71 | public void changedUpdate(DocumentEvent e) { 72 | handleTextChanged(e, EditFunc.INSERT); 73 | } 74 | }); 75 | 76 | add(centerPanel, BorderLayout.CENTER); 77 | 78 | JPanel buttonPanel = getjPanel(); 79 | add(buttonPanel, BorderLayout.SOUTH); 80 | 81 | getContentPane().setBackground(Color.DARK_GRAY); 82 | } 83 | 84 | private JPanel getjPanel() { 85 | JPanel buttonPanel = new JPanel(new BorderLayout()); 86 | buttonPanel.setBackground(Color.DARK_GRAY); 87 | 88 | JPanel buttonSubPanel = new JPanel(); 89 | buttonSubPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10)); 90 | buttonSubPanel.setBackground(Color.DARK_GRAY); 91 | 92 | JButton runButton = new JButton("Run Code"); 93 | runButton.addActionListener(e -> executeCode(codeArea.getText())); 94 | runButton.setBackground(Color.GRAY); 95 | runButton.setForeground(Color.WHITE); 96 | 97 | JButton memoryButton = new JButton("Open Memory Editor"); 98 | memoryButton.addActionListener(e -> new MemoryEditorGUI().runMemoryEditGui()); 99 | memoryButton.setBackground(Color.GRAY); 100 | memoryButton.setForeground(Color.WHITE); 101 | 102 | JButton injectButton = new JButton("Inject DLL"); 103 | injectButton.addActionListener(e -> new InjectorGui().runInjectorGui()); 104 | injectButton.setBackground(Color.GRAY); 105 | injectButton.setForeground(Color.WHITE); 106 | 107 | JButton classesButton = new JButton("Check Loaded Classes"); 108 | classesButton.addActionListener(e -> new ClassCheckerGui().runClassEditGui()); 109 | classesButton.setBackground(Color.GRAY); 110 | classesButton.setForeground(Color.WHITE); 111 | 112 | JButton pidButton = new JButton("Show Pid"); 113 | pidButton.addActionListener(e -> { 114 | JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "Pid: " + ProcessUtil.getProcessPid(), "Process pid", JOptionPane.INFORMATION_MESSAGE); 115 | }); 116 | pidButton.setBackground(Color.GRAY); 117 | pidButton.setForeground(Color.WHITE); 118 | 119 | JButton profilerButton = new JButton("Process Profiler"); 120 | profilerButton.addActionListener(e -> new ProcessProfilerGui().runProfilerGui()); 121 | profilerButton.setBackground(Color.GRAY); 122 | profilerButton.setForeground(Color.WHITE); 123 | 124 | buttonSubPanel.add(runButton); 125 | buttonSubPanel.add(memoryButton); 126 | buttonSubPanel.add(injectButton); 127 | buttonSubPanel.add(classesButton); 128 | buttonSubPanel.add(pidButton); 129 | buttonSubPanel.add(profilerButton); 130 | 131 | buttonPanel.add(buttonSubPanel, BorderLayout.CENTER); 132 | 133 | JLabel authorLabel = new JLabel("Author: 0WhiteDev (https://github.com/0WhiteDev)"); 134 | authorLabel.setForeground(Color.WHITE); 135 | buttonPanel.add(authorLabel, BorderLayout.SOUTH); 136 | 137 | return buttonPanel; 138 | } 139 | 140 | private void executeCode(String code) { 141 | File tempDir; 142 | try { 143 | tempDir = Files.createTempDirectory("dynamic").toFile(); 144 | tempDir.deleteOnExit(); 145 | } catch (IOException e) { 146 | outputArea.setText("Error creating temporary directory: " + e.getMessage()); 147 | return; 148 | } 149 | 150 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 151 | StringWriter compilationOutput = new StringWriter(); 152 | PrintWriter compilationWriter = new PrintWriter(compilationOutput); 153 | 154 | SimpleJavaFileObject file = new JavaSourceFromString("DynamicClass", code); 155 | StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 156 | Iterable compilationUnits = Collections.singletonList(file); 157 | Iterable options = Arrays.asList("-d", tempDir.getAbsolutePath()); 158 | JavaCompiler.CompilationTask task = compiler.getTask(compilationWriter, fileManager, null, options, null, compilationUnits); 159 | 160 | boolean success = task.call(); 161 | if (success) { 162 | try { 163 | InjectClassLoader classLoader = new InjectClassLoader(tempDir.toURI().toURL()); 164 | Class dynamicClass = classLoader.loadClass("DynamicClass"); 165 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 166 | PrintStream ps = new PrintStream(baos); 167 | System.setOut(ps); 168 | 169 | dynamicClass.getMethod("execute", PrintStream.class).invoke(null, ps); 170 | 171 | ps.flush(); 172 | outputArea.setText(baos.toString()); 173 | System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out))); 174 | 175 | } catch (Exception e) { 176 | outputArea.setText("Error during execution: " + e + "\n" + getStackTrace(e)); 177 | } 178 | } else { 179 | outputArea.setText("Compilation failed:\n" + compilationOutput); 180 | } 181 | } 182 | 183 | private String getStackTrace(Throwable t) { 184 | StringWriter sw = new StringWriter(); 185 | t.printStackTrace(new PrintWriter(sw)); 186 | return sw.toString(); 187 | } 188 | 189 | private void handleTextChanged(DocumentEvent e, EditFunc editFunc) { 190 | if (isApplyingHighlighting) return; 191 | int caretPosition = codeArea.getCaretPosition(); 192 | SwingUtilities.invokeLater(() -> { 193 | StyledDocument doc = (StyledDocument) e.getDocument(); 194 | try { 195 | String currentText = doc.getText(0, doc.getLength()); 196 | isApplyingHighlighting = true; 197 | ColorUtils.applySyntaxHighlighting(currentText, doc); 198 | } catch (BadLocationException ex) { 199 | ex.printStackTrace(); 200 | } finally { 201 | isApplyingHighlighting = false; 202 | SwingUtilities.invokeLater(() -> { 203 | codeArea.setCaretPosition(Math.min(caretPosition + (editFunc == EditFunc.INSERT ? 1 : -1), doc.getLength())); 204 | }); 205 | } 206 | }); 207 | } 208 | 209 | private enum EditFunc { 210 | INSERT, REMOVE 211 | } 212 | 213 | public static void main(String[] args) { 214 | new Thread(() -> new InjectableMain().setVisible(true)).start(); 215 | } 216 | } -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/JavaSourceFromString.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev; 2 | 3 | import javax.tools.SimpleJavaFileObject; 4 | import java.net.URI; 5 | 6 | public class JavaSourceFromString extends SimpleJavaFileObject { 7 | private final String code; 8 | 9 | JavaSourceFromString(String name, String code) { 10 | super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); 11 | this.code = code; 12 | } 13 | 14 | @Override 15 | public CharSequence getCharContent(boolean ignoreEncodingErrors) { 16 | return code; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/classes/ClassCheckerGui.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.classes; 2 | 3 | import uk.whitedev.utils.ClassUtil; 4 | import uk.whitedev.utils.ColorUtils; 5 | 6 | import javax.swing.*; 7 | import javax.swing.event.DocumentEvent; 8 | import javax.swing.event.DocumentListener; 9 | import javax.swing.text.StyledDocument; 10 | import java.awt.*; 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.net.URISyntaxException; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class ClassCheckerGui { 18 | private JFrame frame; 19 | private JList classList; 20 | private DefaultListModel listModel; 21 | private JTextField searchField; 22 | private final ClassUtil classUtil = new ClassUtil(); 23 | private final Color backgroundColor = new Color(50, 50, 50); 24 | private final Color textColor = Color.WHITE; 25 | private final Color buttonColor = new Color(80, 80, 80); 26 | private final Color buttonTextColor = Color.WHITE; 27 | 28 | public void runClassEditGui() { 29 | new Thread(this::createAndShowGUI).start(); 30 | } 31 | 32 | private void createAndShowGUI() { 33 | frame = new JFrame("Class Checker [Java Process Inspector]"); 34 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 | frame.setSize(600, 400); 36 | frame.setLayout(new BorderLayout()); 37 | 38 | listModel = new DefaultListModel<>(); 39 | classList = new JList<>(listModel); 40 | classList.setBackground(backgroundColor); 41 | classList.setForeground(textColor); 42 | JScrollPane listScrollPane = new JScrollPane(classList); 43 | 44 | JPanel buttonPanel = new JPanel(); 45 | buttonPanel.setLayout(new GridLayout(3, 1, 10, 10)); 46 | buttonPanel.setBackground(backgroundColor); 47 | 48 | JButton decompileButton = new JButton("Decompile Class"); 49 | JButton reloadButton = new JButton("Reload Class List"); 50 | JButton dumpButton = new JButton("Dump Classes"); 51 | 52 | styleButton(decompileButton, buttonColor, buttonTextColor); 53 | styleButton(reloadButton, buttonColor, buttonTextColor); 54 | styleButton(dumpButton, buttonColor, buttonTextColor); 55 | 56 | decompileButton.addActionListener(e -> decompileClass()); 57 | reloadButton.addActionListener(e -> reloadClassList()); 58 | dumpButton.addActionListener(e -> dumpClasses()); 59 | 60 | buttonPanel.add(decompileButton); 61 | buttonPanel.add(reloadButton); 62 | buttonPanel.add(dumpButton); 63 | 64 | JPanel searchPanel = new JPanel(new BorderLayout()); 65 | searchPanel.setBackground(backgroundColor); 66 | 67 | searchField = new JTextField(); 68 | searchField.setBackground(backgroundColor); 69 | searchField.setForeground(textColor); 70 | JLabel searchLabel = new JLabel("Search:"); 71 | searchLabel.setForeground(textColor); 72 | 73 | searchPanel.add(searchLabel, BorderLayout.WEST); 74 | searchPanel.add(searchField, BorderLayout.CENTER); 75 | 76 | searchField.getDocument().addDocumentListener(new DocumentListener() { 77 | @Override 78 | public void insertUpdate(DocumentEvent e) { 79 | if (!searchField.getText().isEmpty()) { 80 | filterClassList(); 81 | } else { 82 | reloadClassList(); 83 | } 84 | } 85 | 86 | @Override 87 | public void removeUpdate(DocumentEvent e) { 88 | if (!searchField.getText().isEmpty()) { 89 | filterClassList(); 90 | } else { 91 | reloadClassList(); 92 | } 93 | } 94 | 95 | @Override 96 | public void changedUpdate(DocumentEvent e) { 97 | filterClassList(); 98 | } 99 | }); 100 | 101 | frame.add(searchPanel, BorderLayout.NORTH); 102 | frame.add(listScrollPane, BorderLayout.CENTER); 103 | frame.add(buttonPanel, BorderLayout.EAST); 104 | 105 | reloadClassList(); 106 | 107 | frame.setVisible(true); 108 | } 109 | 110 | private void filterClassList() { 111 | String searchText = searchField.getText().toLowerCase(); 112 | List filteredClasses = new ArrayList<>(); 113 | for (int i = 0; i < listModel.getSize(); i++) { 114 | String className = listModel.getElementAt(i).toLowerCase(); 115 | if (className.contains(searchText)) { 116 | filteredClasses.add(listModel.getElementAt(i)); 117 | } 118 | } 119 | listModel.clear(); 120 | for (String className : filteredClasses) { 121 | listModel.addElement(className); 122 | } 123 | } 124 | 125 | private void styleButton(JButton button, Color backgroundColor, Color textColor) { 126 | button.setBackground(backgroundColor); 127 | button.setForeground(textColor); 128 | button.setFocusPainted(false); 129 | } 130 | 131 | private void reloadClassList() { 132 | List loadedClasses = classUtil.getLoadedClasses(); 133 | listModel.clear(); 134 | if (!loadedClasses.isEmpty()) { 135 | for (String className : loadedClasses) { 136 | if (!listModel.contains(className)) { 137 | listModel.addElement(className); 138 | } 139 | } 140 | } else { 141 | JOptionPane.showMessageDialog(frame, "Cannot access loaded classes!", "Classes Error", JOptionPane.ERROR_MESSAGE); 142 | } 143 | } 144 | 145 | private void decompileClass() { 146 | String selectedClass = classList.getSelectedValue(); 147 | if (selectedClass != null) { 148 | JFrame decompileFrame = new JFrame("Decompiled Code - " + selectedClass); 149 | decompileFrame.setSize(500, 400); 150 | decompileFrame.setLayout(new BorderLayout()); 151 | 152 | JTextPane codeArea = new JTextPane(); 153 | StyledDocument doc = codeArea.getStyledDocument(); 154 | ColorUtils.addStylesToDocument(doc); 155 | 156 | try { 157 | String code = classUtil.decompileClass(classUtil.findClassURL(selectedClass)); 158 | ColorUtils.applySyntaxHighlighting(code, doc); 159 | } catch (IOException | InterruptedException | URISyntaxException e) { 160 | codeArea.setText("Can't decompile this class!"); 161 | } 162 | 163 | codeArea.setEditable(false); 164 | codeArea.setBackground(backgroundColor); 165 | codeArea.setForeground(textColor); 166 | 167 | decompileFrame.add(new JScrollPane(codeArea), BorderLayout.CENTER); 168 | 169 | JButton closeButton = new JButton("Close"); 170 | closeButton.addActionListener(e -> decompileFrame.dispose()); 171 | decompileFrame.add(closeButton, BorderLayout.SOUTH); 172 | closeButton.setBackground(buttonColor); 173 | closeButton.setForeground(buttonTextColor); 174 | 175 | decompileFrame.setVisible(true); 176 | } else { 177 | JOptionPane.showMessageDialog(frame, "Please select a class from the list.", "No Class Selected", JOptionPane.WARNING_MESSAGE); 178 | } 179 | } 180 | 181 | private void dumpClasses() { 182 | JFileChooser fileChooser = new JFileChooser(); 183 | fileChooser.setDialogTitle("Select Directory to Save Classes"); 184 | fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 185 | 186 | int result = fileChooser.showSaveDialog(frame); 187 | if (result == JFileChooser.APPROVE_OPTION) { 188 | File selectedDirectory = fileChooser.getSelectedFile(); 189 | List loadedClasses = classUtil.getLoadedClasses(); 190 | if (!loadedClasses.isEmpty()) { 191 | for (String className : loadedClasses) { 192 | try { 193 | classUtil.dumpClass(className, selectedDirectory); 194 | } catch (IOException e) { 195 | System.out.println("[JPI Class Dumper] Ignoring unreachable class: " + className); 196 | } 197 | } 198 | JOptionPane.showMessageDialog(frame, "Classes dumped successfully!", "Success", JOptionPane.INFORMATION_MESSAGE); 199 | }else{ 200 | JOptionPane.showMessageDialog(frame, "Cannot access loaded classes!", "Classes Error", JOptionPane.ERROR_MESSAGE); 201 | } 202 | 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/injector/DLLInjector.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.injector; 2 | 3 | import uk.whitedev.utils.NativeLoader; 4 | 5 | import java.io.IOException; 6 | 7 | public class DLLInjector { 8 | static { 9 | try { 10 | NativeLoader.loadLibraryFromJar("/natives/DLLInjector.dll", "DLLInjector"); 11 | } catch (IOException e) { 12 | e.printStackTrace(); 13 | throw new RuntimeException("Failed to load native library", e); 14 | } 15 | } 16 | 17 | public native boolean injectDLL(long pid, String dllPath); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/injector/InjectorGui.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.injector; 2 | 3 | import uk.whitedev.utils.ProcessUtil; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | public class InjectorGui { 9 | private final DLLInjector injector = new DLLInjector(); 10 | private final Color backgroundColor = new Color(50, 50, 50); 11 | private final Color textColor = Color.WHITE; 12 | private final Color buttonColor = new Color(80, 80, 80); 13 | private final Color buttonTextColor = Color.WHITE; 14 | 15 | public void runInjectorGui() { 16 | new Thread(this::createAndShowGUI).start(); 17 | } 18 | 19 | private void createAndShowGUI(){ 20 | JFrame frame = new JFrame("DLL Injector [Java Process Inspector]"); 21 | JPanel jPanel = new JPanel(new GridLayout(5, 1, 10, 10)); 22 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 | frame.setSize(310, 300); 24 | jPanel.setBackground(backgroundColor); 25 | 26 | 27 | JLabel pidLabel = new JLabel("PID:"); 28 | JTextField pidField = new JTextField(ProcessUtil.getProcessPid()); 29 | JLabel dllLabel = new JLabel("DLL Path:"); 30 | JTextField dllField = new JTextField(); 31 | JButton injectButton = new JButton("Inject!"); 32 | 33 | pidLabel.setForeground(textColor); 34 | dllLabel.setForeground(textColor); 35 | pidField.setBackground(backgroundColor); 36 | pidField.setForeground(textColor); 37 | dllField.setBackground(backgroundColor); 38 | dllField.setForeground(textColor); 39 | injectButton.setBackground(buttonColor); 40 | injectButton.setForeground(buttonTextColor); 41 | 42 | injectButton.addActionListener(e -> { 43 | if(injector.injectDLL(Long.parseLong(pidField.getText()), dllField.getText())){ 44 | JOptionPane.showMessageDialog(frame, "The dll file was injected successfully", "Success", JOptionPane.INFORMATION_MESSAGE); 45 | }else{ 46 | JOptionPane.showMessageDialog(frame, "Can't inject this dll file into the specified process!", "Error", JOptionPane.ERROR_MESSAGE); 47 | } 48 | }); 49 | 50 | jPanel.add(pidLabel); 51 | jPanel.add(pidField); 52 | jPanel.add(dllLabel); 53 | jPanel.add(dllField); 54 | jPanel.add(injectButton); 55 | frame.add(jPanel); 56 | 57 | frame.setVisible(true); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/memory/MemoryEditor.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.memory; 2 | 3 | import uk.whitedev.utils.NativeLoader; 4 | 5 | import java.io.IOException; 6 | import java.util.*; 7 | 8 | public class MemoryEditor { 9 | static { 10 | try { 11 | NativeLoader.loadLibraryFromJar("/natives/MemoryEditor.dll", "MemoryEditor"); 12 | } catch (IOException e) { 13 | e.printStackTrace(); 14 | throw new RuntimeException("Failed to load native library", e); 15 | } 16 | } 17 | public native Map listProcesses(); 18 | public native WindowInfo[] getOpenWindows(); 19 | public native MemoryLocation[] scanMemory(long pid, String searchStr, int dataType); 20 | public native void modifyMemory(long pid, MemoryLocation[] locations, String newValue, int type); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/memory/MemoryEditorGUI.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.memory; 2 | 3 | import uk.whitedev.utils.ProcessUtil; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.util.*; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | public class MemoryEditorGUI { 14 | private final MemoryEditor editor = new MemoryEditor(); 15 | private JFrame frame; 16 | private JTextArea outputArea; 17 | private JTextField pidField; 18 | private JTextField searchStrField; 19 | private JComboBox dataTypeCombo; 20 | private JComboBox scanTypeCombo; 21 | private MemoryLocation[] memoryLocations; 22 | 23 | public void runMemoryEditGui() { 24 | new Thread(this::createAndShowGUI).start(); 25 | } 26 | 27 | private void createAndShowGUI() { 28 | Color backgroundColor = new Color(50, 50, 50); 29 | Color textColor = Color.WHITE; 30 | Color buttonColor = new Color(80, 80, 80); 31 | Color buttonTextColor = Color.WHITE; 32 | 33 | frame = new JFrame("Memory Editor [Java Process Inspector]"); 34 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 | frame.setSize(600, 400); 36 | frame.setLayout(new BorderLayout()); 37 | 38 | 39 | JPanel topPanel = new JPanel(new GridLayout(6, 2)); 40 | topPanel.setBackground(backgroundColor); 41 | topPanel.add(createLabeledComponent("PID:", textColor)); 42 | pidField = new JTextField(ProcessUtil.getProcessPid()); 43 | pidField.setBackground(new Color(70, 70, 70)); 44 | pidField.setForeground(textColor); 45 | topPanel.add(pidField); 46 | 47 | topPanel.add(createLabeledComponent("Search Value:", textColor)); 48 | searchStrField = new JTextField(); 49 | searchStrField.setBackground(new Color(70, 70, 70)); 50 | searchStrField.setForeground(textColor); 51 | topPanel.add(searchStrField); 52 | 53 | topPanel.add(createLabeledComponent("Data Type:", textColor)); 54 | String[] dataTypes = {"String", "Int", "Double", "Long", "Float", "Short"}; 55 | dataTypeCombo = new JComboBox<>(dataTypes); 56 | dataTypeCombo.setBackground(new Color(70, 70, 70)); 57 | dataTypeCombo.setForeground(textColor); 58 | topPanel.add(dataTypeCombo); 59 | 60 | topPanel.add(createLabeledComponent("Scan Type:", textColor)); 61 | String[] scanTypes = {"1 - Windows", "2 - All"}; 62 | scanTypeCombo = new JComboBox<>(scanTypes); 63 | scanTypeCombo.setBackground(new Color(70, 70, 70)); 64 | scanTypeCombo.setForeground(textColor); 65 | topPanel.add(scanTypeCombo); 66 | 67 | JButton scanButton = new JButton("Scan Memory"); 68 | scanButton.setBackground(buttonColor); 69 | scanButton.setForeground(buttonTextColor); 70 | topPanel.add(scanButton); 71 | 72 | JButton scanPidButton = new JButton("Scan PID"); 73 | scanPidButton.setBackground(buttonColor); 74 | scanPidButton.setForeground(buttonTextColor); 75 | topPanel.add(scanPidButton); 76 | 77 | JButton filterButton = new JButton("Filter Results"); 78 | filterButton.setBackground(buttonColor); 79 | filterButton.setForeground(buttonTextColor); 80 | topPanel.add(filterButton); 81 | 82 | JButton modifyButton = new JButton("Modify Memory"); 83 | modifyButton.setBackground(buttonColor); 84 | modifyButton.setForeground(buttonTextColor); 85 | topPanel.add(modifyButton); 86 | 87 | JPanel bottomPanel = new JPanel(new BorderLayout()); 88 | bottomPanel.setBackground(backgroundColor); 89 | 90 | outputArea = new JTextArea(10, 40); 91 | outputArea.setEditable(false); 92 | outputArea.setBackground(new Color(70, 70, 70)); 93 | outputArea.setForeground(textColor); 94 | bottomPanel.add(new JScrollPane(outputArea)); 95 | 96 | frame.add(topPanel, BorderLayout.NORTH); 97 | frame.add(bottomPanel, BorderLayout.CENTER); 98 | 99 | scanPidButton.addActionListener(new ScanPidButtonListener()); 100 | scanButton.addActionListener(new ScanButtonListener()); 101 | filterButton.addActionListener(new FilterButtonListener()); 102 | modifyButton.addActionListener(new ModifyButtonListener()); 103 | 104 | frame.setVisible(true); 105 | } 106 | 107 | private JPanel createLabeledComponent(String labelText, Color textColor) { 108 | JPanel panel = new JPanel(new BorderLayout()); 109 | JLabel label = new JLabel(labelText); 110 | panel.setBackground(new Color(50, 50, 50)); 111 | label.setForeground(textColor); 112 | panel.add(label, BorderLayout.WEST); 113 | return panel; 114 | } 115 | 116 | 117 | private class ScanPidButtonListener implements ActionListener { 118 | @Override 119 | public void actionPerformed(ActionEvent e) { 120 | outputArea.setText(""); 121 | try { 122 | int scanType = scanTypeCombo.getSelectedIndex() + 1; 123 | if (scanType == 1) { 124 | WindowInfo[] win = editor.getOpenWindows(); 125 | for (WindowInfo windowInfo : win) { 126 | outputArea.append("PID: " + windowInfo.getPid() + ", Name: " + windowInfo.getTitle() + "\n"); 127 | } 128 | } else if (scanType == 2) { 129 | Map processes = editor.listProcesses(); 130 | for (Map.Entry entry : processes.entrySet()) { 131 | outputArea.append("PID: " + entry.getKey() + ", Name: " + entry.getValue() + "\n"); 132 | } 133 | } 134 | } catch (Exception ex) { 135 | JOptionPane.showMessageDialog(frame, "Error scanning processes or windows", "Error", JOptionPane.ERROR_MESSAGE); 136 | for (StackTraceElement stackTraceElement : ex.getStackTrace()) { 137 | outputArea.append(stackTraceElement.toString() + '\n'); 138 | } 139 | } 140 | } 141 | } 142 | 143 | private class ScanButtonListener implements ActionListener { 144 | @Override 145 | public void actionPerformed(ActionEvent e) { 146 | outputArea.setText(""); 147 | try { 148 | long pid = Long.parseLong(pidField.getText()); 149 | int dataType = dataTypeCombo.getSelectedIndex(); 150 | memoryLocations = editor.scanMemory(pid, searchStrField.getText(), dataType); 151 | if (memoryLocations.length > 0) { 152 | for (MemoryLocation memoryLocation : memoryLocations) { 153 | outputArea.append("Address: " + memoryLocation.getAddress() + ", Value: " + memoryLocation.getValue() + "\n"); 154 | } 155 | } else { 156 | outputArea.append("Not found any value!"); 157 | } 158 | } catch (Exception ex) { 159 | JOptionPane.showMessageDialog(frame, "Error scanning memory", "Error", JOptionPane.ERROR_MESSAGE); 160 | for (StackTraceElement stackTraceElement : ex.getStackTrace()) { 161 | outputArea.append(stackTraceElement.toString() + '\n'); 162 | } 163 | } 164 | } 165 | } 166 | 167 | private class FilterButtonListener implements ActionListener { 168 | @Override 169 | public void actionPerformed(ActionEvent e) { 170 | outputArea.setText(""); 171 | try { 172 | if (memoryLocations != null && memoryLocations.length > 0) { 173 | String newFilterValue = JOptionPane.showInputDialog(frame, "Provide new value:"); 174 | if (newFilterValue != null && !newFilterValue.isEmpty()) { 175 | long pid = Long.parseLong(pidField.getText()); 176 | int dataType = dataTypeCombo.getSelectedIndex(); 177 | MemoryLocation[] newMemoryLocations = editor.scanMemory(pid, newFilterValue, dataType); 178 | memoryLocations = filterMemLoc(memoryLocations, newMemoryLocations); 179 | for (MemoryLocation memoryLocation : memoryLocations) { 180 | outputArea.append("Address: " + memoryLocation.getAddress() + ", Value: " + memoryLocation.getValue() + "\n"); 181 | } 182 | } 183 | } else { 184 | JOptionPane.showMessageDialog(frame, "Can't filter empty list!", "Error", JOptionPane.ERROR_MESSAGE); 185 | } 186 | } catch (NumberFormatException ex) { 187 | JOptionPane.showMessageDialog(frame, "Invalid PID or data type", "Error", JOptionPane.ERROR_MESSAGE); 188 | for (StackTraceElement stackTraceElement : ex.getStackTrace()) { 189 | outputArea.append(stackTraceElement.toString() + '\n'); 190 | } 191 | } 192 | } 193 | } 194 | 195 | private class ModifyButtonListener implements ActionListener { 196 | @Override 197 | public void actionPerformed(ActionEvent e) { 198 | try { 199 | long pid = Long.parseLong(pidField.getText()); 200 | int dataType = dataTypeCombo.getSelectedIndex(); 201 | String newValue = JOptionPane.showInputDialog(frame, "Provide new value:"); 202 | if (newValue != null && !newValue.isEmpty()) { 203 | MemoryLocation[] memoryLocations = editor.scanMemory(pid, searchStrField.getText(), dataType); 204 | editor.modifyMemory(pid, memoryLocations, newValue, dataType); 205 | JOptionPane.showMessageDialog(frame, "Memory modified successfully", "Success", JOptionPane.INFORMATION_MESSAGE); 206 | } 207 | } catch (NumberFormatException ex) { 208 | JOptionPane.showMessageDialog(frame, "Invalid PID or data type", "Error", JOptionPane.ERROR_MESSAGE); 209 | for (StackTraceElement stackTraceElement : ex.getStackTrace()) { 210 | outputArea.append(stackTraceElement.toString() + '\n'); 211 | } 212 | } 213 | } 214 | } 215 | 216 | private MemoryLocation[] filterMemLoc(MemoryLocation[] oldMemLoc, MemoryLocation[] newMemLoc) { 217 | Set oldAddresses = Arrays.stream(oldMemLoc) 218 | .map(MemoryLocation::getAddress) 219 | .collect(Collectors.toSet()); 220 | List memLocList = Arrays.stream(newMemLoc) 221 | .filter(loc -> oldAddresses.contains(loc.getAddress())) 222 | .collect(Collectors.toList()); 223 | return memLocList.toArray(new MemoryLocation[0]); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/memory/MemoryLocation.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.memory; 2 | 3 | public class MemoryLocation { 4 | private final long address; 5 | private final String value; 6 | 7 | public MemoryLocation(long address, String value) { 8 | this.address = address; 9 | this.value = value; 10 | } 11 | 12 | public long getAddress() { 13 | return address; 14 | } 15 | 16 | public String getValue() { 17 | return value; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/memory/WindowInfo.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.memory; 2 | 3 | public class WindowInfo { 4 | private final String title; 5 | private final long pid; 6 | 7 | public WindowInfo(String title, long pid) { 8 | this.title = title; 9 | this.pid = pid; 10 | } 11 | 12 | public String getTitle() { 13 | return title; 14 | } 15 | 16 | public long getPid() { 17 | return pid; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "WindowInfo{title='" + title + "', pid=" + pid + "}"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/monitor/ProcessProfilerGui.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.monitor; 2 | 3 | import uk.whitedev.utils.FieldUtil; 4 | import uk.whitedev.utils.MonitorUtil; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | public class ProcessProfilerGui { 10 | private JTextArea performanceArea; 11 | private JTextArea resourcesArea; 12 | private JTextArea processInfoArea; 13 | private JTextArea fieldsArea; 14 | 15 | private final Color backgroundColor = new Color(50, 50, 50); 16 | private final Color textColor = Color.WHITE; 17 | private final Color buttonColor = new Color(80, 80, 80); 18 | private final Color buttonTextColor = Color.WHITE; 19 | 20 | private final MonitorUtil monitorUtil = new MonitorUtil(); 21 | private final FieldUtil fieldUtil = new FieldUtil(); 22 | 23 | private JScrollPane performanceScrollPane; 24 | private JScrollPane resourcesScrollPane; 25 | private JScrollPane processInfoScrollPane; 26 | private JScrollPane fieldsScrollPane; 27 | 28 | public void runProfilerGui() { 29 | new Thread(this::createAndShowGUI).start(); 30 | } 31 | 32 | private void createAndShowGUI() { 33 | JFrame frame = new JFrame("Process Profiler [Java Process Inspector]"); 34 | frame.setSize(800, 600); 35 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 36 | frame.setLayout(new BorderLayout()); 37 | 38 | performanceArea = new JTextArea(monitorUtil.getPerformanceData()); 39 | resourcesArea = new JTextArea(monitorUtil.getResourcesData()); 40 | processInfoArea = new JTextArea(monitorUtil.getDetailedInfo()); 41 | fieldsArea = new JTextArea(fieldUtil.getAllFields()); 42 | 43 | performanceArea.setEditable(false); 44 | resourcesArea.setEditable(false); 45 | processInfoArea.setEditable(false); 46 | fieldsArea.setEditable(false); 47 | 48 | performanceArea.setBackground(backgroundColor); 49 | performanceArea.setForeground(textColor); 50 | resourcesArea.setBackground(backgroundColor); 51 | resourcesArea.setForeground(textColor); 52 | processInfoArea.setBackground(backgroundColor); 53 | processInfoArea.setForeground(textColor); 54 | fieldsArea.setBackground(backgroundColor); 55 | fieldsArea.setForeground(textColor); 56 | 57 | performanceScrollPane = new JScrollPane(performanceArea); 58 | resourcesScrollPane = new JScrollPane(resourcesArea); 59 | processInfoScrollPane = new JScrollPane(processInfoArea); 60 | fieldsScrollPane = new JScrollPane(fieldsArea); 61 | 62 | JPanel panel = new JPanel(new GridBagLayout()); 63 | GridBagConstraints gbc = new GridBagConstraints(); 64 | gbc.fill = GridBagConstraints.BOTH; 65 | gbc.weightx = 1.0; 66 | gbc.weighty = 1.0; 67 | 68 | JSplitPane splitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 69 | performanceScrollPane, 70 | processInfoScrollPane); 71 | splitPane1.setDividerLocation(400); 72 | 73 | JSplitPane splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 74 | resourcesScrollPane, 75 | fieldsScrollPane); 76 | splitPane2.setDividerLocation(400); 77 | 78 | gbc.gridx = 0; 79 | gbc.gridy = 0; 80 | gbc.gridwidth = 1; 81 | gbc.gridheight = 1; 82 | gbc.weighty = 0.5; 83 | panel.add(splitPane1, gbc); 84 | 85 | gbc.gridx = 0; 86 | gbc.gridy = 1; 87 | gbc.weightx = 1.0; 88 | gbc.weighty = 0.5; 89 | panel.add(splitPane2, gbc); 90 | 91 | frame.add(panel, BorderLayout.CENTER); 92 | 93 | JButton refreshFieldsButton = new JButton("Refresh Fields"); 94 | refreshFieldsButton.addActionListener(e ->fieldsArea.setText(fieldUtil.getAllFields())); 95 | refreshFieldsButton.setBackground(buttonColor); 96 | refreshFieldsButton.setForeground(buttonTextColor); 97 | refreshFieldsButton.setFocusPainted(false); 98 | frame.add(refreshFieldsButton, BorderLayout.SOUTH); 99 | 100 | initRefreshTimer(); 101 | 102 | frame.setVisible(true); 103 | } 104 | 105 | 106 | private void initRefreshTimer() { 107 | Timer refreshTimer = new Timer(1000, e -> updateTextAreas()); 108 | refreshTimer.start(); 109 | } 110 | 111 | private void updateTextAreas() { 112 | SwingUtilities.invokeLater(() -> { 113 | Point performanceScrollPos = performanceScrollPane.getViewport().getViewPosition(); 114 | Point resourcesScrollPos = resourcesScrollPane.getViewport().getViewPosition(); 115 | Point processInfoScrollPos = processInfoScrollPane.getViewport().getViewPosition(); 116 | Point fieldsScrollPos = fieldsScrollPane.getViewport().getViewPosition(); 117 | 118 | performanceArea.setText(monitorUtil.getPerformanceData()); 119 | resourcesArea.setText(monitorUtil.getResourcesData()); 120 | processInfoArea.setText(monitorUtil.getDetailedInfo()); 121 | 122 | SwingUtilities.invokeLater(() -> { 123 | performanceScrollPane.getViewport().setViewPosition(performanceScrollPos); 124 | resourcesScrollPane.getViewport().setViewPosition(resourcesScrollPos); 125 | processInfoScrollPane.getViewport().setViewPosition(processInfoScrollPos); 126 | fieldsScrollPane.getViewport().setViewPosition(fieldsScrollPos); 127 | }); 128 | }); 129 | } 130 | } -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/ClassUtil.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import java.io.*; 4 | import java.lang.reflect.Field; 5 | import java.net.URI; 6 | import java.net.URISyntaxException; 7 | import java.net.URL; 8 | import java.net.URLClassLoader; 9 | import java.nio.file.Files; 10 | import java.util.*; 11 | import java.util.function.Supplier; 12 | import java.util.jar.JarEntry; 13 | import java.util.jar.JarFile; 14 | 15 | public class ClassUtil { 16 | 17 | public List getLoadedClasses() { 18 | List>> loaders = Arrays.asList( 19 | this::getLoadedClassesFromJMap, 20 | this::getLoadedClassesFromLoader, 21 | this::getLoadedClassesFromUrlLoader 22 | ); 23 | return loaders.stream() 24 | .map(Supplier::get) 25 | .filter(classNames -> !classNames.isEmpty()) 26 | .findFirst() 27 | .orElse(Collections.emptyList()); 28 | } 29 | 30 | private List getLoadedClassesFromJMap() { 31 | List classNames = new ArrayList<>(); 32 | try { 33 | Process process = new ProcessBuilder("jmap", "-histo:live", ProcessUtil.getProcessPid()).start(); 34 | BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 35 | String line; 36 | 37 | while ((line = reader.readLine()) != null) { 38 | String[] parts = line.trim().split("\\s+"); 39 | if (parts.length >= 4) { 40 | String className = parts[3]; 41 | int dollarIndex = className.indexOf('$'); 42 | if (dollarIndex != -1) className = className.substring(0, dollarIndex); 43 | if (className.startsWith("[")) className = className.substring(2); 44 | classNames.add(className); 45 | } 46 | } 47 | int exitCode = process.waitFor(); 48 | if (exitCode != 0) { 49 | System.err.println("Error: jmap command failed with exit code " + exitCode); 50 | } 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | return classNames; 55 | } 56 | 57 | private List getLoadedClassesFromLoader() { 58 | ClassLoader classLoader = ClassLoader.getSystemClassLoader(); 59 | List classNames = new ArrayList<>(); 60 | try { 61 | Field classesField; 62 | classesField = ClassLoader.class.getDeclaredField("classes"); 63 | classesField.setAccessible(true); 64 | Vector> classes; 65 | classes = (Vector>) classesField.get(classLoader); 66 | for (Class clazz : classes) { 67 | classNames.add(clazz.getName()); 68 | } 69 | } catch (IllegalAccessException | NoSuchFieldException e) { 70 | e.printStackTrace(); 71 | } 72 | return classNames; 73 | } 74 | 75 | private List getLoadedClassesFromUrlLoader() { 76 | ClassLoader classLoader = ClassLoader.getSystemClassLoader(); 77 | List classNames = new ArrayList<>(); 78 | try { 79 | if (classLoader instanceof URLClassLoader) { 80 | URLClassLoader urlClassLoader = (URLClassLoader) classLoader; 81 | URL[] urls = urlClassLoader.getURLs(); 82 | for (URL url : urls) { 83 | if (url.getFile().endsWith(".jar")) { 84 | try (JarFile jarFile = new JarFile(url.getFile())) { 85 | Enumeration entries = jarFile.entries(); 86 | while (entries.hasMoreElements()) { 87 | JarEntry entry = entries.nextElement(); 88 | classNames.add(entry.getName()); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } catch (Exception e) { 95 | e.printStackTrace(); 96 | } 97 | return classNames; 98 | } 99 | 100 | private String getClassFilePathFromURL(URL classURL) throws IOException, URISyntaxException { 101 | if (classURL == null) { 102 | throw new IllegalArgumentException("URL cannot be null"); 103 | } 104 | 105 | String protocol = classURL.getProtocol(); 106 | if ("file".equals(protocol)) { 107 | URI uri = classURL.toURI(); 108 | if (!uri.isAbsolute()) { 109 | throw new IllegalArgumentException("URI is not absolute: " + uri); 110 | } 111 | return new File(uri).getAbsolutePath(); 112 | } else if ("jar".equals(protocol)) { 113 | String path = classURL.getPath(); 114 | int bangIndex = path.indexOf('!'); 115 | if (bangIndex == -1) { 116 | throw new IllegalArgumentException("Invalid jar URL: " + path); 117 | } 118 | 119 | String jarPath = path.substring(5, bangIndex); 120 | String classPath = path.substring(bangIndex + 2); 121 | 122 | File tempFile = File.createTempFile("decompiled", ".class"); 123 | try (JarFile jarFile = new JarFile(new File(jarPath))) { 124 | JarEntry entry = jarFile.getJarEntry(classPath); 125 | if (entry == null) { 126 | throw new FileNotFoundException("Class entry not found in JAR: " + classPath); 127 | } 128 | try (InputStream is = jarFile.getInputStream(entry); 129 | OutputStream os = Files.newOutputStream(tempFile.toPath())) { 130 | byte[] buffer = new byte[1024]; 131 | int bytesRead; 132 | while ((bytesRead = is.read(buffer)) != -1) { 133 | os.write(buffer, 0, bytesRead); 134 | } 135 | } 136 | return tempFile.getAbsolutePath(); 137 | } 138 | } else { 139 | throw new UnsupportedOperationException("Protocol not supported: " + protocol); 140 | } 141 | } 142 | 143 | 144 | public String decompileClass(URL classFilePath) throws IOException, InterruptedException, URISyntaxException { 145 | File classFile = new File(getClassFilePathFromURL(classFilePath)); 146 | ProcessBuilder processBuilder = new ProcessBuilder( 147 | "java", "-jar", loadCFR(), classFile.getAbsolutePath() 148 | ); 149 | Process process = processBuilder.start(); 150 | StringBuilder output = new StringBuilder(); 151 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { 152 | String line; 153 | while ((line = reader.readLine()) != null) { 154 | output.append(line).append("\n"); 155 | } 156 | } 157 | int exitCode = process.waitFor(); 158 | if (exitCode != 0) { 159 | throw new RuntimeException("CFR failed with exit code " + exitCode); 160 | } 161 | return output.toString(); 162 | } 163 | 164 | public URL findClassURL(String className) throws IOException, URISyntaxException { 165 | String classFileName = className.replace('.', '/') + ".class"; 166 | 167 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 168 | if (classLoader == null) { 169 | classLoader = ClassLoader.getSystemClassLoader(); 170 | } 171 | 172 | URL classURL = classLoader.getResource(classFileName); 173 | if (classURL != null) { 174 | return classURL; 175 | } 176 | 177 | if (classURL.getProtocol().equals("jar")) { 178 | try (JarFile ignored = new JarFile(new File(classURL.toURI().getPath()))) { 179 | URL entryURL = classLoader.getResource(classFileName); 180 | if (entryURL != null) { 181 | return entryURL; 182 | } 183 | } 184 | } 185 | 186 | return null; 187 | } 188 | 189 | private String loadCFR() { 190 | try (InputStream is = ClassUtil.class.getResourceAsStream("/assets/cfr-0.152.jar")) { 191 | if (is == null) { 192 | throw new IOException("CFR not found in JAR: /assets/cfr-0.152.jar"); 193 | } 194 | File tempFile = File.createTempFile("cfr0152", ".jar"); 195 | tempFile.deleteOnExit(); 196 | Files.copy(is, tempFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); 197 | return tempFile.getAbsolutePath(); 198 | } catch (IOException e) { 199 | throw new RuntimeException(e); 200 | } 201 | } 202 | 203 | public void dumpClass(String className, File baseDir) throws IOException { 204 | String classPath = className.replace('.', '/') + ".class"; 205 | File classFile = new File(baseDir, classPath); 206 | File parentDir = classFile.getParentFile(); 207 | if (!parentDir.exists() && !parentDir.mkdirs()) { 208 | throw new IOException("Failed to create directory: " + parentDir.getAbsolutePath()); 209 | } 210 | InputStream classStream = getClassAsStream(className); 211 | if (classStream != null) { 212 | try (FileOutputStream outputStream = new FileOutputStream(classFile)) { 213 | byte[] buffer = new byte[8192]; 214 | int bytesRead; 215 | while ((bytesRead = classStream.read(buffer)) != -1) { 216 | outputStream.write(buffer, 0, bytesRead); 217 | } 218 | } finally { 219 | classStream.close(); 220 | } 221 | } else { 222 | throw new IOException("Class stream is null for: " + className); 223 | } 224 | } 225 | 226 | private InputStream getClassAsStream(String className) { 227 | String classPath = className.replace('.', '/') + ".class"; 228 | ClassLoader classLoader = getClass().getClassLoader(); 229 | URL classUrl = classLoader.getResource(classPath); 230 | if (classUrl != null) { 231 | try { 232 | return classUrl.openStream(); 233 | } catch (IOException e) { 234 | e.printStackTrace(); 235 | } 236 | } 237 | return null; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/ColorUtils.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import javax.swing.text.BadLocationException; 4 | import javax.swing.text.Style; 5 | import javax.swing.text.StyleConstants; 6 | import javax.swing.text.StyledDocument; 7 | import java.awt.*; 8 | 9 | public class ColorUtils { 10 | public static void addStylesToDocument(StyledDocument doc) { 11 | Style style = doc.addStyle("Keyword", null); 12 | StyleConstants.setForeground(style, new Color(249, 95, 119)); 13 | 14 | StyleConstants.setBold(style, true); 15 | style = doc.addStyle("Comment", null); 16 | StyleConstants.setForeground(style, new Color(121, 199, 101)); 17 | 18 | style = doc.addStyle("String", null); 19 | StyleConstants.setForeground(style, new Color(250, 227, 101)); 20 | } 21 | 22 | public static void applySyntaxHighlighting(String text, StyledDocument doc) { 23 | try { 24 | doc.remove(0, doc.getLength()); 25 | String[] keywords = {"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", 26 | "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", 27 | "finally", "float", "for", "if", "goto", "implements", "import", "instanceof", "int", 28 | "interface", "long", "native", "new", "null", "package", "private", "protected", 29 | "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", 30 | "this", "throw", "throws", "transient", "try", "void", "volatile", "while"}; 31 | for (String keyword : keywords) { 32 | text = text.replaceAll("\\b" + keyword + "\\b", "" + keyword + ""); 33 | } 34 | text = text.replaceAll("//.*", "$0"); 35 | text = text.replaceAll("\".*?\"", "$0"); 36 | 37 | int pos = 0; 38 | while (pos < text.length()) { 39 | if (text.startsWith("", pos)) { 40 | pos = insertStyledText(doc, text, pos, "Keyword"); 41 | } else if (text.startsWith("", pos)) { 42 | pos = insertStyledText(doc, text, pos, "Comment"); 43 | } else if (text.startsWith("", pos)) { 44 | pos = insertStyledText(doc, text, pos, "String"); 45 | } else { 46 | doc.insertString(doc.getLength(), String.valueOf(text.charAt(pos)), null); 47 | pos++; 48 | } 49 | } 50 | } catch (BadLocationException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | public static int insertStyledText(StyledDocument doc, String text, int pos, String styleName) throws BadLocationException { 56 | int endPos = text.indexOf("", pos); 57 | String content = text.substring(pos + styleName.length() + 2, endPos); 58 | doc.insertString(doc.getLength(), content, doc.getStyle(styleName)); 59 | return endPos + styleName.length() + 3; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/FieldUtil.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.*; 5 | 6 | public class FieldUtil { 7 | private final ClassUtil classUtil = new ClassUtil(); 8 | private final String[] blacklist = new String[]{"java.", "javax.", "sun."}; 9 | 10 | public String getAllFields(){ 11 | StringBuilder builder = new StringBuilder("All Process Fields:\n"); 12 | List classes = classUtil.getLoadedClasses(); 13 | for (String aClass : classes) { 14 | try { 15 | Class startClass = Class.forName(aClass); 16 | Map fieldMap = new HashMap<>(); 17 | Set processedFields = new HashSet<>(); 18 | 19 | inspectClass(startClass, fieldMap, processedFields); 20 | 21 | for (Map.Entry entry : fieldMap.entrySet()) { 22 | if(checkClassName(entry.getKey())) 23 | builder.append(" ").append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n"); 24 | } 25 | } catch (Exception ignored) {} 26 | } 27 | return builder.toString(); 28 | } 29 | 30 | private boolean checkClassName(String text){ 31 | for (String s : blacklist) { 32 | if(text.startsWith(s)) return false; 33 | } 34 | return true; 35 | } 36 | 37 | private void inspectClass(Class clazz, Map fieldMap, Set processedFields) throws IllegalAccessException { 38 | while (clazz != null) { 39 | Field[] fields = clazz.getDeclaredFields(); 40 | for (Field field : fields) { 41 | field.setAccessible(true); 42 | String fieldName = field.getName(); 43 | String fieldType = field.getType().getSimpleName(); 44 | Object fieldValue = getFieldValue(field, clazz); 45 | String fieldKey = clazz.getName() + " " + fieldType + " " + fieldName; 46 | 47 | if (fieldValue != null && processedFields.add(fieldKey)) { 48 | fieldMap.put(fieldKey, fieldValue.toString()); 49 | } 50 | } 51 | clazz = clazz.getSuperclass(); 52 | } 53 | } 54 | 55 | private Object getFieldValue(Field field, Class clazz) throws IllegalAccessException { 56 | Object instance = null; 57 | try { 58 | instance = clazz.getDeclaredConstructor().newInstance(); 59 | } catch (Exception ignored) {} 60 | if (instance != null) { 61 | return field.get(instance); 62 | } 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/MonitorUtil.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import java.lang.management.*; 4 | 5 | public class MonitorUtil { 6 | private final MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); 7 | private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); 8 | 9 | public String getPerformanceData() { 10 | StringBuilder sb = new StringBuilder(); 11 | sb.append("Performance Profiling:\n"); 12 | 13 | int threadCount = threadBean.getThreadCount(); 14 | sb.append(" Thread Count: ").append(threadCount).append("\n"); 15 | 16 | long cpuTime = threadBean.getCurrentThreadCpuTime() / 1_000_000; 17 | sb.append(" Current Thread CPU Time: ").append(cpuTime).append(" ms\n"); 18 | 19 | long[] threadIds = threadBean.getAllThreadIds(); 20 | long totalCpuTime = 0; 21 | for (long threadId : threadIds) { 22 | long threadCpuTime = threadBean.getThreadCpuTime(threadId) / 1_000_000; 23 | totalCpuTime += threadCpuTime; 24 | } 25 | sb.append(" Total CPU Time for All Threads: ").append(totalCpuTime).append(" ms\n"); 26 | 27 | return sb.toString(); 28 | } 29 | 30 | 31 | public String getResourcesData() { 32 | StringBuilder sb = new StringBuilder(); 33 | sb.append("Resource Monitoring:\n"); 34 | 35 | MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); 36 | sb.append(" Heap Memory Usage:\n"); 37 | sb.append(" Init: ").append(heapUsage.getInit() / 1_000_000).append(" MB\n"); 38 | sb.append(" Used: ").append(heapUsage.getUsed() / 1_000_000).append(" MB\n"); 39 | sb.append(" Committed: ").append(heapUsage.getCommitted() / 1_000_000).append(" MB\n"); 40 | sb.append(" Max: ").append(heapUsage.getMax() / 1_000_000).append(" MB\n"); 41 | 42 | MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); 43 | sb.append(" Non-Heap Memory Usage:\n"); 44 | sb.append(" Init: ").append(nonHeapUsage.getInit() / 1_000_000).append(" MB\n"); 45 | sb.append(" Used: ").append(nonHeapUsage.getUsed() / 1_000_000).append(" MB\n"); 46 | sb.append(" Committed: ").append(nonHeapUsage.getCommitted() / 1_000_000).append(" MB\n"); 47 | sb.append(" Max: ").append(nonHeapUsage.getMax() / 1_000_000).append(" MB\n"); 48 | 49 | for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) { 50 | sb.append(" Garbage Collector - ").append(gcBean.getName()).append(":\n"); 51 | sb.append(" Collection Count: ").append(gcBean.getCollectionCount()).append("\n"); 52 | sb.append(" Collection Time: ").append(gcBean.getCollectionTime()).append(" ms\n"); 53 | } 54 | 55 | return sb.toString(); 56 | } 57 | 58 | 59 | public String getDetailedInfo() { 60 | StringBuilder sb = new StringBuilder(); 61 | 62 | long[] deadlockedThreads = threadBean.findDeadlockedThreads(); 63 | sb.append("Analysis of locks and deadlocks:\n"); 64 | if (deadlockedThreads != null) { 65 | sb.append(" Deadlocked threads:\n"); 66 | for (long threadId : deadlockedThreads) { 67 | sb.append(" Thread ID: ").append(threadId).append("\n"); 68 | } 69 | } else { 70 | sb.append(" No deadlocked threads found.\n"); 71 | } 72 | sb.append("\n"); 73 | 74 | sb.append("Application Data:\n"); 75 | sb.append(" Java Version: ").append(System.getProperty("java.version")).append("\n"); 76 | sb.append(" Java Vendor: ").append(System.getProperty("java.vendor")).append("\n"); 77 | sb.append(" JVM Version: ").append(System.getProperty("java.vm.version")).append("\n"); 78 | sb.append(" JVM Vendor: ").append(System.getProperty("java.vm.vendor")).append("\n"); 79 | sb.append(" OS: ").append(System.getProperty("os.name")).append("\n"); 80 | sb.append(" OS Version: ").append(System.getProperty("os.version")).append("\n"); 81 | sb.append("\n"); 82 | 83 | sb.append("Threads:\n"); 84 | long[] threadIds = threadBean.getAllThreadIds(); 85 | for (long threadId : threadIds) { 86 | StackTraceElement[] stackTrace = threadBean.getThreadInfo(threadId).getStackTrace(); 87 | sb.append(" Thread ID ").append(threadId).append(":\n"); 88 | for (StackTraceElement elem : stackTrace) { 89 | sb.append(" ").append(elem.toString()).append("\n"); 90 | } 91 | sb.append("\n"); 92 | } 93 | 94 | return sb.toString(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/NativeLoader.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import uk.whitedev.injector.DLLInjector; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.nio.file.Files; 9 | 10 | public class NativeLoader { 11 | public static void loadLibraryFromJar(String path, String nativeLib) throws IOException { 12 | try (InputStream is = DLLInjector.class.getResourceAsStream(path)) { 13 | if (is == null) { 14 | throw new IOException("Native library not found in JAR: " + path); 15 | } 16 | File tempFile = File.createTempFile(nativeLib, ".dll"); 17 | tempFile.deleteOnExit(); 18 | Files.copy(is, tempFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); 19 | System.load(tempFile.getAbsolutePath()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/uk/whitedev/utils/ProcessUtil.java: -------------------------------------------------------------------------------- 1 | package uk.whitedev.utils; 2 | 3 | import java.lang.management.ManagementFactory; 4 | 5 | public class ProcessUtil { 6 | public static String getProcessPid(){ 7 | String processName = ManagementFactory.getRuntimeMXBean().getName(); 8 | return processName.split("@")[0]; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/assets/cfr-0.152.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0WhiteDev/Java-Process-Inspector/6249983183545c0596f39702d39d171b56ab7318/src/main/resources/assets/cfr-0.152.jar -------------------------------------------------------------------------------- /src/main/resources/natives/DLLInjector.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0WhiteDev/Java-Process-Inspector/6249983183545c0596f39702d39d171b56ab7318/src/main/resources/natives/DLLInjector.dll -------------------------------------------------------------------------------- /src/main/resources/natives/MemoryEditor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0WhiteDev/Java-Process-Inspector/6249983183545c0596f39702d39d171b56ab7318/src/main/resources/natives/MemoryEditor.dll --------------------------------------------------------------------------------